Merge branch 'master' into greenkeeper/@types/mysql-2.15.5
This commit is contained in:
commit
5f276fe776
14
.travis.yml
14
.travis.yml
@ -1,6 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
#- stable
|
||||
- stable
|
||||
- 8
|
||||
- 6
|
||||
sudo: required
|
||||
@ -8,7 +8,7 @@ services:
|
||||
- docker
|
||||
env:
|
||||
matrix:
|
||||
- POSTGRES_Skip=0 POSTGRES_Host=localhost POSTGRES_Port=5432 POSTGRES_Username=postgres
|
||||
- POSTGRES_Skip=1 POSTGRES_Host=localhost POSTGRES_Port=5432 POSTGRES_Username=postgres
|
||||
POSTGRES_Password=!Passw0rd POSTGRES_Database=typeorm_mg POSTGRES_SSL=0 MYSQL_Skip=0
|
||||
MYSQL_Host=localhost MYSQL_Port=3306 MYSQL_Username=root MYSQL_Password=!Passw0rd
|
||||
MYSQL_Database=typeorm_mg MYSQL_SSL=1 MARIADB_Skip=0 MARIADB_Host=localhost MARIADB_Port=3307
|
||||
@ -33,17 +33,21 @@ before_install:
|
||||
- if [ -z "$DOCKER_USERNAME" ]; then mv docker-compose-without-login.yml docker-compose.yml; fi
|
||||
- if [ -z "$DOCKER_USERNAME" ]; then export ORACLE_Skip=1; fi
|
||||
- docker-compose up -d
|
||||
- mkdir /opt/oracle
|
||||
- if [ -n "$DOCKER_USERNAME" ]; then docker cp typeorm-mg-oracle-client:/usr/lib/oracle/12.2/client64/lib /opt/oracle/instantclient_12_2; fi
|
||||
- export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2:$LD_LIBRARY_PATH
|
||||
- npm install -g npm@5
|
||||
- npm install -g greenkeeper-lockfile@1
|
||||
- mkdir /opt/oracle
|
||||
install:
|
||||
- case $TRAVIS_BRANCH in greenkeeper*) npm i;; *) npm ci;; esac;
|
||||
before_script:
|
||||
- if [ -n "$DOCKER_USERNAME" ]; then npm i oracledb --no-save; docker cp typeorm-mg-oracle-client:/usr/lib/oracle/12.2/client64/lib /opt/oracle/instantclient_12_2; fi
|
||||
- export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2:$LD_LIBRARY_PATH
|
||||
- greenkeeper-lockfile-update
|
||||
- typings install
|
||||
- npm link typescript
|
||||
- tsc
|
||||
- sleep 180
|
||||
- docker logs typeorm-mg-postgres
|
||||
|
||||
after_script:
|
||||
- greenkeeper-lockfile-upload
|
||||
dd:
|
||||
|
@ -21,6 +21,9 @@ To install module globally simply type `npm i -g typeorm-model-generator` in you
|
||||
### Npx way
|
||||
Thanks to npx you can use npm modules without polluting global installs. So nothing to do here :)
|
||||
>To use `npx` you need to use npm at version at least 5.2.0. Try updating your npm by `npm i -g npm`
|
||||
### Database drivers
|
||||
All database drivers except oracle are installed by default. To use typeorm-model-generator with oracle databese you need to install driver with `npm i oracledb` and configure [oracle install client](http://www.oracle.com/technetwork/database/database-technologies/instant-client/overview/index.html) on your machine.
|
||||
|
||||
## Usage
|
||||
|
||||
```shell
|
||||
@ -53,6 +56,8 @@ Options:
|
||||
--cp, --case-property Convert property names to specified case
|
||||
[choices: "pascal", "camel", "none"] [default: "none"]
|
||||
--lazy Generate lazy relations [boolean] [default: false]
|
||||
--namingStrategy Use custom naming strategy
|
||||
--relationIds Generate RelationId fields [boolean] [default: false]
|
||||
--generateConstructor Generate constructor allowing partial initialization
|
||||
[boolean] [default: false]
|
||||
```
|
||||
@ -85,3 +90,7 @@ Options:
|
||||
```
|
||||
npx typeorm-model-generator -d "Z:\sqlite.db" -e sqlite -o .
|
||||
````
|
||||
## Naming strategy
|
||||
If you want to generate custom names for properties in generated entities you need to use custom naming strategy. You need to create your own version of [NamingStrategy](https://github.com/Kononnable/typeorm-model-generator/blob/master/src/NamingStrategy.ts) and pass it as command parameter.
|
||||
|
||||
```typeorm-model-generator -d typeorm_mg --namingStrategy=./NamingStrategy -e sqlite -db /tmp/sqliteto.db```
|
||||
|
9
changelog.md
Normal file
9
changelog.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## 0.2.17
|
||||
|
||||
* added support for relationId fields
|
||||
* added support for custom naming entity fields
|
||||
* removed oracledb from dependencies
|
||||
* generating nullable column types for nullable columns
|
@ -24,6 +24,7 @@ gulp.task('clean', function () {
|
||||
gulp.task('prettier', function () {
|
||||
return gulp.src('.prettierrc')
|
||||
.pipe(shell(['prettier ./src/**/*.ts --write']))
|
||||
.pipe(shell(['prettier ./src/*.ts --write']))
|
||||
});
|
||||
|
||||
gulp.task('pre-commit', ['prettier'], function () {
|
||||
|
3124
package-lock.json
generated
3124
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "typeorm-model-generator",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"description": "Generates models for TypeORM from existing databases.",
|
||||
"bin": "bin/typeorm-model-generator",
|
||||
"scripts": {
|
||||
@ -25,7 +25,6 @@
|
||||
"handlebars": "^4.0.11",
|
||||
"mssql": "^4.0.4",
|
||||
"mysql": "^2.15.0",
|
||||
"oracledb": "^2.2.0",
|
||||
"pg": "^7.4.0",
|
||||
"reflect-metadata": "^0.1.10",
|
||||
"typeorm": "^0.2.4",
|
||||
|
14
src/AbstractNamingStrategy.ts
Normal file
14
src/AbstractNamingStrategy.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { RelationInfo } from "./models/RelationInfo";
|
||||
import { DatabaseModel } from "./models/DatabaseModel";
|
||||
|
||||
export abstract class AbstractNamingStrategy {
|
||||
abstract relationName(
|
||||
columnName: string,
|
||||
relation: RelationInfo,
|
||||
dbModel: DatabaseModel
|
||||
): string;
|
||||
|
||||
abstract entityName(entityName: string): string;
|
||||
|
||||
abstract columnName(columnName: string): string;
|
||||
}
|
@ -5,6 +5,7 @@ import fs = require("fs");
|
||||
import path = require("path");
|
||||
import * as TomgUtils from "./Utils";
|
||||
import changeCase = require("change-case");
|
||||
import { AbstractNamingStrategy } from "./AbstractNamingStrategy";
|
||||
|
||||
export class Engine {
|
||||
constructor(
|
||||
@ -20,7 +21,9 @@ export class Engine {
|
||||
this.Options.user,
|
||||
this.Options.password,
|
||||
this.Options.schemaName,
|
||||
this.Options.ssl
|
||||
this.Options.ssl,
|
||||
this.Options.namingStrategy,
|
||||
this.Options.relationIds
|
||||
);
|
||||
if (dbModel.entities.length > 0) {
|
||||
this.createModelFromMetadata(dbModel);
|
||||
@ -39,7 +42,9 @@ export class Engine {
|
||||
user: string,
|
||||
password: string,
|
||||
schemaName: string,
|
||||
ssl: boolean
|
||||
ssl: boolean,
|
||||
namingStrategy: AbstractNamingStrategy,
|
||||
relationIds: boolean
|
||||
): Promise<DatabaseModel> {
|
||||
return await this.driver.GetDataFromServer(
|
||||
database,
|
||||
@ -48,7 +53,9 @@ export class Engine {
|
||||
user,
|
||||
password,
|
||||
schemaName,
|
||||
ssl
|
||||
ssl,
|
||||
namingStrategy,
|
||||
relationIds
|
||||
);
|
||||
}
|
||||
private createModelFromMetadata(databaseModel: DatabaseModel) {
|
||||
@ -223,7 +230,7 @@ export class Engine {
|
||||
"username": "${this.Options.user}",
|
||||
"password": "${this.Options.password}",
|
||||
"database": "${this.Options.databaseName}",
|
||||
"synchronize": false
|
||||
"synchronize": false,
|
||||
"entities": [
|
||||
"entities/*.js"
|
||||
]
|
||||
@ -271,4 +278,6 @@ export interface EngineOptions {
|
||||
convertCaseProperty: "pascal" | "camel" | "none";
|
||||
lazy: boolean;
|
||||
constructor: boolean;
|
||||
namingStrategy: AbstractNamingStrategy;
|
||||
relationIds: boolean;
|
||||
}
|
||||
|
76
src/NamingStrategy.ts
Normal file
76
src/NamingStrategy.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { AbstractNamingStrategy } from "./AbstractNamingStrategy";
|
||||
import { RelationInfo } from "./models/RelationInfo";
|
||||
import { DatabaseModel } from "./models/DatabaseModel";
|
||||
|
||||
export class NamingStrategy extends AbstractNamingStrategy {
|
||||
relationName(
|
||||
columnOldName: string,
|
||||
relation: RelationInfo,
|
||||
dbModel: DatabaseModel
|
||||
): string {
|
||||
let isRelationToMany = relation.isOneToMany || relation.isManyToMany;
|
||||
let ownerEntity = dbModel.entities.filter(v => {
|
||||
return v.EntityName == relation.ownerTable;
|
||||
})[0];
|
||||
let referencedEntity = dbModel.entities.filter(v => {
|
||||
return v.EntityName == relation.relatedTable;
|
||||
})[0];
|
||||
|
||||
let columnName =
|
||||
columnOldName[0].toLowerCase() +
|
||||
columnOldName.substring(1, columnOldName.length);
|
||||
if (
|
||||
columnName
|
||||
.toLowerCase()
|
||||
.endsWith(
|
||||
"id"
|
||||
) /*&& !ownerEntity.Columns.some(x=>x.tsName==columnName && x.isPrimary)*/
|
||||
) {
|
||||
columnName = columnName.substring(
|
||||
0,
|
||||
columnName.toLowerCase().lastIndexOf("id")
|
||||
);
|
||||
}
|
||||
if (!isNaN(parseInt(columnName[columnName.length - 1]))) {
|
||||
columnName = columnName.substring(0, columnName.length - 1);
|
||||
}
|
||||
if (!isNaN(parseInt(columnName[columnName.length - 1]))) {
|
||||
columnName = columnName.substring(0, columnName.length - 1);
|
||||
}
|
||||
columnName += isRelationToMany ? "s" : "";
|
||||
|
||||
if (
|
||||
relation.relationType != "ManyToMany" &&
|
||||
columnOldName != columnName
|
||||
) {
|
||||
if (ownerEntity.Columns.some(v => v.tsName == columnName)) {
|
||||
columnName = columnName + "_";
|
||||
for (let i = 2; i <= ownerEntity.Columns.length; i++) {
|
||||
columnName =
|
||||
columnName.substring(
|
||||
0,
|
||||
columnName.length - i.toString().length
|
||||
) + i.toString();
|
||||
if (
|
||||
ownerEntity.Columns.every(
|
||||
v =>
|
||||
v.tsName != columnName ||
|
||||
columnName == columnOldName
|
||||
)
|
||||
)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return columnName;
|
||||
}
|
||||
|
||||
entityName(entityName: string): string {
|
||||
return entityName;
|
||||
}
|
||||
|
||||
columnName(columnName: string): string {
|
||||
return columnName;
|
||||
}
|
||||
}
|
@ -1,15 +1,120 @@
|
||||
import { EntityInfo } from "./../models/EntityInfo";
|
||||
import { DatabaseModel } from "./../models/DatabaseModel";
|
||||
import * as TomgUtils from "./../Utils";
|
||||
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 {
|
||||
WithWidthColumnType,
|
||||
WithPrecisionColumnType,
|
||||
WithLengthColumnType
|
||||
} from "./../../node_modules/typeorm/driver/types/ColumnTypes";
|
||||
} from "typeorm/driver/types/ColumnTypes";
|
||||
import { AbstractNamingStrategy } from "../AbstractNamingStrategy";
|
||||
|
||||
export abstract class AbstractDriver {
|
||||
changeColumnNames(dbModel: DatabaseModel) {
|
||||
dbModel.entities.forEach(entity => {
|
||||
entity.Columns.forEach(column => {
|
||||
let newName = this.namingStrategy.columnName(column.tsName);
|
||||
entity.Indexes.forEach(index => {
|
||||
index.columns
|
||||
.filter(column2 => {
|
||||
return column2.name == column.tsName;
|
||||
})
|
||||
.forEach(column2 => {
|
||||
column2.name = newName;
|
||||
});
|
||||
});
|
||||
dbModel.entities.forEach(entity2 => {
|
||||
entity2.Columns.forEach(column2 => {
|
||||
column2.relations
|
||||
.filter(relation => {
|
||||
return (
|
||||
relation.relatedTable ==
|
||||
entity.EntityName &&
|
||||
relation.relatedColumn == column.tsName
|
||||
);
|
||||
})
|
||||
.map(v => {
|
||||
v.relatedColumn = newName;
|
||||
});
|
||||
column2.relations
|
||||
.filter(relation => {
|
||||
return (
|
||||
relation.ownerTable == entity.EntityName &&
|
||||
relation.ownerColumn == column.tsName
|
||||
);
|
||||
})
|
||||
.map(v => {
|
||||
v.ownerColumn = newName;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
column.tsName = newName;
|
||||
});
|
||||
});
|
||||
}
|
||||
changeEntityNames(dbModel: DatabaseModel) {
|
||||
dbModel.entities.forEach(entity => {
|
||||
let newName = this.namingStrategy.columnName(entity.EntityName);
|
||||
dbModel.entities.forEach(entity2 => {
|
||||
entity2.Columns.forEach(column => {
|
||||
column.relations.forEach(relation => {
|
||||
if (relation.ownerTable == entity.EntityName)
|
||||
relation.ownerTable = newName;
|
||||
if (relation.relatedTable == entity.EntityName)
|
||||
relation.relatedTable = newName;
|
||||
});
|
||||
});
|
||||
});
|
||||
entity.EntityName = newName;
|
||||
});
|
||||
}
|
||||
changeRelationNames(dbModel: DatabaseModel) {
|
||||
dbModel.entities.forEach(entity => {
|
||||
entity.Columns.forEach(column => {
|
||||
column.relations.forEach(relation => {
|
||||
if (true || !relation.isOwner) {
|
||||
let newName = this.namingStrategy.relationName(
|
||||
column.tsName,
|
||||
relation,
|
||||
dbModel
|
||||
);
|
||||
dbModel.entities.forEach(entity2 => {
|
||||
entity2.Columns.forEach(column2 => {
|
||||
column2.relations.forEach(relation2 => {
|
||||
if (
|
||||
relation2.relatedTable ==
|
||||
entity.EntityName &&
|
||||
relation2.ownerColumn == column.tsName
|
||||
) {
|
||||
relation2.ownerColumn = newName;
|
||||
}
|
||||
if (
|
||||
relation2.relatedTable ==
|
||||
entity.EntityName &&
|
||||
relation2.relatedColumn == column.tsName
|
||||
) {
|
||||
relation2.relatedColumn = newName;
|
||||
}
|
||||
if (relation.isOwner) {
|
||||
entity.Indexes.forEach(ind => {
|
||||
ind.columns.forEach(col => {
|
||||
if (col.name == column.tsName) {
|
||||
col.name = newName;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
column.tsName = newName;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
ColumnTypesWithWidth: WithWidthColumnType[] = [
|
||||
"tinyint",
|
||||
"smallint",
|
||||
@ -52,6 +157,8 @@ export abstract class AbstractDriver {
|
||||
"binary",
|
||||
"varbinary"
|
||||
];
|
||||
namingStrategy: AbstractNamingStrategy;
|
||||
generateRelationsIds: boolean;
|
||||
|
||||
FindManyToManyRelations(dbModel: DatabaseModel) {
|
||||
let manyToManyEntities = dbModel.entities.filter(entity => {
|
||||
@ -79,7 +186,7 @@ export abstract class AbstractDriver {
|
||||
)[0];
|
||||
relatedTable1.Columns = relatedTable1.Columns.filter(
|
||||
v =>
|
||||
!v.name
|
||||
!v.tsName
|
||||
.toLowerCase()
|
||||
.startsWith(entity.EntityName.toLowerCase())
|
||||
);
|
||||
@ -88,7 +195,7 @@ export abstract class AbstractDriver {
|
||||
)[0];
|
||||
relatedTable2.Columns = relatedTable2.Columns.filter(
|
||||
v =>
|
||||
!v.name
|
||||
!v.tsName
|
||||
.toLowerCase()
|
||||
.startsWith(entity.EntityName.toLowerCase())
|
||||
);
|
||||
@ -97,21 +204,26 @@ export abstract class AbstractDriver {
|
||||
});
|
||||
|
||||
let column1 = new ColumnInfo();
|
||||
column1.name = namesOfRelatedTables[1];
|
||||
column1.tsName = namesOfRelatedTables[1];
|
||||
|
||||
let col1Rel = new RelationInfo();
|
||||
col1Rel.relatedTable = namesOfRelatedTables[1];
|
||||
col1Rel.relatedColumn = namesOfRelatedTables[1];
|
||||
|
||||
col1Rel.relationType = "ManyToMany";
|
||||
col1Rel.isOwner = true;
|
||||
col1Rel.ownerColumn = namesOfRelatedTables[0];
|
||||
|
||||
column1.relations.push(col1Rel);
|
||||
relatedTable1.Columns.push(column1);
|
||||
|
||||
let column2 = new ColumnInfo();
|
||||
column2.name = namesOfRelatedTables[0];
|
||||
column2.tsName = namesOfRelatedTables[0];
|
||||
|
||||
let col2Rel = new RelationInfo();
|
||||
col2Rel.relatedTable = namesOfRelatedTables[0];
|
||||
col2Rel.relatedColumn = namesOfRelatedTables[1];
|
||||
|
||||
col2Rel.relationType = "ManyToMany";
|
||||
col2Rel.isOwner = false;
|
||||
column2.relations.push(col2Rel);
|
||||
@ -126,9 +238,13 @@ export abstract class AbstractDriver {
|
||||
user: string,
|
||||
password: string,
|
||||
schema: string,
|
||||
ssl: boolean
|
||||
ssl: boolean,
|
||||
namingStrategy: AbstractNamingStrategy,
|
||||
relationIds: boolean
|
||||
): Promise<DatabaseModel> {
|
||||
this.generateRelationsIds = relationIds;
|
||||
let dbModel = <DatabaseModel>{};
|
||||
this.namingStrategy = namingStrategy;
|
||||
await this.ConnectToServer(database, server, port, user, password, ssl);
|
||||
let sqlEscapedSchema = "'" + schema.split(",").join("','") + "'";
|
||||
dbModel.entities = await this.GetAllTables(sqlEscapedSchema);
|
||||
@ -141,8 +257,16 @@ export abstract class AbstractDriver {
|
||||
await this.DisconnectFromServer();
|
||||
this.FindManyToManyRelations(dbModel);
|
||||
this.FindPrimaryColumnsFromIndexes(dbModel);
|
||||
this.ApplyNamingStrategy(dbModel);
|
||||
return dbModel;
|
||||
}
|
||||
|
||||
private ApplyNamingStrategy(dbModel: DatabaseModel) {
|
||||
this.changeRelationNames(dbModel);
|
||||
this.changeEntityNames(dbModel);
|
||||
this.changeColumnNames(dbModel);
|
||||
}
|
||||
|
||||
abstract async ConnectToServer(
|
||||
database: string,
|
||||
server: string,
|
||||
@ -209,7 +333,7 @@ export abstract class AbstractDriver {
|
||||
) {
|
||||
let ownerColumn = ownerEntity.Columns.find(column => {
|
||||
return (
|
||||
column.name ==
|
||||
column.tsName ==
|
||||
relationTmp.ownerColumnsNames[relationColumnIndex]
|
||||
);
|
||||
});
|
||||
@ -227,7 +351,7 @@ export abstract class AbstractDriver {
|
||||
}
|
||||
let relatedColumn = referencedEntity.Columns.find(column => {
|
||||
return (
|
||||
column.name ==
|
||||
column.tsName ==
|
||||
relationTmp.referencedColumnsNames[relationColumnIndex]
|
||||
);
|
||||
});
|
||||
@ -249,48 +373,49 @@ export abstract class AbstractDriver {
|
||||
return (
|
||||
index.isUnique &&
|
||||
index.columns.some(col => {
|
||||
return col.name == ownerColumn!.name;
|
||||
return col.name == ownerColumn!.tsName;
|
||||
})
|
||||
);
|
||||
});
|
||||
isOneToMany = !index;
|
||||
|
||||
let ownerRelation = new RelationInfo();
|
||||
let columnName =
|
||||
ownerEntity.EntityName.toLowerCase() +
|
||||
(isOneToMany ? "s" : "");
|
||||
ownerRelation.actionOnDelete = relationTmp.actionOnDelete;
|
||||
ownerRelation.actionOnUpdate = relationTmp.actionOnUpdate;
|
||||
ownerRelation.isOwner = true;
|
||||
ownerRelation.relatedColumn = relatedColumn.tsName.toLowerCase();
|
||||
ownerRelation.relatedTable = relationTmp.referencedTable;
|
||||
ownerRelation.ownerTable = relationTmp.ownerTable;
|
||||
ownerRelation.relationType = isOneToMany
|
||||
? "ManyToOne"
|
||||
: "OneToOne";
|
||||
ownerRelation.relationIdField = this.generateRelationsIds;
|
||||
|
||||
let columnName = ownerEntity.EntityName;
|
||||
if (
|
||||
referencedEntity.Columns.filter(filterVal => {
|
||||
return filterVal.name == columnName;
|
||||
}).length > 0
|
||||
referencedEntity.Columns.some(v => v.tsName == columnName)
|
||||
) {
|
||||
for (let i = 2; i <= ownerEntity.Columns.length; i++) {
|
||||
columnName = columnName + "_";
|
||||
for (let i = 2; i <= referencedEntity.Columns.length; i++) {
|
||||
columnName =
|
||||
ownerEntity.EntityName.toLowerCase() +
|
||||
(isOneToMany ? "s" : "") +
|
||||
i.toString();
|
||||
columnName.substring(
|
||||
0,
|
||||
columnName.length - i.toString().length
|
||||
) + i.toString();
|
||||
if (
|
||||
referencedEntity.Columns.filter(filterVal => {
|
||||
return filterVal.name == columnName;
|
||||
}).length == 0
|
||||
referencedEntity.Columns.every(
|
||||
v => v.tsName != columnName
|
||||
)
|
||||
)
|
||||
break;
|
||||
}
|
||||
}
|
||||
ownerRelation.actionOnDelete = relationTmp.actionOnDelete;
|
||||
ownerRelation.actionOnUpdate = relationTmp.actionOnUpdate;
|
||||
ownerRelation.isOwner = true;
|
||||
ownerRelation.relatedColumn = relatedColumn.name.toLowerCase();
|
||||
ownerRelation.relatedTable = relationTmp.referencedTable;
|
||||
ownerRelation.ownerTable = relationTmp.ownerTable;
|
||||
|
||||
ownerRelation.ownerColumn = columnName;
|
||||
ownerRelation.relationType = isOneToMany
|
||||
? "ManyToOne"
|
||||
: "OneToOne";
|
||||
ownerColumn.relations.push(ownerRelation);
|
||||
if (isOneToMany) {
|
||||
let col = new ColumnInfo();
|
||||
col.name = columnName;
|
||||
col.tsName = columnName;
|
||||
let referencedRelation = new RelationInfo();
|
||||
col.relations.push(referencedRelation);
|
||||
referencedRelation.actionOnDelete =
|
||||
@ -298,15 +423,15 @@ export abstract class AbstractDriver {
|
||||
referencedRelation.actionOnUpdate =
|
||||
relationTmp.actionOnUpdate;
|
||||
referencedRelation.isOwner = false;
|
||||
referencedRelation.relatedColumn = ownerColumn.name;
|
||||
referencedRelation.relatedColumn = ownerColumn.tsName;
|
||||
referencedRelation.relatedTable = relationTmp.ownerTable;
|
||||
referencedRelation.ownerTable = relationTmp.referencedTable;
|
||||
referencedRelation.ownerColumn = relatedColumn.name.toLowerCase();
|
||||
referencedRelation.ownerColumn = relatedColumn.tsName;
|
||||
referencedRelation.relationType = "OneToMany";
|
||||
referencedEntity.Columns.push(col);
|
||||
} else {
|
||||
let col = new ColumnInfo();
|
||||
col.name = columnName;
|
||||
col.tsName = columnName;
|
||||
let referencedRelation = new RelationInfo();
|
||||
col.relations.push(referencedRelation);
|
||||
referencedRelation.actionOnDelete =
|
||||
@ -314,10 +439,10 @@ export abstract class AbstractDriver {
|
||||
referencedRelation.actionOnUpdate =
|
||||
relationTmp.actionOnUpdate;
|
||||
referencedRelation.isOwner = false;
|
||||
referencedRelation.relatedColumn = ownerColumn.name;
|
||||
referencedRelation.relatedColumn = ownerColumn.tsName;
|
||||
referencedRelation.relatedTable = relationTmp.ownerTable;
|
||||
referencedRelation.ownerTable = relationTmp.referencedTable;
|
||||
referencedRelation.ownerColumn = relatedColumn.name.toLowerCase();
|
||||
referencedRelation.ownerColumn = relatedColumn.tsName;
|
||||
referencedRelation.relationType = "OneToOne";
|
||||
referencedEntity.Columns.push(col);
|
||||
}
|
||||
@ -344,7 +469,9 @@ export abstract class AbstractDriver {
|
||||
entity.Columns.forEach(col => {
|
||||
if (
|
||||
primaryIndex &&
|
||||
primaryIndex.columns.some(cIndex => cIndex.name == col.name)
|
||||
primaryIndex.columns.some(
|
||||
cIndex => cIndex.name == col.tsName
|
||||
)
|
||||
)
|
||||
col.isPrimary = true;
|
||||
});
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { AbstractDriver } from "./AbstractDriver";
|
||||
import * as MSSQL from "mssql";
|
||||
import { ColumnInfo } from "./../models/ColumnInfo";
|
||||
import { EntityInfo } from "./../models/EntityInfo";
|
||||
import * as TomgUtils from "./../Utils";
|
||||
import { ColumnInfo } from "../models/ColumnInfo";
|
||||
import { EntityInfo } from "../models/EntityInfo";
|
||||
import * as TomgUtils from "../Utils";
|
||||
|
||||
export class MssqlDriver extends AbstractDriver {
|
||||
GetAllTablesQuery = async (schema: string) => {
|
||||
@ -53,7 +53,8 @@ export class MssqlDriver extends AbstractDriver {
|
||||
})
|
||||
.forEach(resp => {
|
||||
let colInfo: ColumnInfo = new ColumnInfo();
|
||||
colInfo.name = resp.COLUMN_NAME;
|
||||
colInfo.tsName = resp.COLUMN_NAME;
|
||||
colInfo.sqlName = resp.COLUMN_NAME;
|
||||
colInfo.is_nullable = resp.IS_NULLABLE == "YES";
|
||||
colInfo.is_generated = resp.IsIdentity == 1;
|
||||
colInfo.is_unique = resp.IsUnique == 1;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { AbstractDriver } from "./AbstractDriver";
|
||||
import * as MYSQL from "mysql";
|
||||
import { ColumnInfo } from "./../models/ColumnInfo";
|
||||
import { EntityInfo } from "./../models/EntityInfo";
|
||||
import * as TomgUtils from "./../Utils";
|
||||
import { ColumnInfo } from "../models/ColumnInfo";
|
||||
import { EntityInfo } from "../models/EntityInfo";
|
||||
import * as TomgUtils from "../Utils";
|
||||
|
||||
export class MysqlDriver extends AbstractDriver {
|
||||
readonly EngineName: string = "MySQL";
|
||||
@ -45,7 +45,8 @@ export class MysqlDriver extends AbstractDriver {
|
||||
})
|
||||
.forEach(resp => {
|
||||
let colInfo: ColumnInfo = new ColumnInfo();
|
||||
colInfo.name = resp.COLUMN_NAME;
|
||||
colInfo.tsName = resp.COLUMN_NAME;
|
||||
colInfo.sqlName = resp.COLUMN_NAME;
|
||||
colInfo.is_nullable = resp.IS_NULLABLE == "YES";
|
||||
colInfo.is_generated = resp.IsIdentity == 1;
|
||||
colInfo.is_unique = resp.column_key == "UNI";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { AbstractDriver } from "./AbstractDriver";
|
||||
import { ColumnInfo } from "./../models/ColumnInfo";
|
||||
import { EntityInfo } from "./../models/EntityInfo";
|
||||
import * as TomgUtils from "./../Utils";
|
||||
import { ColumnInfo } from "../models/ColumnInfo";
|
||||
import { EntityInfo } from "../models/EntityInfo";
|
||||
import * as TomgUtils from "../Utils";
|
||||
|
||||
export class OracleDriver extends AbstractDriver {
|
||||
Oracle: any;
|
||||
@ -55,7 +55,8 @@ export class OracleDriver extends AbstractDriver {
|
||||
})
|
||||
.forEach(resp => {
|
||||
let colInfo: ColumnInfo = new ColumnInfo();
|
||||
colInfo.name = resp.COLUMN_NAME;
|
||||
colInfo.tsName = resp.COLUMN_NAME;
|
||||
colInfo.sqlName = resp.COLUMN_NAME;
|
||||
colInfo.is_nullable = resp.NULLABLE == "Y";
|
||||
colInfo.is_generated = resp.IDENTITY_COLUMN == "YES";
|
||||
colInfo.default =
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { AbstractDriver } from "./AbstractDriver";
|
||||
import * as PG from "pg";
|
||||
import { ColumnInfo } from "./../models/ColumnInfo";
|
||||
import { EntityInfo } from "./../models/EntityInfo";
|
||||
import * as TomgUtils from "./../Utils";
|
||||
import { ColumnInfo } from "../models/ColumnInfo";
|
||||
import { EntityInfo } from "../models/EntityInfo";
|
||||
import * as TomgUtils from "../Utils";
|
||||
|
||||
export class PostgresDriver extends AbstractDriver {
|
||||
private Connection: PG.Client;
|
||||
@ -54,7 +54,8 @@ export class PostgresDriver extends AbstractDriver {
|
||||
})
|
||||
.forEach(resp => {
|
||||
let colInfo: ColumnInfo = new ColumnInfo();
|
||||
colInfo.name = resp.column_name;
|
||||
colInfo.tsName = resp.column_name;
|
||||
colInfo.sqlName = resp.column_name;
|
||||
colInfo.is_nullable = resp.is_nullable == "YES";
|
||||
colInfo.is_generated = resp.isidentity == "YES";
|
||||
colInfo.is_unique = resp.isunique == 1;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { AbstractDriver } from "./AbstractDriver";
|
||||
import { ColumnInfo } from "./../models/ColumnInfo";
|
||||
import { EntityInfo } from "./../models/EntityInfo";
|
||||
import * as TomgUtils from "./../Utils";
|
||||
import { ColumnInfo } from "../models/ColumnInfo";
|
||||
import { EntityInfo } from "../models/EntityInfo";
|
||||
import * as TomgUtils from "../Utils";
|
||||
|
||||
export class SqliteDriver extends AbstractDriver {
|
||||
sqlite = require("sqlite3").verbose();
|
||||
@ -41,7 +41,8 @@ export class SqliteDriver extends AbstractDriver {
|
||||
}>(`PRAGMA table_info('${ent.EntityName}');`);
|
||||
response.forEach(resp => {
|
||||
let colInfo: ColumnInfo = new ColumnInfo();
|
||||
colInfo.name = resp.name;
|
||||
colInfo.tsName = resp.name;
|
||||
colInfo.sqlName = resp.name;
|
||||
colInfo.is_nullable = resp.notnull == 0;
|
||||
colInfo.isPrimary = resp.pk > 0;
|
||||
colInfo.default = resp.dflt_value ? resp.dflt_value : null;
|
||||
@ -231,7 +232,7 @@ export class SqliteDriver extends AbstractDriver {
|
||||
indexInfo.isUnique
|
||||
) {
|
||||
ent.Columns.filter(
|
||||
v => v.name == indexColumnInfo.name
|
||||
v => v.tsName == indexColumnInfo.name
|
||||
).map(v => (v.is_unique = true));
|
||||
}
|
||||
indexInfo.columns.push(indexColumnInfo);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm";
|
||||
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm";
|
||||
{{relationImports}}{{#each UniqueImports}}import {{curly true}}{{toEntityName this}}{{curly false}} from "./{{toFileName this}}";
|
||||
{{/each}}
|
||||
|
||||
@ -20,15 +20,19 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Man
|
||||
scale:{{.}},{{/numericScale}}{{#isPrimary}}
|
||||
primary:{{isPrimary}},{{/isPrimary}}{{#enumOptions}}
|
||||
enum:[{{.}}],{{/enumOptions}}
|
||||
name:"{{name}}"
|
||||
name:"{{sqlName}}"
|
||||
})
|
||||
{{toPropertyName name}}:{{ts_type}};
|
||||
{{toPropertyName tsName}}:{{ts_type}}{{#is_nullable}} | null{{/is_nullable}};
|
||||
{{/relations}}{{#relations}}
|
||||
@{{relationType}}(type=>{{toEntityName relatedTable}}, {{toPropertyName ../name}}=>{{toPropertyName ../name}}.{{#if isOwner}}{{toPropertyName ownerColumn}},{ {{#../isPrimary}}primary:true,{{/../isPrimary}}{{^../is_nullable}} nullable:false,{{/../is_nullable}}{{#actionOnDelete}}onDelete: '{{.}}',{{/actionOnDelete}}{{#actionOnUpdate}}onUpdate: '{{.}}'{{/actionOnUpdate}} }{{else}}{{toPropertyName relatedColumn}}{{#actionOnDelete}},{ onDelete: '{{.}}' }{{/actionOnDelete}}{{/if}}){{#isOwner}}
|
||||
{{#if isManyToMany}}@JoinTable(){{else}}@JoinColumn({ name:'{{ ../name}}'}){{/if}}{{/isOwner}}
|
||||
{{#if (or isOneToMany isManyToMany)}}{{toPropertyName ../name}}:{{toLazy (concat (toEntityName relatedTable) "[]")}};
|
||||
{{else}}{{toPropertyName ../name}}:{{toLazy (toEntityName relatedTable)}};
|
||||
{{/if}}{{/relations}}
|
||||
@{{relationType}}(type=>{{toEntityName relatedTable}}, {{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{#if isOwner}}{{toPropertyName ownerColumn}},{ {{#../isPrimary}}primary:true,{{/../isPrimary}}{{^../is_nullable}} nullable:false,{{/../is_nullable}}{{#actionOnDelete}}onDelete: '{{.}}',{{/actionOnDelete}}{{#actionOnUpdate}}onUpdate: '{{.}}'{{/actionOnUpdate}} }{{else}}{{toPropertyName relatedColumn}}{{#actionOnDelete}},{ onDelete: '{{.}}' }{{/actionOnDelete}}{{/if}}){{#isOwner}}
|
||||
{{#if isManyToMany}}@JoinTable(){{else}}@JoinColumn({ name:'{{ ../sqlName}}'}){{/if}}{{/isOwner}}
|
||||
{{#if (or isOneToMany isManyToMany)}}{{toPropertyName ../tsName}}:{{toLazy (concat (toEntityName relatedTable) "[]")}};
|
||||
{{else}}{{toPropertyName ../tsName}}:{{toLazy (concat (toEntityName relatedTable) ' | null')}};
|
||||
{{/if}}
|
||||
{{#if relationIdField }}
|
||||
|
||||
@RelationId(({{../../EntityName}}: {{../../EntityName}}) => {{../../EntityName}}.{{toPropertyName ../tsName}})
|
||||
{{toPropertyName ../tsName}}Id: {{#if isOneToOne}}{{toLazy ../ts_type}}{{else}}{{toLazy (concat ../ts_type "[]")}}{{/if}};{{/if}}{{/relations}}
|
||||
{{/Columns}}
|
||||
{{#if GenerateConstructor}}
|
||||
constructor(init?: Partial<{{toEntityName EntityName}}>) {
|
||||
|
23
src/index.ts
23
src/index.ts
@ -9,6 +9,8 @@ import { Engine } from "./Engine";
|
||||
import * as Yargs from "yargs";
|
||||
import * as TomgUtils from "./Utils";
|
||||
import path = require("path");
|
||||
import { AbstractNamingStrategy } from "./AbstractNamingStrategy";
|
||||
import { NamingStrategy } from "./NamingStrategy";
|
||||
|
||||
var argv = Yargs.usage(
|
||||
"Usage: typeorm-model-generator -h <host> -d <database> -p [port] -u <user> -x [password] -e [engine]"
|
||||
@ -84,6 +86,14 @@ var argv = Yargs.usage(
|
||||
boolean: true,
|
||||
default: false
|
||||
})
|
||||
.option("namingStrategy", {
|
||||
describe: "Use custom naming strategy"
|
||||
})
|
||||
.option("relationIds", {
|
||||
describe: "Generate RelationId fields",
|
||||
boolean: true,
|
||||
default: false
|
||||
})
|
||||
.option("generateConstructor", {
|
||||
describe: "Generate constructor allowing partial initialization",
|
||||
boolean: true,
|
||||
@ -113,7 +123,7 @@ switch (argv.e) {
|
||||
standardUser = "root";
|
||||
break;
|
||||
case "mariadb":
|
||||
driver = new MysqlDriver();
|
||||
driver = new MariaDbDriver();
|
||||
standardPort = 3306;
|
||||
standardUser = "root";
|
||||
break;
|
||||
@ -130,6 +140,13 @@ switch (argv.e) {
|
||||
TomgUtils.LogError("Database engine not recognized.", false);
|
||||
throw new Error("Database engine not recognized.");
|
||||
}
|
||||
let namingStrategy: AbstractNamingStrategy;
|
||||
if (argv.namingStrategy && argv.namingStrategy != "") {
|
||||
let req = require(argv.namingStrategy);
|
||||
namingStrategy = new req.NamingStrategy();
|
||||
} else {
|
||||
namingStrategy = new NamingStrategy();
|
||||
}
|
||||
|
||||
let engine = new Engine(driver, {
|
||||
host: argv.h,
|
||||
@ -146,7 +163,9 @@ let engine = new Engine(driver, {
|
||||
convertCaseEntity: argv.ce,
|
||||
convertCaseProperty: argv.cp,
|
||||
lazy: argv.lazy,
|
||||
constructor: argv.constructor
|
||||
constructor: argv.generateConstructor,
|
||||
relationIds: argv.relationIds,
|
||||
namingStrategy: namingStrategy
|
||||
});
|
||||
|
||||
console.log(TomgUtils.packageVersion());
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { RelationInfo } from "./RelationInfo";
|
||||
|
||||
export class ColumnInfo {
|
||||
name: string = "";
|
||||
tsName: string = "";
|
||||
sqlName: string = "";
|
||||
default: string | null = null;
|
||||
is_nullable: boolean = false;
|
||||
is_unique: boolean = false;
|
||||
@ -24,7 +25,6 @@ export class ColumnInfo {
|
||||
numericScale: number | null = null;
|
||||
enumOptions: string | null = null;
|
||||
relations: RelationInfo[];
|
||||
|
||||
constructor() {
|
||||
this.relations = [];
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ export class RelationInfo {
|
||||
ownerColumn: string;
|
||||
actionOnDelete: "RESTRICT" | "CASCADE" | "SET NULL" | null;
|
||||
actionOnUpdate: "RESTRICT" | "CASCADE" | "SET NULL" | null;
|
||||
relationIdField: boolean = false;
|
||||
|
||||
get isOneToMany(): boolean {
|
||||
return this.relationType == "OneToMany";
|
||||
@ -14,4 +15,10 @@ export class RelationInfo {
|
||||
get isManyToMany(): boolean {
|
||||
return this.relationType == "ManyToMany";
|
||||
}
|
||||
get isOneToOne(): boolean {
|
||||
return this.relationType == "OneToOne";
|
||||
}
|
||||
get isManyToOne(): boolean {
|
||||
return this.relationType == "OneToOne";
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { expect } from "chai";
|
||||
import { MssqlDriver } from './../../src/drivers/MssqlDriver'
|
||||
import { MssqlDriver } from '../../src/drivers/MssqlDriver'
|
||||
import * as Sinon from 'sinon'
|
||||
import * as MSSQL from 'mssql'
|
||||
import { EntityInfo } from './../../src/models/EntityInfo'
|
||||
import { ColumnInfo } from './../../src/models/ColumnInfo'
|
||||
import { RelationInfo } from './../../src/models/RelationInfo'
|
||||
import { EntityInfo } from '../../src/models/EntityInfo'
|
||||
import { ColumnInfo } from '../../src/models/ColumnInfo'
|
||||
import { RelationInfo } from '../../src/models/RelationInfo'
|
||||
import { Table, IColumnMetadata } from "mssql";
|
||||
import { NamingStrategy } from "../../src/NamingStrategy";
|
||||
|
||||
class fakeResponse implements MSSQL.IResult<any> {
|
||||
recordsets: MSSQL.IRecordSet<any>[];
|
||||
@ -27,6 +28,7 @@ describe('MssqlDriver', function () {
|
||||
|
||||
beforeEach(() => {
|
||||
driver = new MssqlDriver();
|
||||
driver.namingStrategy = new NamingStrategy();
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@ -84,7 +86,8 @@ describe('MssqlDriver', function () {
|
||||
is_nullable: true,
|
||||
isPrimary: false,
|
||||
is_generated: true,
|
||||
name: 'name',
|
||||
tsName: 'name',
|
||||
sqlName: 'name',
|
||||
numericPrecision: null,
|
||||
numericScale: null,
|
||||
width: null,
|
||||
@ -92,7 +95,7 @@ describe('MssqlDriver', function () {
|
||||
ts_type: 'number',
|
||||
enumOptions: null,
|
||||
is_unique:false,
|
||||
relations: <RelationInfo[]>[]
|
||||
relations: <RelationInfo[]>[],
|
||||
})
|
||||
let result = await driver.GetCoulmnsFromEntity(entities, 'schema');
|
||||
expect(result).to.be.deep.equal(expected)
|
||||
|
@ -8,7 +8,7 @@ var chai = require('chai');
|
||||
var chaiSubset = require('chai-subset');
|
||||
import * as ts from "typescript";
|
||||
import * as GTU from "../utils/GeneralTestUtils"
|
||||
import { Engine } from "./../../src/Engine";
|
||||
import { Engine } from "../../src/Engine";
|
||||
|
||||
chai.use(chaiSubset);
|
||||
|
||||
|
@ -10,7 +10,7 @@ export class Category {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.Category)
|
||||
Post: Promise<Post[]>;
|
||||
@ManyToMany(type => Post, post => post.categorys)
|
||||
posts: Promise<Post[]>;
|
||||
|
||||
}
|
||||
|
@ -21,10 +21,10 @@ export class Post {
|
||||
})
|
||||
author: Promise<Author | null>;
|
||||
|
||||
@ManyToMany(type => Category, category => category.Post, {
|
||||
@ManyToMany(type => Category, category => category.posts, {
|
||||
// cascade: true
|
||||
})
|
||||
@JoinTable()
|
||||
Category: Promise<Category[]>;
|
||||
categorys: Promise<Category[]>;
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm";
|
||||
import {PostDetails} from "./PostDetails";
|
||||
import {PostDetail} from "./PostDetail";
|
||||
import {PostCategory} from "./PostCategory";
|
||||
import {PostAuthor} from "./PostAuthor";
|
||||
import {PostInformation} from "./PostInformation";
|
||||
@ -23,40 +23,40 @@ export class Post {
|
||||
cascade: true
|
||||
})
|
||||
@JoinTable()
|
||||
PostCategory: PostCategory[];
|
||||
postCategorys: 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, {
|
||||
@ManyToMany(type => PostDetail, details => details.posts, {
|
||||
cascade: true
|
||||
})
|
||||
@JoinTable()
|
||||
PostDetails: PostDetails[];
|
||||
postDetails: PostDetail[];
|
||||
|
||||
// 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, {
|
||||
@ManyToMany(type => PostImage, image => image.posts, {
|
||||
cascade: true
|
||||
})
|
||||
@JoinTable()
|
||||
PostImage: PostImage[];
|
||||
postImages: 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)
|
||||
@ManyToMany(type => PostMetadata, metadata => metadata.posts)
|
||||
@JoinTable()
|
||||
PostMetadata: PostMetadata[];
|
||||
postMetadatas: PostMetadata[];
|
||||
|
||||
// post has relation with details. full cascades here
|
||||
@ManyToMany(type => PostInformation, information => information.Post, {
|
||||
@ManyToMany(type => PostInformation, information => information.posts, {
|
||||
cascade: true
|
||||
})
|
||||
@JoinTable()
|
||||
PostInformation: PostInformation[];
|
||||
postInformations: PostInformation[];
|
||||
|
||||
// post has relation with details. not cascades here. means cannot be persisted, updated or removed
|
||||
@ManyToMany(type => PostAuthor, author => author.Post)
|
||||
@ManyToMany(type => PostAuthor, author => author.posts)
|
||||
@JoinTable()
|
||||
PostAuthor: PostAuthor[];
|
||||
postAuthors: PostAuthor[];
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ export class PostAuthor {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostAuthor)
|
||||
Post: Post[];
|
||||
@ManyToMany(type => Post, post => post.postAuthors)
|
||||
posts: Post[];
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm";
|
||||
import {Post} from "./Post";
|
||||
|
||||
@Entity("PostDetails")
|
||||
export class PostDetails {
|
||||
@Entity("PostDetail")
|
||||
export class PostDetail {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
@ -16,7 +16,7 @@ export class PostDetails {
|
||||
@Column()
|
||||
metadata: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostDetails)
|
||||
Post: Post[];
|
||||
@ManyToMany(type => Post, post => post.postDetails)
|
||||
posts: Post[];
|
||||
|
||||
}
|
@ -10,7 +10,7 @@ export class PostImage {
|
||||
@Column()
|
||||
url: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostImage)
|
||||
Post: Post[];
|
||||
@ManyToMany(type => Post, post => post.postImages)
|
||||
posts: Post[];
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ export class PostInformation {
|
||||
@Column()
|
||||
text: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostInformation)
|
||||
Post: Post[];
|
||||
@ManyToMany(type => Post, post => post.postInformations)
|
||||
posts: Post[];
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ export class PostMetadata {
|
||||
@Column()
|
||||
description: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostMetadata)
|
||||
Post: Post[];
|
||||
@ManyToMany(type => Post, post => post.postMetadatas)
|
||||
posts: Post[];
|
||||
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ export class Post {
|
||||
type: string;
|
||||
|
||||
// post has relation with details. not cascades here. means cannot be persisted, updated or removed
|
||||
@ManyToMany(type => PostAuthor, author => author.Post)
|
||||
@ManyToMany(type => PostAuthor, author => author.posts)
|
||||
@JoinTable()
|
||||
PostAuthor: PostAuthor[];
|
||||
postAuthors: PostAuthor[];
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export class PostAuthor {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.PostAuthor)
|
||||
Post: Post[];
|
||||
@ManyToMany(type => Post, post => post.postAuthors)
|
||||
posts: Post[];
|
||||
|
||||
}
|
||||
|
@ -4,33 +4,33 @@ import {quests} from "./quests";
|
||||
|
||||
|
||||
@Entity("feedextrainfo")
|
||||
@Index("feedExtraInfo_FeedOwnerId_idx",["FeedOwnerId",])
|
||||
@Index("feedExtraInfo_ReaderId_idx",["ReaderId",])
|
||||
@Index("feedExtraInfo_QuestId_idx",["QuestId",])
|
||||
@Index("feedExtraInfo_FeedOwnerId_idx",["feedOwnerId",])
|
||||
@Index("feedExtraInfo_ReaderId_idx",["readerId",])
|
||||
@Index("feedExtraInfo_QuestId_idx",["questId",])
|
||||
export class feedextrainfo {
|
||||
|
||||
|
||||
|
||||
@OneToOne(type=>users, FeedOwnerId=>FeedOwnerId.feedextrainfo,{primary:true, nullable:false, })
|
||||
@JoinColumn({ name:'FeedOwnerId'})
|
||||
FeedOwnerId:users;
|
||||
|
||||
feedOwnerId:users;
|
||||
|
||||
|
||||
|
||||
|
||||
@OneToOne(type=>quests, QuestId=>QuestId.feedextrainfo,{primary:true, nullable:false, })
|
||||
@JoinColumn({ name:'QuestId'})
|
||||
QuestId:quests;
|
||||
|
||||
questId:quests;
|
||||
|
||||
|
||||
|
||||
|
||||
@OneToOne(type=>users, ReaderId=>ReaderId.feedextrainfo2,{primary:true, nullable:false, })
|
||||
@JoinColumn({ name:'ReaderId'})
|
||||
ReaderId:users;
|
||||
|
||||
readerId:users;
|
||||
|
||||
@Column("int",{
|
||||
|
||||
@Column("int",{
|
||||
nullable:false,
|
||||
name:"MostUpdatedFeedEntryIdUserRead"
|
||||
})
|
||||
MostUpdatedFeedEntryIdUserRead:number;
|
||||
|
||||
|
||||
}
|
||||
|
@ -5,16 +5,16 @@ import {feedextrainfo} from "./feedextrainfo";
|
||||
@Entity("quests")
|
||||
export class quests {
|
||||
|
||||
@Column("int",{
|
||||
@Column("int",{
|
||||
nullable:false,
|
||||
primary:true,
|
||||
name:"QuestId"
|
||||
})
|
||||
QuestId:number;
|
||||
|
||||
|
||||
|
||||
@OneToOne(type=>feedextrainfo, feedextrainfo=>feedextrainfo.QuestId)
|
||||
|
||||
|
||||
@OneToOne(type=>feedextrainfo, feedextrainfo=>feedextrainfo.questId)
|
||||
feedextrainfo:feedextrainfo;
|
||||
|
||||
|
||||
}
|
||||
|
@ -5,21 +5,21 @@ import {feedextrainfo} from "./feedextrainfo";
|
||||
@Entity("users")
|
||||
export class users {
|
||||
|
||||
@Column("int",{
|
||||
@Column("int",{
|
||||
nullable:false,
|
||||
primary:true,
|
||||
name:"UserId"
|
||||
})
|
||||
UserId:number;
|
||||
|
||||
|
||||
|
||||
@OneToOne(type=>feedextrainfo, feedextrainfo=>feedextrainfo.FeedOwnerId)
|
||||
|
||||
|
||||
@OneToOne(type=>feedextrainfo, feedextrainfo=>feedextrainfo.feedOwnerId)
|
||||
feedextrainfo:feedextrainfo;
|
||||
|
||||
|
||||
|
||||
@OneToOne(type=>feedextrainfo, feedextrainfo2=>feedextrainfo2.ReaderId)
|
||||
|
||||
|
||||
@OneToOne(type=>feedextrainfo, feedextrainfo2=>feedextrainfo2.readerId)
|
||||
feedextrainfo2:feedextrainfo;
|
||||
|
||||
|
||||
}
|
||||
|
24
test/integration/github-issues/65/entity/Post.ts
Normal file
24
test/integration/github-issues/65/entity/Post.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm";
|
||||
import { PostAuthor } from "./PostAuthor";
|
||||
import { PostReader } from "./PostReader";
|
||||
|
||||
|
||||
@Entity("Post")
|
||||
export class Post {
|
||||
|
||||
@Column("int",{
|
||||
nullable:false,
|
||||
primary:true,
|
||||
name:"Id"
|
||||
})
|
||||
Id:number;
|
||||
|
||||
|
||||
|
||||
@OneToOne(type => PostAuthor, PostAuthor => PostAuthor.Id)
|
||||
postAuthor: PostAuthor;
|
||||
|
||||
@OneToMany(type => PostReader, PostReader => PostReader.Id)
|
||||
postReaders: PostReader[];
|
||||
|
||||
}
|
23
test/integration/github-issues/65/entity/PostAuthor.ts
Normal file
23
test/integration/github-issues/65/entity/PostAuthor.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm";
|
||||
import { Post } from "./Post";
|
||||
|
||||
|
||||
@Entity("PostAuthor")
|
||||
export class PostAuthor {
|
||||
|
||||
@Column("int",{
|
||||
nullable:false,
|
||||
primary:true,
|
||||
name:"Id"
|
||||
})
|
||||
Id:number;
|
||||
|
||||
|
||||
|
||||
@OneToOne(type => Post, Post => Post.Id)
|
||||
@JoinColumn()
|
||||
post:Post;
|
||||
|
||||
@RelationId((postAuthor: PostAuthor) => postAuthor.post)
|
||||
postId: number;
|
||||
}
|
21
test/integration/github-issues/65/entity/PostReader.ts
Normal file
21
test/integration/github-issues/65/entity/PostReader.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm";
|
||||
import { Post } from "./Post";
|
||||
|
||||
|
||||
@Entity("PostReader")
|
||||
export class PostReader {
|
||||
|
||||
@Column("int",{
|
||||
nullable:false,
|
||||
primary:true,
|
||||
name:"Id"
|
||||
})
|
||||
Id:number;
|
||||
|
||||
@ManyToOne(type => Post, Post => Post.Id)
|
||||
@JoinColumn()
|
||||
post:Post;
|
||||
|
||||
@RelationId((postReader: PostReader) => postReader.post)
|
||||
postId: number[];
|
||||
}
|
@ -3,7 +3,7 @@ import "reflect-metadata";
|
||||
import { createConnection, ConnectionOptions, Connection } from "typeorm";
|
||||
import fs = require('fs-extra');
|
||||
import path = require('path')
|
||||
import { Engine } from "./../../src/Engine";
|
||||
import { Engine } from "../../src/Engine";
|
||||
import { expect } from "chai";
|
||||
import * as Sinon from 'sinon'
|
||||
import { EntityFileToJson } from "../utils/EntityFileToJson";
|
||||
@ -78,6 +78,14 @@ describe("GitHub issues", async function () {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (folder) {
|
||||
case '65':
|
||||
engine.Options.relationIds = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
await engine.createModelFromDatabase()
|
||||
let filesGenPath = path.resolve(resultsPath, 'entities')
|
||||
|
||||
|
@ -2,7 +2,7 @@ require('dotenv').config()
|
||||
import "reflect-metadata";
|
||||
import fs = require('fs-extra');
|
||||
import path = require('path')
|
||||
import { Engine } from "./../../src/Engine";
|
||||
import { Engine } from "../../src/Engine";
|
||||
import { expect } from "chai";
|
||||
import { EntityFileToJson } from "../utils/EntityFileToJson";
|
||||
var chai = require('chai');
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as ts from "typescript";
|
||||
import { AbstractDriver } from "../../src/drivers/AbstractDriver";
|
||||
import { MssqlDriver } from "../../src/drivers/MssqlDriver";
|
||||
import { PostgresDriver } from "./../../src/drivers/PostgresDriver";
|
||||
import { PostgresDriver } from "../../src/drivers/PostgresDriver";
|
||||
import { MysqlDriver } from "../../src/drivers/MysqlDriver";
|
||||
import { MariaDbDriver } from "../../src/drivers/MariaDbDriver";
|
||||
import { OracleDriver } from "../../src/drivers/OracleDriver";
|
||||
@ -10,6 +10,8 @@ import { Engine } from "../../src/Engine";
|
||||
import { createConnection, ConnectionOptions } from "typeorm";
|
||||
import * as yn from "yn"
|
||||
import path = require('path')
|
||||
import { AbstractNamingStrategy } from "../../src/AbstractNamingStrategy";
|
||||
import { NamingStrategy } from "../../src/NamingStrategy";
|
||||
|
||||
export async function createMSSQLModels(filesOrgPath: string, resultsPath: string): Promise<Engine> {
|
||||
|
||||
@ -45,6 +47,7 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin
|
||||
if (conn.isConnected)
|
||||
await conn.close()
|
||||
|
||||
let namingStrategy: AbstractNamingStrategy = new NamingStrategy();
|
||||
|
||||
driver = new MssqlDriver();
|
||||
let engine = new Engine(
|
||||
@ -63,7 +66,9 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin
|
||||
convertCaseFile: 'none',
|
||||
convertCaseProperty: 'none',
|
||||
lazy: false,
|
||||
constructor:false
|
||||
constructor: false,
|
||||
namingStrategy: namingStrategy,
|
||||
relationIds:false
|
||||
});
|
||||
|
||||
conn = await createConnection(connOpt)
|
||||
@ -110,6 +115,7 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st
|
||||
|
||||
if (conn.isConnected)
|
||||
await conn.close()
|
||||
let namingStrategy: AbstractNamingStrategy = new NamingStrategy();
|
||||
|
||||
driver = new PostgresDriver();
|
||||
let engine = new Engine(
|
||||
@ -128,7 +134,9 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st
|
||||
convertCaseFile: 'none',
|
||||
convertCaseProperty: 'none',
|
||||
lazy: false,
|
||||
constructor:false
|
||||
constructor:false,
|
||||
namingStrategy: namingStrategy,
|
||||
relationIds: false
|
||||
});
|
||||
|
||||
conn = await createConnection(connOpt)
|
||||
@ -167,6 +175,7 @@ export async function createSQLiteModels(filesOrgPath: string, resultsPath: stri
|
||||
|
||||
if (conn.isConnected)
|
||||
await conn.close()
|
||||
let namingStrategy: AbstractNamingStrategy = new NamingStrategy();
|
||||
|
||||
driver = new SqliteDriver();
|
||||
let engine = new Engine(
|
||||
@ -185,7 +194,9 @@ export async function createSQLiteModels(filesOrgPath: string, resultsPath: stri
|
||||
convertCaseFile: 'none',
|
||||
convertCaseProperty: 'none',
|
||||
lazy: false,
|
||||
constructor:false
|
||||
constructor:false,
|
||||
namingStrategy: namingStrategy,
|
||||
relationIds: false
|
||||
});
|
||||
|
||||
conn = await createConnection(connOpt)
|
||||
@ -222,6 +233,7 @@ export async function createMysqlModels(filesOrgPath: string, resultsPath: strin
|
||||
|
||||
if (conn.isConnected)
|
||||
await conn.close()
|
||||
let namingStrategy: AbstractNamingStrategy = new NamingStrategy();
|
||||
|
||||
driver = new MysqlDriver();
|
||||
let engine = new Engine(
|
||||
@ -240,7 +252,9 @@ export async function createMysqlModels(filesOrgPath: string, resultsPath: strin
|
||||
convertCaseFile: 'none',
|
||||
convertCaseProperty: 'none',
|
||||
lazy: false,
|
||||
constructor:false
|
||||
constructor:false,
|
||||
namingStrategy: namingStrategy,
|
||||
relationIds: false
|
||||
});
|
||||
|
||||
return engine;
|
||||
@ -270,6 +284,7 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str
|
||||
|
||||
if (conn.isConnected)
|
||||
await conn.close()
|
||||
let namingStrategy: AbstractNamingStrategy = new NamingStrategy();
|
||||
|
||||
driver = new MariaDbDriver();
|
||||
let engine = new Engine(
|
||||
@ -288,7 +303,9 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str
|
||||
convertCaseFile: 'none',
|
||||
convertCaseProperty: 'none',
|
||||
lazy: false,
|
||||
constructor:false
|
||||
constructor:false,
|
||||
namingStrategy: namingStrategy,
|
||||
relationIds: false
|
||||
});
|
||||
|
||||
|
||||
@ -321,6 +338,7 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st
|
||||
|
||||
if (conn.isConnected)
|
||||
await conn.close()
|
||||
let namingStrategy: AbstractNamingStrategy = new NamingStrategy();
|
||||
|
||||
driver = new OracleDriver();
|
||||
let engine = new Engine(
|
||||
@ -339,7 +357,9 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st
|
||||
convertCaseFile: 'none',
|
||||
convertCaseProperty: 'none',
|
||||
lazy: false,
|
||||
constructor:false
|
||||
constructor:false,
|
||||
namingStrategy: namingStrategy,
|
||||
relationIds: false
|
||||
});
|
||||
|
||||
return engine;
|
||||
|
Loading…
Reference in New Issue
Block a user