sqlite implementation

This commit is contained in:
Kononnable 2019-10-11 12:01:35 +02:00
parent 6d4a97d39a
commit 95e0cc5854
2 changed files with 330 additions and 270 deletions

View File

@ -11,6 +11,10 @@ import IndexColumnInfo from "../oldModels/IndexColumnInfo";
import RelationTempInfo from "../oldModels/RelationTempInfo";
import IConnectionOptions from "../IConnectionOptions";
import { Entity } from "../models/Entity";
import { Column } from "../models/Column";
import { Index } from "../models/Index";
import IGenerationOptions from "../IGenerationOptions";
import { RelationInternal } from "../models/RelationInternal";
export default class SqliteDriver extends AbstractDriver {
public defaultValues: DataTypeDefaults = new TypeormDriver.SqliteDriver({
@ -54,277 +58,335 @@ export default class SqliteDriver extends AbstractDriver {
}
public async GetCoulmnsFromEntity(entities: Entity[]): Promise<Entity[]> {
throw new Error();
// TODO: Remove
// await Promise.all(
// entities.map(async ent => {
// const response = await this.ExecQuery<{
// cid: number;
// name: string;
// type: string;
// notnull: number;
// dflt_value: string;
// pk: number;
// }>(`PRAGMA table_info('${ent.tsEntityName}');`);
// response.forEach(resp => {
// const colInfo: ColumnInfo = new ColumnInfo();
// colInfo.tsName = resp.name;
// colInfo.options.name = resp.name;
// colInfo.options.nullable = resp.notnull === 0;
// colInfo.options.primary = resp.pk > 0;
// colInfo.options.default = SqliteDriver.ReturnDefaultValueFunction(
// resp.dflt_value
// );
// colInfo.options.type = resp.type
// .replace(/\([0-9 ,]+\)/g, "")
// .toLowerCase()
// .trim() as any;
// colInfo.options.generated =
// colInfo.options.primary &&
// this.tablesWithGeneratedPrimaryKey.includes(
// ent.tsEntityName
// );
// switch (colInfo.options.type) {
// case "int":
// colInfo.tsType = "number";
// break;
// case "integer":
// colInfo.tsType = "number";
// break;
// case "int2":
// colInfo.tsType = "number";
// break;
// case "int8":
// colInfo.tsType = "number";
// break;
// case "tinyint":
// colInfo.tsType = "number";
// break;
// case "smallint":
// colInfo.tsType = "number";
// break;
// case "mediumint":
// colInfo.tsType = "number";
// break;
// case "bigint":
// colInfo.tsType = "string";
// break;
// case "unsigned big int":
// colInfo.tsType = "string";
// break;
// case "character":
// colInfo.tsType = "string";
// break;
// case "varchar":
// colInfo.tsType = "string";
// break;
// case "varying character":
// colInfo.tsType = "string";
// break;
// case "nchar":
// colInfo.tsType = "string";
// break;
// case "native character":
// colInfo.tsType = "string";
// break;
// case "nvarchar":
// colInfo.tsType = "string";
// break;
// case "text":
// colInfo.tsType = "string";
// break;
// case "blob":
// colInfo.tsType = "Buffer";
// break;
// case "clob":
// colInfo.tsType = "string";
// break;
// case "real":
// colInfo.tsType = "number";
// break;
// case "double":
// colInfo.tsType = "number";
// break;
// case "double precision":
// colInfo.tsType = "number";
// break;
// case "float":
// colInfo.tsType = "number";
// break;
// case "numeric":
// colInfo.tsType = "number";
// break;
// case "decimal":
// colInfo.tsType = "number";
// break;
// case "boolean":
// colInfo.tsType = "boolean";
// break;
// case "date":
// colInfo.tsType = "string";
// break;
// case "datetime":
// colInfo.tsType = "Date";
// break;
// default:
// TomgUtils.LogError(
// `Unknown column type: ${colInfo.options.type} table name: ${ent.tsEntityName} column name: ${resp.name}`
// );
// break;
// }
// const options = resp.type.match(/\([0-9 ,]+\)/g);
// if (
// this.ColumnTypesWithPrecision.some(
// v => v === colInfo.options.type
// ) &&
// options
// ) {
// colInfo.options.precision = options[0]
// .substring(1, options[0].length - 1)
// .split(",")[0] as any;
// colInfo.options.scale = options[0]
// .substring(1, options[0].length - 1)
// .split(",")[1] as any;
// }
// if (
// this.ColumnTypesWithLength.some(
// v => v === colInfo.options.type
// ) &&
// options
// ) {
// colInfo.options.length = options[0].substring(
// 1,
// options[0].length - 1
// ) as any;
// }
// if (
// this.ColumnTypesWithWidth.some(
// v =>
// v === colInfo.options.type &&
// colInfo.tsType !== "boolean"
// ) &&
// options
// ) {
// colInfo.options.width = options[0].substring(
// 1,
// options[0].length - 1
// ) as any;
// }
await Promise.all(
entities.map(async ent => {
const response = await this.ExecQuery<{
cid: number;
name: string;
type: string;
notnull: number;
dflt_value: string;
pk: number;
}>(`PRAGMA table_info('${ent.tscName}');`);
response.forEach(resp => {
const tscName = resp.name;
let tscType = "";
const options: Partial<Column["options"]> = {};
options.name = resp.name;
if (resp.notnull === 0) options.nullable = true;
const isPrimary = resp.pk > 0 ? true : undefined;
const defaultValue = SqliteDriver.ReturnDefaultValueFunction(
resp.dflt_value
);
let columnType = resp.type
.replace(/\([0-9 ,]+\)/g, "")
.toLowerCase()
.trim();
const generated =
isPrimary &&
this.tablesWithGeneratedPrimaryKey.includes(ent.tscName)
? true
: undefined;
switch (columnType) {
case "int":
tscType = "number";
break;
case "integer":
tscType = "number";
break;
case "int2":
tscType = "number";
break;
case "int8":
tscType = "number";
break;
case "tinyint":
tscType = "number";
break;
case "smallint":
tscType = "number";
break;
case "mediumint":
tscType = "number";
break;
case "bigint":
tscType = "string";
break;
case "unsigned big int":
tscType = "string";
break;
case "character":
tscType = "string";
break;
case "varchar":
tscType = "string";
break;
case "varying character":
tscType = "string";
break;
case "nchar":
tscType = "string";
break;
case "native character":
tscType = "string";
break;
case "nvarchar":
tscType = "string";
break;
case "text":
tscType = "string";
break;
case "blob":
tscType = "Buffer";
break;
case "clob":
tscType = "string";
break;
case "real":
tscType = "number";
break;
case "double":
tscType = "number";
break;
case "double precision":
tscType = "number";
break;
case "float":
tscType = "number";
break;
case "numeric":
tscType = "number";
break;
case "decimal":
tscType = "number";
break;
case "boolean":
tscType = "boolean";
break;
case "date":
tscType = "string";
break;
case "datetime":
tscType = "Date";
break;
default:
TomgUtils.LogError(
`Unknown column type: ${columnType} table name: ${ent.tscName} column name: ${resp.name}`
);
break;
}
const sqlOptions = resp.type.match(/\([0-9 ,]+\)/g);
if (
this.ColumnTypesWithPrecision.some(
v => v === columnType
) &&
sqlOptions
) {
options.precision = sqlOptions[0]
.substring(1, sqlOptions[0].length - 1)
.split(",")[0] as any;
options.scale = sqlOptions[0]
.substring(1, sqlOptions[0].length - 1)
.split(",")[1] as any;
}
if (
this.ColumnTypesWithLength.some(
v => v === columnType
) &&
sqlOptions
) {
options.length = Number.parseInt(
sqlOptions[0].substring(
1,
sqlOptions[0].length - 1
),
10
);
}
if (
this.ColumnTypesWithWidth.some(
v => v === columnType && tscType !== "boolean"
) &&
sqlOptions
) {
options.width = sqlOptions[0].substring(
1,
sqlOptions[0].length - 1
) as any;
}
// if (colInfo.options.type) {
// ent.Columns.push(colInfo);
// }
// });
// })
// );
if (columnType) {
ent.columns.push({
generated,
primary: isPrimary,
type: columnType,
default: defaultValue,
options: { name: "", ...options }, // TODO: Change
tscName,
tscType
});
}
});
})
);
// return entities;
return entities;
}
public async GetIndexesFromEntity(entities: Entity[]): Promise<Entity[]> {
throw new Error();
// TODO: Remove
// await Promise.all(
// entities.map(async ent => {
// const response = await this.ExecQuery<{
// seq: number;
// name: string;
// unique: number;
// origin: string;
// partial: number;
// }>(`PRAGMA index_list('${ent.tsEntityName}');`);
// await Promise.all(
// response.map(async resp => {
// const indexColumnsResponse = await this.ExecQuery<{
// seqno: number;
// cid: number;
// name: string;
// }>(`PRAGMA index_info('${resp.name}');`);
// indexColumnsResponse.forEach(element => {
// let indexInfo: IndexInfo = {} as IndexInfo;
// const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo;
// if (
// ent.Indexes.filter(filterVal => {
// return filterVal.name === resp.name;
// }).length > 0
// ) {
// indexInfo = ent.Indexes.find(
// filterVal => filterVal.name === resp.name
// )!;
// } else {
// indexInfo.columns = [] as IndexColumnInfo[];
// indexInfo.name = resp.name;
// indexInfo.isUnique = resp.unique === 1;
// ent.Indexes.push(indexInfo);
// }
// indexColumnInfo.name = element.name;
// if (
// indexColumnsResponse.length === 1 &&
// indexInfo.isUnique
// ) {
// ent.Columns.filter(
// v => v.tsName === indexColumnInfo.name
// ).forEach(v => {
// // eslint-disable-next-line no-param-reassign
// v.options.unique = true;
// });
// }
// indexInfo.columns.push(indexColumnInfo);
// });
// })
// );
// })
// );
await Promise.all(
entities.map(async ent => {
const response = await this.ExecQuery<{
seq: number;
name: string;
unique: number;
origin: string;
partial: number;
}>(`PRAGMA index_list('${ent.tscName}');`);
await Promise.all(
response.map(async resp => {
const indexColumnsResponse = await this.ExecQuery<{
seqno: number;
cid: number;
name: string;
}>(`PRAGMA index_info('${resp.name}');`);
// return entities;
const indexInfo: Index = {
name: resp.name,
columns: [],
options: {}
};
if (resp.unique === 1) indexInfo.options.unique = true;
indexColumnsResponse.forEach(record => {
indexInfo.columns.push(record.name);
});
if (
indexColumnsResponse.length === 1 &&
indexInfo.options.unique
) {
ent.columns
.filter(v => v.tscName === indexInfo.columns[0])
.forEach(v => {
// eslint-disable-next-line no-param-reassign
v.options.unique = true;
});
}
ent.indices.push(indexInfo);
// indexColumnsResponse.forEach(element => {
// const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo;
// if (
// ent.indices.filter(filterVal => {
// return filterVal.name === resp.name;
// }).length > 0
// ) {
// indexInfo = ent.indices.find(
// filterVal => filterVal.name === resp.name
// )!;
// } else {
// indexInfo.columns = [] as IndexColumnInfo[];
// indexInfo.name = resp.name;
// indexInfo.isUnique = resp.unique === 1;
// ent.indices.push(indexInfo);
// }
// indexColumnInfo.name = element.name;
// if (
// indexColumnsResponse.length === 1 &&
// indexInfo.isUnique
// ) {
// ent.columns
// .filter(
// v => v.tscName === indexColumnInfo.name
// )
// .forEach(v => {
// // eslint-disable-next-line no-param-reassign
// v.options.unique = true;
// });
// }
// indexInfo.columns.push(indexColumnInfo);
// });
})
);
})
);
return entities;
}
public async GetRelations(entities: Entity[]): Promise<Entity[]> {
throw new Error();
// TODO: Remove
// let retVal = entities;
// await Promise.all(
// retVal.map(async entity => {
// const response = await this.ExecQuery<{
// id: number;
// seq: number;
// table: string;
// from: string;
// to: string;
// on_update:
// | "RESTRICT"
// | "CASCADE"
// | "SET NULL"
// | "NO ACTION";
// on_delete:
// | "RESTRICT"
// | "CASCADE"
// | "SET NULL"
// | "NO ACTION";
// match: string;
// }>(`PRAGMA foreign_key_list('${entity.tsEntityName}');`);
// const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[];
// response.forEach(resp => {
// const rels = {} as RelationTempInfo;
// rels.ownerColumnsNames = [];
// rels.referencedColumnsNames = [];
// rels.actionOnDelete =
// resp.on_delete === "NO ACTION" ? null : resp.on_delete;
// rels.actionOnUpdate =
// resp.on_update === "NO ACTION" ? null : resp.on_update;
// rels.ownerTable = entity.tsEntityName;
// rels.referencedTable = resp.table;
// relationsTemp.push(rels);
// rels.ownerColumnsNames.push(resp.from);
// rels.referencedColumnsNames.push(resp.to);
// });
// retVal = SqliteDriver.GetRelationsFromRelationTempInfo(
// relationsTemp,
// retVal
// );
// })
// );
// return retVal;
public async GetRelations(
entities: Entity[],
schema: string,
dbNames: string,
generationOptions: IGenerationOptions
): Promise<Entity[]> {
let retVal = entities;
await Promise.all(
retVal.map(async entity => {
const response = await this.ExecQuery<{
id: number;
seq: number;
table: string;
from: string;
to: string;
on_update:
| "RESTRICT"
| "CASCADE"
| "SET NULL"
| "NO ACTION";
on_delete:
| "RESTRICT"
| "CASCADE"
| "SET NULL"
| "NO ACTION";
match: string;
}>(`PRAGMA foreign_key_list('${entity.tscName}');`);
const relationsTemp: RelationInternal[] = [] as RelationInternal[];
const relationKeys = new Set(response.map(v => v.id));
relationKeys.forEach(relationId => {
const rows = response.filter(v => v.id === relationId);
const ownerTable = entities.find(
v => v.sqlName === entity.tscName
);
const relatedTable = entities.find(
v => v.sqlName === rows[0].table
);
if (!ownerTable || !relatedTable) {
TomgUtils.LogError(
`Relation between tables ${entity.tscName} and ${rows[0].table} wasn't found in entity model.`,
true
);
return;
}
const internal: RelationInternal = {
ownerColumns: [],
relatedColumns: [],
ownerTable,
relatedTable
};
if (rows[0].on_delete !== "NO ACTION") {
internal.onDelete = rows[0].on_delete;
}
if (rows[0].on_update !== "NO ACTION") {
internal.onUpdate = rows[0].on_update;
}
rows.forEach(row => {
internal.ownerColumns.push(row.from);
internal.relatedColumns.push(row.to);
});
relationsTemp.push(internal);
});
retVal = SqliteDriver.GetRelationsFromRelationTempInfo(
relationsTemp,
retVal,
generationOptions
);
})
);
return retVal;
}
public async DisconnectFromServer() {
@ -393,9 +455,9 @@ export default class SqliteDriver extends AbstractDriver {
private static ReturnDefaultValueFunction(
defVal: string | null
): string | null {
): string | undefined {
if (!defVal) {
return null;
return undefined;
}
if (defVal.startsWith(`'`)) {
return `() => "${defVal}"`;

View File

@ -2,7 +2,6 @@ import { Entity, PrimaryColumn, Column } from "typeorm";
@Entity("Post")
export class Post {
@PrimaryColumn()
id: number;
@ -34,7 +33,7 @@ export class Post {
bigint: string;
@Column("unsigned big int")
unsigned_big_int: string;
unsignedBigInt: string;
@Column("character")
character: string;
@ -43,13 +42,13 @@ export class Post {
varchar: string;
@Column("varying character")
varying_character: string;
varyingCharacter: string;
@Column("nchar")
nchar: string;
@Column("native character")
native_character: string;
nativeCharacter: string;
@Column("nvarchar")
nvarchar: string;
@ -88,5 +87,4 @@ export class Post {
@Column("datetime")
datetime: Date;
}