diff --git a/src/alias.ts b/src/alias.ts index 501753c..c66da53 100644 --- a/src/alias.ts +++ b/src/alias.ts @@ -1,9 +1,51 @@ -import { Attribute, Table } from "./db" - -export class TableAlias extends Table{ +import { Attribute, DB, Table } from "./db" +import { Handler } from "./defaultHandler"; +export class AttributeAlias { + name: string; + nameO: string; + table: TableAlias; + attr: Attribute; + constructor(attr: Attribute, table: TableAlias) { + this.name = attr.name; + this.nameO = attr.nameO; + this.attr = attr; + this.table = table; + } + serialize(handler: Handler) { + return handler.builders.escapeID(this.name); + } + toString(handler: Handler = this.table.dbLangDatabaseInstance.getHandler()) { + return this.table.serialize(handler) + "." + this.serialize(handler); + } + toStringFunc(handler: Handler) { + return this.table.serialize(handler) + "(" + this.serialize(handler) + ")"; + } } -export class AttributeAlias extends Attribute{ - +export class TableAlias { + dbLangTableName: string; + dbLangTableAttributes: { [key: string]: AttributeAlias; } = {}; + dbLangDatabaseInstance: DB; + dbLangTableInstance: Table; + [key: string]: AttributeAlias | any; + constructor(name: string, table: Table) { + this.dbLangTableName = name; + this.dbLangTableInstance = table; + this.dbLangDatabaseInstance = table.dbLangDatabaseInstance; + let keys = Object.keys(table.dbLangTableAttributes); + for (let i = 0; i < keys.length; i++) { + const a = table.dbLangTableAttributes[keys[i]]; + let attrAlias = new AttributeAlias(a, this); + this[a.name] = attrAlias; + this[a.nameO] = attrAlias; + this.dbLangTableAttributes[a.name] = attrAlias; + } + } + serialize(handler: Handler) { + return this.toString(handler); + } + toString(handler: Handler = this.dbLangDatabaseInstance.getHandler()) { + return handler.builders.escapeID(this.dbLangTableName); + } } \ No newline at end of file diff --git a/src/db.ts b/src/db.ts index 1ea9169..7b9de08 100644 --- a/src/db.ts +++ b/src/db.ts @@ -3,6 +3,7 @@ import { checkConstraint, Constraint, Datatype, foreignConstraint, uniqueConstra import { Handler } from './defaultHandler'; import { Query } from './query'; import { attributeSettings, extendedAttributeSettings, onAction, dbType } from './types'; +import { TableAlias } from "./alias" //import { postgresHandler } from "./postgresHandler" @@ -16,7 +17,7 @@ export class DB { constructor({ host, user, password, database, connectionLimit = 5, databaseType = dbType.mariadb }: { host: string, user: string, password: string, database: string, connectionLimit: number, databaseType: dbType }) { this.type = databaseType; if (databaseType == dbType.mariadb) { - this.mariaPool = mariadb.createPool({ host, user, password, database, connectionLimit, multipleStatements: true }); + this.mariaPool = mariadb.createPool({ host, user, password, database, connectionLimit, multipleStatements: false }); this.handler = new Handler(this); } /*else if (databaseType == dbType.postgres) { @@ -28,7 +29,7 @@ export class DB { this.name = database; } async query(query: Query) { - //console.log(query); + console.log(query); if (this.type == dbType.mariadb) return await this.mariaPool.query(query); /*else if (this.type == dbType.postgres) { let res = await this.pgPool.query(query.sql, query.values); @@ -64,11 +65,13 @@ export class DB { export class Attribute { name: string; + nameO: string; table: Table; ops: attributeSettings; type: Datatype; - constructor(name: string, table: Table, type: Datatype, ops: attributeSettings) { + constructor(name: string, nameO: string, table: Table, type: Datatype, ops: attributeSettings) { this.name = name.toLowerCase(); + this.nameO = nameO; this.type = type; this.table = table; this.ops = ops; @@ -133,9 +136,9 @@ export class Table { addAttribute(name: string, type: Datatype, ops: attributeSettings = {}, noErrorOnNameConflict = false) { let lowName = name.toLowerCase(); if (this.dbLangTableAttributes[lowName] != null) throw new Error("You are tring to create an Attribute twise!"); - let attr = new Attribute(lowName, this, type, ops); + let attr = new Attribute(lowName, name, this, type, ops); this.dbLangTableAttributes[lowName] = attr; - if (["serialize", "toString", "addAttribute", "dbLangTableName", "dbLangTableAttributes", "dbLangDatabaseInstance", "addConstraint", "addAttributes"].includes(lowName)) { + if (["serialize", "toString", "addAttribute", "dbLangTableName", "dbLangTableAttributes", "dbLangDatabaseInstance", "addConstraint", "addAttributes", "createAlias"].includes(lowName)) { if (!noErrorOnNameConflict) throw new Error("You cannot name Attribute like Methode of this Table!"); } else { this[lowName] = attr; @@ -152,6 +155,9 @@ export class Table { c.check(this); this.dbLangConstrains.push(c); } + createAlias(name: string) { + return new TableAlias(name, this); + } } export * from './funcs'; diff --git a/src/defaultHandler.ts b/src/defaultHandler.ts index d5f9c3c..510da7e 100644 --- a/src/defaultHandler.ts +++ b/src/defaultHandler.ts @@ -1,3 +1,4 @@ +import { AttributeAlias, TableAlias } from "./alias"; import { Attribute, DB, Table } from "./db" import { Aggregation, checkConstraint, joinCross, Datatype, foreignConstraint, Modifier, joinNatural, onJoin, uniqueConstraint, usingJoin } from "./dbStructure" import { insertQuery, Query, QueryBuilder, removeQuery, selectQuery, updateQuery } from "./query" @@ -5,13 +6,13 @@ import { allModifierInput, joinType, onAction, primaryData } from "./types" export class Handler { db: DB; - constructor(db: DB){ + constructor(db: DB) { this.db = db; } async syncDB(db: DB, handler: Handler, deleteInDB: boolean = false) { //Constraint Data let constraints = await db.query(handler.builders.query(handler.querys.listConstraints(handler, db))); - let key = await db.query(handler.builders.query(handler.querys.listConstraintDetails(handler, db))); + let key = [...await db.query(handler.builders.query(handler.querys.listConstraintDetails(handler, db)))]; //Table List let allTables = (await db.query(handler.builders.query(handler.querys.listTables(handler, db)))).map((d: any) => d.TABLE_NAME ?? d.table_name); @@ -23,10 +24,10 @@ export class Handler { const tableDataBuilder = new QueryBuilder(); tableDataBuilder.addCode("DESCRIBE "); tableDataBuilder.addCode(table.serialize(handler)); - tableData[table.dbLangTableName.toLowerCase()] = + tableData[table.dbLangTableName] = Object.fromEntries((await db.query(handler.builders.query(tableDataBuilder))).map((d: any) => [d.Field.toLowerCase(), d])); } catch (_) { - tableData[table.dbLangTableName.toLowerCase()] = null; + tableData[table.dbLangTableName] = null; } } @@ -126,12 +127,12 @@ export class Handler { del.appendEnding(handler.querys.removeCheck(handler, (c.TABLE_NAME ?? c.table_name), (c.CONSTRAINT_NAME ?? c.constraint_name))); } else if ((c.CONSTRAINT_TYPE ?? c.constraint_type) == "UNIQUE") { if ( - (typeof tableData[(c.TABLE_NAME ?? c.table_name).toLowerCase()] == "undefined" && deleteInDB) + (typeof tableData[c.TABLE_NAME ?? c.table_name] == "undefined" && deleteInDB) || !checkUniqueIsVaild((c.CONSTRAINT_NAME ?? c.constraint_name), (c.TABLE_NAME ?? c.table_name)) ) del.appendEnding(handler.querys.removeUnique(handler, (c.TABLE_NAME ?? c.table_name), (c.CONSTRAINT_NAME ?? c.constraint_name))); } else if ((c.CONSTRAINT_TYPE ?? c.constraint_type) == "FOREIGN KEY") { if ( - (typeof tableData[(c.TABLE_NAME ?? c.table_name).toLowerCase()] == "undefined" && deleteInDB) + (typeof tableData[c.TABLE_NAME ?? c.table_name] == "undefined" && deleteInDB) || !checkForeignIsVaild((c.CONSTRAINT_NAME ?? c.constraint_name), (c.TABLE_NAME ?? c.table_name)) ) del.appendEnding(handler.querys.removeForeignKey(handler, (c.TABLE_NAME ?? c.table_name), (c.CONSTRAINT_NAME ?? c.constraint_name))); } @@ -149,6 +150,7 @@ export class Handler { && (k.REFERENCED_COLUMN_NAME ?? k.referenced_column_name).toLowerCase() == attr.toLowerCase() ) { del.appendEnding(handler.querys.removeForeignKey(handler, (k.TABLE_NAME ?? k.table_name), (k.CONSTRAINT_NAME ?? k.constraint_name))); + key.splice(i--, 1); } } } @@ -156,7 +158,7 @@ export class Handler { //create tables for (let i = 0; i < db.tables.length; i++) { const table = db.tables[i]; - const tableD = tableData[table.dbLangTableName.toLowerCase()]; + const tableD = tableData[table.dbLangTableName]; //delete unused Columns if (deleteInDB && tableD != null) { let keys = Object.keys(tableD); @@ -191,7 +193,8 @@ export class Handler { (!!a.ops.notNull || !!a.ops.autoIncrement || !!a.ops.primaryKey), (attrData.Null == "NO"), "|", (!!a.ops.autoIncrement), (attrData.Extra == "auto_increment"));*/ freeForUpdate(a.name, a.table.dbLangTableName); - create.appendEnding(handler.querys.changeColumn(handler, a)); + if (a.ops.autoIncrement) + create.appendEnding(handler.querys.changeColumn(handler, a)); } if (attrData == null) { changePrimary = true; @@ -207,6 +210,9 @@ export class Handler { create.appendEnding(handler.querys.removePrimaryKey(handler, table.dbLangTableName)); create.appendEnding(handler.querys.addPrimaryKey(handler, table)); } + } + for (let i = 0; i < db.tables.length; i++) { + const table = db.tables[i]; for (let j = 0; j < table.dbLangConstrains.length; j++) { const c = table.dbLangConstrains[j]; if (c instanceof checkConstraint) { @@ -235,7 +241,7 @@ export class Handler { builder.addCode(` from `); if (q.from == null) { builder.addCode(" DUAL"); - } else if (q.from instanceof Table) { + } else if (q.from instanceof Table || q.from instanceof TableAlias) { builder.addCode(q.from.serialize(handler)); } else { builder.append(q.from.serialize(handler)); @@ -299,7 +305,7 @@ export class Handler { const s = q.setD[i]; qb.addCode(s[0].serialize(handler)); qb.addCode(" = ("); - if (s[1] instanceof Attribute) qb.addCode(s[1].serialize(handler)); + if (s[1] instanceof Attribute || s[1] instanceof AttributeAlias) qb.addCode(s[1].serialize(handler)); else if (s[1] instanceof Modifier || s[1] instanceof selectQuery || s[1] instanceof Aggregation) { qb.append(s[1].serialize(handler)); } else { @@ -443,14 +449,15 @@ export class Handler { return builder; }, addPrimaryKey: (handler: Handler, table: Table) => { + let primaAttr = Object.entries(table.dbLangTableAttributes) + .filter(([n, attr]) => !!attr.ops.primaryKey); const qb = new QueryBuilder(); + if(primaAttr.length == 0) return qb; qb.addCode("ALTER TABLE "); qb.addCode(table.serialize(handler)); qb.addCode(" add PRIMARY KEY if not exists ("); qb.addCodeCommaSeperated( - Object.entries(table.dbLangTableAttributes) - .filter(([n, attr]) => !!attr.ops.primaryKey) - .map(([n, attr]) => handler.builders.escapeID(n)) + primaAttr.map(([n, attr]) => handler.builders.escapeID(n)) ); qb.addCode(")"); return qb; @@ -550,7 +557,7 @@ export class Handler { let sql = ""; for (let i = 0; i < qb.list.length; i++) { const [inject, data] = qb.list[i]; - if(inject)sql += handler.builders.escapeLiteral(data); + if (inject) sql += handler.builders.escapeLiteral(data); else sql += data; } return curr.split(", ").join(",").startsWith(sql.split(", ").join(",")); @@ -664,7 +671,7 @@ export class Handler { divide: joinArg("-/"), not: (handler: Handler, a: allModifierInput[]): QueryBuilder => { let e = a[0]; - if (e instanceof Attribute) return new QueryBuilder([{ data: "not (" + e.toString(handler) + ")" }]) + if (e instanceof Attribute || e instanceof AttributeAlias) return new QueryBuilder([{ data: "not (" + e.toString(handler) + ")" }]) if (e instanceof Modifier || e instanceof selectQuery || e instanceof Aggregation) { const builder = new QueryBuilder(); builder.addCode("not ("); @@ -680,14 +687,14 @@ export class Handler { }, like: (handler: Handler, a: allModifierInput[]): QueryBuilder => { const builder = new QueryBuilder(); - if (a[0] instanceof Attribute) builder.addCode(a[0].toString()); + if (a[0] instanceof Attribute || a[0] instanceof AttributeAlias) builder.addCode(a[0].toString()); else if (a[0] instanceof Modifier || a[0] instanceof selectQuery || a[0] instanceof Aggregation) { builder.append(a[0].serialize(handler)); } else { builder.addInjection(a[0]); } builder.addCode(" LIKE "); - if (a[1] instanceof Attribute) builder.addCode(a[1].toString()); + if (a[1] instanceof Attribute || a[1] instanceof AttributeAlias) builder.addCode(a[1].toString()); else if (a[1] instanceof Modifier || a[1] instanceof selectQuery || a[1] instanceof Aggregation) { builder.append(a[1].serialize(handler)); } else { @@ -700,7 +707,7 @@ export class Handler { builder.addCode("CONCAT("); for (let i = 0; i < a.length; i++) { const e = a[i]; - if (e instanceof Attribute) builder.addCode(e.toString()); + if (e instanceof Attribute || e instanceof AttributeAlias) builder.addCode(e.toString()); else if (e instanceof Modifier || e instanceof selectQuery || e instanceof Aggregation) { builder.append(e.serialize(handler)); } else { @@ -798,7 +805,7 @@ function joinArg(type: string) { const builder = new QueryBuilder(); for (let i = 0; i < a.length; i++) { const d = a[i]; - if (d instanceof Attribute) builder.addCode(d.toString(handler)); + if (d instanceof Attribute || d instanceof AttributeAlias) builder.addCode(d.toString(handler)); else if (d instanceof Modifier || d instanceof selectQuery || d instanceof Aggregation) { builder.addCode("("); builder.append(d.serialize(handler)); diff --git a/src/query.ts b/src/query.ts index 0c39120..29b713e 100644 --- a/src/query.ts +++ b/src/query.ts @@ -1,3 +1,4 @@ +import { AttributeAlias } from "./alias"; import { Attribute, DB, Table } from "./db"; import { BooleanModifier, Modifier } from "./dbStructure"; import { Handler } from "./defaultHandler"; @@ -48,6 +49,7 @@ export class QueryBuilder { this.list.push(...qb.list); } appendEnding(qb: QueryBuilder) { + if(qb.isEmpty()) return; this.append(qb); this.list.push([false, ";"]); } @@ -72,8 +74,8 @@ export class selectQuery { this.whereD = m; return this; } - groupByD: Attribute[] = []; - groupBy(a: Attribute[]) { + groupByD: (Attribute | AttributeAlias)[] = []; + groupBy(a: (Attribute | AttributeAlias)[]) { this.groupByD = a; return this; } diff --git a/src/types.ts b/src/types.ts index 8f95678..f256d8d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,12 +1,13 @@ +import { AttributeAlias, TableAlias } from "./alias"; import { Attribute, Table } from "./db"; import { Aggregation, BooleanModifier, Datatype, Joins, Modifier } from "./dbStructure"; import { QueryBuilder, selectQuery } from "./query"; export type primaryData = string | number | boolean | null; -export type allModifierInput = primaryData | Modifier | selectQuery | Attribute | Aggregation; +export type allModifierInput = primaryData | Modifier | selectQuery | Attribute | AttributeAlias | Aggregation; -export type selectElements = primaryData | Attribute | Aggregation | selectQuery -export type selectFromElements = Table | Joins | null; +export type selectElements = primaryData | Attribute | AttributeAlias | Aggregation | selectQuery +export type selectFromElements = TableAlias | Table | Joins | null; export type joinElements = Table | Joins; export type serializeReturn = [string, primaryData[]];