Merge branch 'master' into greenkeeper/sinon-5.0.0
This commit is contained in:
commit
4f976853a5
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "typeorm-model-generator",
|
||||
"version": "0.2.11",
|
||||
"version": "0.2.12",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "typeorm-model-generator",
|
||||
"version": "0.2.11",
|
||||
"version": "0.2.12",
|
||||
"description": "Generates models for TypeORM from existing databases.",
|
||||
"bin": "bin/typeorm-model-generator",
|
||||
"scripts": {
|
||||
@ -39,7 +39,7 @@
|
||||
"@types/chai-subset": "^1.3.1",
|
||||
"@types/fs-extra": "^5.0.0",
|
||||
"@types/handlebars": "^4.0.36",
|
||||
"@types/mocha": "^2.2.44",
|
||||
"@types/mocha": "^5.0.0",
|
||||
"@types/mssql": "^4.0.4",
|
||||
"@types/mysql": "2.15.3",
|
||||
"@types/node": "^9.3.0",
|
||||
@ -62,7 +62,7 @@
|
||||
"husky": "^0.14.3",
|
||||
"istanbul": "^0.4.5",
|
||||
"lint-staged": "^7.0.0",
|
||||
"mocha": "^3.0.1",
|
||||
"mocha": "^5.0.5",
|
||||
"prettier": "^1.10.2",
|
||||
"remap-istanbul": "^0.11.0",
|
||||
"sinon": "^5.0.0",
|
||||
|
@ -27,7 +27,7 @@ export class Engine {
|
||||
if (dbModel.entities.length > 0) {
|
||||
this.createModelFromMetadata(dbModel);
|
||||
} else {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
"Tables not found in selected database. Skipping creation of typeorm model.",
|
||||
false
|
||||
);
|
||||
@ -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,20 +1,19 @@
|
||||
import * as data from "./../../package.json";
|
||||
export function LogFatalError(
|
||||
export function LogError(
|
||||
errText: string,
|
||||
isABug: boolean = true,
|
||||
errObject?: any
|
||||
) {
|
||||
let x = <any>data;
|
||||
console.error(errText);
|
||||
console.error(`Fatal error occured.`);
|
||||
console.error(`Error occured in typeorm-model-generator.`);
|
||||
console.error(`${x.name}@${x.version} node@${process.version}`);
|
||||
console.error(`Fatal error occured in typeorm-model-generator.`);
|
||||
console.error(
|
||||
`If this is a bug please open an issue including this log on ${
|
||||
`If you think this is a bug please open an issue including this log on ${
|
||||
x.bugs.url
|
||||
}`
|
||||
);
|
||||
if (isABug && !errObject) errObject = new Error().stack;
|
||||
if (!!errObject) console.error(errObject);
|
||||
process.abort();
|
||||
// process.abort();
|
||||
}
|
||||
|
@ -1,9 +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.toLowerCase() != entity.EntityName.toLowerCase()
|
||||
);
|
||||
let relatedTable2 = dbModel.entities.filter(
|
||||
v => v.EntityName == relations[1].relatedTable
|
||||
)[0];
|
||||
relatedTable2.Columns = relatedTable2.Columns.filter(
|
||||
v => v.name.toLowerCase() != entity.EntityName.toLowerCase()
|
||||
);
|
||||
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,
|
||||
@ -24,6 +86,7 @@ export abstract class AbstractDriver {
|
||||
sqlEscapedSchema
|
||||
);
|
||||
await this.DisconnectFromServer();
|
||||
this.FindManyToManyRelations(dbModel);
|
||||
this.FindPrimaryColumnsFromIndexes(dbModel);
|
||||
return dbModel;
|
||||
}
|
||||
@ -48,7 +111,27 @@ export abstract class AbstractDriver {
|
||||
entities: EntityInfo[],
|
||||
schema: string
|
||||
): Promise<EntityInfo[]>;
|
||||
abstract async FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel);
|
||||
|
||||
FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) {
|
||||
dbModel.entities.forEach(entity => {
|
||||
let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey);
|
||||
if (!primaryIndex) {
|
||||
TomgUtils.LogError(
|
||||
`Table ${entity.EntityName} has no PK.`,
|
||||
false
|
||||
);
|
||||
return;
|
||||
}
|
||||
entity.Columns.forEach(col => {
|
||||
if (
|
||||
primaryIndex!.columns.some(
|
||||
cIndex => cIndex.name == col.name
|
||||
)
|
||||
)
|
||||
col.isPrimary = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
abstract async DisconnectFromServer();
|
||||
|
||||
abstract async CreateDB(dbName: string);
|
||||
|
@ -10,27 +10,6 @@ import * as TomgUtils from "./../Utils";
|
||||
* MssqlDriver
|
||||
*/
|
||||
export class MssqlDriver extends AbstractDriver {
|
||||
FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) {
|
||||
dbModel.entities.forEach(entity => {
|
||||
let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey);
|
||||
if (!primaryIndex) {
|
||||
TomgUtils.LogFatalError(
|
||||
`Table ${entity.EntityName} has no PK.`,
|
||||
false
|
||||
);
|
||||
return;
|
||||
}
|
||||
entity.Columns.forEach(col => {
|
||||
if (
|
||||
primaryIndex!.columns.some(
|
||||
cIndex => cIndex.name == col.name
|
||||
)
|
||||
)
|
||||
col.isPrimary = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async GetAllTables(schema: string): Promise<EntityInfo[]> {
|
||||
let request = new MSSQL.Request(this.Connection);
|
||||
let response: {
|
||||
@ -238,7 +217,7 @@ export class MssqlDriver extends AbstractDriver {
|
||||
colInfo.ts_type = "string";
|
||||
break;
|
||||
default:
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Unknown column type: ${
|
||||
resp.DATA_TYPE
|
||||
} table name: ${
|
||||
@ -384,7 +363,7 @@ order by
|
||||
return entitity.EntityName == relationTmp.ownerTable;
|
||||
});
|
||||
if (!ownerEntity) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity model ${relationTmp.ownerTable}.`
|
||||
@ -395,7 +374,7 @@ order by
|
||||
return entitity.EntityName == relationTmp.referencedTable;
|
||||
});
|
||||
if (!referencedEntity) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity model ${relationTmp.referencedTable}.`
|
||||
@ -406,7 +385,7 @@ order by
|
||||
return column.name == relationTmp.ownerColumnsNames[0];
|
||||
});
|
||||
if (!ownerColumn) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity column ${
|
||||
@ -419,7 +398,7 @@ order by
|
||||
return column.name == relationTmp.referencedColumnsNames[0];
|
||||
});
|
||||
if (!relatedColumn) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity column ${
|
||||
@ -538,7 +517,7 @@ order by
|
||||
//Connection successfull
|
||||
resolve(true);
|
||||
} else {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
"Error connecting to MSSQL Server.",
|
||||
false,
|
||||
err.message
|
||||
|
@ -11,27 +11,6 @@ import * as TomgUtils from "./../Utils";
|
||||
export class MysqlDriver extends AbstractDriver {
|
||||
readonly EngineName: string = "MySQL";
|
||||
|
||||
FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) {
|
||||
dbModel.entities.forEach(entity => {
|
||||
let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey);
|
||||
if (!primaryIndex) {
|
||||
TomgUtils.LogFatalError(
|
||||
`Table ${entity.EntityName} has no PK.`,
|
||||
false
|
||||
);
|
||||
return;
|
||||
}
|
||||
entity.Columns.forEach(col => {
|
||||
if (
|
||||
primaryIndex!.columns.some(
|
||||
cIndex => cIndex.name == col.name
|
||||
)
|
||||
)
|
||||
col.isPrimary = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async GetAllTables(schema: string): Promise<EntityInfo[]> {
|
||||
let response = await this.ExecQuery<{
|
||||
TABLE_SCHEMA: string;
|
||||
@ -231,7 +210,7 @@ export class MysqlDriver extends AbstractDriver {
|
||||
.replace(/\'/gi, '"');
|
||||
break;
|
||||
default:
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Unknown column type: ${
|
||||
resp.DATA_TYPE
|
||||
} table name: ${
|
||||
@ -347,7 +326,7 @@ export class MysqlDriver extends AbstractDriver {
|
||||
return entitity.EntityName == relationTmp.ownerTable;
|
||||
});
|
||||
if (!ownerEntity) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity model ${relationTmp.ownerTable}.`
|
||||
@ -358,7 +337,7 @@ export class MysqlDriver extends AbstractDriver {
|
||||
return entitity.EntityName == relationTmp.referencedTable;
|
||||
});
|
||||
if (!referencedEntity) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity model ${relationTmp.referencedTable}.`
|
||||
@ -369,7 +348,7 @@ export class MysqlDriver extends AbstractDriver {
|
||||
return column.name == relationTmp.ownerColumnsNames[0];
|
||||
});
|
||||
if (!ownerColumn) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity column ${
|
||||
@ -382,7 +361,7 @@ export class MysqlDriver extends AbstractDriver {
|
||||
return column.name == relationTmp.referencedColumnsNames[0];
|
||||
});
|
||||
if (!relatedColumn) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity column ${
|
||||
@ -477,7 +456,7 @@ export class MysqlDriver extends AbstractDriver {
|
||||
//Connection successfull
|
||||
resolve(true);
|
||||
} else {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Error disconnecting to ${this.EngineName} Server.`,
|
||||
false,
|
||||
err.message
|
||||
@ -529,7 +508,7 @@ export class MysqlDriver extends AbstractDriver {
|
||||
//Connection successfull
|
||||
resolve(true);
|
||||
} else {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Error connecting to ${this.EngineName} Server.`,
|
||||
false,
|
||||
err.message
|
||||
|
@ -17,32 +17,11 @@ export class OracleDriver extends AbstractDriver {
|
||||
try {
|
||||
this.Oracle = require("oracledb");
|
||||
} catch (error) {
|
||||
TomgUtils.LogFatalError("", false, error);
|
||||
TomgUtils.LogError("", false, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) {
|
||||
dbModel.entities.forEach(entity => {
|
||||
let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey);
|
||||
if (!primaryIndex) {
|
||||
TomgUtils.LogFatalError(
|
||||
`Table ${entity.EntityName} has no PK.`,
|
||||
false
|
||||
);
|
||||
return;
|
||||
}
|
||||
entity.Columns.forEach(col => {
|
||||
if (
|
||||
primaryIndex!.columns.some(
|
||||
cIndex => cIndex.name == col.name
|
||||
)
|
||||
)
|
||||
col.isPrimary = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async GetAllTables(schema: string): Promise<EntityInfo[]> {
|
||||
let response: any[][] = (await this.Connection.execute(
|
||||
` SELECT TABLE_NAME FROM all_tables WHERE owner = (select user from dual)`
|
||||
@ -91,7 +70,7 @@ export class OracleDriver extends AbstractDriver {
|
||||
resp[5] > 0 ? resp[5] : null;
|
||||
break;
|
||||
default:
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
"Unknown column type:" + resp[4]
|
||||
);
|
||||
break;
|
||||
@ -185,7 +164,7 @@ export class OracleDriver extends AbstractDriver {
|
||||
return entitity.EntityName == relationTmp.ownerTable;
|
||||
});
|
||||
if (!ownerEntity) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity model ${relationTmp.ownerTable}.`
|
||||
@ -196,7 +175,7 @@ export class OracleDriver extends AbstractDriver {
|
||||
return entitity.EntityName == relationTmp.referencedTable;
|
||||
});
|
||||
if (!referencedEntity) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity model ${relationTmp.referencedTable}.`
|
||||
@ -207,7 +186,7 @@ export class OracleDriver extends AbstractDriver {
|
||||
return column.name == relationTmp.ownerColumnsNames[0];
|
||||
});
|
||||
if (!ownerColumn) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity column ${
|
||||
@ -220,7 +199,7 @@ export class OracleDriver extends AbstractDriver {
|
||||
return column.name == relationTmp.referencedColumnsNames[0];
|
||||
});
|
||||
if (!relatedColumn) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity column ${
|
||||
@ -337,7 +316,7 @@ export class OracleDriver extends AbstractDriver {
|
||||
that.Connection = connection;
|
||||
resolve(true);
|
||||
} else {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
"Error connecting to Oracle Server.",
|
||||
false,
|
||||
err.message
|
||||
|
@ -11,27 +11,6 @@ import * as TomgUtils from "./../Utils";
|
||||
export class PostgresDriver extends AbstractDriver {
|
||||
private Connection: PG.Client;
|
||||
|
||||
FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) {
|
||||
dbModel.entities.forEach(entity => {
|
||||
let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey);
|
||||
if (!primaryIndex) {
|
||||
TomgUtils.LogFatalError(
|
||||
`Table ${entity.EntityName} has no PK.`,
|
||||
false
|
||||
);
|
||||
return;
|
||||
}
|
||||
entity.Columns.forEach(col => {
|
||||
if (
|
||||
primaryIndex!.columns.some(
|
||||
cIndex => cIndex.name == col.name
|
||||
)
|
||||
)
|
||||
col.isPrimary = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async GetAllTables(schema: string): Promise<EntityInfo[]> {
|
||||
let response: {
|
||||
table_schema: string;
|
||||
@ -209,7 +188,7 @@ export class PostgresDriver extends AbstractDriver {
|
||||
colInfo.ts_type = "string";
|
||||
break;
|
||||
default:
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Unknown column type: ${
|
||||
resp.data_type
|
||||
} table name: ${
|
||||
@ -235,33 +214,31 @@ export class PostgresDriver extends AbstractDriver {
|
||||
is_unique: number;
|
||||
is_primary_key: number; //, is_descending_key: number//, is_included_column: number
|
||||
}[] = (await this.Connection.query(`SELECT
|
||||
c.relname AS tablename,
|
||||
i.relname as indexname,
|
||||
f.attname AS columnname,
|
||||
CASE
|
||||
WHEN ix.indisunique = true THEN '1'
|
||||
ELSE '0'
|
||||
END AS is_unique,
|
||||
CASE
|
||||
WHEN p.contype = 'p' THEN '1'
|
||||
ELSE '0'
|
||||
END AS is_primary_key
|
||||
FROM pg_attribute f
|
||||
JOIN pg_class c ON c.oid = f.attrelid
|
||||
JOIN pg_type t ON t.oid = f.atttypid
|
||||
LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum
|
||||
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
|
||||
LEFT JOIN pg_class AS g ON p.confrelid = g.oid
|
||||
LEFT JOIN pg_index AS ix ON f.attnum = ANY(ix.indkey) and c.oid = f.attrelid and c.oid = ix.indrelid
|
||||
LEFT JOIN pg_class AS i ON ix.indexrelid = i.oid
|
||||
c.relname AS tablename,
|
||||
i.relname as indexname,
|
||||
f.attname AS columnname,
|
||||
CASE
|
||||
WHEN ix.indisunique = true THEN '1'
|
||||
ELSE '0'
|
||||
END AS is_unique,
|
||||
CASE
|
||||
WHEN ix.indisprimary='true' THEN '1'
|
||||
ELSE '0'
|
||||
END AS is_primary_key
|
||||
FROM pg_attribute f
|
||||
JOIN pg_class c ON c.oid = f.attrelid
|
||||
JOIN pg_type t ON t.oid = f.atttypid
|
||||
LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum
|
||||
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
LEFT JOIN pg_index AS ix ON f.attnum = ANY(ix.indkey) and c.oid = f.attrelid and c.oid = ix.indrelid
|
||||
LEFT JOIN pg_class AS i ON ix.indexrelid = i.oid
|
||||
|
||||
WHERE c.relkind = 'r'::char
|
||||
AND n.nspname in (${schema})
|
||||
--AND c.relname = 'nodes' -- Replace with table name, or Comment this for get all tables
|
||||
AND f.attnum > 0
|
||||
AND i.oid<>0
|
||||
ORDER BY c.relname,f.attname;`)).rows;
|
||||
WHERE c.relkind = 'r'::char
|
||||
AND n.nspname in (${schema})
|
||||
--AND c.relname = 'nodes' -- Replace with table name, or Comment this for get all tables
|
||||
AND f.attnum > 0
|
||||
AND i.oid<>0
|
||||
ORDER BY c.relname,f.attname;`)).rows;
|
||||
entities.forEach(ent => {
|
||||
response
|
||||
.filter(filterVal => {
|
||||
@ -373,7 +350,7 @@ export class PostgresDriver extends AbstractDriver {
|
||||
return entitity.EntityName == relationTmp.ownerTable;
|
||||
});
|
||||
if (!ownerEntity) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity model ${relationTmp.ownerTable}.`
|
||||
@ -384,7 +361,7 @@ export class PostgresDriver extends AbstractDriver {
|
||||
return entitity.EntityName == relationTmp.referencedTable;
|
||||
});
|
||||
if (!referencedEntity) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity model ${relationTmp.referencedTable}.`
|
||||
@ -395,7 +372,7 @@ export class PostgresDriver extends AbstractDriver {
|
||||
return column.name == relationTmp.ownerColumnsNames[0];
|
||||
});
|
||||
if (!ownerColumn) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity column ${
|
||||
@ -408,7 +385,7 @@ export class PostgresDriver extends AbstractDriver {
|
||||
return column.name == relationTmp.referencedColumnsNames[0];
|
||||
});
|
||||
if (!relatedColumn) {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
`Relation between tables ${relationTmp.ownerTable} and ${
|
||||
relationTmp.referencedTable
|
||||
} didn't found entity column ${
|
||||
@ -504,7 +481,7 @@ export class PostgresDriver extends AbstractDriver {
|
||||
//Connection successfull
|
||||
resolve(true);
|
||||
} else {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
"Error connecting to Postgres Server.",
|
||||
false,
|
||||
err.message
|
||||
@ -540,7 +517,7 @@ export class PostgresDriver extends AbstractDriver {
|
||||
//Connection successfull
|
||||
resolve(true);
|
||||
} else {
|
||||
TomgUtils.LogFatalError(
|
||||
TomgUtils.LogError(
|
||||
"Error connecting to Postgres Server.",
|
||||
false,
|
||||
err.message
|
||||
|
@ -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}}
|
||||
|
@ -107,7 +107,7 @@ switch (argv.e) {
|
||||
standardPort = 1521;
|
||||
break;
|
||||
default:
|
||||
TomgUtils.LogFatalError("Database engine not recognized.", false);
|
||||
TomgUtils.LogError("Database engine not recognized.", false);
|
||||
throw new Error("Database engine not recognized.");
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,4 @@
|
||||
import { EntityInfo } from "./EntityInfo";
|
||||
export class DatabaseModel {
|
||||
entities: EntityInfo[];
|
||||
config: {
|
||||
cascadeInsert: boolean;
|
||||
cascadeUpdate: boolean;
|
||||
cascadeRemove: boolean;
|
||||
};
|
||||
|
||||
//TODO:check if unused
|
||||
relationImports(): any {
|
||||
let that = this;
|
||||
return function(text, render) {
|
||||
if ("l" != render(text))
|
||||
return `import {{curly true}}{{toEntityName ${render(
|
||||
text
|
||||
)}}}{{curly false}} from "./{{ ${render(
|
||||
"toFileName" + text
|
||||
)}}}`;
|
||||
else return "";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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