@saltcorn/data 0.6.1 → 0.6.2-beta.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/base-plugin/fieldviews.js +33 -28
- package/base-plugin/types.js +223 -94
- package/base-plugin/viewtemplates/edit.js +21 -17
- package/base-plugin/viewtemplates/filter.js +62 -15
- package/base-plugin/viewtemplates/list.js +16 -16
- package/base-plugin/viewtemplates/room.js +24 -22
- package/base-plugin/viewtemplates/show.js +26 -26
- package/base-plugin/viewtemplates/viewable_fields.js +25 -26
- package/db/index.js +6 -3
- package/models/expression.js +37 -25
- package/models/field.js +18 -12
- package/models/form.js +7 -6
- package/package.json +12 -7
- package/plugin-helper.js +31 -11
- package/tests/calc.test.js +22 -0
|
@@ -16,7 +16,7 @@ const { traverseSync } = require("../../models/layout");
|
|
|
16
16
|
const { structuredClone } = require("../../utils");
|
|
17
17
|
const db = require("../../db");
|
|
18
18
|
|
|
19
|
-
/**
|
|
19
|
+
/**
|
|
20
20
|
* @function
|
|
21
21
|
* @param {string} viewname
|
|
22
22
|
* @param {Table|object} table
|
|
@@ -42,8 +42,8 @@ const action_url = contract(
|
|
|
42
42
|
);
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
* @param {string} url
|
|
46
|
-
* @param {object} req
|
|
45
|
+
* @param {string} url
|
|
46
|
+
* @param {object} req
|
|
47
47
|
* @param {object} opts
|
|
48
48
|
* @param {string} opts.action_name
|
|
49
49
|
* @param {string} opts.action_label
|
|
@@ -55,7 +55,7 @@ const action_url = contract(
|
|
|
55
55
|
* @param {string} opts.action_bgcol
|
|
56
56
|
* @param {string} opts.action_bordercol
|
|
57
57
|
* @param {string} opts.action_textcol
|
|
58
|
-
* @param {*} __
|
|
58
|
+
* @param {*} __
|
|
59
59
|
* @returns {object}
|
|
60
60
|
*/
|
|
61
61
|
const action_link = (
|
|
@@ -174,7 +174,7 @@ const make_link = contract(
|
|
|
174
174
|
);
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
|
-
* @param {string} s
|
|
177
|
+
* @param {string} s
|
|
178
178
|
* @returns {object}
|
|
179
179
|
*/
|
|
180
180
|
const parse_view_select = (s) => {
|
|
@@ -197,7 +197,7 @@ const parse_view_select = (s) => {
|
|
|
197
197
|
};
|
|
198
198
|
|
|
199
199
|
//todo: use above to simplify code
|
|
200
|
-
/**
|
|
200
|
+
/**
|
|
201
201
|
* @function
|
|
202
202
|
* @param {object} opts
|
|
203
203
|
* @param {string} opts.view,
|
|
@@ -338,7 +338,7 @@ const view_linker = contract(
|
|
|
338
338
|
);
|
|
339
339
|
|
|
340
340
|
/**
|
|
341
|
-
* @param {string} nm
|
|
341
|
+
* @param {string} nm
|
|
342
342
|
* @returns {boolean}
|
|
343
343
|
*/
|
|
344
344
|
const action_requires_write = (nm) => {
|
|
@@ -347,7 +347,7 @@ const action_requires_write = (nm) => {
|
|
|
347
347
|
if (nm.startsWith("Toggle")) return true;
|
|
348
348
|
};
|
|
349
349
|
|
|
350
|
-
/**
|
|
350
|
+
/**
|
|
351
351
|
* @function
|
|
352
352
|
* @param {string} viewname
|
|
353
353
|
* @param {Table|object} table
|
|
@@ -527,8 +527,8 @@ const get_viewable_fields = contract(
|
|
|
527
527
|
);
|
|
528
528
|
|
|
529
529
|
/**
|
|
530
|
-
* @param {string} fname
|
|
531
|
-
* @param {object} req
|
|
530
|
+
* @param {string} fname
|
|
531
|
+
* @param {object} req
|
|
532
532
|
* @returns {string}
|
|
533
533
|
*/
|
|
534
534
|
const sortlinkForName = (fname, req) => {
|
|
@@ -543,10 +543,10 @@ const sortlinkForName = (fname, req) => {
|
|
|
543
543
|
};
|
|
544
544
|
|
|
545
545
|
/**
|
|
546
|
-
* @param {object} column
|
|
547
|
-
* @param {object} f
|
|
548
|
-
* @param {object} req
|
|
549
|
-
* @param {*} __
|
|
546
|
+
* @param {object} column
|
|
547
|
+
* @param {object} f
|
|
548
|
+
* @param {object} req
|
|
549
|
+
* @param {*} __
|
|
550
550
|
* @returns {string}
|
|
551
551
|
*/
|
|
552
552
|
const headerLabelForName = (column, f, req, __) => {
|
|
@@ -563,7 +563,7 @@ const headerLabelForName = (column, f, req, __) => {
|
|
|
563
563
|
return label + arrow;
|
|
564
564
|
};
|
|
565
565
|
|
|
566
|
-
/**
|
|
566
|
+
/**
|
|
567
567
|
* @function
|
|
568
568
|
* @param {Field[]} fields
|
|
569
569
|
* @param {object} state
|
|
@@ -597,12 +597,12 @@ const splitUniques = contract(
|
|
|
597
597
|
);
|
|
598
598
|
|
|
599
599
|
/**
|
|
600
|
-
* @param {object} table
|
|
601
|
-
* @param {string} viewname
|
|
602
|
-
* @param {object[]} [columns]
|
|
603
|
-
* @param {object} layout0
|
|
604
|
-
* @param {boolean} id
|
|
605
|
-
* @param {object} req
|
|
600
|
+
* @param {object} table
|
|
601
|
+
* @param {string} viewname
|
|
602
|
+
* @param {object[]} [columns]
|
|
603
|
+
* @param {object} layout0
|
|
604
|
+
* @param {boolean} id
|
|
605
|
+
* @param {object} req
|
|
606
606
|
* @returns {Promise<Form>}
|
|
607
607
|
*/
|
|
608
608
|
const getForm = async (table, viewname, columns, layout0, id, req) => {
|
|
@@ -626,7 +626,7 @@ const getForm = async (table, viewname, columns, layout0, id, req) => {
|
|
|
626
626
|
}
|
|
627
627
|
if (f.calculated)
|
|
628
628
|
f.sourceURL = `/field/show-calculated/${table.name}/${f.name}/${f.fieldview}`;
|
|
629
|
-
|
|
629
|
+
f.attributes = { ...column.configuration, ...f.attributes };
|
|
630
630
|
return f;
|
|
631
631
|
} else if (table.name === "users" && column.field_name === "password") {
|
|
632
632
|
return new Field({
|
|
@@ -669,15 +669,14 @@ const getForm = async (table, viewname, columns, layout0, id, req) => {
|
|
|
669
669
|
fields: tfields,
|
|
670
670
|
layout,
|
|
671
671
|
});
|
|
672
|
-
await form.fill_fkey_options();
|
|
673
672
|
if (id) form.hidden("id");
|
|
674
673
|
return form;
|
|
675
674
|
};
|
|
676
675
|
|
|
677
676
|
/**
|
|
678
|
-
* @param {object} table
|
|
679
|
-
* @param {object} req
|
|
680
|
-
* @param {object} fixed
|
|
677
|
+
* @param {object} table
|
|
678
|
+
* @param {object} req
|
|
679
|
+
* @param {object} fixed
|
|
681
680
|
* @returns {Promise<object>}
|
|
682
681
|
*/
|
|
683
682
|
const fill_presets = async (table, req, fixed) => {
|
package/db/index.js
CHANGED
|
@@ -24,9 +24,12 @@ var connectObj = getConnectObject();
|
|
|
24
24
|
/** @type {db/sqlite|db/pg|null} */
|
|
25
25
|
let dbmodule = null;
|
|
26
26
|
try {
|
|
27
|
-
|
|
28
|
-
require("@saltcorn/sqlite/sqlite")
|
|
29
|
-
|
|
27
|
+
if(is_sqlite(connectObj)) {
|
|
28
|
+
dbmodule = require("@saltcorn/sqlite/sqlite");
|
|
29
|
+
dbmodule.init(getConnectObject);
|
|
30
|
+
}
|
|
31
|
+
else
|
|
32
|
+
dbmodule = require("@saltcorn/postgres/postgres")(getConnectObject);
|
|
30
33
|
} catch(e) {
|
|
31
34
|
console.log("No database package found.")
|
|
32
35
|
throw e;
|
package/models/expression.js
CHANGED
|
@@ -9,7 +9,7 @@ const estraverse = require("estraverse");
|
|
|
9
9
|
const astring = require("astring");
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* @param {string} s
|
|
12
|
+
* @param {string} s
|
|
13
13
|
* @returns {boolean|void}
|
|
14
14
|
*/
|
|
15
15
|
function expressionValidator(s) {
|
|
@@ -23,7 +23,7 @@ function expressionValidator(s) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* @param {string} expression
|
|
26
|
+
* @param {string} expression
|
|
27
27
|
* @returns {string}
|
|
28
28
|
*/
|
|
29
29
|
function jsexprToSQL(expression) {
|
|
@@ -32,11 +32,11 @@ function jsexprToSQL(expression) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* @param {string} expression
|
|
35
|
+
* @param {string} expression
|
|
36
36
|
* @throws {Error}
|
|
37
37
|
* @returns {object}
|
|
38
38
|
*/
|
|
39
|
-
function jsexprToWhere(expression) {
|
|
39
|
+
function jsexprToWhere(expression, extraCtx = {}) {
|
|
40
40
|
if (!expression) return {};
|
|
41
41
|
try {
|
|
42
42
|
const ast = acorn.parseExpressionAt(expression, 0, {
|
|
@@ -47,18 +47,26 @@ function jsexprToWhere(expression) {
|
|
|
47
47
|
const compile = (node) =>
|
|
48
48
|
({
|
|
49
49
|
BinaryExpression() {
|
|
50
|
+
const cleft = compile(node.left);
|
|
51
|
+
const cright = compile(node.right);
|
|
52
|
+
const cmp =
|
|
53
|
+
typeof cleft === "string" || cleft === null
|
|
54
|
+
? { eq: [cleft, cright] }
|
|
55
|
+
: typeof cleft === "symbol"
|
|
56
|
+
? { [cleft.description]: cright }
|
|
57
|
+
: { [cleft]: cright };
|
|
50
58
|
return {
|
|
51
|
-
"=="(
|
|
52
|
-
return
|
|
59
|
+
"=="() {
|
|
60
|
+
return cmp;
|
|
53
61
|
},
|
|
54
|
-
"==="(
|
|
55
|
-
return
|
|
62
|
+
"==="() {
|
|
63
|
+
return cmp;
|
|
56
64
|
},
|
|
57
|
-
"!="(
|
|
58
|
-
return { not:
|
|
65
|
+
"!="() {
|
|
66
|
+
return { not: cmp };
|
|
59
67
|
},
|
|
60
|
-
"!=="(
|
|
61
|
-
return { not:
|
|
68
|
+
"!=="() {
|
|
69
|
+
return { not: cmp };
|
|
62
70
|
},
|
|
63
71
|
}[node.operator](node);
|
|
64
72
|
},
|
|
@@ -83,14 +91,18 @@ function jsexprToWhere(expression) {
|
|
|
83
91
|
}[node.operator](node);
|
|
84
92
|
},
|
|
85
93
|
Identifier({ name }) {
|
|
86
|
-
|
|
94
|
+
if (name[0] === "$") {
|
|
95
|
+
return extraCtx[name.substring(1)] || null;
|
|
96
|
+
}
|
|
97
|
+
return Symbol(name);
|
|
87
98
|
},
|
|
88
99
|
Literal({ value }) {
|
|
89
100
|
return value;
|
|
90
101
|
},
|
|
91
102
|
}[node.type](node));
|
|
92
103
|
return compile(ast);
|
|
93
|
-
} catch {
|
|
104
|
+
} catch (e) {
|
|
105
|
+
console.error(e);
|
|
94
106
|
throw new Error(
|
|
95
107
|
`Expression "${expression}" is too complicated, I do not understand`
|
|
96
108
|
);
|
|
@@ -98,8 +110,8 @@ function jsexprToWhere(expression) {
|
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
/**
|
|
101
|
-
* @param {string} expression
|
|
102
|
-
* @param {object[]} statefuns
|
|
113
|
+
* @param {string} expression
|
|
114
|
+
* @param {object[]} statefuns
|
|
103
115
|
* @returns {object}
|
|
104
116
|
*/
|
|
105
117
|
function transform_for_async(expression, statefuns) {
|
|
@@ -125,8 +137,8 @@ function transform_for_async(expression, statefuns) {
|
|
|
125
137
|
}
|
|
126
138
|
|
|
127
139
|
/**
|
|
128
|
-
* @param {string} expression
|
|
129
|
-
* @param {object[]} fields
|
|
140
|
+
* @param {string} expression
|
|
141
|
+
* @param {object[]} fields
|
|
130
142
|
* @returns {any}
|
|
131
143
|
*/
|
|
132
144
|
function get_expression_function(expression, fields) {
|
|
@@ -142,8 +154,8 @@ function get_expression_function(expression, fields) {
|
|
|
142
154
|
}
|
|
143
155
|
|
|
144
156
|
/**
|
|
145
|
-
* @param {string} expression
|
|
146
|
-
* @param {object[]} fields
|
|
157
|
+
* @param {string} expression
|
|
158
|
+
* @param {object[]} fields
|
|
147
159
|
* @param {object} [extraContext = {}]
|
|
148
160
|
* @returns {any}
|
|
149
161
|
*/
|
|
@@ -162,9 +174,9 @@ function get_async_expression_function(expression, fields, extraContext = {}) {
|
|
|
162
174
|
}
|
|
163
175
|
|
|
164
176
|
/**
|
|
165
|
-
* @param {object[]} rows
|
|
166
|
-
* @param {object[]} fields
|
|
167
|
-
* @returns {object[]}
|
|
177
|
+
* @param {object[]} rows
|
|
178
|
+
* @param {object[]} fields
|
|
179
|
+
* @returns {object[]}
|
|
168
180
|
*/
|
|
169
181
|
function apply_calculated_fields(rows, fields) {
|
|
170
182
|
let hasExprs = false;
|
|
@@ -196,8 +208,8 @@ function apply_calculated_fields(rows, fields) {
|
|
|
196
208
|
}
|
|
197
209
|
|
|
198
210
|
/**
|
|
199
|
-
* @param {*} row
|
|
200
|
-
* @param {*} fields
|
|
211
|
+
* @param {*} row
|
|
212
|
+
* @param {*} fields
|
|
201
213
|
* @returns {Promise<any>}
|
|
202
214
|
*/
|
|
203
215
|
const apply_calculated_fields_stored = async (row, fields) => {
|
package/models/field.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const db = require("../db");
|
|
9
9
|
const { contract, is } = require("contractis");
|
|
10
|
-
const { recalculate_for_stored } = require("./expression");
|
|
10
|
+
const { recalculate_for_stored, jsexprToWhere } = require("./expression");
|
|
11
11
|
const { sqlsanitize } = require("@saltcorn/db-common/internal.js");
|
|
12
12
|
const { InvalidAdminAction } = require("../utils");
|
|
13
13
|
const { mkWhere } = require("../db");
|
|
@@ -153,7 +153,13 @@ class Field {
|
|
|
153
153
|
* @param {object} where
|
|
154
154
|
* @returns {Promise<void>}
|
|
155
155
|
*/
|
|
156
|
-
async fill_fkey_options(force_allow_none = false,
|
|
156
|
+
async fill_fkey_options(force_allow_none = false, where0, extraCtx) {
|
|
157
|
+
const where =
|
|
158
|
+
where0 ||
|
|
159
|
+
(this.attributes.where
|
|
160
|
+
? jsexprToWhere(this.attributes.where, extraCtx)
|
|
161
|
+
: undefined);
|
|
162
|
+
//console.log(where);
|
|
157
163
|
if (
|
|
158
164
|
this.is_fkey &&
|
|
159
165
|
(this.type !== "File" ||
|
|
@@ -288,7 +294,7 @@ class Field {
|
|
|
288
294
|
}
|
|
289
295
|
|
|
290
296
|
/**
|
|
291
|
-
* @param {object} whole_rec
|
|
297
|
+
* @param {object} whole_rec
|
|
292
298
|
* @returns {object}
|
|
293
299
|
*/
|
|
294
300
|
validate(whole_rec) {
|
|
@@ -316,8 +322,8 @@ class Field {
|
|
|
316
322
|
}
|
|
317
323
|
|
|
318
324
|
/**
|
|
319
|
-
*
|
|
320
|
-
* @param {object} where
|
|
325
|
+
*
|
|
326
|
+
* @param {object} where
|
|
321
327
|
* @param {object} [selectopts]
|
|
322
328
|
* @returns {Field[]}
|
|
323
329
|
*/
|
|
@@ -327,7 +333,7 @@ class Field {
|
|
|
327
333
|
}
|
|
328
334
|
|
|
329
335
|
/**
|
|
330
|
-
* @param {object} where
|
|
336
|
+
* @param {object} where
|
|
331
337
|
* @returns {Promise<Field>}
|
|
332
338
|
*/
|
|
333
339
|
static async findOne(where) {
|
|
@@ -352,8 +358,8 @@ class Field {
|
|
|
352
358
|
}
|
|
353
359
|
|
|
354
360
|
/**
|
|
355
|
-
*
|
|
356
|
-
* @param {boolean} not_null
|
|
361
|
+
*
|
|
362
|
+
* @param {boolean} not_null
|
|
357
363
|
* @returns {Promise<void>}
|
|
358
364
|
*/
|
|
359
365
|
async toggle_not_null(not_null) {
|
|
@@ -370,7 +376,7 @@ class Field {
|
|
|
370
376
|
}
|
|
371
377
|
|
|
372
378
|
/**
|
|
373
|
-
* @param {object} new_field
|
|
379
|
+
* @param {object} new_field
|
|
374
380
|
* @returns {Promise<void>}
|
|
375
381
|
*/
|
|
376
382
|
async alter_sql_type(new_field) {
|
|
@@ -421,7 +427,7 @@ class Field {
|
|
|
421
427
|
}
|
|
422
428
|
|
|
423
429
|
/**
|
|
424
|
-
* @param {object} v
|
|
430
|
+
* @param {object} v
|
|
425
431
|
* @returns {Promise<void>}
|
|
426
432
|
*/
|
|
427
433
|
async update(v) {
|
|
@@ -523,7 +529,7 @@ class Field {
|
|
|
523
529
|
}
|
|
524
530
|
|
|
525
531
|
/**
|
|
526
|
-
* @param {object} table
|
|
532
|
+
* @param {object} table
|
|
527
533
|
* @returns {Promise<void>}
|
|
528
534
|
*/
|
|
529
535
|
async enable_fkey_constraint(table) {
|
|
@@ -542,7 +548,7 @@ class Field {
|
|
|
542
548
|
}
|
|
543
549
|
|
|
544
550
|
/**
|
|
545
|
-
* @param {object} fld
|
|
551
|
+
* @param {object} fld
|
|
546
552
|
* @param {boolean} [bare = false]
|
|
547
553
|
* @returns {Promise<Field>}
|
|
548
554
|
*/
|
package/models/form.js
CHANGED
|
@@ -14,9 +14,9 @@ const Field = require("./field");
|
|
|
14
14
|
*/
|
|
15
15
|
class Form {
|
|
16
16
|
/**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
* Constructor
|
|
18
|
+
* @param o
|
|
19
|
+
*/
|
|
20
20
|
constructor(o) {
|
|
21
21
|
this.fields = o.fields.map((f) =>
|
|
22
22
|
f.constructor.name === Object.name ? new Field(f) : f
|
|
@@ -48,7 +48,7 @@ class Form {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* @param {object} ks
|
|
51
|
+
* @param {object} ks
|
|
52
52
|
*/
|
|
53
53
|
hidden(...ks) {
|
|
54
54
|
ks.forEach((k) => {
|
|
@@ -66,8 +66,9 @@ class Form {
|
|
|
66
66
|
* @param {boolean} [force_allow_none = false]
|
|
67
67
|
*/
|
|
68
68
|
async fill_fkey_options(force_allow_none = false) {
|
|
69
|
+
//console.log(this.values);
|
|
69
70
|
for (const f of this.fields) {
|
|
70
|
-
await f.fill_fkey_options(force_allow_none);
|
|
71
|
+
await f.fill_fkey_options(force_allow_none, undefined, this.values);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
|
|
@@ -98,7 +99,7 @@ class Form {
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
/**
|
|
101
|
-
* @param {*} v
|
|
102
|
+
* @param {*} v
|
|
102
103
|
* @returns {object}
|
|
103
104
|
*/
|
|
104
105
|
validate(v) {
|
package/package.json
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/data",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2-beta.0",
|
|
4
4
|
"description": "Data models for Saltcorn, open-source no-code platform",
|
|
5
5
|
"homepage": "https://saltcorn.com",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "jest --runInBand"
|
|
7
|
+
"test": "jest --runInBand",
|
|
8
|
+
"tsc": "echo \"Error: no TypeScript support yet\"",
|
|
9
|
+
"clean": "echo \"Error: no TypeScript support yet\""
|
|
8
10
|
},
|
|
9
11
|
"author": "Tom Nielsen",
|
|
10
12
|
"license": "MIT",
|
|
11
13
|
"main": "index.js",
|
|
12
14
|
"optionalDependencies": {
|
|
13
|
-
"@saltcorn/postgres": "0.6.
|
|
14
|
-
"@saltcorn/sqlite": "0.6.
|
|
15
|
+
"@saltcorn/postgres": "0.6.2-beta.0",
|
|
16
|
+
"@saltcorn/sqlite": "0.6.2-beta.0"
|
|
15
17
|
},
|
|
16
18
|
"dependencies": {
|
|
17
|
-
"@saltcorn/markup": "0.6.
|
|
18
|
-
"@saltcorn/db-common": "0.6.
|
|
19
|
+
"@saltcorn/markup": "0.6.2-beta.0",
|
|
20
|
+
"@saltcorn/db-common": "0.6.2-beta.0",
|
|
19
21
|
"acorn": "^8.0.3",
|
|
20
22
|
"adm-zip": "0.5.5",
|
|
21
23
|
"astring": "^1.4.3",
|
|
@@ -47,7 +49,10 @@
|
|
|
47
49
|
"jest": "^25.1.0"
|
|
48
50
|
},
|
|
49
51
|
"jest": {
|
|
50
|
-
"testEnvironment": "node"
|
|
52
|
+
"testEnvironment": "node",
|
|
53
|
+
"moduleNameMapper": {
|
|
54
|
+
"@saltcorn/sqlite/(.*)": "@saltcorn/sqlite/dist/$1"
|
|
55
|
+
}
|
|
51
56
|
},
|
|
52
57
|
"publishConfig": {
|
|
53
58
|
"access": "public"
|
package/plugin-helper.js
CHANGED
|
@@ -112,16 +112,19 @@ const stateToQueryString = contract(
|
|
|
112
112
|
*/
|
|
113
113
|
const calcfldViewOptions = contract(
|
|
114
114
|
is.fun(
|
|
115
|
-
[is.array(is.class("Field")), is.
|
|
115
|
+
[is.array(is.class("Field")), is.str],
|
|
116
116
|
is.obj({ field_view_options: is.objVals(is.array(is.str)) })
|
|
117
117
|
),
|
|
118
|
-
(fields,
|
|
119
|
-
|
|
118
|
+
(fields, mode) => {
|
|
119
|
+
const isEdit = mode === "edit";
|
|
120
|
+
const isFilter = mode === "filter";
|
|
121
|
+
let fvs = {};
|
|
120
122
|
const handlesTextStyle = {};
|
|
121
123
|
fields.forEach((f) => {
|
|
122
124
|
handlesTextStyle[f.name] = [];
|
|
123
125
|
if (f.type === "File") {
|
|
124
|
-
if (!isEdit
|
|
126
|
+
if (!isEdit && !isFilter)
|
|
127
|
+
fvs[f.name] = Object.keys(getState().fileviews);
|
|
125
128
|
else fvs[f.name] = ["upload"];
|
|
126
129
|
} else if (f.type === "Key") {
|
|
127
130
|
if (isEdit) fvs[f.name] = Object.keys(getState().keyFieldviews);
|
|
@@ -129,7 +132,7 @@ const calcfldViewOptions = contract(
|
|
|
129
132
|
if (f.reftable && f.reftable.fields) {
|
|
130
133
|
const { field_view_options } = calcfldViewOptions(
|
|
131
134
|
f.reftable.fields,
|
|
132
|
-
|
|
135
|
+
mode
|
|
133
136
|
);
|
|
134
137
|
for (const jf of f.reftable.fields) {
|
|
135
138
|
fvs[`${f.name}.${jf.name}`] = field_view_options[jf.name];
|
|
@@ -142,15 +145,20 @@ const calcfldViewOptions = contract(
|
|
|
142
145
|
});
|
|
143
146
|
} else if (f.type && f.type.fieldviews) {
|
|
144
147
|
const tfvs = Object.entries(f.type.fieldviews).filter(([k, fv]) =>
|
|
145
|
-
f.calculated ? !fv.isEdit : !fv.isEdit || isEdit
|
|
148
|
+
f.calculated ? !fv.isEdit : !fv.isEdit || isEdit || isFilter
|
|
146
149
|
);
|
|
147
150
|
let tfvs_ordered = [];
|
|
148
151
|
if (isEdit) {
|
|
149
152
|
tfvs_ordered = [
|
|
150
153
|
...tfvs.filter(([k, fv]) => fv.isEdit),
|
|
151
|
-
...tfvs.filter(([k, fv]) => !fv.isEdit),
|
|
154
|
+
...tfvs.filter(([k, fv]) => !fv.isEdit && !fv.isFilter),
|
|
152
155
|
];
|
|
153
|
-
} else
|
|
156
|
+
} else if (isFilter) {
|
|
157
|
+
tfvs_ordered = [
|
|
158
|
+
...tfvs.filter(([k, fv]) => fv.isFilter),
|
|
159
|
+
...tfvs.filter(([k, fv]) => fv.isEdit),
|
|
160
|
+
];
|
|
161
|
+
} else tfvs_ordered = tfvs.filter(([k, fv]) => !fv.isFilter);
|
|
154
162
|
fvs[f.name] = tfvs_ordered.map(([k, fv]) => {
|
|
155
163
|
if (fv && fv.handlesTextStyle) handlesTextStyle[f.name].push(k);
|
|
156
164
|
return k;
|
|
@@ -323,7 +331,7 @@ const field_picker_fields = contract(
|
|
|
323
331
|
}
|
|
324
332
|
}
|
|
325
333
|
const fldOptions = fields.map((f) => f.name);
|
|
326
|
-
const { field_view_options } = calcfldViewOptions(fields,
|
|
334
|
+
const { field_view_options } = calcfldViewOptions(fields, "show");
|
|
327
335
|
const fieldViewConfigForms = await calcfldViewConfig(fields, false);
|
|
328
336
|
const fvConfigFields = [];
|
|
329
337
|
for (const [field_name, fvOptFields] of Object.entries(
|
|
@@ -954,6 +962,14 @@ const stateFieldsToWhere = contract(
|
|
|
954
962
|
const dfield = fields.find((fld) => fld.name == datefield);
|
|
955
963
|
if (dfield)
|
|
956
964
|
addOrCreateList(qstate, datefield, { lt: new Date(v), equal: true });
|
|
965
|
+
} else if (k.startsWith("_gte_")) {
|
|
966
|
+
const datefield = db.sqlsanitize(k.replace("_gte_", ""));
|
|
967
|
+
const dfield = fields.find((fld) => fld.name == datefield);
|
|
968
|
+
if (dfield) addOrCreateList(qstate, datefield, { gt: v, equal: true });
|
|
969
|
+
} else if (k.startsWith("_lte_")) {
|
|
970
|
+
const datefield = db.sqlsanitize(k.replace("_lte_", ""));
|
|
971
|
+
const dfield = fields.find((fld) => fld.name == datefield);
|
|
972
|
+
if (dfield) addOrCreateList(qstate, datefield, { lt: v, equal: true });
|
|
957
973
|
} else if (
|
|
958
974
|
field &&
|
|
959
975
|
field.type.name === "String" &&
|
|
@@ -964,7 +980,9 @@ const stateFieldsToWhere = contract(
|
|
|
964
980
|
} else if (field && field.type.name === "Bool" && state[k] === "?") {
|
|
965
981
|
// omit
|
|
966
982
|
} else if (field && field.type && field.type.read)
|
|
967
|
-
qstate[k] =
|
|
983
|
+
qstate[k] = Array.isArray(v)
|
|
984
|
+
? { or: v.map(field.type.read) }
|
|
985
|
+
: field.type.read(v);
|
|
968
986
|
else if (field) qstate[k] = v;
|
|
969
987
|
else if (k.includes(".")) {
|
|
970
988
|
const kpath = k.split(".");
|
|
@@ -1124,7 +1142,9 @@ const readState = (state, fields, req) => {
|
|
|
1124
1142
|
fields.forEach((f) => {
|
|
1125
1143
|
const current = state[f.name];
|
|
1126
1144
|
if (typeof current !== "undefined") {
|
|
1127
|
-
if (
|
|
1145
|
+
if (Array.isArray(current) && f.type.read) {
|
|
1146
|
+
state[f.name] = current.map(f.type.read);
|
|
1147
|
+
} else if (f.type.read) state[f.name] = f.type.read(current);
|
|
1128
1148
|
else if (typeof current === "string" && current.startsWith("Preset:")) {
|
|
1129
1149
|
const preset = f.presets[current.replace("Preset:", "")];
|
|
1130
1150
|
state[f.name] = preset(req);
|
package/tests/calc.test.js
CHANGED
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
get_expression_function,
|
|
8
8
|
transform_for_async,
|
|
9
9
|
expressionValidator,
|
|
10
|
+
jsexprToWhere,
|
|
10
11
|
} = require("../models/expression");
|
|
11
12
|
|
|
12
13
|
getState().registerPlugin("base", require("../base-plugin"));
|
|
@@ -219,3 +220,24 @@ describe("expressions", () => {
|
|
|
219
220
|
expect(expressionValidator("2+")).toBe("Unexpected end of input");
|
|
220
221
|
});
|
|
221
222
|
});
|
|
223
|
+
describe("jsexprToWhere", () => {
|
|
224
|
+
it("translates equality", () => {
|
|
225
|
+
expect(jsexprToWhere("foo==4")).toEqual({ foo: 4 });
|
|
226
|
+
});
|
|
227
|
+
it("translates equal to col", () => {
|
|
228
|
+
expect(jsexprToWhere("foo==bar").foo.description).toBe("bar");
|
|
229
|
+
});
|
|
230
|
+
it("translates context", () => {
|
|
231
|
+
expect(jsexprToWhere("foo==$bar", { bar: 5 })).toEqual({ foo: 5 });
|
|
232
|
+
});
|
|
233
|
+
it("translates context", () => {
|
|
234
|
+
const w = jsexprToWhere("$father !== null && married_to === $father", {
|
|
235
|
+
father: "1",
|
|
236
|
+
});
|
|
237
|
+
expect(w).toEqual({ married_to: "1", not: { eq: ["1", null] } });
|
|
238
|
+
});
|
|
239
|
+
it("translates context", () => {
|
|
240
|
+
const w = jsexprToWhere("$father !== null && married_to === $father", {});
|
|
241
|
+
expect(w).toEqual({ married_to: null, not: { eq: [null, null] } });
|
|
242
|
+
});
|
|
243
|
+
});
|