datasquirel/package-shared/functions/dsql/sql/sql-generator.ts
2025-12-03 11:45:32 +01:00

401 lines
14 KiB
TypeScript

import {
ServerQueryParam,
ServerQueryParamsJoin,
ServerQueryParamsJoinMatchObject,
ServerQueryQueryObject,
} from "../../../types";
import sqlGenOperatorGen from "./sql-gen-operator-gen";
type Param<T extends { [key: string]: any } = { [key: string]: any }> = {
genObject?: ServerQueryParam<T>;
tableName: string;
dbFullName?: string;
count?: boolean;
};
type Return = {
string: string;
values: string[];
};
/**
* # SQL Query Generator
* @description Generates an SQL Query for node module `mysql` or `serverless-mysql`
*/
export default function sqlGenerator<
T extends { [key: string]: any } = { [key: string]: any }
>({ tableName, genObject, dbFullName, count }: Param<T>): Return {
const finalQuery = genObject?.query ? genObject.query : undefined;
const queryKeys = finalQuery ? Object.keys(finalQuery) : undefined;
const sqlSearhValues: string[] = [];
const finalDbName = dbFullName ? `${dbFullName}.` : "";
/**
* # Generate Query
*/
function genSqlSrchStr({
queryObj,
join,
field,
}: {
queryObj: ServerQueryQueryObject[string];
join?: ServerQueryParamsJoin[];
field?: string;
}) {
const finalFieldName = (() => {
if (queryObj?.tableName) {
return `${finalDbName}${queryObj.tableName}.${field}`;
}
if (join) {
return `${finalDbName}${tableName}.${field}`;
}
return field;
})();
let str = `${finalFieldName}=?`;
if (Array.isArray(queryObj.value)) {
const strArray: string[] = [];
queryObj.value.forEach((val) => {
const valueParsed = val;
if (!valueParsed) return;
const valueString =
typeof valueParsed == "string"
? valueParsed
: valueParsed
? valueParsed.value?.toString()
: undefined;
const valueEquality =
typeof valueParsed == "object"
? valueParsed.equality || queryObj.equality
: queryObj.equality;
const operatorStrParam = sqlGenOperatorGen({
queryObj,
equality: valueEquality,
fieldName: finalFieldName || "",
value: valueString?.toString() || "",
});
if (operatorStrParam.str && operatorStrParam.param) {
strArray.push(operatorStrParam.str);
sqlSearhValues.push(operatorStrParam.param);
} else if (operatorStrParam.str) {
strArray.push(operatorStrParam.str);
}
});
str = "(" + strArray.join(` ${queryObj.operator || "AND"} `) + ")";
} else {
const valueParsed = queryObj.value
? String(queryObj.value)
: undefined;
const operatorStrParam = sqlGenOperatorGen({
equality: queryObj.equality,
fieldName: finalFieldName || "",
value: valueParsed,
queryObj,
});
if (operatorStrParam.str && operatorStrParam.param) {
str = operatorStrParam.str;
sqlSearhValues.push(operatorStrParam.param);
} else if (operatorStrParam.str) {
str = operatorStrParam.str;
}
}
return str;
}
function generateJoinStr(
mtch: ServerQueryParamsJoinMatchObject,
join: ServerQueryParamsJoin
) {
return `${finalDbName}${
typeof mtch.source == "object" ? mtch.source.tableName : tableName
}.${
typeof mtch.source == "object" ? mtch.source.fieldName : mtch.source
}=${(() => {
if (mtch.targetLiteral) {
return `'${mtch.targetLiteral}'`;
}
if (join.alias) {
return `${finalDbName}${
typeof mtch.target == "object"
? mtch.target.tableName
: join.alias
}.${
typeof mtch.target == "object"
? mtch.target.fieldName
: mtch.target
}`;
}
return `${finalDbName}${
typeof mtch.target == "object"
? mtch.target.tableName
: join.tableName
}.${
typeof mtch.target == "object"
? mtch.target.fieldName
: mtch.target
}`;
})()}`;
}
let fullTextMatchStr = genObject?.fullTextSearch
? ` MATCH(${genObject.fullTextSearch.fields
.map((f) =>
genObject.join ? `${tableName}.${String(f)}` : `${String(f)}`
)
.join(",")}) AGAINST (? IN BOOLEAN MODE)`
: undefined;
const fullTextSearchStr = genObject?.fullTextSearch
? genObject.fullTextSearch.searchTerm
.split(` `)
.map((t) => `${t}`)
.join(" ")
: undefined;
let queryString = (() => {
let str = "SELECT";
if (count) {
str += ` COUNT(*)`;
} else if (genObject?.selectFields?.[0]) {
if (genObject.join) {
str += ` ${genObject.selectFields
?.map((fld) =>
typeof fld == "object"
? `${finalDbName}${tableName}.${fld.fieldName.toString()}` +
(fld.alias ? ` as ${fld.alias}` : ``)
: `${finalDbName}${tableName}.${String(fld)}`
)
.join(",")}`;
} else {
str += ` ${genObject.selectFields
?.map((fld) =>
typeof fld == "object"
? `${fld.fieldName.toString()}` +
(fld.alias ? ` as ${fld.alias}` : ``)
: fld
)
.join(",")}`;
}
} else {
if (genObject?.join) {
str += ` ${finalDbName}${tableName}.*`;
} else {
str += " *";
}
}
if (genObject?.countSubQueries) {
let countSqls: string[] = [];
for (let i = 0; i < genObject.countSubQueries.length; i++) {
const countSubQuery = genObject.countSubQueries[i];
let subQStr = `(SELECT COUNT(*)`;
subQStr += ` FROM ${countSubQuery.table}`;
subQStr += ` WHERE (`;
for (let j = 0; j < countSubQuery.srcTrgMap.length; j++) {
const csqSrc = countSubQuery.srcTrgMap[j];
subQStr += ` ${countSubQuery.table}.${csqSrc.src}`;
if (typeof csqSrc.trg == "string") {
subQStr += ` = ?`;
sqlSearhValues.push(csqSrc.trg);
} else if (typeof csqSrc.trg == "object") {
subQStr += ` = ${csqSrc.trg.table}.${csqSrc.trg.field}`;
}
if (j < countSubQuery.srcTrgMap.length - 1) {
subQStr += ` AND `;
}
}
subQStr += ` )) AS ${countSubQuery.alias}`;
countSqls.push(subQStr);
}
str += `, ${countSqls.join(",")}`;
}
if (genObject?.join && !count) {
const existingJoinTableNames: string[] = [tableName];
str +=
"," +
genObject.join
.map((joinObj) => {
const joinTableName = joinObj.alias
? joinObj.alias
: joinObj.tableName;
if (existingJoinTableNames.includes(joinTableName))
return null;
existingJoinTableNames.push(joinTableName);
if (joinObj.selectFields) {
return joinObj.selectFields
.map((selectField) => {
if (typeof selectField == "string") {
return `${finalDbName}${joinTableName}.${selectField}`;
} else if (typeof selectField == "object") {
let aliasSelectField = selectField.count
? `COUNT(${finalDbName}${joinTableName}.${selectField.field})`
: `${finalDbName}${joinTableName}.${selectField.field}`;
if (selectField.alias)
aliasSelectField += ` AS ${selectField.alias}`;
return aliasSelectField;
}
})
.join(",");
} else {
return `${finalDbName}${joinTableName}.*`;
}
})
.filter((_) => Boolean(_))
.join(",");
}
if (
genObject?.fullTextSearch &&
fullTextMatchStr &&
fullTextSearchStr
) {
str += `, ${fullTextMatchStr} AS ${genObject.fullTextSearch.scoreAlias}`;
sqlSearhValues.push(fullTextSearchStr);
}
str += ` FROM ${finalDbName}${tableName}`;
if (genObject?.join) {
str +=
" " +
genObject.join
.map((join) => {
return (
join.joinType +
" " +
(join.alias
? `${finalDbName}${join.tableName}` +
" " +
join.alias
: `${finalDbName}${join.tableName}`) +
" ON " +
(() => {
if (Array.isArray(join.match)) {
return (
"(" +
join.match
.map((mtch) =>
generateJoinStr(mtch, join)
)
.join(
join.operator
? ` ${join.operator} `
: " AND "
) +
")"
);
} else if (typeof join.match == "object") {
return generateJoinStr(join.match, join);
}
})()
);
})
.join(" ");
}
return str;
})();
const sqlSearhString = queryKeys?.map((field) => {
const queryObj = finalQuery?.[field];
if (!queryObj) return;
if (queryObj.__query) {
const subQueryGroup = queryObj.__query;
const subSearchKeys = Object.keys(subQueryGroup);
const subSearchString = subSearchKeys.map((_field) => {
const newSubQueryObj = subQueryGroup?.[_field];
return genSqlSrchStr({
queryObj: newSubQueryObj,
field: _field,
join: genObject?.join,
});
});
return (
"(" +
subSearchString.join(` ${queryObj.operator || "AND"} `) +
")"
);
}
return genSqlSrchStr({ queryObj, field, join: genObject?.join });
});
const isSearchStr =
sqlSearhString?.[0] && sqlSearhString.find((str) => str);
if (isSearchStr) {
const stringOperator = genObject?.searchOperator || "AND";
queryString += ` WHERE ${sqlSearhString.join(` ${stringOperator} `)}`;
}
if (genObject?.fullTextSearch && fullTextSearchStr && fullTextMatchStr) {
queryString += `${isSearchStr ? " AND" : " WHERE"} ${fullTextMatchStr}`;
sqlSearhValues.push(fullTextSearchStr);
}
if (genObject?.group?.[0]) {
queryString += ` GROUP BY ${genObject.group
.map((g) => `\`${g.toString()}\``)
.join(",")}`;
}
if (genObject?.order && !count) {
let orderFields = [];
let orderSrt = ` ORDER BY`;
if (genObject?.fullTextSearch && genObject.fullTextSearch.scoreAlias) {
orderFields.push(genObject.fullTextSearch.scoreAlias);
} else if (genObject.join) {
orderFields.push(
`${finalDbName}${tableName}.${String(genObject.order.field)}`
);
} else {
orderFields.push(genObject.order.field);
}
orderSrt += ` ${orderFields.join(", ")} ${genObject.order.strategy}`;
queryString += ` ${orderSrt}`;
}
if (genObject?.limit && !count) queryString += ` LIMIT ${genObject.limit}`;
if (genObject?.offset && !count)
queryString += ` OFFSET ${genObject.offset}`;
return {
string: queryString,
values: sqlSearhValues,
};
}