import mariadb from 'mariadb'; import { checkConstraint, Constraint, Datatype, foreignConstraint, uniqueConstraint } from './dbStructure.js'; import { Handler } from './defaultHandler.js'; import { Query } from './query.js'; import { attributeSettings, extendedAttributeSettings, onAction, dbType } from './types.js'; import { TableAlias } from "./alias.js" import { insertResponse, readResponse, writeResponse, singleResponse } from "./responses.js" //import { postgresHandler } from "./postgresHandler" declare module "mariadb" { interface Pool{ on(ev: 'error', callback: () => void): Pool; } } export class DB { tables: Table[] = []; handler!: Handler; name!: string; type!: dbType; mariaPool!: mariadb.Pool; private connected = false; //pgPool!: pg.Pool; connect({ host, user, password, database, port = 3306, connectionLimit = 5, databaseType = dbType.mariadb }: { host: string, user: string, password: string, database: string, port?: number, connectionLimit?: number, databaseType?: dbType }) { this.connected = true; this.type = databaseType; if (databaseType == dbType.mariadb) { this.mariaPool = mariadb.createPool({ host, user, password, port, database, connectionLimit, multipleStatements: true }); // catch errors this.mariaPool.on("error",()=>{}); this.handler = new Handler(this); } /*else if (databaseType == dbType.postgres) { this.pgPool = new pg.Pool({ host, user, password, max: connectionLimit, database, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000 }); this.handler = new postgresHandler(this); }*/ else throw new Error("Unsuported Database type!"); this.name = database; } async query(query: Query, printQuery = false) { if (!this.connected) throw new Error("Not connected yet!"); if (printQuery) 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); console.log([...res.rows]); return res.rows; }*/ else throw new Error("Invalid Database Type!"); } getHandler() { if (!this.connected) throw new Error("Not connected yet!"); return this.handler; } async sync(force = false) { if (!this.connected) throw new Error("Not connected yet!"); let handler = this.getHandler(); await handler.syncDB(this, handler, force); } newTable(name: string) { let tabel = new Table(name, this); this.tables.push(tabel); return tabel; } getTable(name: string) { for (let i = 0; i < this.tables.length; i++) if (this.tables[i].dbLangTableName == name) return this.tables[i]; return null; } async close() { if (!this.connected) throw new Error("Not connected yet!"); if (this.type == dbType.mariadb && this.mariaPool) await this.mariaPool.end(); //if (this.type == dbType.postgres && this.pgPool) await this.pgPool.end(); this.connected = false; } } export class Attribute { name: string; nameO: string; table: Table; ops: attributeSettings; type: Datatype; 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; if (ops.check != null) { if (typeof ops.check == "function") ops.check = ops.check(this); table.addConstraint(new checkConstraint( table.dbLangDatabaseInstance.name + "_" + table.dbLangTableName + "_" + name + "_check_constraint", ops.check )) } if (ops.unique != null) { table.addConstraint(new uniqueConstraint( table.dbLangDatabaseInstance.name + "_" + table.dbLangTableName + "_" + name + "_unique_constraint", [this] )) } if (ops.foreignKey != null) { table.addConstraint(new foreignConstraint( table.dbLangDatabaseInstance.name + "_" + table.dbLangTableName + "_" + name + "_foreign_constraint_to_" + ops.foreignKey.link.name, [this], [ops.foreignKey.link], ops.foreignKey.onDelete, ops.foreignKey.onUpdate )); } } serializeDatatype(handler: Handler) { return this.type.serialize(handler); } serializeSettings(handler: Handler) { return handler.builders.attributeSettings(handler, this); } serialize(handler: Handler) { return handler.builders.escapeID(this.name); } getString(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) + ")"; } toString() { return this.table.dbLangTableName + "_" + this.name; } } export class Table { dbLangTableName: string; dbLangTableAttributes: { [key: string]: Attribute; } = {}; dbLangDatabaseInstance: DB; dbLangConstrains: Constraint[] = []; [key: string]: Attribute | any; constructor(name: string, db: DB) { this.dbLangTableName = name; this.dbLangDatabaseInstance = db; } serialize(handler: Handler) { return this.toString(handler); } toString(handler: Handler = this.dbLangDatabaseInstance.getHandler()) { return handler.builders.escapeID(this.dbLangTableName); } 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, name, this, type, ops); this.dbLangTableAttributes[lowName] = attr; 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; this[name] = attr; } return attr; } addAttributes(list: { [key: string]: (extendedAttributeSettings) }): { [key: string]: Attribute } { return Object.fromEntries(Object.entries(list).map(([k, a]) => { return [k, this.addAttribute(k, a.type, a)]; })); } addConstraint(c: Constraint) { let check = c.check(this); if(typeof check == "string") throw new Error(check); this.dbLangConstrains.push(c); } createAlias(name: string) { return new TableAlias(name, this); } } export * from './funcs.js'; export { onAction }; export { dbType as databaseType } export { readResponse, writeResponse, insertResponse, singleResponse }