2023-01-24 20:34:03 +01:00
|
|
|
import { Attribute, DB, Table } from "./db"
|
2023-01-23 21:19:18 +01:00
|
|
|
import { Aggregation, Modifier } from "./dbStructure"
|
2023-01-29 22:11:24 +01:00
|
|
|
import { QueryBuilder, selectQuery } from "./query"
|
2023-01-23 21:19:18 +01:00
|
|
|
import { allModifierInput, primaryData, serializeReturn } from "./types"
|
|
|
|
|
|
|
|
export class Handler {
|
2023-01-29 22:11:24 +01:00
|
|
|
/*syncDB(db : DB){
|
2023-01-24 20:34:03 +01:00
|
|
|
|
2023-01-29 22:11:24 +01:00
|
|
|
}*/
|
2023-01-24 20:34:03 +01:00
|
|
|
|
|
|
|
querys = {
|
2023-01-29 22:11:24 +01:00
|
|
|
select: (handler: Handler, q: selectQuery): QueryBuilder => {
|
|
|
|
const builder = new QueryBuilder();
|
|
|
|
builder.addCode("select ");
|
|
|
|
builder.append(joinArg(", ")(handler, q.attr));
|
|
|
|
builder.addCode(` from ${q.from == null ? 'DUAL' : q.from.serialize(handler)}`);
|
2023-01-23 21:19:18 +01:00
|
|
|
if (q.whereD) {
|
2023-01-29 22:11:24 +01:00
|
|
|
builder.addCode(" where ");
|
|
|
|
builder.append(q.whereD.serialize(handler));
|
2023-01-23 21:19:18 +01:00
|
|
|
}
|
2023-01-23 22:10:33 +01:00
|
|
|
if (q.groupByD.length > 0) {
|
2023-01-29 22:11:24 +01:00
|
|
|
builder.addCode(" group by ");
|
|
|
|
builder.append(joinArg(",")(handler, q.groupByD));
|
2023-01-23 21:19:18 +01:00
|
|
|
if (q.havingD) {
|
2023-01-29 22:11:24 +01:00
|
|
|
builder.addCode(" having ");
|
|
|
|
builder.append(q.havingD.serialize(handler));
|
2023-01-23 21:19:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-29 22:11:24 +01:00
|
|
|
if (q.havingD) {
|
|
|
|
builder.addCode(" limit ");
|
|
|
|
builder.addInjection(q.limitD);
|
|
|
|
}
|
|
|
|
return builder;
|
2023-01-24 20:34:03 +01:00
|
|
|
},
|
2023-01-29 22:11:24 +01:00
|
|
|
create: (handler: Handler, table: Table): QueryBuilder => {
|
|
|
|
const builder = new QueryBuilder();
|
|
|
|
builder.addCode(`create table if not exists ${table.toString(handler)}(`);
|
|
|
|
let keys = Object.keys(table.dbLangTableAttributes);
|
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
|
|
const a = table.dbLangTableAttributes[keys[i]];
|
|
|
|
builder.addCode(a.serialize(handler) + " ");
|
|
|
|
builder.append(a.serializeSettings(handler));
|
|
|
|
if (i + 1 < keys.length) builder.addCode(", ");
|
|
|
|
}
|
|
|
|
builder.addCode(")");
|
|
|
|
return builder;
|
|
|
|
},
|
|
|
|
|
2023-01-24 20:34:03 +01:00
|
|
|
}
|
|
|
|
|
2023-01-29 22:11:24 +01:00
|
|
|
constraints = {
|
|
|
|
// 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(),
|
|
|
|
// add constraints
|
|
|
|
appPrimaryKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
|
|
|
appForeignKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
|
|
|
addUniqueKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
|
|
|
addChecks: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
|
|
|
//should drop all keys to be able to recreate them
|
|
|
|
dropPrimaryKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
|
|
|
dropForeignKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
|
|
|
dropUniqueKeys: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
|
|
|
dropChecks: (handler: Handler, table: Table): QueryBuilder => new QueryBuilder(),
|
|
|
|
}
|
2023-01-24 20:34:03 +01:00
|
|
|
|
|
|
|
builders = {
|
2023-01-29 22:11:24 +01:00
|
|
|
query: (qb: QueryBuilder): serializeReturn => {
|
|
|
|
let args: primaryData[] = [];
|
|
|
|
let sql = "";
|
|
|
|
for (let i = 0; i < qb.list.length; i++) {
|
|
|
|
const [inject, data] = qb.list[i];
|
|
|
|
if (inject) {
|
|
|
|
sql += "?";
|
|
|
|
args.push(data);
|
|
|
|
} else {
|
|
|
|
sql += data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return [sql, args];
|
|
|
|
},
|
|
|
|
|
|
|
|
attributeSettings: (handler: Handler, a: Attribute): QueryBuilder => {
|
|
|
|
const builder = new QueryBuilder();
|
|
|
|
builder.append(a.type.serialize(handler));
|
2023-01-24 20:34:03 +01:00
|
|
|
if (a.ops.autoIncrement) {
|
2023-01-29 22:11:24 +01:00
|
|
|
builder.addCode(" auto_increment");
|
2023-01-24 20:34:03 +01:00
|
|
|
}
|
2023-01-29 22:11:24 +01:00
|
|
|
/*if (a.ops.primaryKey) {
|
2023-01-24 20:34:03 +01:00
|
|
|
sql += " primary key";
|
2023-01-29 22:11:24 +01:00
|
|
|
}*/
|
2023-01-24 20:34:03 +01:00
|
|
|
if (a.ops.default != null) {
|
|
|
|
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)}`);
|
2023-01-29 22:11:24 +01:00
|
|
|
builder.addCode(" default ");
|
|
|
|
builder.addInjection(a.ops.default);
|
2023-01-24 20:34:03 +01:00
|
|
|
}
|
|
|
|
|
2023-01-29 22:11:24 +01:00
|
|
|
/*if (a.ops.unique != null) {
|
2023-01-24 20:34:03 +01:00
|
|
|
if (!a.ops.autoIncrement && !a.ops.primaryKey){
|
|
|
|
sql += " unique";
|
|
|
|
}
|
2023-01-29 22:11:24 +01:00
|
|
|
}*/
|
2023-01-24 20:34:03 +01:00
|
|
|
if (a.ops.notNull != null) {
|
2023-01-29 22:11:24 +01:00
|
|
|
if (!a.ops.autoIncrement && !a.ops.primaryKey && a.ops.default == null) {
|
|
|
|
builder.addCode(" not null");
|
2023-01-24 20:34:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-29 22:11:24 +01:00
|
|
|
/*if (a.ops.foreginKey != null) {
|
2023-01-24 20:34:03 +01:00
|
|
|
sql += ` foreign key references (${a.ops.foreginKey.link.toStringFunc(handler)})`
|
2023-01-29 22:11:24 +01:00
|
|
|
}*/
|
2023-01-24 20:34:03 +01:00
|
|
|
|
2023-01-29 22:11:24 +01:00
|
|
|
return builder;
|
2023-01-24 20:34:03 +01:00
|
|
|
},
|
2023-01-29 22:11:24 +01:00
|
|
|
escapeID: (key: string): string => {
|
|
|
|
if (!key || key === "" || key.includes('\u0000')) throw new Error("Can not escape empty key or with null unicode!");
|
2023-01-24 20:34:03 +01:00
|
|
|
if (key.match(/^`.+`$/g)) return key;
|
|
|
|
return `\`${key.replace(/`/g, '``')}\``;
|
2023-01-23 21:19:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-24 20:34:03 +01:00
|
|
|
|
|
|
|
aggregations = {
|
2023-01-29 22:11:24 +01:00
|
|
|
count: (handler: Handler, a: Attribute): QueryBuilder => new QueryBuilder([{ data: "count(" + a.toString(handler) + ")" }]),
|
|
|
|
sum: (handler: Handler, a: Attribute): QueryBuilder => new QueryBuilder([{ data: "sum(" + a.toString(handler) + ")" }]),
|
|
|
|
avg: (handler: Handler, a: Attribute): QueryBuilder => new QueryBuilder([{ data: "avg(" + a.toString(handler) + ")" }]),
|
|
|
|
min: (handler: Handler, a: Attribute): QueryBuilder => new QueryBuilder([{ data: "min(" + a.toString(handler) + ")" }]),
|
|
|
|
max: (handler: Handler, a: Attribute): QueryBuilder => new QueryBuilder([{ data: "max(" + a.toString(handler) + ")" }]),
|
2023-01-23 21:19:18 +01:00
|
|
|
}
|
|
|
|
|
2023-01-24 20:34:03 +01:00
|
|
|
modifiers = {
|
|
|
|
and: joinArg("and"),
|
|
|
|
or: joinArg("or"),
|
|
|
|
le: joinArg("<"),
|
|
|
|
leq: joinArg("<="),
|
|
|
|
eq: joinArg("="),
|
|
|
|
geq: joinArg(">="),
|
|
|
|
ge: joinArg(">"),
|
|
|
|
plus: joinArg("+"),
|
|
|
|
minus: joinArg("-"),
|
2023-01-29 22:11:24 +01:00
|
|
|
not: (handler: Handler, a: allModifierInput[]): QueryBuilder => {
|
2023-01-23 21:19:18 +01:00
|
|
|
let e = a[0];
|
2023-01-29 22:11:24 +01:00
|
|
|
if (e instanceof Attribute) return new QueryBuilder([{ data: "not (" + e.toString(handler) + ")" }])
|
2023-01-23 21:19:18 +01:00
|
|
|
if (e instanceof Modifier || e instanceof selectQuery || e instanceof Aggregation) {
|
2023-01-29 22:11:24 +01:00
|
|
|
const builder = new QueryBuilder();
|
|
|
|
builder.addCode("not (");
|
|
|
|
builder.append(e.serialize(handler));
|
|
|
|
builder.addCode(")");
|
|
|
|
return builder;
|
2023-01-23 21:19:18 +01:00
|
|
|
}
|
2023-01-29 22:11:24 +01:00
|
|
|
return new QueryBuilder([
|
|
|
|
{ data: "not(" },
|
|
|
|
{ inject: true, data: e },
|
|
|
|
{ data: ")" }
|
|
|
|
])
|
2023-01-23 21:19:18 +01:00
|
|
|
}
|
|
|
|
}
|
2023-01-24 20:34:03 +01:00
|
|
|
datatypes = {
|
2023-01-24 10:40:16 +01:00
|
|
|
char: dataTypeSingleNum("char"),
|
|
|
|
varchar: dataTypeSingleNum("varchar"),
|
|
|
|
binary: dataTypeSingleNum("binary"),
|
|
|
|
varbinary: dataTypeSingleNum("varbinary"),
|
|
|
|
|
|
|
|
tinyblob: dataTypeNoArg("tinyblob"),
|
|
|
|
blob: dataTypeNoArg("blob"),
|
|
|
|
mediumblob: dataTypeNoArg("mediumblob"),
|
|
|
|
longblob: dataTypeNoArg("longblob"),
|
|
|
|
tinytext: dataTypeNoArg("tinytext"),
|
|
|
|
text: dataTypeNoArg("text"),
|
|
|
|
mediumtext: dataTypeNoArg("mediumtext"),
|
|
|
|
longtext: dataTypeNoArg("longtext"),
|
|
|
|
|
2023-01-29 22:11:24 +01:00
|
|
|
enum: (a: primaryData[]): QueryBuilder => {
|
|
|
|
const builder = new QueryBuilder();
|
|
|
|
builder.addCode("enum(");
|
|
|
|
builder.addInjectionCommaSeperated(a);
|
|
|
|
builder.addCode(")");
|
|
|
|
return builder;
|
2023-01-24 10:40:16 +01:00
|
|
|
},
|
2023-01-29 22:11:24 +01:00
|
|
|
set: (a: primaryData[]): QueryBuilder => {
|
|
|
|
const builder = new QueryBuilder();
|
|
|
|
builder.addCode("set(");
|
|
|
|
builder.addInjectionCommaSeperated(a);
|
|
|
|
builder.addCode(")");
|
|
|
|
return builder;
|
2023-01-24 10:40:16 +01:00
|
|
|
},
|
|
|
|
bool: dataTypeNoArg("bool"),
|
|
|
|
bit: dataTypeNoArg("bit"),
|
|
|
|
tinyint: dataTypeNoArg("tinyint"),
|
|
|
|
smallint: dataTypeNoArg("smallint"),
|
|
|
|
mediumint: dataTypeNoArg("mediumint"),
|
|
|
|
int: dataTypeNoArg("int"),
|
|
|
|
bigint: dataTypeNoArg("bigint"),
|
|
|
|
|
|
|
|
float: dataTypeDblNum("float"),
|
|
|
|
double: dataTypeDblNum("double"),
|
|
|
|
decimal: dataTypeDblNum("decimal"),
|
|
|
|
|
2023-01-24 20:34:03 +01:00
|
|
|
date: dataTypeNoArg("data"),
|
|
|
|
datetime: dataTypeNoArg("datatime"),
|
2023-01-24 10:40:16 +01:00
|
|
|
timestamp: dataTypeNoArg("timestamp"),
|
|
|
|
time: dataTypeNoArg("time"),
|
|
|
|
year: dataTypeNoArg("year"),
|
|
|
|
}
|
2023-01-23 21:19:18 +01:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2023-01-24 20:34:03 +01:00
|
|
|
function dataTypeNoArg(type: string) {
|
2023-01-29 22:11:24 +01:00
|
|
|
return (a: primaryData[]): QueryBuilder => {
|
|
|
|
return new QueryBuilder([{
|
|
|
|
inject: false,
|
|
|
|
data: type
|
|
|
|
}]);
|
2023-01-24 10:40:16 +01:00
|
|
|
}
|
|
|
|
}
|
2023-01-24 20:34:03 +01:00
|
|
|
function dataTypeSingleNum(type: string) {
|
2023-01-29 22:11:24 +01:00
|
|
|
return (a: primaryData[]): QueryBuilder => {
|
|
|
|
return new QueryBuilder([
|
|
|
|
{ data: type + "(" },
|
|
|
|
{ inject: true, data: a[0] },
|
|
|
|
{ data: ")" }
|
|
|
|
]);
|
2023-01-24 10:40:16 +01:00
|
|
|
}
|
|
|
|
}
|
2023-01-24 20:34:03 +01:00
|
|
|
function dataTypeDblNum(type: string) {
|
2023-01-29 22:11:24 +01:00
|
|
|
return (a: primaryData[]): QueryBuilder => {
|
|
|
|
return new QueryBuilder([
|
|
|
|
{ data: type + "(" },
|
|
|
|
{ inject: true, data: a[0] },
|
|
|
|
{ data: ", " },
|
|
|
|
{ inject: true, data: a[1] },
|
|
|
|
{ data: ")" }
|
|
|
|
]);
|
2023-01-24 10:40:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-24 20:34:03 +01:00
|
|
|
function joinArg(type: string) {
|
2023-01-29 22:11:24 +01:00
|
|
|
return (handler: Handler, a: (allModifierInput)[]): QueryBuilder => {
|
|
|
|
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));
|
|
|
|
else if (d instanceof Modifier || d instanceof selectQuery || d instanceof Aggregation) {
|
|
|
|
builder.addCode("(");
|
|
|
|
builder.append(d.serialize(handler));
|
|
|
|
builder.addCode(")");
|
|
|
|
} else {
|
|
|
|
builder.addInjection(d);
|
2023-01-23 21:19:18 +01:00
|
|
|
}
|
2023-01-29 22:11:24 +01:00
|
|
|
if (i + 1 < a.length) builder.addCode(" " + type + " ");
|
|
|
|
}
|
|
|
|
return builder;
|
2023-01-23 21:19:18 +01:00
|
|
|
}
|
|
|
|
}
|