many to many relations
This commit is contained in:
parent
d46738e932
commit
f7e7cdd649
@ -160,6 +160,32 @@ export class Engine {
|
||||
Handlebars.registerHelper("toLowerCase", str => {
|
||||
return str.toLowerCase();
|
||||
});
|
||||
Handlebars.registerHelper({
|
||||
eq: function(v1, v2) {
|
||||
return v1 === v2;
|
||||
},
|
||||
ne: function(v1, v2) {
|
||||
return v1 !== v2;
|
||||
},
|
||||
lt: function(v1, v2) {
|
||||
return v1 < v2;
|
||||
},
|
||||
gt: function(v1, v2) {
|
||||
return v1 > v2;
|
||||
},
|
||||
lte: function(v1, v2) {
|
||||
return v1 <= v2;
|
||||
},
|
||||
gte: function(v1, v2) {
|
||||
return v1 >= v2;
|
||||
},
|
||||
and: function(v1, v2) {
|
||||
return v1 && v2;
|
||||
},
|
||||
or: function(v1, v2) {
|
||||
return v1 || v2;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//TODO:Move to mustache template file
|
||||
|
@ -1,10 +1,71 @@
|
||||
import { EntityInfo } from "./../models/EntityInfo";
|
||||
import { DatabaseModel } from "./../models/DatabaseModel";
|
||||
import * as TomgUtils from "./../Utils";
|
||||
import { RelationInfo } from "../models/RelationInfo";
|
||||
import { ColumnInfo } from "../models/ColumnInfo";
|
||||
import { ManyToMany } from "typeorm";
|
||||
/**
|
||||
* AbstractDriver
|
||||
*/
|
||||
export abstract class AbstractDriver {
|
||||
FindManyToManyRelations(dbModel: DatabaseModel) {
|
||||
let manyToManyEntities = dbModel.entities.filter(entity => {
|
||||
return (
|
||||
entity.Columns.filter(column => {
|
||||
return (
|
||||
column.relations.length == 1 &&
|
||||
!column.relations[0].isOneToMany &&
|
||||
column.relations[0].isOwner
|
||||
);
|
||||
}).length == entity.Columns.length
|
||||
);
|
||||
});
|
||||
manyToManyEntities.map(entity => {
|
||||
let relations: RelationInfo[] = [];
|
||||
relations = entity.Columns.reduce((prev: RelationInfo[], curr) => {
|
||||
return prev.concat(curr.relations);
|
||||
}, relations);
|
||||
//TODO: Composed keys
|
||||
if (relations.length == 2) {
|
||||
let relatedTable1 = dbModel.entities.filter(
|
||||
v => v.EntityName == relations[0].relatedTable
|
||||
)[0];
|
||||
relatedTable1.Columns = relatedTable1.Columns.filter(
|
||||
v => v.name != entity.EntityName
|
||||
);
|
||||
let relatedTable2 = dbModel.entities.filter(
|
||||
v => v.EntityName == relations[1].relatedTable
|
||||
)[0];
|
||||
relatedTable2.Columns = relatedTable2.Columns.filter(
|
||||
v => v.name != entity.EntityName
|
||||
);
|
||||
dbModel.entities = dbModel.entities.filter(ent => {
|
||||
return ent.EntityName != entity.EntityName;
|
||||
});
|
||||
|
||||
let column1 = new ColumnInfo();
|
||||
column1.name = relations[1].relatedTable;
|
||||
let col1Rel = new RelationInfo();
|
||||
col1Rel.relatedTable = relations[1].relatedTable;
|
||||
col1Rel.relatedColumn = relations[1].relatedTable;
|
||||
col1Rel.relationType = "ManyToMany";
|
||||
col1Rel.isOwner = true;
|
||||
col1Rel.ownerColumn = relations[0].relatedTable;
|
||||
column1.relations.push(col1Rel);
|
||||
relatedTable1.Columns.push(column1);
|
||||
|
||||
let column2 = new ColumnInfo();
|
||||
column2.name = relations[0].relatedTable;
|
||||
let col2Rel = new RelationInfo();
|
||||
col2Rel.relatedTable = relations[0].relatedTable;
|
||||
col2Rel.relatedColumn = relations[1].relatedTable;
|
||||
col2Rel.relationType = "ManyToMany";
|
||||
col2Rel.isOwner = false;
|
||||
column2.relations.push(col2Rel);
|
||||
relatedTable2.Columns.push(column2);
|
||||
}
|
||||
});
|
||||
}
|
||||
async GetDataFromServer(
|
||||
database: string,
|
||||
server: string,
|
||||
@ -25,6 +86,7 @@ export abstract class AbstractDriver {
|
||||
sqlEscapedSchema
|
||||
);
|
||||
await this.DisconnectFromServer();
|
||||
this.FindManyToManyRelations(dbModel);
|
||||
this.FindPrimaryColumnsFromIndexes(dbModel);
|
||||
return dbModel;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, JoinColumn} from "typeorm";
|
||||
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm";
|
||||
{{relationImports}}{{#each UniqueImports}}import {{curly true}}{{toEntityName this}}{{curly false}} from "./{{toFileName this}}";
|
||||
{{/each}}
|
||||
|
||||
@ -23,8 +23,8 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Joi
|
||||
{{toPropertyName name}}:{{ts_type}};
|
||||
{{/relations}}{{#relations}}
|
||||
@{{relationType}}(type=>{{toEntityName relatedTable}}, {{toPropertyName ../name}}=>{{toPropertyName ../name}}.{{#if isOwner}}{{toPropertyName ownerColumn}}{{else}}{{toPropertyName relatedColumn}}{{/if}}){{#isOwner}}
|
||||
@JoinColumn({ name:'{{ ../name}}'}){{/isOwner}}
|
||||
{{#if isOneToMany}}{{toPropertyName ../name}}:{{toEntityName relatedTable}}[];
|
||||
{{#if isManyToMany}}@JoinTable(){{else}}@JoinColumn({ name:'{{ ../name}}'}){{/if}}{{/isOwner}}
|
||||
{{#if (or isOneToMany isManyToMany)}}{{toPropertyName ../name}}:{{toEntityName relatedTable}}[];
|
||||
{{else}}{{toPropertyName ../name}}:{{toEntityName relatedTable}};
|
||||
{{/if}}{{/relations}}
|
||||
{{/Columns}}
|
||||
|
@ -2,7 +2,7 @@ export class RelationInfo {
|
||||
[x: string]: any;
|
||||
|
||||
isOwner: boolean;
|
||||
relationType: "OneToOne" | "OneToMany" | "ManyToOne";
|
||||
relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany";
|
||||
relatedTable: string;
|
||||
relatedColumn: string;
|
||||
ownerTable: string;
|
||||
@ -13,4 +13,7 @@ export class RelationInfo {
|
||||
get isOneToMany(): boolean {
|
||||
return this.relationType == "OneToMany";
|
||||
}
|
||||
get isManyToMany(): boolean {
|
||||
return this.relationType == "ManyToMany";
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm";
|
||||
import {PostDetails} from "./PostDetails";
|
||||
import {PostCategory} from "./PostCategory";
|
||||
import {PostAuthor} from "./PostAuthor";
|
||||
import {PostInformation} from "./PostInformation";
|
||||
import {PostImage} from "./PostImage";
|
||||
import {PostMetadata} from "./PostMetadata";
|
||||
|
||||
@Entity("Post")
|
||||
export class Post {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
@Column()
|
||||
text: string;
|
||||
|
||||
// post has relation with category, however inverse relation is not set (category does not have relation with post set)
|
||||
@ManyToMany(type => PostCategory, {
|
||||
cascade: true
|
||||
})
|
||||
@JoinTable()
|
||||
PostCategory: PostCategory[];
|
||||
|
||||
// post has relation with details. cascade inserts here means if new PostDetails instance will be set to this
|
||||
// relation it will be inserted automatically to the db when you save this Post entity
|
||||
@ManyToMany(type => PostDetails, details => details.Post, {
|
||||
cascade: true
|
||||
})
|
||||
@JoinTable()
|
||||
PostDetails: PostDetails[];
|
||||
|
||||
// post has relation with details. cascade update here means if new PostDetail instance will be set to this relation
|
||||
// it will be inserted automatically to the db when you save this Post entity
|
||||
@ManyToMany(type => PostImage, image => image.Post, {
|
||||
cascade: true
|
||||
})
|
||||
@JoinTable()
|
||||
PostImage: PostImage[];
|
||||
|
||||
// post has relation with details. cascade update here means if new PostDetail instance will be set to this relation
|
||||
// it will be inserted automatically to the db when you save this Post entity
|
||||
@ManyToMany(type => PostMetadata, metadata => metadata.Post)
|
||||
@JoinTable()
|
||||
PostMetadata: PostMetadata[];
|
||||
|
||||
// post has relation with details. full cascades here
|
||||
@ManyToMany(type => PostInformation, information => information.Post, {
|
||||
cascade: true
|
||||
})
|
||||
@JoinTable()
|
||||
PostInformation: PostInformation[];
|
||||
|
||||
// post has relation with details. not cascades here. means cannot be persisted, updated or removed
|
||||
@ManyToMany(type => PostAuthor, author => author.Post)
|
||||
@JoinTable()
|
||||
PostAuthor: PostAuthor[];
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm";
|
||||
import {Post} from "./Post";
|
||||
|
||||
@Entity("PostAuthor")
|
||||
export class PostAuthor {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostAuthor)
|
||||
Post: Post[];
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm";
|
||||
|
||||
@Entity("PostCategory")
|
||||
export class PostCategory {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm";
|
||||
import {Post} from "./Post";
|
||||
|
||||
@Entity("PostDetails")
|
||||
export class PostDetails {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
authorName: string;
|
||||
|
||||
@Column()
|
||||
comment: string;
|
||||
|
||||
@Column()
|
||||
metadata: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostDetails)
|
||||
Post: Post[];
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm";
|
||||
import {Post} from "./Post";
|
||||
|
||||
@Entity("PostImage")
|
||||
export class PostImage {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
url: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostImage)
|
||||
Post: Post[];
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm";
|
||||
import {Post} from "./Post";
|
||||
|
||||
@Entity("PostInformation")
|
||||
export class PostInformation {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
text: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostInformation)
|
||||
Post: Post[];
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm";
|
||||
import {Post} from "./Post";
|
||||
|
||||
@Entity("PostMetadata")
|
||||
export class PostMetadata {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
description: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostMetadata)
|
||||
Post: Post[];
|
||||
|
||||
}
|
@ -5,15 +5,15 @@ export class EntityFileToJson {
|
||||
let decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')'))
|
||||
|
||||
if (decoratorParameters.length > 0) {
|
||||
if (decoratorParameters[0] == '"' && decoratorParameters.endsWith('"')) {
|
||||
if (decoratorParameters[0] == '"' && decoratorParameters.endsWith('"')) {
|
||||
|
||||
} else {
|
||||
let badJSON = decoratorParameters.substring(decoratorParameters.indexOf(',') + 1).trim()
|
||||
if (badJSON.lastIndexOf(',') == badJSON.length - 3) {
|
||||
badJSON = badJSON.slice(0, badJSON.length - 3) + badJSON[badJSON.length - 2] + badJSON[badJSON.length - 1]
|
||||
}
|
||||
ent.entityOptions = JSON.parse(badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '))
|
||||
} else {
|
||||
let badJSON = decoratorParameters.substring(decoratorParameters.indexOf(',') + 1).trim()
|
||||
if (badJSON.lastIndexOf(',') == badJSON.length - 3) {
|
||||
badJSON = badJSON.slice(0, badJSON.length - 3) + badJSON[badJSON.length - 2] + badJSON[badJSON.length - 1]
|
||||
}
|
||||
ent.entityOptions = JSON.parse(badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '))
|
||||
}
|
||||
}
|
||||
}
|
||||
getColumnOptionsAndType(trimmedLine: string, col: EntityColumn) {
|
||||
@ -126,8 +126,8 @@ export class EntityFileToJson {
|
||||
priorPartOfMultilineStatement = trimmedLine;
|
||||
continue;
|
||||
} else {
|
||||
let options = trimmedLine.substring(trimmedLine.lastIndexOf('{'), trimmedLine.lastIndexOf('}')+1).trim().toLowerCase()
|
||||
this.getEntityOptions(trimmedLine,retVal);
|
||||
let options = trimmedLine.substring(trimmedLine.lastIndexOf('{'), trimmedLine.lastIndexOf('}') + 1).trim().toLowerCase()
|
||||
this.getEntityOptions(trimmedLine, retVal);
|
||||
continue;
|
||||
}
|
||||
} else if (trimmedLine.startsWith('export class')) {
|
||||
@ -225,6 +225,18 @@ export class EntityFileToJson {
|
||||
column.relationType = "OneToMany"
|
||||
continue;
|
||||
}
|
||||
} else if (trimmedLine.startsWith('@ManyToMany')) {
|
||||
if (this.isPartOfMultilineStatement(trimmedLine)) {
|
||||
isMultilineStatement = true;
|
||||
priorPartOfMultilineStatement = trimmedLine;
|
||||
continue;
|
||||
} else {
|
||||
isMultilineStatement = false;
|
||||
let column = new EntityColumn()
|
||||
retVal.columns.push(column)
|
||||
column.relationType = "ManyToMany"
|
||||
continue;
|
||||
}
|
||||
} else if (trimmedLine.startsWith('@OneToOne')) {
|
||||
if (this.isPartOfMultilineStatement(trimmedLine)) {
|
||||
isMultilineStatement = true;
|
||||
@ -247,6 +259,16 @@ export class EntityFileToJson {
|
||||
retVal.columns[retVal.columns.length - 1].isOwnerOfRelation = true;
|
||||
continue;
|
||||
}
|
||||
} else if (trimmedLine.startsWith('@JoinTable')) {
|
||||
if (this.isPartOfMultilineStatement(trimmedLine)) {
|
||||
isMultilineStatement = true;
|
||||
priorPartOfMultilineStatement = trimmedLine;
|
||||
continue;
|
||||
} else {
|
||||
isMultilineStatement = false;
|
||||
retVal.columns[retVal.columns.length - 1].isOwnerOfRelation = true;
|
||||
continue;
|
||||
}
|
||||
} else if (trimmedLine.startsWith('@Index')) {
|
||||
if (this.isPartOfMultilineStatement(trimmedLine)) {
|
||||
isMultilineStatement = true;
|
||||
@ -332,7 +354,7 @@ class EntityColumn {
|
||||
columnName: string
|
||||
columnTypes: string[] = []
|
||||
columnOptions: any = {}
|
||||
relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "None" = "None"
|
||||
relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany" | "None" = "None"
|
||||
isOwnerOfRelation: boolean = false;
|
||||
}
|
||||
class EntityIndex {
|
||||
|
Loading…
Reference in New Issue
Block a user