@saltcorn/sql 0.5.0 → 0.5.1
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/index.js +10 -5
- package/package.json +1 -1
- package/table-provider.js +154 -141
package/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const Table = require("@saltcorn/data/models/table");
|
|
|
5
5
|
const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
|
|
6
6
|
const Workflow = require("@saltcorn/data/models/workflow");
|
|
7
7
|
const { eval_expression } = require("@saltcorn/data/models/expression");
|
|
8
|
+
const { interpolate } = require("@saltcorn/data/utils");
|
|
8
9
|
const {
|
|
9
10
|
text,
|
|
10
11
|
div,
|
|
@@ -107,20 +108,24 @@ const run = async (
|
|
|
107
108
|
);
|
|
108
109
|
}
|
|
109
110
|
qres = await client.query(sql, phValues);
|
|
110
|
-
} catch (e) {
|
|
111
|
-
throw e;
|
|
112
111
|
} finally {
|
|
113
112
|
await client.query(`ROLLBACK;`);
|
|
114
113
|
if (!is_sqlite) client.release(true);
|
|
115
114
|
}
|
|
116
115
|
switch (output_type) {
|
|
117
116
|
case "HTML":
|
|
118
|
-
const template = _.template(html_code || "", {
|
|
117
|
+
/*const template = _.template(html_code || "", {
|
|
119
118
|
evaluate: /\{\{#(.+?)\}\}/g,
|
|
120
119
|
interpolate: /\{\{([^#].+?)\}\}/g,
|
|
121
120
|
});
|
|
122
|
-
|
|
123
|
-
return
|
|
121
|
+
console.log("template", viewname, state, html_code);*/
|
|
122
|
+
return interpolate(
|
|
123
|
+
html_code,
|
|
124
|
+
{ rows: qres.rows },
|
|
125
|
+
req.user,
|
|
126
|
+
`HTML code interpolation in view ${viewname}`
|
|
127
|
+
);
|
|
128
|
+
//return template();
|
|
124
129
|
|
|
125
130
|
case "JSON":
|
|
126
131
|
return `<pre>${JSON.stringify(qres.rows, null, 2)}</pre>`;
|
package/package.json
CHANGED
package/table-provider.js
CHANGED
|
@@ -46,6 +46,13 @@ const configuration_workflow = (req) =>
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
label: "Ignore where/order",
|
|
51
|
+
sublabel:
|
|
52
|
+
"Always use this SQL directly without attempting to modify it",
|
|
53
|
+
type: "Bool",
|
|
54
|
+
name: "ignore_where",
|
|
55
|
+
},
|
|
49
56
|
],
|
|
50
57
|
});
|
|
51
58
|
},
|
|
@@ -176,161 +183,168 @@ const runQuery = async (cfg, where, opts) => {
|
|
|
176
183
|
const opt = {
|
|
177
184
|
database: is_sqlite ? "SQLite" : "PostgreSQL",
|
|
178
185
|
};
|
|
179
|
-
|
|
180
|
-
const { ast } = parser.parse(sql, opt);
|
|
181
|
-
|
|
182
|
-
const colNames = new Set((cfg?.columns || []).map((c) => c.name));
|
|
183
|
-
let phIndex = 1;
|
|
186
|
+
let sqlQ;
|
|
184
187
|
const phValues = [];
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
ast[0].columns == "*"
|
|
190
|
-
? {
|
|
191
|
-
type: "expr",
|
|
192
|
-
expr: { type: "column_ref", table: null, column: k },
|
|
193
|
-
as: null,
|
|
194
|
-
}
|
|
195
|
-
: (ast[0].columns || []).find(
|
|
196
|
-
(c) => k === c.as || (!c.as && k === c.expr?.column)
|
|
197
|
-
);
|
|
198
|
-
const sqlExprCol =
|
|
199
|
-
ast[0].columns == "*"
|
|
200
|
-
? {
|
|
201
|
-
type: "expr",
|
|
202
|
-
expr: { type: "column_ref", table: null, column: k },
|
|
203
|
-
as: null,
|
|
204
|
-
}
|
|
205
|
-
: (ast[0].columns || []).find((c) => c.expr?.as == k);
|
|
206
|
-
const sqlAggrCol = (ast[0].columns || []).find(
|
|
207
|
-
(c) =>
|
|
208
|
-
c.expr?.type === "aggr_func" &&
|
|
209
|
-
c.expr?.name?.toUpperCase() === k.toUpperCase()
|
|
210
|
-
);
|
|
188
|
+
if (cfg?.ignore_where) {
|
|
189
|
+
sqlQ = sql;
|
|
190
|
+
} else {
|
|
191
|
+
const { ast } = parser.parse(sql, opt);
|
|
211
192
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
193
|
+
const colNames = new Set((cfg?.columns || []).map((c) => c.name));
|
|
194
|
+
let phIndex = 1;
|
|
195
|
+
//console.log(ast[0].columns);
|
|
196
|
+
for (const k of Object.keys(where)) {
|
|
197
|
+
if (!colNames.has(k)) continue;
|
|
198
|
+
const sqlCol =
|
|
199
|
+
ast[0].columns == "*"
|
|
200
|
+
? {
|
|
201
|
+
type: "expr",
|
|
202
|
+
expr: { type: "column_ref", table: null, column: k },
|
|
203
|
+
as: null,
|
|
204
|
+
}
|
|
205
|
+
: (ast[0].columns || []).find(
|
|
206
|
+
(c) => k === c.as || (!c.as && k === c.expr?.column)
|
|
207
|
+
);
|
|
208
|
+
const sqlExprCol =
|
|
209
|
+
ast[0].columns == "*"
|
|
210
|
+
? {
|
|
211
|
+
type: "expr",
|
|
212
|
+
expr: { type: "column_ref", table: null, column: k },
|
|
213
|
+
as: null,
|
|
214
|
+
}
|
|
215
|
+
: (ast[0].columns || []).find((c) => c.expr?.as == k);
|
|
216
|
+
const sqlAggrCol = (ast[0].columns || []).find(
|
|
217
|
+
(c) =>
|
|
218
|
+
c.expr?.type === "aggr_func" &&
|
|
219
|
+
c.expr?.name?.toUpperCase() === k.toUpperCase()
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
let left = sqlExprCol
|
|
223
|
+
? { ...sqlExprCol.expr, as: null }
|
|
224
|
+
: sqlAggrCol
|
|
225
|
+
? { ...sqlAggrCol.expr }
|
|
226
|
+
: {
|
|
227
|
+
type: "column_ref",
|
|
228
|
+
table: sqlCol?.expr?.table,
|
|
229
|
+
column: sqlCol?.expr?.column || db.sqlsanitize(k),
|
|
230
|
+
};
|
|
231
|
+
//console.log({ k, sqlCol, sqlExprCol });
|
|
232
|
+
if (!sqlCol) {
|
|
233
|
+
const starCol = (ast[0].columns || []).find(
|
|
234
|
+
(c) => c.type === "star_ref"
|
|
235
|
+
);
|
|
236
|
+
if (starCol)
|
|
237
|
+
left = {
|
|
238
|
+
type: "column_ref",
|
|
239
|
+
table: starCol?.expr?.table,
|
|
240
|
+
column: db.sqlsanitize(k),
|
|
241
|
+
};
|
|
248
242
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
243
|
+
const newClause = {
|
|
244
|
+
type: "binary_expr",
|
|
245
|
+
operator: where[k]?.ilike && !sqlAggrCol ? "ILIKE" : "=",
|
|
246
|
+
left,
|
|
247
|
+
right: { type: "number", value: "$" + phIndex },
|
|
248
|
+
};
|
|
249
|
+
phIndex += 1;
|
|
250
|
+
phValues.push(where[k]?.ilike ? where[k]?.ilike : where[k]);
|
|
251
|
+
if (!sqlAggrCol) {
|
|
252
|
+
if (!ast[0].where) ast[0].where = newClause;
|
|
253
|
+
else {
|
|
254
|
+
ast[0].where = {
|
|
255
|
+
type: "binary_expr",
|
|
256
|
+
operator: "AND",
|
|
257
|
+
left: ast[0].where,
|
|
258
|
+
right: newClause,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
if (!ast[0].having) ast[0].having = newClause;
|
|
263
|
+
else {
|
|
264
|
+
ast[0].having = {
|
|
265
|
+
type: "binary_expr",
|
|
266
|
+
operator: "AND",
|
|
267
|
+
left: ast[0].having,
|
|
268
|
+
right: newClause,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
258
271
|
}
|
|
259
272
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
//console.log(ast[0].orderby[[0]]);
|
|
273
|
+
if (where?.limit && where?.offset) {
|
|
274
|
+
ast[0].limit = {
|
|
275
|
+
seperator: "offset",
|
|
276
|
+
value: [
|
|
277
|
+
{ type: "number", value: where.limit },
|
|
278
|
+
{ type: "number", value: where.offset },
|
|
279
|
+
],
|
|
280
|
+
};
|
|
281
|
+
} else if (opts?.limit && opts?.offset) {
|
|
282
|
+
ast[0].limit = {
|
|
283
|
+
seperator: "offset",
|
|
284
|
+
value: [
|
|
285
|
+
{ type: "number", value: opts.limit },
|
|
286
|
+
{ type: "number", value: opts.offset },
|
|
287
|
+
],
|
|
288
|
+
};
|
|
289
|
+
} else if (where?.limit) {
|
|
290
|
+
ast[0].limit = {
|
|
291
|
+
seperator: "",
|
|
292
|
+
value: [{ type: "number", value: where.limit }],
|
|
293
|
+
};
|
|
294
|
+
} else if (opts?.limit) {
|
|
295
|
+
ast[0].limit = {
|
|
296
|
+
seperator: "",
|
|
297
|
+
value: [{ type: "number", value: opts.limit }],
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
//console.log(ast[0]);
|
|
301
|
+
//console.log(ast[0].orderby[[0]]);
|
|
290
302
|
|
|
291
|
-
|
|
292
|
-
|
|
303
|
+
const orderBy = where?.orderBy || opts?.orderBy;
|
|
304
|
+
const orderDesc = where?.orderDesc || opts?.orderDesc;
|
|
293
305
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
ast[0].orderby = [
|
|
297
|
-
{
|
|
298
|
-
expr: {
|
|
299
|
-
type: "column_ref",
|
|
300
|
-
table: null,
|
|
301
|
-
column: db.sqlsanitize(orderBy),
|
|
302
|
-
},
|
|
303
|
-
type: orderDesc ? "DESC" : "ASC",
|
|
304
|
-
},
|
|
305
|
-
];
|
|
306
|
-
else if (orderBy.operator) {
|
|
307
|
-
const { operator, field, target } = orderBy;
|
|
308
|
-
const fieldCol = (cfg.columns || []).find((c) => c.name === field);
|
|
309
|
-
const type = getState().types[fieldCol?.type];
|
|
310
|
-
const op = type?.distance_operators[operator];
|
|
311
|
-
if (op?.type === "SqlBinOp") {
|
|
306
|
+
if (orderBy) {
|
|
307
|
+
if (typeof orderBy === "string")
|
|
312
308
|
ast[0].orderby = [
|
|
313
309
|
{
|
|
314
310
|
expr: {
|
|
315
|
-
type: "
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
type: "column_ref",
|
|
319
|
-
table: null,
|
|
320
|
-
column: db.sqlsanitize(field),
|
|
321
|
-
},
|
|
322
|
-
right: {
|
|
323
|
-
type: "number",
|
|
324
|
-
value: "$" + phIndex,
|
|
325
|
-
},
|
|
311
|
+
type: "column_ref",
|
|
312
|
+
table: null,
|
|
313
|
+
column: db.sqlsanitize(orderBy),
|
|
326
314
|
},
|
|
327
315
|
type: orderDesc ? "DESC" : "ASC",
|
|
328
316
|
},
|
|
329
317
|
];
|
|
330
|
-
|
|
331
|
-
|
|
318
|
+
else if (orderBy.operator) {
|
|
319
|
+
const { operator, field, target } = orderBy;
|
|
320
|
+
const fieldCol = (cfg.columns || []).find((c) => c.name === field);
|
|
321
|
+
const type = getState().types[fieldCol?.type];
|
|
322
|
+
const op = type?.distance_operators[operator];
|
|
323
|
+
if (op?.type === "SqlBinOp") {
|
|
324
|
+
ast[0].orderby = [
|
|
325
|
+
{
|
|
326
|
+
expr: {
|
|
327
|
+
type: "binary_expr",
|
|
328
|
+
operator: op.name,
|
|
329
|
+
left: {
|
|
330
|
+
type: "column_ref",
|
|
331
|
+
table: null,
|
|
332
|
+
column: db.sqlsanitize(field),
|
|
333
|
+
},
|
|
334
|
+
right: {
|
|
335
|
+
type: "number",
|
|
336
|
+
value: "$" + phIndex,
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
type: orderDesc ? "DESC" : "ASC",
|
|
340
|
+
},
|
|
341
|
+
];
|
|
342
|
+
phIndex += 1;
|
|
343
|
+
phValues.push(target);
|
|
344
|
+
}
|
|
332
345
|
}
|
|
333
346
|
}
|
|
347
|
+
sqlQ = parser.sqlify(ast, opt);
|
|
334
348
|
}
|
|
335
349
|
const client = is_sqlite ? db : await db.getClient();
|
|
336
350
|
await client.query(`BEGIN;`);
|
|
@@ -339,8 +353,7 @@ const runQuery = async (cfg, where, opts) => {
|
|
|
339
353
|
await client.query(`SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;`);
|
|
340
354
|
}
|
|
341
355
|
|
|
342
|
-
|
|
343
|
-
console.log({ sqlQ, phValues, opts });
|
|
356
|
+
//console.log({ sqlQ, phValues, opts });
|
|
344
357
|
const qres = await client.query(sqlQ, phValues);
|
|
345
358
|
qres.query = sqlQ;
|
|
346
359
|
await client.query(`ROLLBACK;`);
|