Merge branch 'next' into pr/arimus/233
This commit is contained in:
commit
986ae97410
@ -36,7 +36,7 @@ module.exports = {
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
node: {
|
||||
extensions: [".js", ".jsx", ".ts", ".tsx"]
|
||||
extensions: [".ts"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
package-lock.json
generated
16
package-lock.json
generated
@ -274,12 +274,28 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
|
||||
},
|
||||
"@types/eslint": {
|
||||
"version": "6.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-6.1.3.tgz",
|
||||
"integrity": "sha512-llYf1QNZaDweXtA7uY6JczcwHmFwJL9TpK3E6sY0B18l6ulDT6VWNMAdEjYccFHiDfxLPxffd8QmSDV4QUUspA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/estree": "*",
|
||||
"@types/json-schema": "*"
|
||||
}
|
||||
},
|
||||
"@types/eslint-visitor-keys": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||
"integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/estree": {
|
||||
"version": "0.0.41",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.41.tgz",
|
||||
"integrity": "sha512-rIAmXyJlqw4KEBO7+u9gxZZSQHaCNnIzYrnNmYVpgfJhxTqO0brCX0SYpqUTkVI5mwwUwzmtspLBGBKroMeynA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/events": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
|
||||
|
@ -11,7 +11,7 @@
|
||||
"prepare": "npm run build",
|
||||
"pretest": "tsc --noEmit",
|
||||
"test": "nyc --reporter=lcov ts-node ./node_modules/mocha/bin/_mocha test/**/*.test.ts -- --bail",
|
||||
"posttest": "eslint ./**/*.ts ./src/**/*.ts ./test/**/*.ts",
|
||||
"posttest": "eslint ./src/**/*.ts ./test/**/*.ts",
|
||||
"clean": "rimraf coverage output dist",
|
||||
"prettier": "prettier --write ./src/*.ts ./src/**/*.ts"
|
||||
},
|
||||
@ -47,6 +47,7 @@
|
||||
"@types/chai": "^4.2.7",
|
||||
"@types/chai-as-promised": "^7.1.2",
|
||||
"@types/chai-subset": "^1.3.3",
|
||||
"@types/eslint": "^6.1.3",
|
||||
"@types/fs-extra": "^8.0.1",
|
||||
"@types/handlebars": "^4.1.0",
|
||||
"@types/inquirer": "^6.5.0",
|
||||
|
@ -16,6 +16,7 @@ export default interface IConnectionOptions {
|
||||
| "sqlite";
|
||||
schemaName: string;
|
||||
ssl: boolean;
|
||||
skipTables: string[];
|
||||
}
|
||||
|
||||
export function getDefaultConnectionOptions(): IConnectionOptions {
|
||||
@ -27,7 +28,8 @@ export function getDefaultConnectionOptions(): IConnectionOptions {
|
||||
password: "",
|
||||
databaseType: undefined as any,
|
||||
schemaName: "",
|
||||
ssl: false
|
||||
ssl: false,
|
||||
skipTables: []
|
||||
};
|
||||
return connectionOptions;
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ export default interface IGenerationOptions {
|
||||
relationIds: boolean;
|
||||
strictMode: "none" | "?" | "!";
|
||||
skipSchema: boolean;
|
||||
indexFile: boolean;
|
||||
exportType: "named" | "default";
|
||||
}
|
||||
export function getDefaultGenerationOptions(): IGenerationOptions {
|
||||
const generationOptions: IGenerationOptions = {
|
||||
@ -34,7 +36,9 @@ export function getDefaultGenerationOptions(): IGenerationOptions {
|
||||
customNamingStrategyPath: "",
|
||||
relationIds: false,
|
||||
strictMode: "none",
|
||||
skipSchema: false
|
||||
skipSchema: false,
|
||||
indexFile: false,
|
||||
exportType: "named"
|
||||
};
|
||||
return generationOptions;
|
||||
}
|
||||
|
@ -14,8 +14,7 @@ export default function modelGenerationPhase(
|
||||
databaseModel: Entity[]
|
||||
): void {
|
||||
createHandlebarsHelpers(generationOptions);
|
||||
const templatePath = path.resolve(__dirname, "templates", "entity.mst");
|
||||
const template = fs.readFileSync(templatePath, "UTF-8");
|
||||
|
||||
const resultPath = generationOptions.resultsPath;
|
||||
if (!fs.existsSync(resultPath)) {
|
||||
fs.mkdirSync(resultPath);
|
||||
@ -29,7 +28,24 @@ export default function modelGenerationPhase(
|
||||
fs.mkdirSync(entitiesPath);
|
||||
}
|
||||
}
|
||||
const compliedTemplate = Handlebars.compile(template, {
|
||||
if (generationOptions.indexFile) {
|
||||
createIndexFile(databaseModel, generationOptions, entitiesPath);
|
||||
}
|
||||
generateModels(databaseModel, generationOptions, entitiesPath);
|
||||
}
|
||||
|
||||
function generateModels(
|
||||
databaseModel: Entity[],
|
||||
generationOptions: IGenerationOptions,
|
||||
entitiesPath: string
|
||||
) {
|
||||
const entityTemplatePath = path.resolve(
|
||||
__dirname,
|
||||
"templates",
|
||||
"entity.mst"
|
||||
);
|
||||
const entityTemplate = fs.readFileSync(entityTemplatePath, "UTF-8");
|
||||
const entityCompliedTemplate = Handlebars.compile(entityTemplate, {
|
||||
noEscape: true
|
||||
});
|
||||
databaseModel.forEach(element => {
|
||||
@ -54,7 +70,7 @@ export default function modelGenerationPhase(
|
||||
entitiesPath,
|
||||
`${casedFileName}.ts`
|
||||
);
|
||||
const rendered = compliedTemplate(element);
|
||||
const rendered = entityCompliedTemplate(element);
|
||||
const withImportStatements = removeUnusedImports(rendered);
|
||||
const formatted = Prettier.format(withImportStatements, {
|
||||
parser: "typescript"
|
||||
@ -65,6 +81,41 @@ export default function modelGenerationPhase(
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createIndexFile(
|
||||
databaseModel: Entity[],
|
||||
generationOptions: IGenerationOptions,
|
||||
entitiesPath: string
|
||||
) {
|
||||
const templatePath = path.resolve(__dirname, "templates", "index.mst");
|
||||
const template = fs.readFileSync(templatePath, "UTF-8");
|
||||
const compliedTemplate = Handlebars.compile(template, {
|
||||
noEscape: true
|
||||
});
|
||||
const rendered = compliedTemplate({ entities: databaseModel });
|
||||
const formatted = Prettier.format(rendered, {
|
||||
parser: "typescript"
|
||||
});
|
||||
let fileName = "index";
|
||||
switch (generationOptions.convertCaseFile) {
|
||||
case "camel":
|
||||
fileName = changeCase.camelCase(fileName);
|
||||
break;
|
||||
case "param":
|
||||
fileName = changeCase.paramCase(fileName);
|
||||
break;
|
||||
case "pascal":
|
||||
fileName = changeCase.pascalCase(fileName);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
const resultFilePath = path.resolve(entitiesPath, `${fileName}.ts`);
|
||||
fs.writeFileSync(resultFilePath, formatted, {
|
||||
encoding: "UTF-8",
|
||||
flag: "w"
|
||||
});
|
||||
}
|
||||
|
||||
function removeUnusedImports(rendered: string) {
|
||||
const openBracketIndex = rendered.indexOf("{") + 1;
|
||||
const closeBracketIndex = rendered.indexOf("}");
|
||||
@ -160,6 +211,14 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions): void {
|
||||
return retVal;
|
||||
}
|
||||
);
|
||||
Handlebars.registerHelper("defaultExport", () =>
|
||||
generationOptions.exportType === "default" ? "default" : ""
|
||||
);
|
||||
Handlebars.registerHelper("localImport", (entityName: string) =>
|
||||
generationOptions.exportType === "default"
|
||||
? entityName
|
||||
: `{${entityName}}`
|
||||
);
|
||||
Handlebars.registerHelper("strictMode", () =>
|
||||
generationOptions.strictMode !== "none"
|
||||
? generationOptions.strictMode
|
||||
|
@ -69,7 +69,8 @@ export default abstract class AbstractDriver {
|
||||
|
||||
public abstract GetAllTablesQuery: (
|
||||
schema: string,
|
||||
dbNames: string
|
||||
dbNames: string,
|
||||
tableNames: string[]
|
||||
) => Promise<
|
||||
{
|
||||
TABLE_SCHEMA: string;
|
||||
@ -186,7 +187,8 @@ export default abstract class AbstractDriver {
|
||||
);
|
||||
dbModel = await this.GetAllTables(
|
||||
sqlEscapedSchema,
|
||||
connectionOptions.databaseName
|
||||
connectionOptions.databaseName,
|
||||
connectionOptions.skipTables
|
||||
);
|
||||
await this.GetCoulmnsFromEntity(
|
||||
dbModel,
|
||||
@ -214,9 +216,14 @@ export default abstract class AbstractDriver {
|
||||
|
||||
public async GetAllTables(
|
||||
schema: string,
|
||||
dbNames: string
|
||||
dbNames: string,
|
||||
tableNames: string[]
|
||||
): Promise<Entity[]> {
|
||||
const response = await this.GetAllTablesQuery(schema, dbNames);
|
||||
const response = await this.GetAllTablesQuery(
|
||||
schema,
|
||||
dbNames,
|
||||
tableNames
|
||||
);
|
||||
const ret: Entity[] = [] as Entity[];
|
||||
response.forEach(val => {
|
||||
ret.push({
|
||||
|
@ -24,8 +24,16 @@ export default class MssqlDriver extends AbstractDriver {
|
||||
|
||||
private Connection: MSSQL.ConnectionPool;
|
||||
|
||||
public GetAllTablesQuery = async (schema: string, dbNames: string) => {
|
||||
public GetAllTablesQuery = async (
|
||||
schema: string,
|
||||
dbNames: string,
|
||||
tableNames: string[]
|
||||
) => {
|
||||
const request = new MSSQL.Request(this.Connection);
|
||||
const tableCondition =
|
||||
tableNames.length > 0
|
||||
? ` AND NOT TABLE_NAME IN ('${tableNames.join("','")}')`
|
||||
: "";
|
||||
const response: {
|
||||
TABLE_SCHEMA: string;
|
||||
TABLE_NAME: string;
|
||||
@ -35,7 +43,7 @@ export default class MssqlDriver extends AbstractDriver {
|
||||
`SELECT TABLE_SCHEMA,TABLE_NAME, table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList(
|
||||
dbNames
|
||||
)})`
|
||||
)}) ${tableCondition}`
|
||||
)
|
||||
).recordset;
|
||||
return response;
|
||||
|
@ -26,7 +26,15 @@ export default class MysqlDriver extends AbstractDriver {
|
||||
|
||||
private Connection: MYSQL.Connection;
|
||||
|
||||
public GetAllTablesQuery = async (schema: string, dbNames: string) => {
|
||||
public GetAllTablesQuery = async (
|
||||
schema: string,
|
||||
dbNames: string,
|
||||
tableNames: string[]
|
||||
) => {
|
||||
const tableCondition =
|
||||
tableNames.length > 0
|
||||
? ` AND NOT TABLE_NAME IN ('${tableNames.join("','")}')`
|
||||
: "";
|
||||
const response = this.ExecQuery<{
|
||||
TABLE_SCHEMA: string;
|
||||
TABLE_NAME: string;
|
||||
@ -36,7 +44,7 @@ export default class MysqlDriver extends AbstractDriver {
|
||||
WHERE table_type='BASE TABLE'
|
||||
AND table_schema IN (${MysqlDriver.escapeCommaSeparatedList(
|
||||
dbNames
|
||||
)})`);
|
||||
)}) ${tableCondition}`);
|
||||
return response;
|
||||
};
|
||||
|
||||
|
@ -36,14 +36,22 @@ export default class OracleDriver extends AbstractDriver {
|
||||
}
|
||||
}
|
||||
|
||||
public GetAllTablesQuery = async () => {
|
||||
public GetAllTablesQuery = async (
|
||||
schema: string,
|
||||
dbNames: string,
|
||||
tableNames: string[]
|
||||
) => {
|
||||
const tableCondition =
|
||||
tableNames.length > 0
|
||||
? ` AND NOT TABLE_NAME IN ('${tableNames.join("','")}')`
|
||||
: "";
|
||||
const response: {
|
||||
TABLE_SCHEMA: string;
|
||||
TABLE_NAME: string;
|
||||
DB_NAME: string;
|
||||
}[] = (
|
||||
await this.Connection.execute(
|
||||
`SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual)`
|
||||
`SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual) ${tableCondition}`
|
||||
)
|
||||
).rows!;
|
||||
return response;
|
||||
|
@ -24,14 +24,22 @@ export default class PostgresDriver extends AbstractDriver {
|
||||
|
||||
private Connection: PG.Client;
|
||||
|
||||
public GetAllTablesQuery = async (schema: string) => {
|
||||
public GetAllTablesQuery = async (
|
||||
schema: string,
|
||||
dbNames: string,
|
||||
tableNames: string[]
|
||||
) => {
|
||||
const tableCondition =
|
||||
tableNames.length > 0
|
||||
? ` AND NOT table_name IN ('${tableNames.join("','")}')`
|
||||
: "";
|
||||
const response: {
|
||||
TABLE_SCHEMA: string;
|
||||
TABLE_NAME: string;
|
||||
DB_NAME: string;
|
||||
}[] = (
|
||||
await this.Connection.query(
|
||||
`SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME", table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema}) `
|
||||
`SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME", table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema}) ${tableCondition}`
|
||||
)
|
||||
).rows;
|
||||
return response;
|
||||
|
@ -30,10 +30,18 @@ export default class SqliteDriver extends AbstractDriver {
|
||||
|
||||
public GetAllTablesQuery: any;
|
||||
|
||||
public async GetAllTables(): Promise<Entity[]> {
|
||||
public async GetAllTables(
|
||||
schema: string,
|
||||
dbNames: string,
|
||||
tableNames: string[]
|
||||
): Promise<Entity[]> {
|
||||
const ret: Entity[] = [] as Entity[];
|
||||
const tableCondition =
|
||||
tableNames.length > 0
|
||||
? ` AND NOT tbl_name IN ('${tableNames.join("','")}')`
|
||||
: "";
|
||||
const rows = await this.ExecQuery<{ tbl_name: string; sql: string }>(
|
||||
`SELECT tbl_name, sql FROM "sqlite_master" WHERE "type" = 'table' AND name NOT LIKE 'sqlite_%'`
|
||||
`SELECT tbl_name, sql FROM "sqlite_master" WHERE "type" = 'table' AND name NOT LIKE 'sqlite_%' ${tableCondition}`
|
||||
);
|
||||
rows.forEach(val => {
|
||||
if (val.sql.includes("AUTOINCREMENT")) {
|
||||
|
70
src/index.ts
70
src/index.ts
@ -243,12 +243,28 @@ function checkYargsParameters(options: options): options {
|
||||
boolean: true,
|
||||
default: !options.generationOptions.pluralizeNames,
|
||||
describe:
|
||||
"Disable pluralization of OneToMany, ManyToMany relation names."
|
||||
"Disable pluralization of OneToMany, ManyToMany relation names"
|
||||
},
|
||||
skipTables: {
|
||||
string: true,
|
||||
default: options.connectionOptions.skipTables.join(","),
|
||||
describe:
|
||||
"Skip schema generation for specific tables. You can pass multiple values separated by comma"
|
||||
},
|
||||
strictMode: {
|
||||
choices: ["none", "?", "!"],
|
||||
default: options.generationOptions.strictMode,
|
||||
describe: "Mark fields as optional(?) or non-null(!)"
|
||||
},
|
||||
index: {
|
||||
boolean: true,
|
||||
default: options.generationOptions.indexFile,
|
||||
describe: "Generate index file"
|
||||
},
|
||||
defaultExport: {
|
||||
boolean: true,
|
||||
default: options.generationOptions.exportType === "default",
|
||||
describe: "Generate index file"
|
||||
}
|
||||
});
|
||||
|
||||
@ -266,6 +282,7 @@ function checkYargsParameters(options: options): options {
|
||||
: standardSchema;
|
||||
options.connectionOptions.ssl = argv.ssl;
|
||||
options.connectionOptions.user = argv.u || standardUser;
|
||||
options.connectionOptions.skipTables = argv.skipTables.split(",");
|
||||
options.generationOptions.activeRecord = argv.a;
|
||||
options.generationOptions.generateConstructor = argv.generateConstructor;
|
||||
options.generationOptions.convertCaseEntity = argv.ce as IGenerationOptions["convertCaseEntity"];
|
||||
@ -280,6 +297,10 @@ function checkYargsParameters(options: options): options {
|
||||
options.generationOptions.resultsPath = argv.o;
|
||||
options.generationOptions.pluralizeNames = !argv.disablePluralization;
|
||||
options.generationOptions.strictMode = argv.strictMode as IGenerationOptions["strictMode"];
|
||||
options.generationOptions.indexFile = argv.index;
|
||||
options.generationOptions.exportType = argv.defaultExport
|
||||
? "default"
|
||||
: "named";
|
||||
|
||||
return options;
|
||||
}
|
||||
@ -387,6 +408,33 @@ async function useInquirer(options: options): Promise<options> {
|
||||
])
|
||||
).dbName;
|
||||
}
|
||||
|
||||
const ignoreSpecyficTables = (
|
||||
await inquirer.prompt([
|
||||
{
|
||||
default:
|
||||
options.connectionOptions.skipTables.length === 0
|
||||
? "All of them"
|
||||
: "Ignore specific tables",
|
||||
message: "Generate schema for tables:",
|
||||
choices: ["All of them", "Ignore specific tables"],
|
||||
name: "specyficTables",
|
||||
type: "list"
|
||||
}
|
||||
])
|
||||
).specyficTables;
|
||||
if (ignoreSpecyficTables === "Ignore specific tables") {
|
||||
const { tableNames } = await inquirer.prompt({
|
||||
default: options.connectionOptions.skipTables.join(","),
|
||||
message: "Table names(separated by comma)",
|
||||
name: "tableNames",
|
||||
type: "input"
|
||||
});
|
||||
options.connectionOptions.skipTables = tableNames.split(",");
|
||||
} else {
|
||||
options.connectionOptions.skipTables = [];
|
||||
}
|
||||
|
||||
options.generationOptions.resultsPath = (
|
||||
await inquirer.prompt([
|
||||
{
|
||||
@ -465,9 +513,21 @@ async function useInquirer(options: options): Promise<options> {
|
||||
},
|
||||
{
|
||||
name:
|
||||
"Pluralize OneToMany, ManyToMany relation names.",
|
||||
"Pluralize OneToMany, ManyToMany relation names",
|
||||
value: "pluralize",
|
||||
checked: options.generationOptions.pluralizeNames
|
||||
},
|
||||
{
|
||||
name: "Generate index file",
|
||||
value: "index",
|
||||
checked: options.generationOptions.indexFile
|
||||
},
|
||||
{
|
||||
name: "Prefer default exports",
|
||||
value: "defaultExport",
|
||||
checked:
|
||||
options.generationOptions.exportType ===
|
||||
"default"
|
||||
}
|
||||
],
|
||||
message: "Available customizations",
|
||||
@ -521,6 +581,12 @@ async function useInquirer(options: options): Promise<options> {
|
||||
options.generationOptions.generateConstructor = customizations.includes(
|
||||
"constructor"
|
||||
);
|
||||
options.generationOptions.indexFile = customizations.includes("index");
|
||||
options.generationOptions.exportType = customizations.includes(
|
||||
"defaultExport"
|
||||
)
|
||||
? "default"
|
||||
: "named";
|
||||
|
||||
if (customizations.includes("namingStrategy")) {
|
||||
const namingStrategyPath = (
|
||||
|
@ -2,7 +2,7 @@
|
||||
@Index("{{name}}",[{{#columns}}"{{toPropertyName .}}",{{/columns~}}],{ {{json options}} })
|
||||
{{/inline}}
|
||||
{{#*inline "Import"}}
|
||||
import { {{toEntityName .}} } from './{{toFileName .}}'
|
||||
import {{localImport (toEntityName .)}} from './{{toFileName .}}'
|
||||
{{/inline}}
|
||||
{{#*inline "Column"}}
|
||||
{{#generated}}@PrimaryGeneratedColumn({ type:"{{type}}", {{/generated}}{{^generated}}@Column("{{type}}",{ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}}{{#default}},default: {{.}},{{/default}} })
|
||||
@ -13,7 +13,7 @@ import { {{toEntityName .}} } from './{{toFileName .}}'
|
||||
{ name: "{{name}}", referencedColumnName: "{{toPropertyName referencedColumnName}}" },
|
||||
{{/inline}}
|
||||
{{#*inline "Relation"}}
|
||||
@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}})
|
||||
@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}_=>{{toEntityName relatedTable}}_.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}})
|
||||
{{#if joinColumnOptions}}@JoinColumn([{{#joinColumnOptions}}{{> JoinColumnOptions}}{{/joinColumnOptions}}]){{/if}}
|
||||
{{#joinTableOptions}}@JoinTable({ name:"{{name}}", joinColumns:[{{#joinColumns}}{{> JoinColumnOptions}}{{/joinColumns}}],inverseJoinColumns:[{{#inverseJoinColumns}}{{> JoinColumnOptions}}{{/inverseJoinColumns}}],{{#database}}database:"{{.}}",{{/database}}{{#schema}}schema:"{{.}}"{{/schema}} }){{/joinTableOptions}}
|
||||
{{printPropertyVisibility}}{{toPropertyName fieldName}}{{strictMode}}:{{toRelation (toEntityName relatedTable) relationType}};
|
||||
@ -33,7 +33,7 @@ import { {{toEntityName .}} } from './{{toFileName .}}'
|
||||
{{#*inline "Entity"}}
|
||||
{{#indices}}{{> Index}}{{/indices~}}
|
||||
@Entity("{{sqlName}}"{{#schema}} ,{schema:"{{.}}"{{#if ../database}}, database:"{{../database}}"{{/if}} } {{/schema}})
|
||||
export class {{toEntityName tscName}}{{#activeRecord}} extends BaseEntity{{/activeRecord}} {
|
||||
export {{defaultExport}} class {{toEntityName tscName}}{{#activeRecord}} extends BaseEntity{{/activeRecord}} {
|
||||
|
||||
{{#columns}}{{> Column}}{{/columns~}}
|
||||
{{#relations}}{{> Relation}}{{/relations~}}
|
||||
|
5
src/templates/index.mst
Normal file
5
src/templates/index.mst
Normal file
@ -0,0 +1,5 @@
|
||||
{{#entities~}}
|
||||
import {{localImport (toEntityName tscName)}} from './{{toFileName tscName}}'
|
||||
{{/entities}}
|
||||
|
||||
export { {{#entities}}{{toEntityName tscName}},{{/entities~}} }
|
30
test/configs/.eslintrc.js
Normal file
30
test/configs/.eslintrc.js
Normal file
@ -0,0 +1,30 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
"airbnb-base",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier",
|
||||
"prettier/@typescript-eslint"
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: "test/configs/tsconfig.json"
|
||||
},
|
||||
plugins: ["@typescript-eslint"],
|
||||
rules: { // TODO: remove some rule overrides after disabling eslint on model customization tests(?)
|
||||
"import/extensions": ["off"],
|
||||
"import/prefer-default-export": ["off"],
|
||||
"@typescript-eslint/no-explicit-any": ["off"],
|
||||
"@typescript-eslint/camelcase": ["off"],
|
||||
"@typescript-eslint/class-name-casing": ["off"]
|
||||
},
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
node: {
|
||||
extensions: [".ts"]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
17
test/configs/tsconfig.json
Normal file
17
test/configs/tsconfig.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"newLine": "LF",
|
||||
"typeRoots": [
|
||||
"../../node_modules/@types"
|
||||
],
|
||||
"resolveJsonModule": true,
|
||||
},
|
||||
"include": [
|
||||
"../../output"
|
||||
]
|
||||
}
|
@ -47,7 +47,7 @@ describe("MssqlDriver", () => {
|
||||
return response;
|
||||
}
|
||||
});
|
||||
const result = await driver.GetAllTables("schema", "db");
|
||||
const result = await driver.GetAllTables("schema", "db", []);
|
||||
const expectedResult = [] as Entity[];
|
||||
const y: Entity = {
|
||||
columns: [],
|
||||
|
@ -6,6 +6,7 @@ import * as path from "path";
|
||||
import * as chaiSubset from "chai-subset";
|
||||
import * as flatMap from "array.prototype.flatmap";
|
||||
import yn from "yn";
|
||||
import { CLIEngine } from "eslint";
|
||||
import EntityFileToJson from "../utils/EntityFileToJson";
|
||||
import { createDriver, dataCollectionPhase } from "../../src/Engine";
|
||||
import * as GTU from "../utils/GeneralTestUtils";
|
||||
@ -277,6 +278,15 @@ export function compileGeneratedModel(filesGenPath: string, drivers: string[]) {
|
||||
compiledWithoutErrors,
|
||||
"Errors detected while compiling generated model"
|
||||
).to.equal(true);
|
||||
|
||||
|
||||
const cli = new CLIEngine({ configFile: "test/configs/.eslintrc.js" });
|
||||
const lintReport = cli.executeOnFiles(currentDirectoryFiles)
|
||||
lintReport.results.forEach(result => result.messages.forEach(message => {
|
||||
console.error(`${result.filePath}:${message.line} - ${message.message}`)
|
||||
}))
|
||||
expect(lintReport.errorCount).to.equal(0)
|
||||
expect(lintReport.warningCount).to.equal(0)
|
||||
}
|
||||
|
||||
async function prepareTestRuns(
|
||||
@ -320,7 +330,8 @@ async function prepareTestRuns(
|
||||
password: String(process.env.MYSQL_Password),
|
||||
databaseType: "mysql",
|
||||
schemaName: "ignored",
|
||||
ssl: yn(process.env.MYSQL_SSL, { default: false })
|
||||
ssl: yn(process.env.MYSQL_SSL, { default: false }),
|
||||
skipTables: []
|
||||
};
|
||||
break;
|
||||
case "mariadb":
|
||||
@ -332,7 +343,8 @@ async function prepareTestRuns(
|
||||
password: String(process.env.MARIADB_Password),
|
||||
databaseType: "mariadb",
|
||||
schemaName: "ignored",
|
||||
ssl: yn(process.env.MARIADB_SSL, { default: false })
|
||||
ssl: yn(process.env.MARIADB_SSL, { default: false }),
|
||||
skipTables: []
|
||||
};
|
||||
break;
|
||||
|
||||
|
@ -15,6 +15,8 @@ import { compileGeneratedModel } from "../integration/runTestsFromPath.test";
|
||||
|
||||
chai.use(chaiSubset);
|
||||
const { expect } = chai;
|
||||
|
||||
// TODO: test for connectionOptions.specyficTables
|
||||
describe("Model customization phase", async () => {
|
||||
const generateSampleData: () => Entity[] = () => [
|
||||
{
|
||||
@ -663,4 +665,81 @@ describe("Model customization phase", async () => {
|
||||
compileGeneratedModel(generationOptions.resultsPath, [""]);
|
||||
})
|
||||
})
|
||||
describe("index file generation", () => {
|
||||
it("named export", async () => {
|
||||
|
||||
const data = generateSampleData();
|
||||
const generationOptions = generateGenerationOptions();
|
||||
generationOptions.indexFile = true;
|
||||
clearGenerationDir();
|
||||
|
||||
const customizedModel = modelCustomizationPhase(
|
||||
data,
|
||||
generationOptions,
|
||||
{}
|
||||
);
|
||||
modelGenerationPhase(
|
||||
getDefaultConnectionOptions(),
|
||||
generationOptions,
|
||||
customizedModel
|
||||
);
|
||||
const filesGenPath = path.resolve(resultsPath, "entities");
|
||||
const indexFileContent = fs
|
||||
.readFileSync(path.resolve(filesGenPath, "Index.ts"))
|
||||
.toString();
|
||||
expect(indexFileContent).to.contain('import { PostAuthor } from "./PostAuthor');
|
||||
expect(indexFileContent).to.contain('import { Post } from "./Post');
|
||||
expect(indexFileContent).to.contain('export { PostAuthor, Post }');
|
||||
compileGeneratedModel(generationOptions.resultsPath, [""]);
|
||||
})
|
||||
it("default export", async () => {
|
||||
|
||||
const data = generateSampleData();
|
||||
const generationOptions = generateGenerationOptions();
|
||||
generationOptions.indexFile = true;
|
||||
generationOptions.exportType = "default"
|
||||
clearGenerationDir();
|
||||
|
||||
const customizedModel = modelCustomizationPhase(
|
||||
data,
|
||||
generationOptions,
|
||||
{}
|
||||
);
|
||||
modelGenerationPhase(
|
||||
getDefaultConnectionOptions(),
|
||||
generationOptions,
|
||||
customizedModel
|
||||
);
|
||||
const filesGenPath = path.resolve(resultsPath, "entities");
|
||||
const indexFileContent = fs
|
||||
.readFileSync(path.resolve(filesGenPath, "Index.ts"))
|
||||
.toString();
|
||||
expect(indexFileContent).to.contain('import PostAuthor from "./PostAuthor');
|
||||
expect(indexFileContent).to.contain('import Post from "./Post');
|
||||
expect(indexFileContent).to.contain('export { PostAuthor, Post }');
|
||||
compileGeneratedModel(generationOptions.resultsPath, [""]);
|
||||
})
|
||||
it("disabled", async () => {
|
||||
|
||||
const data = generateSampleData();
|
||||
const generationOptions = generateGenerationOptions();
|
||||
generationOptions.pluralizeNames = false;
|
||||
clearGenerationDir();
|
||||
|
||||
const customizedModel = modelCustomizationPhase(
|
||||
data,
|
||||
generationOptions,
|
||||
{}
|
||||
);
|
||||
modelGenerationPhase(
|
||||
getDefaultConnectionOptions(),
|
||||
generationOptions,
|
||||
customizedModel
|
||||
);
|
||||
const filesGenPath = path.resolve(resultsPath, "entities");
|
||||
expect(fs.existsSync(path.resolve(filesGenPath, "Index.ts"))).to.equal(false);
|
||||
compileGeneratedModel(generationOptions.resultsPath, [""]);
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
|
@ -29,7 +29,8 @@ export async function createMSSQLModels(
|
||||
password: String(process.env.MSSQL_Password),
|
||||
databaseType: "mssql",
|
||||
schemaName: "dbo,sch1,sch2",
|
||||
ssl: yn(process.env.MSSQL_SSL, { default: false })
|
||||
ssl: yn(process.env.MSSQL_SSL, { default: false }),
|
||||
skipTables: []
|
||||
};
|
||||
await driver.ConnectToServer(connectionOptions);
|
||||
connectionOptions.databaseName = String(process.env.MSSQL_Database);
|
||||
@ -80,7 +81,8 @@ export async function createPostgresModels(
|
||||
password: String(process.env.POSTGRES_Password),
|
||||
databaseType: "postgres",
|
||||
schemaName: "public,sch1,sch2",
|
||||
ssl: yn(process.env.POSTGRES_SSL, { default: false })
|
||||
ssl: yn(process.env.POSTGRES_SSL, { default: false }),
|
||||
skipTables: []
|
||||
};
|
||||
await driver.ConnectToServer(connectionOptions);
|
||||
connectionOptions.databaseName = String(process.env.POSTGRES_Database);
|
||||
@ -130,7 +132,8 @@ export async function createSQLiteModels(
|
||||
password: "",
|
||||
databaseType: "sqlite",
|
||||
schemaName: "",
|
||||
ssl: false
|
||||
ssl: false,
|
||||
skipTables: []
|
||||
};
|
||||
|
||||
const connOpt: ConnectionOptions = {
|
||||
@ -164,7 +167,8 @@ export async function createMysqlModels(
|
||||
password: String(process.env.MYSQL_Password),
|
||||
databaseType: "mysql",
|
||||
schemaName: "ignored",
|
||||
ssl: yn(process.env.MYSQL_SSL, { default: false })
|
||||
ssl: yn(process.env.MYSQL_SSL, { default: false }),
|
||||
skipTables: []
|
||||
};
|
||||
await driver.ConnectToServer(connectionOptions);
|
||||
|
||||
@ -206,7 +210,8 @@ export async function createMariaDBModels(
|
||||
password: String(process.env.MARIADB_Password),
|
||||
databaseType: "mariadb",
|
||||
schemaName: "ignored",
|
||||
ssl: yn(process.env.MARIADB_SSL, { default: false })
|
||||
ssl: yn(process.env.MARIADB_SSL, { default: false }),
|
||||
skipTables: []
|
||||
};
|
||||
await driver.ConnectToServer(connectionOptions);
|
||||
|
||||
@ -250,7 +255,8 @@ export async function createOracleDBModels(
|
||||
password: String(process.env.ORACLE_PasswordSys),
|
||||
databaseType: "oracle",
|
||||
schemaName: String(process.env.ORACLE_Username),
|
||||
ssl: yn(process.env.ORACLE_SSL, { default: false })
|
||||
ssl: yn(process.env.ORACLE_SSL, { default: false }),
|
||||
skipTables: []
|
||||
};
|
||||
await driver.ConnectToServer(connectionOptions);
|
||||
connectionOptions.user = String(process.env.ORACLE_Username);
|
||||
|
@ -1,29 +1,30 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"noImplicitAny": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"stripInternal": true,
|
||||
"strictNullChecks": true,
|
||||
"moduleResolution": "node",
|
||||
"newLine": "LF",
|
||||
"outDir": "dist",
|
||||
"lib": [
|
||||
"es2019","es2019.array"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"resolveJsonModule": true,
|
||||
},
|
||||
"include": [
|
||||
"src",
|
||||
"test"
|
||||
]
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"noImplicitAny": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"stripInternal": true,
|
||||
"strictNullChecks": true,
|
||||
"moduleResolution": "node",
|
||||
"newLine": "LF",
|
||||
"outDir": "dist",
|
||||
"lib": [
|
||||
"es2019",
|
||||
"es2019.array"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"resolveJsonModule": true,
|
||||
},
|
||||
"include": [
|
||||
"src",
|
||||
"test",
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user