partial RelationId implementation

This commit is contained in:
Kononnable 2019-10-09 23:08:25 +02:00
parent 102ff614f6
commit 0936f81e3c
9 changed files with 136 additions and 84 deletions

View File

@ -46,7 +46,11 @@ export async function createModelFromDatabase(
connectionOptions: IConnectionOptions,
generationOptions: IGenerationOptions
) {
let dbModel = await dataCollectionPhase(driver, connectionOptions);
let dbModel = await dataCollectionPhase(
driver,
connectionOptions,
generationOptions
);
if (dbModel.length === 0) {
TomgUtils.LogError(
"Tables not found in selected database. Skipping creation of typeorm model.",
@ -123,9 +127,10 @@ export async function createModelFromDatabase(
}
export async function dataCollectionPhase(
driver: AbstractDriver,
connectionOptions: IConnectionOptions
connectionOptions: IConnectionOptions,
generationOptions: IGenerationOptions
) {
return driver.GetDataFromServer(connectionOptions);
return driver.GetDataFromServer(connectionOptions, generationOptions);
}
export function modelCustomizationPhase(

View File

@ -37,6 +37,9 @@ export function findNameForNewField(
) &&
entity.relations.every(
v => v.fieldName.toLowerCase() !== fieldName.toLowerCase()
) &&
entity.relationIds.every(
v => v.fieldName.toLowerCase() !== fieldName.toLowerCase()
)) ||
(columnOldName &&
columnOldName.toLowerCase() === fieldName.toLowerCase());

View File

@ -13,6 +13,8 @@ import IConnectionOptions from "../IConnectionOptions";
import { Entity } from "../models/Entity";
import { RelationInternal } from "../models/RelationInternal";
import { Relation } from "../models/Relation";
import IGenerationOptions from "../IGenerationOptions";
import { Column } from "../models/Column";
export default abstract class AbstractDriver {
public abstract standardPort: number;
@ -175,7 +177,8 @@ export default abstract class AbstractDriver {
}
public async GetDataFromServer(
connectionOptions: IConnectionOptions
connectionOptions: IConnectionOptions,
generationOptions: IGenerationOptions
): Promise<Entity[]> {
let dbModel = [] as Entity[];
await this.ConnectToServer(connectionOptions);
@ -200,7 +203,8 @@ export default abstract class AbstractDriver {
dbModel = await this.GetRelations(
dbModel,
sqlEscapedSchema,
connectionOptions.databaseName
connectionOptions.databaseName,
generationOptions
);
await this.DisconnectFromServer();
dbModel = AbstractDriver.FindManyToManyRelations(dbModel);
@ -234,6 +238,7 @@ export default abstract class AbstractDriver {
columns: [],
indices: [],
relations: [],
relationIds: [],
sqlName: val.TABLE_NAME,
tscName: val.TABLE_NAME,
database: dbNames.includes(",") ? val.DB_NAME : "",
@ -246,7 +251,8 @@ export default abstract class AbstractDriver {
public static GetRelationsFromRelationTempInfo(
relationsTemp: RelationInternal[],
entities: Entity[]
entities: Entity[],
generationOptions: IGenerationOptions
) {
relationsTemp.forEach(relationTmp => {
if (relationTmp.ownerColumns.length > 1) {
@ -298,8 +304,8 @@ export default abstract class AbstractDriver {
return;
}
let ownerRelation: Relation | undefined;
let relatedRelation: Relation | undefined;
const ownerColumns: Column[] = [];
const relatedColumns: Column[] = [];
for (
let relationColumnIndex = 0;
relationColumnIndex < relationTmp.ownerColumns.length;
@ -327,77 +333,91 @@ export default abstract class AbstractDriver {
);
return;
}
let isOneToMany: boolean;
isOneToMany = false;
const index = ownerEntity.indices.find(
ind =>
ind.options.unique &&
ind.columns.length === 1 &&
ind.columns[0] === ownerColumn!.tscName
);
isOneToMany = !index;
if (true) {
// TODO: RelationId
ownerEntity.columns = ownerEntity.columns.filter(
v =>
!relationTmp.ownerColumns.some(
u => u === v.tscName
) || v.primary
);
relationTmp.relatedTable.columns = relationTmp.relatedTable.columns.filter(
v =>
!relationTmp.relatedColumns.some(
u => u === v.tscName
) || v.primary
);
}
let fieldName = "";
if (relationTmp.ownerColumns.length === 1) {
fieldName = TomgUtils.findNameForNewField(
ownerColumn.tscName,
ownerEntity
);
} else {
fieldName = TomgUtils.findNameForNewField(
relationTmp.relatedTable.tscName,
ownerEntity
);
}
ownerRelation = {
fieldName,
relatedField: TomgUtils.findNameForNewField(
relationTmp.ownerTable.tscName,
relationTmp.relatedTable
),
relationOptions: {
onDelete: relationTmp.onDelete,
onUpdate: relationTmp.onUpdate
},
joinColumnOptions: relationTmp.ownerColumns.map(
(v, idx) => {
const retVal: JoinColumnOptions = {
name: v,
referencedColumnName:
relationTmp.relatedColumns[idx]
};
return retVal;
}
),
relatedTable: relationTmp.relatedTable.tscName,
relationType: isOneToMany ? "ManyToOne" : "OneToOne"
};
relatedRelation = {
fieldName: ownerRelation.relatedField,
relatedField: ownerRelation.fieldName,
relatedTable: relationTmp.ownerTable.tscName,
// relationOptions: ownerRelation.relationOptions,
relationType: isOneToMany ? "OneToMany" : "OneToOne"
};
ownerColumns.push(ownerColumn);
relatedColumns.push(relatedColumn);
}
let isOneToMany: boolean;
isOneToMany = false;
const index = ownerEntity.indices.find(
ind =>
ind.options.unique &&
ind.columns.length === ownerColumns.length &&
ownerColumns.every(ownerColumn =>
ind.columns.some(col => col === ownerColumn.tscName)
)
);
isOneToMany = !index;
// TODO: RelationId
ownerEntity.columns = ownerEntity.columns.filter(
v =>
!relationTmp.ownerColumns.some(u => u === v.tscName) ||
v.primary
);
relationTmp.relatedTable.columns = relationTmp.relatedTable.columns.filter(
v =>
!relationTmp.relatedColumns.some(u => u === v.tscName) ||
v.primary
);
let fieldName = "";
if (ownerColumns.length === 1) {
fieldName = TomgUtils.findNameForNewField(
ownerColumns[0].tscName,
ownerEntity
);
} else {
fieldName = TomgUtils.findNameForNewField(
relationTmp.relatedTable.tscName,
ownerEntity
);
}
const ownerRelation: Relation = {
fieldName,
relatedField: TomgUtils.findNameForNewField(
relationTmp.ownerTable.tscName,
relationTmp.relatedTable
),
relationOptions: {
onDelete: relationTmp.onDelete,
onUpdate: relationTmp.onUpdate
},
joinColumnOptions: relationTmp.ownerColumns.map((v, idx) => {
const retVal: JoinColumnOptions = {
name: v,
referencedColumnName: relationTmp.relatedColumns[idx]
};
return retVal;
}),
relatedTable: relationTmp.relatedTable.tscName,
relationType: isOneToMany ? "ManyToOne" : "OneToOne"
};
const relatedRelation: Relation = {
fieldName: ownerRelation.relatedField,
relatedField: ownerRelation.fieldName,
relatedTable: relationTmp.ownerTable.tscName,
// relationOptions: ownerRelation.relationOptions,
relationType: isOneToMany ? "OneToMany" : "OneToOne"
};
ownerEntity.relations.push(ownerRelation);
relationTmp.relatedTable.relations.push(relatedRelation);
if (generationOptions.relationIds && ownerColumns.length === 1) {
let relationIdFieldName = "";
relationIdFieldName = TomgUtils.findNameForNewField(
ownerColumns[0].tscName,
ownerEntity
);
ownerEntity.relationIds.push({
fieldName: relationIdFieldName, // TODO: generate name without number(naming strategy)
fieldType: isOneToMany
? `${ownerColumns[0].tscType}[]`
: ownerColumns[0].tscType,
relationField: ownerRelation.fieldName // TODO: naming strategy
});
// TODO: RelationId on ManyToMany
}
if (ownerRelation) ownerEntity.relations.push(ownerRelation);
if (relatedRelation)
relationTmp.relatedTable.relations.push(relatedRelation);
});
return entities;
}
@ -417,7 +437,8 @@ export default abstract class AbstractDriver {
public abstract async GetRelations(
entities: Entity[],
schema: string,
dbNames: string
dbNames: string,
generationOptions: IGenerationOptions
): Promise<Entity[]>;
public static FindPrimaryColumnsFromIndexes(dbModel: Entity[]) {

View File

@ -14,6 +14,7 @@ import { Entity } from "../models/Entity";
import { Column } from "../models/Column";
import { Index } from "../models/Index";
import { RelationInternal } from "../models/RelationInternal";
import IGenerationOptions from "../IGenerationOptions";
export default class MysqlDriver extends AbstractDriver {
public defaultValues: DataTypeDefaults = new TypeormDriver.MysqlDriver({
@ -316,7 +317,8 @@ export default class MysqlDriver extends AbstractDriver {
public async GetRelations(
entities: Entity[],
schema: string,
dbNames: string
dbNames: string,
generationOptions: IGenerationOptions
): Promise<Entity[]> {
const response = await this.ExecQuery<{
TableWithForeignKey: string;
@ -385,7 +387,8 @@ export default class MysqlDriver extends AbstractDriver {
const retVal = MysqlDriver.GetRelationsFromRelationTempInfo(
relationsTemp,
entities
entities,
generationOptions
);
return retVal;
}

View File

@ -44,6 +44,7 @@ export default class SqliteDriver extends AbstractDriver {
columns: [],
indices: [],
relations: [],
relationIds: [],
sqlName: val.tbl_name,
tscName: val.tbl_name,
fileImports: []

View File

@ -15,6 +15,11 @@ import { {{toEntityName .}} } from './{{toFileName .}}'
{{#if joinTableOptions}}@JoinTable({ {{json joinTableOptions}} }){{/if}}
{{toPropertyName fieldName}}:{{toRelation (toEntityName relatedTable) relationType}};
{{/inline}}
{{#*inline "RelationId"}}
@RelationId(({{toPropertyName entityName}}:{{toEntityName entityName}})=>{{toPropertyName entityName}}.{{toPropertyName relationField}})
{{toPropertyName fieldName}}:{{fieldType}};
{{/inline}}
{{#*inline "Entity"}}
{{#indices}}{{> Index}}{{/indices~}}
@ -23,6 +28,7 @@ export class {{toEntityName tscName}} {
{{#columns}}{{> Column}}{{/columns~}}
{{#relations}}{{> Relation}}{{/relations~}}
{{#relationIds}}{{> RelationId entityName=../tscName}}{{/relationIds~}}
}
{{/inline}}

View File

@ -1,6 +1,7 @@
import { Column } from "./Column";
import { Relation } from "./Relation";
import { Index } from "./Index";
import { RelationId } from "./RelationId";
export type Entity = {
sqlName: string;
@ -10,6 +11,7 @@ export type Entity = {
schema?: string;
columns: Column[];
relationIds: RelationId[];
relations: Relation[];
indices: Index[];
fileImports: string[];

5
src/models/RelationId.ts Normal file
View File

@ -0,0 +1,5 @@
export type RelationId = {
fieldName: string;
fieldType: string;
relationField: string;
};

View File

@ -94,14 +94,16 @@ function runTestForMultipleDrivers(
driver,
Object.assign(connectionOptions, {
databaseName: "db1,db2"
})
}),
generationOptions
);
break;
default:
dbModel = await dataCollectionPhase(
driver,
connectionOptions
connectionOptions,
generationOptions
);
break;
}
@ -160,7 +162,11 @@ async function runTest(
resultsPath,
filesOrgPathTS
} = await prepareTestRuns(testPartialPath, dbDriver, dbDriver);
let dbModel = await dataCollectionPhase(driver, connectionOptions);
let dbModel = await dataCollectionPhase(
driver,
connectionOptions,
generationOptions
);
dbModel = modelCustomizationPhase(
dbModel,
generationOptions,