This commit is contained in:
parent
37385589d6
commit
78d894c415
6 changed files with 304 additions and 86 deletions
|
@ -1,4 +1,4 @@
|
||||||
# DBlang
|
# DBlang
|
||||||
sql Querys with js ot ts Syntax.
|
sql Querys with js or ts Syntax.
|
||||||
|
|
||||||
[![status-badge](https://ci.jusax.de/api/badges/jusax23/dblang/status.svg)](https://ci.jusax.de/jusax23/dblang)
|
[![status-badge](https://ci.jusax.de/api/badges/jusax23/dblang/status.svg)](https://ci.jusax.de/jusax23/dblang)
|
78
src/db.ts
78
src/db.ts
|
@ -1,37 +1,38 @@
|
||||||
import mariadb from 'mariadb';
|
import mariadb from 'mariadb';
|
||||||
import { checkConstraint, Constraint, Datatype, uniqueConstraint } from './dbStructure';
|
import { checkConstraint, Constraint, Datatype, uniqueConstraint } from './dbStructure';
|
||||||
import { Handler } from './defaultHandler';
|
import { Handler } from './defaultHandler';
|
||||||
import { Query, selectQuery } from './query';
|
import { Query } from './query';
|
||||||
import { attributeSettings, extendedAttributeSettings, onAction, primaryData, serializeReturn } from './types';
|
import { attributeSettings, extendedAttributeSettings, onAction } from './types';
|
||||||
|
|
||||||
|
|
||||||
export class DB {
|
export class DB {
|
||||||
tables:Table[] = [];
|
tables: Table[] = [];
|
||||||
handler: Handler;
|
handler: Handler;
|
||||||
name: string;
|
name: string;
|
||||||
//pool:mariadb.Pool;
|
pool: mariadb.Pool;
|
||||||
constructor(/*{ host, user, password, database, connectionLimit = 5 }*/) {
|
constructor({ host, user, password, database, connectionLimit = 5 }: { host: string, user: string, password: string, database: string, connectionLimit: number }) {
|
||||||
//this.pool = mariadb.createPool({ host, user, password, database, connectionLimit, multipleStatements: true });
|
this.pool = mariadb.createPool({ host, user, password, database, connectionLimit, multipleStatements: true });
|
||||||
this.handler = new Handler();
|
this.handler = new Handler();
|
||||||
this.name = "notimplemented"
|
this.name = database;
|
||||||
}
|
}
|
||||||
async query(query: Query) {
|
async query(query: Query) {
|
||||||
console.log(query);
|
console.log(query);
|
||||||
//return this.pool.query(query);
|
return await this.pool.query(query);
|
||||||
}
|
}
|
||||||
getHandler() {
|
getHandler() {
|
||||||
return this.handler;
|
return this.handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
sync(){
|
async sync() {
|
||||||
let handler = this.getHandler();
|
let handler = this.getHandler();
|
||||||
this.tables.forEach(t=>{
|
await handler.syncDB(this, handler);
|
||||||
console.log(new Query(handler.builders.query(handler.querys.create(handler,t))));
|
//this.tables.forEach(t=>{
|
||||||
})
|
// console.log(handler.builders.query(handler.querys.create(handler,t)));
|
||||||
|
//})
|
||||||
}
|
}
|
||||||
|
|
||||||
newTable(name: string) {
|
newTable(name: string) {
|
||||||
let tabel = new Table(name,this);
|
let tabel = new Table(name, this);
|
||||||
this.tables.push(tabel);
|
this.tables.push(tabel);
|
||||||
return tabel;
|
return tabel;
|
||||||
}
|
}
|
||||||
|
@ -42,39 +43,40 @@ export class Attribute {
|
||||||
table: Table;
|
table: Table;
|
||||||
ops: attributeSettings;
|
ops: attributeSettings;
|
||||||
type: Datatype;
|
type: Datatype;
|
||||||
constructor(name: string, table:Table, type: Datatype, ops: attributeSettings) {
|
constructor(name: string, table: Table, type: Datatype, ops: attributeSettings) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.ops = ops;
|
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.table = table;
|
this.table = table;
|
||||||
|
this.ops = ops;
|
||||||
|
|
||||||
if(ops.check != null){
|
if (ops.check != null) {
|
||||||
|
if(typeof ops.check == "function")ops.check = ops.check(this);
|
||||||
table.addConstraint(new checkConstraint(
|
table.addConstraint(new checkConstraint(
|
||||||
table.dbLangDatabaseInstance.name+"_"+table.dbLangTableName+"_"+name+"_check_constraint",
|
table.dbLangDatabaseInstance.name + "_" + table.dbLangTableName + "_" + name + "_check_constraint",
|
||||||
ops.check
|
ops.check
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
if(ops.unique != null){
|
if (ops.unique != null) {
|
||||||
table.addConstraint(new uniqueConstraint(
|
table.addConstraint(new uniqueConstraint(
|
||||||
table.dbLangDatabaseInstance.name+"_"+table.dbLangTableName+" "+name+"_unique_constraint",
|
table.dbLangDatabaseInstance.name + "_" + table.dbLangTableName + " " + name + "_unique_constraint",
|
||||||
[this]
|
[this]
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serializeDatatype(handler : Handler){
|
serializeDatatype(handler: Handler) {
|
||||||
return this.type.serialize(handler);
|
return this.type.serialize(handler);
|
||||||
}
|
}
|
||||||
serializeSettings(handler : Handler){
|
serializeSettings(handler: Handler) {
|
||||||
return handler.builders.attributeSettings(handler,this);
|
return handler.builders.attributeSettings(handler, this);
|
||||||
}
|
}
|
||||||
serialize(handler : Handler) {
|
serialize(handler: Handler) {
|
||||||
return handler.builders.escapeID(this.name);
|
return handler.builders.escapeID(this.name);
|
||||||
}
|
}
|
||||||
toString(handler : Handler = this.table.dbLangDatabaseInstance.getHandler()) {
|
toString(handler: Handler = this.table.dbLangDatabaseInstance.getHandler()) {
|
||||||
return this.table.serialize(handler)+"."+this.serialize(handler);
|
return this.table.serialize(handler) + "." + this.serialize(handler);
|
||||||
}
|
}
|
||||||
toStringFunc(handler : Handler){
|
toStringFunc(handler: Handler) {
|
||||||
return this.table.serialize(handler)+"("+this.serialize(handler)+")";
|
return this.table.serialize(handler) + "(" + this.serialize(handler) + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,34 +86,34 @@ export class Table {
|
||||||
dbLangTableAttributes: { [key: string]: Attribute; } = {};
|
dbLangTableAttributes: { [key: string]: Attribute; } = {};
|
||||||
dbLangDatabaseInstance: DB;
|
dbLangDatabaseInstance: DB;
|
||||||
dbLangConstrains: Constraint[] = [];
|
dbLangConstrains: Constraint[] = [];
|
||||||
[key: string]: Attribute | any
|
[key: string]: Attribute | any;
|
||||||
constructor(name: string, db:DB) {
|
constructor(name: string, db: DB) {
|
||||||
this.dbLangTableName = name;
|
this.dbLangTableName = name;
|
||||||
this.dbLangDatabaseInstance = db;
|
this.dbLangDatabaseInstance = db;
|
||||||
}
|
}
|
||||||
serialize(handler : Handler) {
|
serialize(handler: Handler) {
|
||||||
return this.toString(handler);
|
return this.toString(handler);
|
||||||
}
|
}
|
||||||
toString(handler : Handler = this.dbLangDatabaseInstance.getHandler()) {
|
toString(handler: Handler = this.dbLangDatabaseInstance.getHandler()) {
|
||||||
return handler.builders.escapeID(this.dbLangTableName);
|
return handler.builders.escapeID(this.dbLangTableName);
|
||||||
}
|
}
|
||||||
addAttribute(name: string, type: Datatype, ops: attributeSettings = {}, noErrorOnNameConflict = false) {
|
addAttribute(name: string, type: Datatype, ops: attributeSettings = {}, noErrorOnNameConflict = false) {
|
||||||
if(this.dbLangTableAttributes[name] != null) throw new Error("You are tring to create an Attribute twise!");
|
if (this.dbLangTableAttributes[name] != null) throw new Error("You are tring to create an Attribute twise!");
|
||||||
let attr = new Attribute(name,this,type,ops);
|
let attr = new Attribute(name, this, type, ops);
|
||||||
this.dbLangTableAttributes[name] = attr;
|
this.dbLangTableAttributes[name] = attr;
|
||||||
if (["serialize", "toString", "addAttribute", "dbLangTableName", "dbLangTableAttributes", "dbLangDatabaseInstance","addConstraint","addAttributes"].includes(name)) {
|
if (["serialize", "toString", "addAttribute", "dbLangTableName", "dbLangTableAttributes", "dbLangDatabaseInstance", "addConstraint", "addAttributes"].includes(name)) {
|
||||||
if (!noErrorOnNameConflict) throw new Error("You cannot name Attribute like Methode of this Table!");
|
if (!noErrorOnNameConflict) throw new Error("You cannot name Attribute like Methode of this Table!");
|
||||||
} else {
|
} else {
|
||||||
this[name] = attr;
|
this[name] = attr;
|
||||||
}
|
}
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
addAttributes(list:{[key: string]:extendedAttributeSettings}):{[key: string]:Attribute} {
|
addAttributes(list: { [key: string]: (extendedAttributeSettings) }): { [key: string]: Attribute } {
|
||||||
return Object.fromEntries(Object.entries(list).map(([k,a])=>{
|
return Object.fromEntries(Object.entries(list).map(([k, a]) => {
|
||||||
return [k,this.addAttribute(k,a.type,a)];
|
return [k, this.addAttribute(k, a.type, a)];
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
addConstraint(c:Constraint){
|
addConstraint(c: Constraint) {
|
||||||
c.check(this);
|
c.check(this);
|
||||||
this.dbLangConstrains.push(c);
|
this.dbLangConstrains.push(c);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ export class checkConstraint implements Constraint{
|
||||||
this.checkQuery = check;
|
this.checkQuery = check;
|
||||||
}
|
}
|
||||||
check(attr: Table): boolean {
|
check(attr: Table): boolean {
|
||||||
throw new Error("Method not implemented.");
|
return true;
|
||||||
}
|
}
|
||||||
uses(attr: Attribute): boolean {
|
uses(attr: Attribute): boolean {
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
|
@ -76,19 +76,19 @@ export class checkConstraint implements Constraint{
|
||||||
|
|
||||||
export class uniqueConstraint implements Constraint{
|
export class uniqueConstraint implements Constraint{
|
||||||
name: string;
|
name: string;
|
||||||
attr: Attribute[];
|
attrs: Attribute[];
|
||||||
constructor(name:string, attr:Attribute[]){
|
constructor(name:string, attrs:Attribute[]){
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.attr = attr;
|
this.attrs = attrs;
|
||||||
}
|
}
|
||||||
check(table: Table): boolean|string {
|
check(table: Table): boolean|string {
|
||||||
for(let i = 0; i < this.attr.length; i++){
|
for(let i = 0; i < this.attrs.length; i++){
|
||||||
if(this.attr[i].ops.primaryKey) return "Can not combine unique Constraint and primary key";
|
if(this.attrs[i].ops.primaryKey) return "Can not combine unique Constraint and primary key";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uses(attr: Attribute): boolean {
|
uses(attr: Attribute): boolean {
|
||||||
throw new Error("Method not implemented.");
|
return this.attrs.includes(attr);
|
||||||
}
|
}
|
||||||
serialize(handler: Handler): QueryBuilder {
|
serialize(handler: Handler): QueryBuilder {
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
|
|
|
@ -1,12 +1,115 @@
|
||||||
import { Attribute, DB, Table } from "./db"
|
import { Attribute, DB, Table } from "./db"
|
||||||
import { Aggregation, Modifier } from "./dbStructure"
|
import { Aggregation, checkConstraint, Constraint, Datatype, Modifier, uniqueConstraint } from "./dbStructure"
|
||||||
import { QueryBuilder, selectQuery } from "./query"
|
import { Query, QueryBuilder, selectQuery } from "./query"
|
||||||
import { allModifierInput, primaryData, serializeReturn } from "./types"
|
import { allModifierInput, primaryData, serializeReturn } from "./types"
|
||||||
|
|
||||||
export class Handler {
|
export class Handler {
|
||||||
/*syncDB(db : DB){
|
async syncDB(db: DB, handler: Handler, deleteInDB: boolean = false) {
|
||||||
|
console.log("start sync");
|
||||||
|
|
||||||
}*/
|
let gd = new QueryBuilder();
|
||||||
|
gd.addCode(`SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE where CONSTRAINT_SCHEMA = `);
|
||||||
|
gd.addInjection(db.name);
|
||||||
|
gd.addCode(` or TABLE_SCHEMA = `);
|
||||||
|
gd.addInjection(db.name);
|
||||||
|
gd.addCode(`;select * from information_schema.table_constraints where CONSTRAINT_SCHEMA = `);
|
||||||
|
gd.addInjection(db.name)
|
||||||
|
gd.addCode(` or TABLE_SCHEMA = `);
|
||||||
|
gd.addInjection(db.name);
|
||||||
|
|
||||||
|
let [key, constraints] = await db.query(handler.builders.query(gd));
|
||||||
|
|
||||||
|
|
||||||
|
let tableData = [];
|
||||||
|
for (let i = 0; i < db.tables.length; i++) {
|
||||||
|
const table = db.tables[i];
|
||||||
|
try {
|
||||||
|
const tableDataBuilder = new QueryBuilder();
|
||||||
|
tableDataBuilder.addCode("DESCRIBE ");
|
||||||
|
tableDataBuilder.addCode(table.serialize(handler));
|
||||||
|
tableData[i] = Object.fromEntries((await db.query(handler.builders.query(tableDataBuilder))).map((d: any) => [d.Field, d]));
|
||||||
|
} catch (_) {
|
||||||
|
tableData[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const del = new QueryBuilder();
|
||||||
|
const create = new QueryBuilder();
|
||||||
|
|
||||||
|
for (let i = 0; i < constraints.length; i++) {
|
||||||
|
const c = constraints[i];
|
||||||
|
if (c.CONSTRAINT_TYPE == "CHECK") {
|
||||||
|
del.appendEnding(handler.querys.removeCheck(handler, c.TABLE_NAME, c.CONSTRAINT_NAME));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: delete old constraints/tables
|
||||||
|
|
||||||
|
function freeForUpdate(a: Attribute) {
|
||||||
|
for (let i = 0; i < key.length; i++) {
|
||||||
|
const k = key[i];
|
||||||
|
if (
|
||||||
|
k.REFERENCED_TABLE_NAME == a.table.dbLangTableName
|
||||||
|
&& k.REFERENCED_TABLE_NAME == a.name
|
||||||
|
) {
|
||||||
|
del.appendEnding(handler.querys.removeForeignKey(handler, k.TABLE_NAME, k.CONSTRAINT_NAME));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//create tables
|
||||||
|
for (let i = 0; i < db.tables.length; i++) {
|
||||||
|
const table = db.tables[i];
|
||||||
|
const tableD = tableData[i];
|
||||||
|
let changePrimary = false;
|
||||||
|
if (tableD == null) {
|
||||||
|
create.appendEnding(handler.querys.create(handler, table));
|
||||||
|
changePrimary = true;
|
||||||
|
} else {
|
||||||
|
let keys = Object.keys(table.dbLangTableAttributes);
|
||||||
|
for (let j = 0; j < keys.length; j++) {
|
||||||
|
const a = table.dbLangTableAttributes[keys[j]];
|
||||||
|
const attrData = tableD[keys[j]];
|
||||||
|
if (attrData == null) {
|
||||||
|
create.appendEnding(handler.querys.addColumn(handler, a));
|
||||||
|
changePrimary = true;
|
||||||
|
} else if (
|
||||||
|
!handler.builders.compareDatatypes(handler, a.type, attrData.Type) ||
|
||||||
|
a.ops.default != attrData.Default ||
|
||||||
|
(!!a.ops.notNull || !!a.ops.autoIncrement || !!a.ops.primaryKey) != (attrData.Null == "NO") ||
|
||||||
|
(!!a.ops.autoIncrement) != (attrData.Extra == "auto_increment")
|
||||||
|
) {
|
||||||
|
console.log(!handler.builders.compareDatatypes(handler, a.type, attrData.Type), "|",
|
||||||
|
a.ops.default, attrData.Default, "|",
|
||||||
|
(!!a.ops.notNull || !!a.ops.autoIncrement || !!a.ops.primaryKey), (attrData.Null == "NO"), "|",
|
||||||
|
(!!a.ops.autoIncrement), (attrData.Extra == "auto_increment"));
|
||||||
|
freeForUpdate(a);
|
||||||
|
create.appendEnding(handler.querys.changeColumn(handler, a));
|
||||||
|
}
|
||||||
|
if (attrData == null) {
|
||||||
|
changePrimary = true;
|
||||||
|
} else {
|
||||||
|
if ((attrData.Key == "PRI") != (!!a.ops.primaryKey)) {
|
||||||
|
freeForUpdate(a);
|
||||||
|
changePrimary = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changePrimary) {
|
||||||
|
create.appendEnding(handler.querys.removePrimaryKey(handler, table));
|
||||||
|
create.appendEnding(handler.querys.addPrimaryKey(handler, table));
|
||||||
|
}
|
||||||
|
for (let j = 0; j < table.dbLangConstrains.length; j++) {
|
||||||
|
const c = table.dbLangConstrains[j];
|
||||||
|
if (c instanceof checkConstraint) {
|
||||||
|
create.appendEnding(handler.querys.addCheck(handler, table, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: unique
|
||||||
|
}
|
||||||
|
if (!create.isEmpty()) del.append(create);
|
||||||
|
if (!del.isEmpty()) await db.query(handler.builders.query(del));
|
||||||
|
}
|
||||||
|
|
||||||
querys = {
|
querys = {
|
||||||
select: (handler: Handler, q: selectQuery): QueryBuilder => {
|
select: (handler: Handler, q: selectQuery): QueryBuilder => {
|
||||||
|
@ -26,11 +129,15 @@ export class Handler {
|
||||||
builder.append(q.havingD.serialize(handler));
|
builder.append(q.havingD.serialize(handler));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q.havingD) {
|
if (q.havingD) {
|
||||||
builder.addCode(" limit ");
|
builder.addCode(" limit ");
|
||||||
builder.addInjection(q.limitD);
|
builder.addInjection(q.limitD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*builder.setHandler((json)=>{
|
||||||
|
return json;
|
||||||
|
});*/
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
},
|
},
|
||||||
create: (handler: Handler, table: Table): QueryBuilder => {
|
create: (handler: Handler, table: Table): QueryBuilder => {
|
||||||
|
@ -46,16 +153,102 @@ export class Handler {
|
||||||
builder.addCode(")");
|
builder.addCode(")");
|
||||||
return builder;
|
return builder;
|
||||||
},
|
},
|
||||||
|
addColumn: (handler: Handler, attr: Attribute): QueryBuilder => {
|
||||||
|
const builder = new QueryBuilder();
|
||||||
|
builder.addCode(`alter table `);
|
||||||
|
builder.addCode(attr.table.toString(handler));
|
||||||
|
builder.addCode(` add if not exists `);
|
||||||
|
builder.addCode(attr.serialize(handler) + " ");
|
||||||
|
builder.append(attr.serializeSettings(handler));
|
||||||
|
return builder;
|
||||||
|
},
|
||||||
|
changeColumn: (handler: Handler, attr: Attribute): QueryBuilder => {
|
||||||
|
const builder = new QueryBuilder();
|
||||||
|
builder.addCode(`alter table `);
|
||||||
|
builder.addCode(attr.table.toString(handler));
|
||||||
|
builder.addCode(` change `);
|
||||||
|
builder.addCode(attr.serialize(handler) + " ");
|
||||||
|
builder.addCode(attr.serialize(handler) + " ");
|
||||||
|
builder.append(attr.serializeSettings(handler));
|
||||||
|
return builder;
|
||||||
|
},
|
||||||
|
addForeignKey: (handler: Handler, table: Table) => {
|
||||||
|
const builder = new QueryBuilder();
|
||||||
|
|
||||||
}
|
return builder;
|
||||||
|
},
|
||||||
|
removeForeignKey: (handler: Handler, tablenName: string, name: string) => {
|
||||||
|
const builder = new QueryBuilder();
|
||||||
|
builder.addCode("ALTER TABLE ");
|
||||||
|
builder.addCode(handler.builders.escapeID(tablenName));
|
||||||
|
builder.addCode(" DROP FOREIGN KEY IF EXISTS ");
|
||||||
|
builder.addCode(handler.builders.escapeID(name));
|
||||||
|
builder.addCode(";ALTER TABLE ");
|
||||||
|
builder.addCode(handler.builders.escapeID(tablenName));
|
||||||
|
builder.addCode(" DROP INDEX IF EXISTS ");
|
||||||
|
builder.addCode(handler.builders.escapeID(name));
|
||||||
|
|
||||||
constraints = {
|
return builder;
|
||||||
// check constraints
|
},
|
||||||
listPrimaryKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
addPrimaryKey: (handler: Handler, table: Table) => {
|
||||||
listForeignKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
const qb = new QueryBuilder();
|
||||||
listUniqueKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
qb.addCode("ALTER TABLE ");
|
||||||
listChecks: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
qb.addCode(table.serialize(handler));
|
||||||
// add constraints
|
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))
|
||||||
|
);
|
||||||
|
qb.addCode(")");
|
||||||
|
return qb;
|
||||||
|
},
|
||||||
|
removePrimaryKey: (handler: Handler, table: Table) => {
|
||||||
|
const qb = new QueryBuilder();
|
||||||
|
qb.addCode("ALTER TABLE ");
|
||||||
|
qb.addCode(table.serialize(handler));
|
||||||
|
qb.addCode(" DROP INDEX IF EXISTS `PRIMARY`");
|
||||||
|
return qb;
|
||||||
|
},
|
||||||
|
removeCheck: (handler: Handler, table: string, name: string) => {
|
||||||
|
const qb = new QueryBuilder();
|
||||||
|
qb.addCode("ALTER TABLE ");
|
||||||
|
qb.addCode(handler.builders.escapeID(table));
|
||||||
|
qb.addCode(" DROP CONSTRAINT IF EXISTS ");
|
||||||
|
qb.addCode(handler.builders.escapeID(name));
|
||||||
|
return qb;
|
||||||
|
},
|
||||||
|
addCheck: (handler: Handler, table: Table, c: checkConstraint) => {
|
||||||
|
const qb = new QueryBuilder();
|
||||||
|
qb.addCode(`ALTER TABLE `);
|
||||||
|
qb.addCode(table.serialize(handler));
|
||||||
|
qb.addCode(` ADD CONSTRAINT `);
|
||||||
|
qb.addCode(handler.builders.escapeID(c.name));
|
||||||
|
qb.addCode(` CHECK (`);
|
||||||
|
qb.append(c.checkQuery.serialize(handler));
|
||||||
|
qb.addCode(")");
|
||||||
|
return qb;
|
||||||
|
},
|
||||||
|
removeUnique: (handler: Handler, table: string, name: string) => {
|
||||||
|
const qb = new QueryBuilder();
|
||||||
|
qb.addCode("ALTER TABLE ");
|
||||||
|
qb.addCode(handler.builders.escapeID(table));
|
||||||
|
qb.addCode(" DROP INDEX IF EXISTS ");
|
||||||
|
qb.addCode(handler.builders.escapeID(name));
|
||||||
|
return qb;
|
||||||
|
},
|
||||||
|
addUnique: (handler: Handler, table: Table, u: uniqueConstraint) => {
|
||||||
|
const qb = new QueryBuilder();
|
||||||
|
qb.addCode("ALTER TABLE ");
|
||||||
|
qb.addCode(table.serialize(handler));
|
||||||
|
qb.addCode(" ADD CONSTRAINT ");
|
||||||
|
qb.addCode(handler.builders.escapeID(u.name));
|
||||||
|
qb.addCode(" UNIQUE (");
|
||||||
|
qb.addCodeCommaSeperated(u.attrs.map(a => a.serialize(handler)));
|
||||||
|
qb.addCode(")");
|
||||||
|
return qb;
|
||||||
|
},
|
||||||
|
/*// add constraints
|
||||||
appPrimaryKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
appPrimaryKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
||||||
appForeignKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
appForeignKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
||||||
addUniqueKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
addUniqueKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
||||||
|
@ -65,10 +258,15 @@ export class Handler {
|
||||||
dropForeignKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
dropForeignKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
||||||
dropUniqueKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
dropUniqueKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
||||||
dropChecks: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
dropChecks: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
||||||
|
// check constraints
|
||||||
|
listPrimaryKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
||||||
|
listForeignKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
||||||
|
listUniqueKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
||||||
|
listChecks: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),*/
|
||||||
}
|
}
|
||||||
|
|
||||||
builders = {
|
builders = {
|
||||||
query: (qb: QueryBuilder): serializeReturn => {
|
query: (qb: QueryBuilder): Query => {
|
||||||
let args: primaryData[] = [];
|
let args: primaryData[] = [];
|
||||||
let sql = "";
|
let sql = "";
|
||||||
for (let i = 0; i < qb.list.length; i++) {
|
for (let i = 0; i < qb.list.length; i++) {
|
||||||
|
@ -80,7 +278,7 @@ export class Handler {
|
||||||
sql += data;
|
sql += data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [sql, args];
|
return new Query([sql, args]);
|
||||||
},
|
},
|
||||||
|
|
||||||
attributeSettings: (handler: Handler, a: Attribute): QueryBuilder => {
|
attributeSettings: (handler: Handler, a: Attribute): QueryBuilder => {
|
||||||
|
@ -89,38 +287,34 @@ export class Handler {
|
||||||
if (a.ops.autoIncrement) {
|
if (a.ops.autoIncrement) {
|
||||||
builder.addCode(" auto_increment");
|
builder.addCode(" auto_increment");
|
||||||
}
|
}
|
||||||
/*if (a.ops.primaryKey) {
|
|
||||||
sql += " primary key";
|
|
||||||
}*/
|
|
||||||
if (a.ops.default != null) {
|
if (a.ops.default != null) {
|
||||||
if (a.ops.autoIncrement || a.ops.primaryKey || a.ops.notNull)
|
if (a.ops.autoIncrement || a.ops.primaryKey || a.ops.notNull)
|
||||||
throw new Error(`Can not set default when autoIncrement, primaryKey or notNull ist set on Attribute: ${a.toStringFunc(handler)}`);
|
throw new Error(`Can not set default when autoIncrement, primaryKey or notNull ist set on Attribute: ${a.toStringFunc(handler)}`);
|
||||||
builder.addCode(" default ");
|
builder.addCode(" default ");
|
||||||
builder.addInjection(a.ops.default);
|
builder.addInjection(a.ops.default);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (a.ops.unique != null) {
|
|
||||||
if (!a.ops.autoIncrement && !a.ops.primaryKey){
|
|
||||||
sql += " unique";
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
if (a.ops.notNull != null) {
|
if (a.ops.notNull != null) {
|
||||||
if (!a.ops.autoIncrement && !a.ops.primaryKey && a.ops.default == null) {
|
if (!a.ops.autoIncrement && !a.ops.primaryKey && a.ops.default == null) {
|
||||||
builder.addCode(" not null");
|
builder.addCode(" not null");
|
||||||
}
|
} else builder.addCode(" null");
|
||||||
}
|
} else builder.addCode(" null");
|
||||||
|
|
||||||
/*if (a.ops.foreginKey != null) {
|
|
||||||
sql += ` foreign key references (${a.ops.foreginKey.link.toStringFunc(handler)})`
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
},
|
},
|
||||||
escapeID: (key: string): string => {
|
escapeID: (key: string): string => {
|
||||||
if (!key || key === "" || key.includes('\u0000')) throw new Error("Can not escape empty key or with null unicode!");
|
if (!key || key === "" || key.includes('\u0000')) throw new Error("Can not escape empty key or with null unicode!");
|
||||||
if (key.match(/^`.+`$/g)) return key;
|
if (key.match(/^`.+`$/g)) return key;
|
||||||
return `\`${key.replace(/`/g, '``')}\``;
|
return `\`${key.replace(/`/g, '``')}\``;
|
||||||
}
|
},
|
||||||
|
compareDatatypes: (handler: Handler, attr: Datatype, curr: String) => {
|
||||||
|
let qb = attr.serialize(handler);
|
||||||
|
let sql = "";
|
||||||
|
for (let i = 0; i < qb.list.length; i++) {
|
||||||
|
const [inject, data] = qb.list[i];
|
||||||
|
sql += data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return curr.split(" ").join("").startsWith(sql.split(" ").join(""));
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,7 +394,7 @@ export class Handler {
|
||||||
double: dataTypeDblNum("double"),
|
double: dataTypeDblNum("double"),
|
||||||
decimal: dataTypeDblNum("decimal"),
|
decimal: dataTypeDblNum("decimal"),
|
||||||
|
|
||||||
date: dataTypeNoArg("data"),
|
date: dataTypeNoArg("date"),
|
||||||
datetime: dataTypeNoArg("datatime"),
|
datetime: dataTypeNoArg("datatime"),
|
||||||
timestamp: dataTypeNoArg("timestamp"),
|
timestamp: dataTypeNoArg("timestamp"),
|
||||||
time: dataTypeNoArg("time"),
|
time: dataTypeNoArg("time"),
|
||||||
|
|
25
src/query.ts
25
src/query.ts
|
@ -16,6 +16,7 @@ export class Query {
|
||||||
export class QueryBuilder {
|
export class QueryBuilder {
|
||||||
//injekt and data
|
//injekt and data
|
||||||
list: ([boolean, primaryData])[] = [];
|
list: ([boolean, primaryData])[] = [];
|
||||||
|
|
||||||
constructor(l?: ({ inject?: boolean, data: primaryData })[]) {
|
constructor(l?: ({ inject?: boolean, data: primaryData })[]) {
|
||||||
if (Array.isArray(l))
|
if (Array.isArray(l))
|
||||||
for (let i = 0; i < l.length; i++) {
|
for (let i = 0; i < l.length; i++) {
|
||||||
|
@ -26,6 +27,13 @@ export class QueryBuilder {
|
||||||
addCode(text: string) {
|
addCode(text: string) {
|
||||||
this.list.push([false, text]);
|
this.list.push([false, text]);
|
||||||
}
|
}
|
||||||
|
addCodeCommaSeperated(data: string[], comma = ", ") {
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const e = data[i];
|
||||||
|
this.list.push([false, e]);
|
||||||
|
if(i+1<data.length)this.list.push([false, comma]);
|
||||||
|
}
|
||||||
|
}
|
||||||
addInjection(data: primaryData) {
|
addInjection(data: primaryData) {
|
||||||
this.list.push([true, data]);
|
this.list.push([true, data]);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +47,16 @@ export class QueryBuilder {
|
||||||
append(qb: QueryBuilder) {
|
append(qb: QueryBuilder) {
|
||||||
this.list.push(...qb.list);
|
this.list.push(...qb.list);
|
||||||
}
|
}
|
||||||
|
appendEnding(qb: QueryBuilder){
|
||||||
|
this.append(qb);
|
||||||
|
this.list.push([false,";"]);
|
||||||
|
}
|
||||||
|
isEmpty(){
|
||||||
|
return this.list.length == 0;
|
||||||
|
}
|
||||||
|
/*setHandler(fun:(d:any)=>any){
|
||||||
|
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,9 +92,10 @@ export class selectQuery {
|
||||||
return handler.querys.select(handler, this);
|
return handler.querys.select(handler, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
query(db: DB) {
|
async query(db: DB) {
|
||||||
const handler = db.getHandler();
|
const handler = db.getHandler();
|
||||||
const s = handler.builders.query(this.serialize(handler));
|
const builder = this.serialize(handler);
|
||||||
return db.query(new Query(s));
|
const s = handler.builders.query(builder);
|
||||||
|
return await db.query(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { Attribute, Table } from "./db";
|
import { Attribute, Table } from "./db";
|
||||||
import { Aggregation, BooleanModifier, Datatype, Joins, Modifier } from "./dbStructure";
|
import { Aggregation, BooleanModifier, Datatype, Joins, Modifier } from "./dbStructure";
|
||||||
import { selectQuery } from "./query";
|
import { QueryBuilder, selectQuery } from "./query";
|
||||||
|
|
||||||
export type primaryData = string | number | boolean | null;
|
export type primaryData = string | number | boolean | null;
|
||||||
export type allModifierInput = primaryData | Modifier | selectQuery | Attribute | Aggregation;
|
export type allModifierInput = primaryData | Modifier | selectQuery | Attribute | Aggregation;
|
||||||
|
@ -10,6 +10,8 @@ export type selectFromElements = Table | Joins | null;
|
||||||
|
|
||||||
export type serializeReturn = [string, primaryData[]];
|
export type serializeReturn = [string, primaryData[]];
|
||||||
|
|
||||||
|
export type DatatypeBuild = [QueryBuilder, number];
|
||||||
|
|
||||||
export type attributeSettings = {
|
export type attributeSettings = {
|
||||||
unique?: boolean,
|
unique?: boolean,
|
||||||
autoIncrement?: boolean,
|
autoIncrement?: boolean,
|
||||||
|
@ -21,8 +23,9 @@ export type attributeSettings = {
|
||||||
onDelete?: onAction,
|
onDelete?: onAction,
|
||||||
onUpdate?: onAction
|
onUpdate?: onAction
|
||||||
},
|
},
|
||||||
check?:BooleanModifier
|
check?: BooleanModifier | ((a: Attribute) => BooleanModifier)
|
||||||
};
|
};
|
||||||
|
|
||||||
export type extendedAttributeSettings = {
|
export type extendedAttributeSettings = {
|
||||||
type: Datatype,
|
type: Datatype,
|
||||||
unique?: boolean,
|
unique?: boolean,
|
||||||
|
@ -35,7 +38,7 @@ export type extendedAttributeSettings = {
|
||||||
onDelete?: onAction,
|
onDelete?: onAction,
|
||||||
onUpdate?: onAction
|
onUpdate?: onAction
|
||||||
},
|
},
|
||||||
check?:BooleanModifier
|
check?: BooleanModifier | ((a: Attribute) => BooleanModifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum onAction {
|
export enum onAction {
|
||||||
|
|
Loading…
Reference in a new issue