@technicity/data-service-generator 0.9.0 → 0.10.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -2
- package/dist/index.js +3 -4
- package/dist/runtime/Cache.d.ts +18 -0
- package/dist/runtime/Cache.js +90 -0
- package/dist/runtime/Runtime.d.ts +23 -0
- package/dist/runtime/Runtime.js +29 -0
- package/dist/runtime/RuntimeKSQL.d.ts +1 -1
- package/dist/runtime/RuntimeKSQL.js +13 -11
- package/dist/runtime/RuntimeMSSQL.d.ts +18 -14
- package/dist/runtime/RuntimeMSSQL.js +48 -43
- package/dist/runtime/RuntimeMySQL.d.ts +11 -12
- package/dist/runtime/RuntimeMySQL.js +46 -79
- package/dist/runtime/lib/create.d.ts +12 -0
- package/dist/runtime/lib/create.js +175 -0
- package/dist/runtime/lib/delete.d.ts +5 -0
- package/dist/runtime/lib/delete.js +43 -0
- package/dist/runtime/lib/error.d.ts +9 -0
- package/dist/runtime/lib/error.js +22 -0
- package/dist/runtime/lib/getData.d.ts +4 -0
- package/dist/runtime/lib/getData.js +227 -0
- package/dist/runtime/lib/getSqlAst.js +2 -2
- package/dist/runtime/lib/getWhere.d.ts +17 -0
- package/dist/runtime/lib/getWhere.js +228 -4
- package/dist/runtime/lib/prepareWhere.d.ts +2 -0
- package/dist/runtime/lib/prepareWhere.js +158 -0
- package/dist/runtime/lib/resolve.d.ts +10 -0
- package/dist/runtime/lib/resolve.js +66 -0
- package/dist/runtime/lib/shared.d.ts +22 -12
- package/dist/runtime/lib/shared.js +16 -746
- package/dist/runtime/lib/typeCastMSSQL.js +1 -1
- package/dist/runtime/lib/update.d.ts +4 -0
- package/dist/runtime/lib/update.js +143 -0
- package/dist/runtime/lib/utility.d.ts +5 -0
- package/dist/runtime/lib/utility.js +15 -0
- package/package.json +7 -6
- package/dist/runtime/lib/MSSQL.d.ts +0 -13
- package/dist/runtime/lib/MSSQL.js +0 -73
- package/dist/runtime/lib/SDKBadWhereError.d.ts +0 -4
- package/dist/runtime/lib/SDKBadWhereError.js +0 -10
- package/dist/runtime/lib/SDKNotFoundError.d.ts +0 -4
- package/dist/runtime/lib/SDKNotFoundError.js +0 -10
- package/dist/runtime/lib/getDateTimeStringMySQL.d.ts +0 -1
- package/dist/runtime/lib/getDateTimeStringMySQL.js +0 -8
- package/dist/runtime/lib/stringifyWhere.d.ts +0 -18
- package/dist/runtime/lib/stringifyWhere.js +0 -228
|
@@ -5,7 +5,7 @@ const mssql = require("mssql");
|
|
|
5
5
|
// TODO: see https://github.com/tediousjs/node-mssql/pull/1171
|
|
6
6
|
function typeCastMSSQL(customTypeCast) {
|
|
7
7
|
return function (result, meta) {
|
|
8
|
-
|
|
8
|
+
const typeCasts = {};
|
|
9
9
|
for (let k in meta) {
|
|
10
10
|
const v = meta[k];
|
|
11
11
|
if (typeof customTypeCast === "function") {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import Cache from '../Cache';
|
|
2
|
+
import { IDialect, TDbCall, TFormatQuery, TResolveParams } from '../IRuntime';
|
|
3
|
+
export declare function update(input: TResolveParams, dbCall: TDbCall, formatQuery: TFormatQuery, dialect: IDialect, cache?: Cache): Promise<any>;
|
|
4
|
+
export declare function updateMany(input: TResolveParams, dbCall: TDbCall, formatQuery: TFormatQuery, dialect: IDialect, cache?: Cache): Promise<any>;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateMany = exports.update = void 0;
|
|
4
|
+
const error_1 = require("./error");
|
|
5
|
+
const getData_1 = require("./getData");
|
|
6
|
+
const getWhere_1 = require("./getWhere");
|
|
7
|
+
const shared_1 = require("./shared");
|
|
8
|
+
async function update(input, dbCall, formatQuery, dialect, cache) {
|
|
9
|
+
async function _update() {
|
|
10
|
+
const escapeId = (0, getWhere_1.getEscapeId)(dialect);
|
|
11
|
+
const tableArtifacts = input.artifacts[input.resource];
|
|
12
|
+
const where = (0, getWhere_1.getWhere)(escapeId(input.resource), input.args, dialect);
|
|
13
|
+
if (where == null) {
|
|
14
|
+
throw new Error("Null where");
|
|
15
|
+
}
|
|
16
|
+
const current = await dbCall(formatQuery("SELECT * FROM ?? WHERE " + where, [input.resource])).then((xs) => xs[0]);
|
|
17
|
+
if (current == null) {
|
|
18
|
+
throw new error_1.SDKNotFoundError();
|
|
19
|
+
}
|
|
20
|
+
if (cache && current.uuid)
|
|
21
|
+
cache.purge(current.uuid);
|
|
22
|
+
// Shallow clone, as we're going to mutate later
|
|
23
|
+
const data = { ...input.data };
|
|
24
|
+
if ((0, shared_1.hasMappedFields)(input.artifacts, input.resource, data)) {
|
|
25
|
+
await (0, shared_1.mapMappedFields)(tableArtifacts, data, dbCall, formatQuery);
|
|
26
|
+
}
|
|
27
|
+
if (dialect === "mysql" && tableArtifacts.dateTimeFieldsCount > 0) {
|
|
28
|
+
for (let k in tableArtifacts.dateTimeFields) {
|
|
29
|
+
if (data[k] != null) {
|
|
30
|
+
data[k] = (0, shared_1.getDateTimeStringMySQL)(data[k]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Delete keys with value of undefined
|
|
35
|
+
for (let k in data) {
|
|
36
|
+
if (data[k] === void 0) {
|
|
37
|
+
delete data[k];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Nothing to update
|
|
41
|
+
if (Object.keys(data).length === 0) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
await dbCall(getUpdateQuery(input.resource, data, where, dialect, formatQuery));
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
await _update();
|
|
48
|
+
return (0, getData_1.getData)(input, dbCall, formatQuery, dialect);
|
|
49
|
+
}
|
|
50
|
+
exports.update = update;
|
|
51
|
+
async function updateMany(input, dbCall, formatQuery, dialect, cache) {
|
|
52
|
+
async function _updateMany() {
|
|
53
|
+
const escapeId = (0, getWhere_1.getEscapeId)(dialect);
|
|
54
|
+
const tableArtifacts = input.artifacts[input.resource];
|
|
55
|
+
const where = (0, getWhere_1.getWhere)(escapeId(input.resource), input.args, dialect);
|
|
56
|
+
if (where == null)
|
|
57
|
+
throw new Error("Null where");
|
|
58
|
+
if (cache)
|
|
59
|
+
try {
|
|
60
|
+
const query = formatQuery(`SELECT uuid FROM ?? WHERE ${where}`, [input.resource]);
|
|
61
|
+
const matches = await dbCall(query);
|
|
62
|
+
const uuids = matches.map((x) => x.uuid);
|
|
63
|
+
cache.purge(...uuids);
|
|
64
|
+
}
|
|
65
|
+
catch (err) { }
|
|
66
|
+
// Shallow clone, as we're going to mutate later
|
|
67
|
+
const data = { ...input.data };
|
|
68
|
+
if ((0, shared_1.hasMappedFields)(input.artifacts, input.resource, data)) {
|
|
69
|
+
await (0, shared_1.mapMappedFields)(tableArtifacts, data, dbCall, formatQuery);
|
|
70
|
+
}
|
|
71
|
+
if (dialect === "mysql" && tableArtifacts.dateTimeFieldsCount > 0) {
|
|
72
|
+
for (let k in tableArtifacts.dateTimeFields) {
|
|
73
|
+
if (data[k] != null) {
|
|
74
|
+
data[k] = (0, shared_1.getDateTimeStringMySQL)(data[k]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Delete keys with value of undefined
|
|
79
|
+
for (let k in data) {
|
|
80
|
+
if (data[k] === void 0) {
|
|
81
|
+
delete data[k];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Nothing to update
|
|
85
|
+
if (Object.keys(data).length === 0) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
await dbCall(getUpdateQuery(input.resource, data, where, dialect, formatQuery));
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
await _updateMany();
|
|
92
|
+
return (0, getData_1.getData)(input, dbCall, formatQuery, dialect);
|
|
93
|
+
}
|
|
94
|
+
exports.updateMany = updateMany;
|
|
95
|
+
function getUpdateQuery(table, data, where, dialect, formatQuery) {
|
|
96
|
+
// Assumes `data` is not empty
|
|
97
|
+
const escapeId = (0, getWhere_1.getEscapeId)(dialect);
|
|
98
|
+
const escape = (0, getWhere_1.getEscape)(dialect);
|
|
99
|
+
let q = "UPDATE ?? ";
|
|
100
|
+
const values = [table];
|
|
101
|
+
const opsStrs = [];
|
|
102
|
+
const dataRegular = {};
|
|
103
|
+
for (let k in data) {
|
|
104
|
+
const v = data[k];
|
|
105
|
+
if (typeof v === "object" && v != null && Object.keys(v).length === 1) {
|
|
106
|
+
const _entries = Object.entries(v)?.[0];
|
|
107
|
+
const op = _entries?.[0];
|
|
108
|
+
const vv = _entries?.[1];
|
|
109
|
+
if (op === "$prepend") {
|
|
110
|
+
opsStrs.push(`${table}.${escapeId(k)} = CASE WHEN ${table}.${escapeId(k)} IS NULL THEN NULL ELSE CONCAT(${escape(vv)}, ${table}.${escapeId(k)}) END`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (op === "$append") {
|
|
114
|
+
opsStrs.push(`${table}.${escapeId(k)} = CASE WHEN ${table}.${escapeId(k)} IS NULL THEN NULL ELSE CONCAT(${table}.${escapeId(k)}, ${escape(vv)}) END`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (op === "$increment") {
|
|
118
|
+
opsStrs.push(`${table}.${escapeId(k)} = ${table}.${escapeId(k)} + ${escape(vv)}`);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (op === "$decrement") {
|
|
122
|
+
opsStrs.push(`${table}.${escapeId(k)} = ${table}.${escapeId(k)} - ${escape(vv)}`);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
dataRegular[k] = v;
|
|
126
|
+
}
|
|
127
|
+
dataRegular[k] = v;
|
|
128
|
+
}
|
|
129
|
+
if (opsStrs.length > 0) {
|
|
130
|
+
q += `SET ${opsStrs.join(", ")}`;
|
|
131
|
+
}
|
|
132
|
+
if (Object.keys(dataRegular).length > 0) {
|
|
133
|
+
if (opsStrs.length > 0) {
|
|
134
|
+
q += ", ?";
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
q += "SET ?";
|
|
138
|
+
}
|
|
139
|
+
values.push(dataRegular);
|
|
140
|
+
}
|
|
141
|
+
q += ` WHERE ${where}`;
|
|
142
|
+
return formatQuery(q, values);
|
|
143
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eagerly resolve and map input values then concatinate.
|
|
3
|
+
*/
|
|
4
|
+
export declare function mapAsync<T, R>(source: T[] | Promise<T[]>, mapFunction: (item: T) => R | R[] | Promise<R>[] | Promise<R | R[]>): Promise<R[]>;
|
|
5
|
+
export declare function flatten<T>(array: (T | T[])[]): T[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flatten = exports.mapAsync = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Eagerly resolve and map input values then concatinate.
|
|
6
|
+
*/
|
|
7
|
+
async function mapAsync(source, mapFunction) {
|
|
8
|
+
const output = (await source).map(mapFunction);
|
|
9
|
+
return Promise.all(flatten(output)).then(flatten);
|
|
10
|
+
}
|
|
11
|
+
exports.mapAsync = mapAsync;
|
|
12
|
+
function flatten(array) {
|
|
13
|
+
return [].concat(...array);
|
|
14
|
+
}
|
|
15
|
+
exports.flatten = flatten;
|
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@technicity/data-service-generator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0-next.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
7
7
|
],
|
|
8
8
|
"scripts": {
|
|
9
9
|
"compile": "rm -rf dist && tsc",
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"test": "
|
|
13
|
-
"test:sdk": "
|
|
14
|
-
"test:only": "npm run create-database && npm run test:sdk"
|
|
10
|
+
"generate": "npm run compile && concurrently \"node ./test/mysql/generate.js\" \"node ./test/mysql8/generate.js\"",
|
|
11
|
+
"test": "npm run generate && mocha ./test/addNullFallbacks.test.js && mocha ./test/stringifyWhere.test.js && npm run test:sdk",
|
|
12
|
+
"test:prepare": "docker-compose down --volumes && docker-compose up -d --build",
|
|
13
|
+
"test:sdk": "mocha ./test/test.js"
|
|
15
14
|
},
|
|
16
15
|
"dependencies": {
|
|
17
16
|
"bluebird": "^3.7.2",
|
|
@@ -25,6 +24,7 @@
|
|
|
25
24
|
"mssql": "^6.3.1",
|
|
26
25
|
"mysql": "^2.18.1",
|
|
27
26
|
"prettier": "^2.1.2",
|
|
27
|
+
"redis": "^4.3.0",
|
|
28
28
|
"sqlstring": "^2.3.2",
|
|
29
29
|
"tsqlstring": "^1.0.1",
|
|
30
30
|
"uuid": "^8.3.2"
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"@types/prettier": "^2.1.5",
|
|
38
38
|
"@types/sqlstring": "^2.2.1",
|
|
39
39
|
"@types/uuid": "^8.3.1",
|
|
40
|
+
"concurrently": "^7.1.0",
|
|
40
41
|
"env-cmd": "^10.1.0",
|
|
41
42
|
"mocha": "9.1.3",
|
|
42
43
|
"sinon": "12.0.1",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import * as mssql from "mssql";
|
|
2
|
-
export declare class MSSQL {
|
|
3
|
-
#private;
|
|
4
|
-
constructor(clientOpts: mssql.config, typeCast?: Function);
|
|
5
|
-
dbCall(q: string): Promise<any>;
|
|
6
|
-
private mapResult;
|
|
7
|
-
formatQuery(q: string, values: any[]): any;
|
|
8
|
-
beginTransaction(): Promise<{
|
|
9
|
-
commit: () => Promise<void>;
|
|
10
|
-
dbCall: (q: string) => Promise<any>;
|
|
11
|
-
}>;
|
|
12
|
-
closePool(): Promise<void>;
|
|
13
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
-
};
|
|
8
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
-
};
|
|
13
|
-
var _MSSQL_pool, _MSSQL_poolConnect, _MSSQL_typeCast;
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.MSSQL = void 0;
|
|
16
|
-
const mssql = require("mssql");
|
|
17
|
-
// @ts-ignore
|
|
18
|
-
const TSqlString = require("tsqlstring");
|
|
19
|
-
class MSSQL {
|
|
20
|
-
constructor(clientOpts, typeCast) {
|
|
21
|
-
_MSSQL_pool.set(this, void 0);
|
|
22
|
-
_MSSQL_poolConnect.set(this, void 0);
|
|
23
|
-
_MSSQL_typeCast.set(this, void 0);
|
|
24
|
-
__classPrivateFieldSet(this, _MSSQL_typeCast, typeCast, "f");
|
|
25
|
-
__classPrivateFieldSet(this, _MSSQL_pool, new mssql.ConnectionPool(clientOpts), "f");
|
|
26
|
-
__classPrivateFieldSet(this, _MSSQL_poolConnect, __classPrivateFieldGet(this, _MSSQL_pool, "f").connect(), "f");
|
|
27
|
-
}
|
|
28
|
-
async dbCall(q) {
|
|
29
|
-
await __classPrivateFieldGet(this, _MSSQL_poolConnect, "f");
|
|
30
|
-
const request = __classPrivateFieldGet(this, _MSSQL_pool, "f").request();
|
|
31
|
-
const result = await request.query(q);
|
|
32
|
-
return this.mapResult(result);
|
|
33
|
-
}
|
|
34
|
-
mapResult(result) {
|
|
35
|
-
// TODO: see https://github.com/tediousjs/node-mssql/pull/1171
|
|
36
|
-
const meta = result.recordset?.columns;
|
|
37
|
-
if (meta != null && typeof __classPrivateFieldGet(this, _MSSQL_typeCast, "f") === "function") {
|
|
38
|
-
return __classPrivateFieldGet(this, _MSSQL_typeCast, "f").call(this, result, meta);
|
|
39
|
-
}
|
|
40
|
-
return result.recordset;
|
|
41
|
-
}
|
|
42
|
-
formatQuery(q, values) {
|
|
43
|
-
return TSqlString.format(q, values);
|
|
44
|
-
}
|
|
45
|
-
async beginTransaction() {
|
|
46
|
-
const transaction = new mssql.Transaction(__classPrivateFieldGet(this, _MSSQL_pool, "f"));
|
|
47
|
-
let rolledBack = false;
|
|
48
|
-
transaction.on("rollback", (aborted) => {
|
|
49
|
-
// emited with aborted === true
|
|
50
|
-
rolledBack = true;
|
|
51
|
-
});
|
|
52
|
-
async function handleError(err) {
|
|
53
|
-
if (!rolledBack) {
|
|
54
|
-
await transaction.rollback();
|
|
55
|
-
}
|
|
56
|
-
throw err;
|
|
57
|
-
}
|
|
58
|
-
const mapResult = this.mapResult.bind(this);
|
|
59
|
-
await transaction.begin();
|
|
60
|
-
return {
|
|
61
|
-
commit: () => transaction.commit().catch(handleError),
|
|
62
|
-
dbCall: (q) => new mssql.Request(transaction)
|
|
63
|
-
.query(q)
|
|
64
|
-
.then(mapResult)
|
|
65
|
-
.catch(handleError),
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
async closePool() {
|
|
69
|
-
await __classPrivateFieldGet(this, _MSSQL_pool, "f").close();
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
exports.MSSQL = MSSQL;
|
|
73
|
-
_MSSQL_pool = new WeakMap(), _MSSQL_poolConnect = new WeakMap(), _MSSQL_typeCast = new WeakMap();
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SDKBadWhereError = void 0;
|
|
4
|
-
const CustomError_1 = require("../../lib/CustomError");
|
|
5
|
-
class SDKBadWhereError extends CustomError_1.CustomError {
|
|
6
|
-
constructor(message) {
|
|
7
|
-
super(message || "Invalid $where");
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
exports.SDKBadWhereError = SDKBadWhereError;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SDKNotFoundError = void 0;
|
|
4
|
-
const CustomError_1 = require("../../lib/CustomError");
|
|
5
|
-
class SDKNotFoundError extends CustomError_1.CustomError {
|
|
6
|
-
constructor() {
|
|
7
|
-
super("Not found");
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
exports.SDKNotFoundError = SDKNotFoundError;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function getDateTimeStringMySQL(dateTimeString: string): string;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDateTimeStringMySQL = void 0;
|
|
4
|
-
// Assumes input uses zero offset
|
|
5
|
-
function getDateTimeStringMySQL(dateTimeString) {
|
|
6
|
-
return dateTimeString.replace("T", " ").slice(0, 19);
|
|
7
|
-
}
|
|
8
|
-
exports.getDateTimeStringMySQL = getDateTimeStringMySQL;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { IOrderBy, IDialect } from "../IRuntime";
|
|
2
|
-
declare type IWhere = {
|
|
3
|
-
[k: string]: any;
|
|
4
|
-
};
|
|
5
|
-
declare type IArgs = {
|
|
6
|
-
[k: string]: any;
|
|
7
|
-
};
|
|
8
|
-
export declare function stringifyWhere(input: {
|
|
9
|
-
where: IWhere;
|
|
10
|
-
table: string;
|
|
11
|
-
dialect: IDialect;
|
|
12
|
-
args: IArgs;
|
|
13
|
-
orderBy?: IOrderBy | undefined;
|
|
14
|
-
rowWithMatchingCursor?: any;
|
|
15
|
-
}): string;
|
|
16
|
-
export declare function getEscapeId(dialect: IDialect): any;
|
|
17
|
-
export declare function getEscape(dialect: IDialect): any;
|
|
18
|
-
export {};
|
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getEscape = exports.getEscapeId = exports.stringifyWhere = void 0;
|
|
4
|
-
const _ = require("lodash/fp");
|
|
5
|
-
const MySqlString = require("sqlstring");
|
|
6
|
-
// @ts-ignore
|
|
7
|
-
const TSqlString = require("tsqlstring");
|
|
8
|
-
function stringifyWhere(input) {
|
|
9
|
-
const { where, table, dialect, args, orderBy, rowWithMatchingCursor } = input;
|
|
10
|
-
const escapeId = getEscapeId(dialect);
|
|
11
|
-
const escape = getEscape(dialect);
|
|
12
|
-
let result = _stringifyWhere(where, table, escapeId, escape, "");
|
|
13
|
-
const paginationWhere = stringifyPaginationWhere({
|
|
14
|
-
table,
|
|
15
|
-
args,
|
|
16
|
-
orderBy,
|
|
17
|
-
escapeId,
|
|
18
|
-
escape,
|
|
19
|
-
rowWithMatchingCursor,
|
|
20
|
-
});
|
|
21
|
-
if (paginationWhere) {
|
|
22
|
-
result =
|
|
23
|
-
result.length === 0
|
|
24
|
-
? paginationWhere
|
|
25
|
-
: result + " AND " + paginationWhere;
|
|
26
|
-
}
|
|
27
|
-
return result;
|
|
28
|
-
}
|
|
29
|
-
exports.stringifyWhere = stringifyWhere;
|
|
30
|
-
function _stringifyWhere(where, table, escapeId, escape, result) {
|
|
31
|
-
if (Object.prototype.hasOwnProperty.call(where, "$and")) {
|
|
32
|
-
if (Object.keys(where).length !== 1) {
|
|
33
|
-
throw new Error("Must have 1 key: " + JSON.stringify(where, null, 2));
|
|
34
|
-
}
|
|
35
|
-
const _xs = where.$and.filter((x) => x != null);
|
|
36
|
-
if (_xs.length === 0) {
|
|
37
|
-
return result;
|
|
38
|
-
}
|
|
39
|
-
const xs = _xs
|
|
40
|
-
.map((x) => _stringifyWhere(x, table, escapeId, escape, result))
|
|
41
|
-
.filter(Boolean);
|
|
42
|
-
if (xs.length === 0) {
|
|
43
|
-
return result;
|
|
44
|
-
}
|
|
45
|
-
return `(${xs.join(" AND ")})`;
|
|
46
|
-
}
|
|
47
|
-
if (Object.prototype.hasOwnProperty.call(where, "$or")) {
|
|
48
|
-
if (Object.keys(where).length !== 1) {
|
|
49
|
-
throw new Error("Must have 1 key: " + JSON.stringify(where, null, 2));
|
|
50
|
-
}
|
|
51
|
-
const _xs = where.$or.filter((x) => x != null);
|
|
52
|
-
if (_xs.length === 0) {
|
|
53
|
-
return result;
|
|
54
|
-
}
|
|
55
|
-
const xs = _xs
|
|
56
|
-
.map((x) => _stringifyWhere(x, table, escapeId, escape, result))
|
|
57
|
-
.filter(Boolean);
|
|
58
|
-
if (xs.length === 0) {
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
|
-
return `(${xs.join(" OR ")})`;
|
|
62
|
-
}
|
|
63
|
-
function printValue(v) {
|
|
64
|
-
if (v === true) {
|
|
65
|
-
v = 1;
|
|
66
|
-
}
|
|
67
|
-
if (v === false) {
|
|
68
|
-
v = 0;
|
|
69
|
-
}
|
|
70
|
-
return escape(v);
|
|
71
|
-
}
|
|
72
|
-
return Object.keys(where)
|
|
73
|
-
.map((k) => {
|
|
74
|
-
let v = where[k];
|
|
75
|
-
if (v === void 0) {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
// Can't do this, since we need this function to be sync
|
|
79
|
-
// if (relationMap[k] !== null) {
|
|
80
|
-
// const relationData = await getRelationData(k, v, relationMap);
|
|
81
|
-
// k = relationData.k;
|
|
82
|
-
// v = relationData.v;
|
|
83
|
-
// }
|
|
84
|
-
if (v === null) {
|
|
85
|
-
return `${table}.${escapeId(k)} IS NULL`;
|
|
86
|
-
}
|
|
87
|
-
if (typeof v === "string" ||
|
|
88
|
-
typeof v === "number" ||
|
|
89
|
-
typeof v === "boolean") {
|
|
90
|
-
return `${table}.${escapeId(k)} = ${printValue(v)}`;
|
|
91
|
-
}
|
|
92
|
-
if (_.isPlainObject(v)) {
|
|
93
|
-
const keys = Object.keys(v);
|
|
94
|
-
if (keys.length !== 1) {
|
|
95
|
-
throw new Error("Must have 1 key: " + JSON.stringify(v, null, 2));
|
|
96
|
-
}
|
|
97
|
-
const operator = keys[0];
|
|
98
|
-
const operand = v[operator];
|
|
99
|
-
if (operator === "$ne") {
|
|
100
|
-
return `${table}.${escapeId(k)} ${getOperatorNeq(v)} ${printValue(operand)}`;
|
|
101
|
-
}
|
|
102
|
-
if (operator === "$gt") {
|
|
103
|
-
return `${table}.${escapeId(k)} > ${printValue(operand)}`;
|
|
104
|
-
}
|
|
105
|
-
if (operator === "$gte") {
|
|
106
|
-
return `${table}.${escapeId(k)} >= ${printValue(operand)}`;
|
|
107
|
-
}
|
|
108
|
-
if (operator === "$lt") {
|
|
109
|
-
return `${table}.${escapeId(k)} < ${printValue(operand)}`;
|
|
110
|
-
}
|
|
111
|
-
if (operator === "$lte") {
|
|
112
|
-
return `${table}.${escapeId(k)} <= ${printValue(operand)}`;
|
|
113
|
-
}
|
|
114
|
-
if (operator === "$like") {
|
|
115
|
-
return `${table}.${escapeId(k)} LIKE ${printValue(operand)}`;
|
|
116
|
-
}
|
|
117
|
-
if (operator === "$nlike") {
|
|
118
|
-
return `${table}.${escapeId(k)} NOT LIKE ${printValue(operand)}`;
|
|
119
|
-
}
|
|
120
|
-
if (operator === "$in") {
|
|
121
|
-
if (operand.length === 0) {
|
|
122
|
-
// Would do "FALSE" instead, as it's more readable, but it
|
|
123
|
-
// causes a RequestError in MSSQL.
|
|
124
|
-
return "(1=0)";
|
|
125
|
-
}
|
|
126
|
-
return `${table}.${escapeId(k)} IN (${operand
|
|
127
|
-
.map((x) => printValue(x))
|
|
128
|
-
.join(",")})`;
|
|
129
|
-
}
|
|
130
|
-
if (operator === "$nin") {
|
|
131
|
-
if (operand.length === 0) {
|
|
132
|
-
// Would do "TRUE" instead, as it's more readable, but it
|
|
133
|
-
// causes a RequestError in MSSQL.
|
|
134
|
-
return "(1=1)";
|
|
135
|
-
}
|
|
136
|
-
return `${table}.${escapeId(k)} NOT IN (${operand
|
|
137
|
-
.map((x) => printValue(x))
|
|
138
|
-
.join(",")})`;
|
|
139
|
-
}
|
|
140
|
-
if (operator === "$btwn") {
|
|
141
|
-
if (operand.length !== 2) {
|
|
142
|
-
throw new Error("Expected length of 2, got: " + operand.length);
|
|
143
|
-
}
|
|
144
|
-
return `${table}.${escapeId(k)} BETWEEN ${printValue(operand[0])} AND ${printValue(operand[1])}`;
|
|
145
|
-
}
|
|
146
|
-
if (operator === "$nbtwn") {
|
|
147
|
-
if (operand.length !== 2) {
|
|
148
|
-
throw new Error("Expected length of 2, got: " + operand.length);
|
|
149
|
-
}
|
|
150
|
-
return `${table}.${escapeId(k)} NOT BETWEEN ${printValue(operand[0])} AND ${printValue(operand[1])}`;
|
|
151
|
-
}
|
|
152
|
-
throw new Error("Invalid operator: " + operator);
|
|
153
|
-
}
|
|
154
|
-
throw new Error("Invalid value: " + v);
|
|
155
|
-
})
|
|
156
|
-
.filter((x) => x != null)
|
|
157
|
-
.join(" AND ");
|
|
158
|
-
}
|
|
159
|
-
const valuesThatUseIsOrIsNot = new Set([null]);
|
|
160
|
-
function getOperatorNeq(value) {
|
|
161
|
-
return valuesThatUseIsOrIsNot.has(value) ? "IS NOT" : "!=";
|
|
162
|
-
}
|
|
163
|
-
// async function getRelationData(k: string, v: any, relationMap: IRelationMap) {
|
|
164
|
-
// // TODO
|
|
165
|
-
// return { k, v };
|
|
166
|
-
// }
|
|
167
|
-
function stringifyPaginationWhere(input) {
|
|
168
|
-
const { table, args, orderBy, escapeId, escape, rowWithMatchingCursor } = input;
|
|
169
|
-
if (args?.$paginate?.after == null && args?.$paginate?.before == null) {
|
|
170
|
-
return "";
|
|
171
|
-
}
|
|
172
|
-
if (rowWithMatchingCursor == null) {
|
|
173
|
-
return "";
|
|
174
|
-
}
|
|
175
|
-
// orderBy should never be null because of getOrderBy, but add a check.
|
|
176
|
-
if (orderBy == null) {
|
|
177
|
-
throw new Error("orderBy cannot be null when paginating");
|
|
178
|
-
}
|
|
179
|
-
function getCompOp(dir) {
|
|
180
|
-
return dir === "asc" ? ">" : "<";
|
|
181
|
-
}
|
|
182
|
-
function printValue(v) {
|
|
183
|
-
if (v === true) {
|
|
184
|
-
v = 1;
|
|
185
|
-
}
|
|
186
|
-
if (v === false) {
|
|
187
|
-
v = 0;
|
|
188
|
-
}
|
|
189
|
-
return escape(v);
|
|
190
|
-
}
|
|
191
|
-
// https://gist.github.com/pcattori/2bb645d587e45c9fdbcabf5cef7a7106
|
|
192
|
-
const cond = orderBy
|
|
193
|
-
.map(({ column, direction }, i) => {
|
|
194
|
-
let a = orderBy.slice(0, i).map(({ column: col2 }) => {
|
|
195
|
-
const field = `${table}.${escapeId(col2)}`;
|
|
196
|
-
const op = "=";
|
|
197
|
-
const v = printValue(rowWithMatchingCursor[col2]);
|
|
198
|
-
return `${field} ${op} ${v}`;
|
|
199
|
-
});
|
|
200
|
-
const field = `${table}.${escapeId(column)}`;
|
|
201
|
-
const op = getCompOp(direction);
|
|
202
|
-
const v = printValue(rowWithMatchingCursor[column]);
|
|
203
|
-
a.push(`${field} ${op} ${v}`);
|
|
204
|
-
return "(" + a.join(" AND ") + ")";
|
|
205
|
-
})
|
|
206
|
-
.join(" OR ");
|
|
207
|
-
return "(" + cond + ")";
|
|
208
|
-
}
|
|
209
|
-
function getEscapeId(dialect) {
|
|
210
|
-
if (dialect === "mysql") {
|
|
211
|
-
return MySqlString.escapeId.bind(MySqlString);
|
|
212
|
-
}
|
|
213
|
-
if (dialect === "mssql") {
|
|
214
|
-
return TSqlString.escapeId.bind(TSqlString);
|
|
215
|
-
}
|
|
216
|
-
throw new Error("Unsupported dialect: " + dialect);
|
|
217
|
-
}
|
|
218
|
-
exports.getEscapeId = getEscapeId;
|
|
219
|
-
function getEscape(dialect) {
|
|
220
|
-
if (dialect === "mysql") {
|
|
221
|
-
return MySqlString.escape.bind(MySqlString);
|
|
222
|
-
}
|
|
223
|
-
if (dialect === "mssql") {
|
|
224
|
-
return TSqlString.escape.bind(TSqlString);
|
|
225
|
-
}
|
|
226
|
-
throw new Error("Unsupported dialect: " + dialect);
|
|
227
|
-
}
|
|
228
|
-
exports.getEscape = getEscape;
|