integration tests column options comparision, added generated column option to creating model from db

This commit is contained in:
Kononnable 2017-05-22 22:46:33 +02:00
parent 5e307aca65
commit 126d9ce185
8 changed files with 62 additions and 22 deletions

View File

@ -32,6 +32,7 @@
"devDependencies": {
"@types/chai": "^3.5.2",
"@types/chai-as-promised": "0.0.30",
"@types/chai-subset": "^1.3.0",
"@types/fs-extra": "^3.0.0",
"@types/mocha": "^2.2.41",
"@types/mssql": "^3.3.0",
@ -39,6 +40,7 @@
"@types/sinon": "^2.1.3",
"chai": "^3.5.0",
"chai-as-promised": "^6.0.0",
"chai-subset": "^1.5.0",
"codecov": "^2.1.0",
"dotenv": "^4.0.0",
"fs-extra": "^3.0.1",

View File

@ -39,9 +39,10 @@ export class MssqlDriver extends AbstractDriver {
let request = new MSSQL.Request(this.Connection)
let response: { TABLE_NAME: string, COLUMN_NAME: string, COLUMN_DEFAULT: string,
IS_NULLABLE: string, DATA_TYPE: string, CHARACTER_MAXIMUM_LENGTH: number,
NUMERIC_PRECISION:number,NUMERIC_SCALE:number }[]
NUMERIC_PRECISION:number,NUMERIC_SCALE:number,IsIdentity:number }[]
= await request.query(`SELECT TABLE_NAME,COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE,
DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE FROM INFORMATION_SCHEMA.COLUMNS`);
DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE,
COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') IsIdentity FROM INFORMATION_SCHEMA.COLUMNS`);
entities.forEach((ent) => {
response.filter((filterVal) => {
return filterVal.TABLE_NAME == ent.EntityName;
@ -49,6 +50,7 @@ export class MssqlDriver extends AbstractDriver {
let colInfo: ColumnInfo = new ColumnInfo();
colInfo.name = resp.COLUMN_NAME;
colInfo.is_nullable = resp.IS_NULLABLE == 'YES' ? true : false;
colInfo.is_generated = resp.IsIdentity == 1 ? true : false;
colInfo.default = resp.COLUMN_DEFAULT;
switch (resp.DATA_TYPE) {
case "int":

View File

@ -7,7 +7,7 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Joi
{{#Columns}}
@Column("{{sql_type}}",{ {{#is_nullable}}nullable:true,{{/is_nullable}}{{#char_max_lenght}}length:{{char_max_lenght}},{{/char_max_lenght}}{{#default}}default:"{{default}}",{{/default}}{{#numericPrecision}}precision:{{numericPrecision}},{{/numericPrecision}}{{#numericScale}}scale:{{numericScale}},{{/numericScale}}{{#isPrimary}}primary:{{isPrimary}},{{/isPrimary}}}){{#relations}}
@Column("{{sql_type}}",{ {{#is_generated}}generated:true,{{/is_generated}}{{#is_nullable}}nullable:true,{{/is_nullable}}{{^is_nullable}}nullable:false,{{/is_nullable}}{{#char_max_lenght}}length:{{char_max_lenght}},{{/char_max_lenght}}{{#default}}default:"{{default}}",{{/default}}{{#numericPrecision}}precision:{{numericPrecision}},{{/numericPrecision}}{{#numericScale}}scale:{{numericScale}},{{/numericScale}}{{#isPrimary}}primary:{{isPrimary}},{{/isPrimary}}}){{#relations}}
@{{relationType}}(type=>{{relatedTable}},x=>x.{{relatedColumn}}){{#isOwner}}
@JoinTable(){{/isOwner}}{{/relations}}
{{name}}:{{ts_type}};

View File

@ -10,10 +10,12 @@ export class ColumnInfo {
"float" | "double" | "decimal" | "date" | "time" | "datetime" | "boolean" | "json";
char_max_lenght: number|null=null;
isPrimary:boolean=false;
is_generated:boolean=false;
numericPrecision:number|null=null;
numericScale:number|null=null;
relations:RelationInfo[];
constructor() {
this.relations=[];
}

View File

@ -56,12 +56,13 @@ describe('MssqlDriver', function () {
let response = <{
TABLE_NAME: string, COLUMN_NAME: string, COLUMN_DEFAULT: string,
IS_NULLABLE: string, DATA_TYPE: string, CHARACTER_MAXIMUM_LENGTH: number,
NUMERIC_PRECISION: number, NUMERIC_SCALE: number
NUMERIC_PRECISION: number, NUMERIC_SCALE: number, IsIdentity:number
}[]>[]
response.push({
TABLE_NAME: 'name', CHARACTER_MAXIMUM_LENGTH: 0,
COLUMN_DEFAULT: 'a', COLUMN_NAME: 'name', DATA_TYPE: 'int',
IS_NULLABLE: 'YES', NUMERIC_PRECISION: 0, NUMERIC_SCALE: 0
IS_NULLABLE: 'YES', NUMERIC_PRECISION: 0, NUMERIC_SCALE: 0,
IsIdentity:1
})
return response;
}
@ -81,6 +82,7 @@ describe('MssqlDriver', function () {
default: 'a',
is_nullable: true,
isPrimary: false,
is_generated:true,
name: 'name',
numericPrecision: null,
numericScale: null,

View File

@ -1,6 +1,6 @@
import {Column, Entity,PrimaryColumn,Index} from "typeorm";
@Entity()
@Entity("Post")
export class Post {
@PrimaryColumn("int", { generated: true })

View File

@ -3,7 +3,6 @@ import "reflect-metadata";
import { createConnection, ConnectionOptions, Connection } from "typeorm";
import fs = require('fs-extra');
import path = require('path')
import { Post } from "./examples/sample1-simple-entity/entity/Post";
import { Engine } from "./../../src/Engine";
import { AbstractDriver } from "./../../src/drivers/AbstractDriver";
import { MssqlDriver } from "./../../src/drivers/MssqlDriver";
@ -11,7 +10,10 @@ import { DriverType } from "typeorm/driver/DriverOptions";
import { expect } from "chai";
import * as Sinon from 'sinon'
import { EntityFileToJson } from "../utils/EntityFileToJson";
var chai = require('chai');
var chaiSubset = require('chai-subset');
chai.use(chaiSubset);
describe("integration tests", async function () {
let examplesPath = path.resolve(process.cwd(), 'test/integration/examples')
@ -54,7 +56,6 @@ describe("integration tests", async function () {
let resultsPath = path.resolve(process.cwd(), `output`)
let engine = new Engine(
driver, {
//TODO:get data from env
host: process.env.MSSQL_Host,
port: process.env.MSSQL_Port,
databaseName: process.env.MSSQL_Database,
@ -70,8 +71,8 @@ describe("integration tests", async function () {
let filesGenPath = path.resolve(resultsPath, 'entities')
let filesOrg = fs.readdirSync(filesOrgPath).map(function (this, val) { return val.toString().toLowerCase(); }).filter(function (this, val, ind, arr) { return val.toString().endsWith('.ts') })
let filesGen = fs.readdirSync(filesGenPath).map(function (this, val) { return val.toString().toLowerCase(); }).filter(function (this, val, ind, arr) { return val.toString().endsWith('.ts') })
let filesOrg = fs.readdirSync(filesOrgPath).filter(function (this, val, ind, arr) { return val.toString().endsWith('.ts') })
let filesGen = fs.readdirSync(filesGenPath).filter(function (this, val, ind, arr) { return val.toString().endsWith('.ts') })
expect(filesOrg).to.be.deep.equal(filesGen)
@ -79,7 +80,7 @@ describe("integration tests", async function () {
let entftj = new EntityFileToJson();
let jsonEntityOrg= entftj.convert(fs.readFileSync(path.resolve(filesOrgPath, file)))
let jsonEntityGen= entftj.convert(fs.readFileSync(path.resolve(filesGenPath, file)))
expect(jsonEntityGen).to.be.deep.eq(jsonEntityOrg)
expect(jsonEntityGen).to.containSubset(jsonEntityOrg)
}
});

View File

@ -1,4 +1,28 @@
export class EntityFileToJson {
getColumnOptionsAndType(trimmedLine: string, col: EntityColumn) {
let decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')'))
if (decoratorParameters.length > 0) {
if (decoratorParameters.search(',') > 0) {
col.columnType = decoratorParameters.substring(0, decoratorParameters.indexOf(',')).trim()
let badJSON = decoratorParameters.substring(decoratorParameters.indexOf(',') + 1).trim()
if (badJSON.lastIndexOf(',') == badJSON.length - 2) {
badJSON = badJSON.slice(0, badJSON.length - 2) + badJSON[badJSON.length - 1]
}
col.columnOptions = JSON.parse(badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '))
} else {
if (decoratorParameters[0] == '"' && decoratorParameters.endsWith('"')) {
col.columnType = decoratorParameters
} else {
let badJSON = decoratorParameters.substring(decoratorParameters.indexOf(',') + 1).trim()
if (badJSON.lastIndexOf(',') == badJSON.length - 2) {
badJSON = badJSON.slice(0, badJSON.length - 2) + badJSON[badJSON.length - 1]
}
col.columnOptions = JSON.parse(badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '))
}
}
}
}
convert(entityFile: Buffer): EntityJson {
let retVal = new EntityJson();
@ -7,7 +31,7 @@ export class EntityFileToJson {
let isMultilineStatement = false;
let priorPartOfMultilineStatement = '';
let lines = entityFile.toString().replace('\r','').split('\n');
let lines = entityFile.toString().replace('\r', '').split('\n');
for (let line of lines) {
let trimmedLine = line.trim();
if (isMultilineStatement)
@ -33,8 +57,9 @@ export class EntityFileToJson {
continue;
} else {
isMultilineStatement = false;
retVal.columns.push(new EntityColumn())
//TODO:Options, column type if declared
let col = new EntityColumn()
this.getColumnOptionsAndType(trimmedLine, col)
retVal.columns.push(col);
continue;
}
@ -45,8 +70,10 @@ export class EntityFileToJson {
continue;
} else {
isMultilineStatement = false;
retVal.columns.push(new EntityColumn())
//TODO:Options, column type if declared
let col = new EntityColumn()
this.getColumnOptionsAndType(trimmedLine, col)
col.columnOptions['primary'] = true
retVal.columns.push(col);
continue;
}
} else if (trimmedLine.startsWith('@PrimaryGeneratedColumn')) {
@ -56,8 +83,11 @@ export class EntityFileToJson {
continue;
} else {
isMultilineStatement = false;
retVal.columns.push(new EntityColumn())
//TODO:Options, column type if declared
let col = new EntityColumn()
this.getColumnOptionsAndType(trimmedLine, col)
col.columnOptions['primary'] = true
col.columnOptions['generated'] = true
retVal.columns.push(col);
continue;
}
} else if (trimmedLine.startsWith('@ManyToOne')) {
@ -83,11 +113,11 @@ export class EntityFileToJson {
continue;
}
} else if (trimmedLine.split(':').length - 1 > 0) {
retVal.columns[retVal.columns.length-1].columnName=trimmedLine.split(':')[0].trim();
retVal.columns[retVal.columns.length-1].columnType=trimmedLine.split(':')[1].split(';')[0].trim();
retVal.columns[retVal.columns.length - 1].columnName = trimmedLine.split(':')[0].trim();
retVal.columns[retVal.columns.length - 1].columnType = trimmedLine.split(':')[1].split(';')[0].trim();
continue
}else if(trimmedLine='}'){
isInClassBody=false;
} else if (trimmedLine = '}') {
isInClassBody = false;
continue; //class declaration end
}
}
@ -112,4 +142,5 @@ class EntityJson {
class EntityColumn {
columnName: string
columnType: string
columnOptions: any = {}
}