@saltcorn/data 0.6.2-beta.4 → 0.6.3-beta.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/dist/base-plugin/fieldviews.d.ts.map +1 -1
- package/dist/base-plugin/fieldviews.js +2 -0
- package/dist/base-plugin/fieldviews.js.map +1 -1
- package/dist/base-plugin/fileviews.d.ts +2 -2
- package/dist/base-plugin/index.d.ts +16 -11
- package/dist/base-plugin/index.d.ts.map +1 -1
- package/dist/base-plugin/types.d.ts +8 -8
- package/dist/base-plugin/types.d.ts.map +1 -1
- package/dist/base-plugin/viewtemplates/edit.d.ts +1 -1
- package/dist/base-plugin/viewtemplates/edit.d.ts.map +1 -1
- package/dist/base-plugin/viewtemplates/edit.js +25 -2
- package/dist/base-plugin/viewtemplates/edit.js.map +1 -1
- package/dist/base-plugin/viewtemplates/feed.d.ts +1 -1
- package/dist/base-plugin/viewtemplates/feed.d.ts.map +1 -1
- package/dist/base-plugin/viewtemplates/feed.js +11 -1
- package/dist/base-plugin/viewtemplates/feed.js.map +1 -1
- package/dist/base-plugin/viewtemplates/list.d.ts +1 -1
- package/dist/base-plugin/viewtemplates/list.d.ts.map +1 -1
- package/dist/base-plugin/viewtemplates/list.js +23 -11
- package/dist/base-plugin/viewtemplates/list.js.map +1 -1
- package/dist/base-plugin/viewtemplates/show.d.ts +5 -0
- package/dist/base-plugin/viewtemplates/show.d.ts.map +1 -1
- package/dist/base-plugin/viewtemplates/show.js +40 -5
- package/dist/base-plugin/viewtemplates/show.js.map +1 -1
- package/dist/base-plugin/viewtemplates/viewable_fields.d.ts +2 -1
- package/dist/base-plugin/viewtemplates/viewable_fields.d.ts.map +1 -1
- package/dist/base-plugin/viewtemplates/viewable_fields.js +29 -9
- package/dist/base-plugin/viewtemplates/viewable_fields.js.map +1 -1
- package/dist/db/connect.d.ts.map +1 -1
- package/dist/db/connect.js +8 -2
- package/dist/db/connect.js.map +1 -1
- package/dist/db/index.d.ts +6 -0
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +6 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/state.d.ts.map +1 -1
- package/dist/db/state.js +6 -4
- package/dist/db/state.js.map +1 -1
- package/dist/migrate.js +1 -1
- package/dist/migrate.js.map +1 -1
- package/dist/migrations/202112282254.d.ts +3 -0
- package/dist/migrations/202112282254.d.ts.map +1 -0
- package/dist/migrations/202112282254.js +5 -0
- package/dist/migrations/202112282254.js.map +1 -0
- package/dist/models/backup.d.ts +8 -21
- package/dist/models/backup.d.ts.map +1 -1
- package/dist/models/backup.js +105 -103
- package/dist/models/backup.js.map +1 -1
- package/dist/models/config.d.ts.map +1 -1
- package/dist/models/config.js +3 -1
- package/dist/models/config.js.map +1 -1
- package/dist/models/eventlog.d.ts +39 -38
- package/dist/models/eventlog.d.ts.map +1 -1
- package/dist/models/eventlog.js +14 -29
- package/dist/models/eventlog.js.map +1 -1
- package/dist/models/expression.d.ts.map +1 -1
- package/dist/models/expression.js +14 -3
- package/dist/models/expression.js.map +1 -1
- package/dist/models/field.d.ts +125 -121
- package/dist/models/field.d.ts.map +1 -1
- package/dist/models/field.js +125 -147
- package/dist/models/field.js.map +1 -1
- package/dist/models/fieldrepeat.d.ts +22 -20
- package/dist/models/fieldrepeat.d.ts.map +1 -1
- package/dist/models/fieldrepeat.js +6 -14
- package/dist/models/fieldrepeat.js.map +1 -1
- package/dist/models/form.d.ts +69 -50
- package/dist/models/form.d.ts.map +1 -1
- package/dist/models/form.js +49 -49
- package/dist/models/form.js.map +1 -1
- package/dist/models/library.d.ts +29 -19
- package/dist/models/library.d.ts.map +1 -1
- package/dist/models/library.js +10 -8
- package/dist/models/library.js.map +1 -1
- package/dist/models/role.d.ts +22 -9
- package/dist/models/role.d.ts.map +1 -1
- package/dist/models/role.js +16 -8
- package/dist/models/role.js.map +1 -1
- package/dist/models/table.d.ts +98 -133
- package/dist/models/table.d.ts.map +1 -1
- package/dist/models/table.js +236 -180
- package/dist/models/table.js.map +1 -1
- package/dist/models/tenant.d.ts +6 -0
- package/dist/models/tenant.d.ts.map +1 -1
- package/dist/models/tenant.js +9 -0
- package/dist/models/tenant.js.map +1 -1
- package/dist/models/trigger.d.ts +62 -66
- package/dist/models/trigger.d.ts.map +1 -1
- package/dist/models/trigger.js +7 -33
- package/dist/models/trigger.js.map +1 -1
- package/dist/models/view.d.ts +109 -98
- package/dist/models/view.d.ts.map +1 -1
- package/dist/models/view.js +105 -80
- package/dist/models/view.js.map +1 -1
- package/dist/models/workflow.d.ts +23 -21
- package/dist/models/workflow.d.ts.map +1 -1
- package/dist/models/workflow.js +9 -17
- package/dist/models/workflow.js.map +1 -1
- package/dist/plugin-helper.d.ts.map +1 -1
- package/dist/plugin-helper.js +30 -12
- package/dist/plugin-helper.js.map +1 -1
- package/dist/tests/calc.test.js +13 -0
- package/dist/tests/calc.test.js.map +1 -1
- package/dist/tests/exact_views.test.js +214 -0
- package/dist/tests/exact_views.test.js.map +1 -1
- package/dist/tests/table.test.js +57 -2
- package/dist/tests/table.test.js.map +1 -1
- package/dist/tsconfig.ref.tsbuildinfo +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +26 -0
- package/dist/utils.js.map +1 -1
- package/package.json +14 -6
package/dist/models/field.js
CHANGED
|
@@ -5,18 +5,22 @@
|
|
|
5
5
|
* @module models/field
|
|
6
6
|
* @subcategory models
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
const db_1 = __importDefault(require("../db"));
|
|
10
12
|
const { recalculate_for_stored, jsexprToWhere } = require("./expression");
|
|
11
|
-
const
|
|
13
|
+
const internal_1 = require("@saltcorn/db-common/internal");
|
|
12
14
|
const { InvalidAdminAction } = require("../utils");
|
|
13
|
-
const
|
|
15
|
+
const common_types_1 = require("@saltcorn/types/common_types");
|
|
14
16
|
const readKey = (v, field) => {
|
|
15
17
|
if (v === "")
|
|
16
18
|
return null;
|
|
17
19
|
if (typeof v === "string" && v.startsWith("Preset:"))
|
|
18
20
|
return v;
|
|
19
21
|
const { getState } = require("../db/state");
|
|
22
|
+
if (!field.reftype)
|
|
23
|
+
throw new Error("Unable to find the type, 'reftype' is undefined.");
|
|
20
24
|
const type = getState().types[field.reftype];
|
|
21
25
|
const parsed = type.read(v);
|
|
22
26
|
return parsed || (v ? { error: "Unable to read key" } : null);
|
|
@@ -31,10 +35,13 @@ class Field {
|
|
|
31
35
|
* @param o
|
|
32
36
|
*/
|
|
33
37
|
constructor(o) {
|
|
38
|
+
this.refname = "";
|
|
39
|
+
if (!o.name && !o.label)
|
|
40
|
+
throw new Error(`Field initialised with no name and no label`);
|
|
41
|
+
this.label = (o.label || o.name);
|
|
42
|
+
this.name = (o.name || Field.labelToName(this.label));
|
|
34
43
|
if (!o.type && !o.input_type)
|
|
35
44
|
throw new Error(`Field ${o.name} initialised with no type`);
|
|
36
|
-
this.label = o.label || o.name;
|
|
37
|
-
this.name = o.name || Field.labelToName(o.label);
|
|
38
45
|
this.fieldview = o.fieldview;
|
|
39
46
|
this.validator = o.validator || (() => true);
|
|
40
47
|
this.showIf = o.showIf;
|
|
@@ -48,7 +55,7 @@ class Field {
|
|
|
48
55
|
const { getState } = require("../db/state");
|
|
49
56
|
this.type = typeof o.type === "string" ? getState().types[o.type] : o.type;
|
|
50
57
|
if (!this.type)
|
|
51
|
-
this.typename = o.type;
|
|
58
|
+
this.typename = typeof o.type === "string" ? o.type : o.type?.name;
|
|
52
59
|
this.options = o.options;
|
|
53
60
|
this.required = o.required ? true : false;
|
|
54
61
|
this.is_unique = o.is_unique ? true : false;
|
|
@@ -74,10 +81,9 @@ class Field {
|
|
|
74
81
|
this.refname = "id";
|
|
75
82
|
}
|
|
76
83
|
else {
|
|
77
|
-
this.reftable_name =
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
o.type.replace("Key to ", "");
|
|
84
|
+
this.reftable_name = o.reftable_name || (o.reftable && o.reftable.name);
|
|
85
|
+
if (!this.reftable_name && o.type && typeof o.type === "string")
|
|
86
|
+
this.reftable_name = o.type.replace("Key to ", "");
|
|
81
87
|
this.reftable = o.reftable;
|
|
82
88
|
this.type = "Key";
|
|
83
89
|
this.input_type =
|
|
@@ -96,7 +102,6 @@ class Field {
|
|
|
96
102
|
if (o.table.id && !o.table_id)
|
|
97
103
|
this.table_id = o.table.id;
|
|
98
104
|
}
|
|
99
|
-
contract.class(this);
|
|
100
105
|
}
|
|
101
106
|
/**
|
|
102
107
|
* To Json
|
|
@@ -114,7 +119,7 @@ class Field {
|
|
|
114
119
|
expression: this.expression,
|
|
115
120
|
sublabel: this.sublabel,
|
|
116
121
|
fieldview: this.fieldview,
|
|
117
|
-
type: typeof this.type === "string" ? this.type : this.type
|
|
122
|
+
type: typeof this.type === "string" ? this.type : this.type?.name,
|
|
118
123
|
reftable_name: this.reftable_name,
|
|
119
124
|
attributes: this.attributes,
|
|
120
125
|
required: this.required,
|
|
@@ -132,7 +137,7 @@ class Field {
|
|
|
132
137
|
// todo from internalization point of view better to separate label, name. sqlname
|
|
133
138
|
// because label can contain characters that cannot be used in PG for sql names
|
|
134
139
|
static labelToName(label) {
|
|
135
|
-
return sqlsanitize(label.toLowerCase().replace(" ", "_"));
|
|
140
|
+
return (0, internal_1.sqlsanitize)(label.toLowerCase().replace(" ", "_"));
|
|
136
141
|
}
|
|
137
142
|
/**
|
|
138
143
|
* ???
|
|
@@ -150,7 +155,7 @@ class Field {
|
|
|
150
155
|
* @param {object} where
|
|
151
156
|
* @returns {Promise<void>}
|
|
152
157
|
*/
|
|
153
|
-
async fill_fkey_options(force_allow_none = false, where0, extraCtx) {
|
|
158
|
+
async fill_fkey_options(force_allow_none = false, where0, extraCtx = {}) {
|
|
154
159
|
const where = where0 ||
|
|
155
160
|
(this.attributes.where
|
|
156
161
|
? jsexprToWhere(this.attributes.where, extraCtx)
|
|
@@ -159,7 +164,7 @@ class Field {
|
|
|
159
164
|
if (this.is_fkey &&
|
|
160
165
|
(this.type !== "File" ||
|
|
161
166
|
typeof this.attributes.select_file_where !== "undefined")) {
|
|
162
|
-
const rows = await
|
|
167
|
+
const rows = await db_1.default.select(this.reftable_name, this.type === "File" ? this.attributes.select_file_where : where);
|
|
163
168
|
const summary_field = this.attributes.summary_field ||
|
|
164
169
|
(this.type === "File" ? "filename" : "id");
|
|
165
170
|
const dbOpts = rows.map((r) => ({
|
|
@@ -179,7 +184,8 @@ class Field {
|
|
|
179
184
|
*/
|
|
180
185
|
async distinct_values(req, where) {
|
|
181
186
|
const __ = req && req.__ ? req.__ : (s) => s;
|
|
182
|
-
if (this.type
|
|
187
|
+
if ((0, common_types_1.instanceOfType)(this.type) &&
|
|
188
|
+
this.type.name === "String" &&
|
|
183
189
|
this.attributes &&
|
|
184
190
|
this.attributes.options) {
|
|
185
191
|
return [
|
|
@@ -193,7 +199,7 @@ class Field {
|
|
|
193
199
|
await this.fill_fkey_options(false, where);
|
|
194
200
|
return this.options || [];
|
|
195
201
|
}
|
|
196
|
-
if (this.type.name === "Bool") {
|
|
202
|
+
if ((0, common_types_1.instanceOfType)(this.type) && this.type.name === "Bool") {
|
|
197
203
|
return [
|
|
198
204
|
{ label: "", value: "" },
|
|
199
205
|
{ label: __("True"), value: "on", jsvalue: true },
|
|
@@ -204,11 +210,11 @@ class Field {
|
|
|
204
210
|
let whereS = "";
|
|
205
211
|
let values = [];
|
|
206
212
|
if (where) {
|
|
207
|
-
const whereValues = mkWhere(where);
|
|
213
|
+
const whereValues = db_1.default.mkWhere(where);
|
|
208
214
|
whereS = whereValues.where;
|
|
209
215
|
values = whereValues.values;
|
|
210
216
|
}
|
|
211
|
-
const { rows } = await
|
|
217
|
+
const { rows } = await db_1.default.query(`select distinct "${db_1.default.sqlsanitize(this.name)}" from ${this.table?.sql_name} ${whereS} order by "${db_1.default.sqlsanitize(this.name)}"`, values);
|
|
212
218
|
const dbOpts = rows.map((r) => ({
|
|
213
219
|
label: `${r[this.name]}`,
|
|
214
220
|
value: r[this.name],
|
|
@@ -220,13 +226,17 @@ class Field {
|
|
|
220
226
|
*/
|
|
221
227
|
get sql_type() {
|
|
222
228
|
if (this.is_fkey) {
|
|
223
|
-
|
|
229
|
+
if (!this.reftype || !this.reftable_name) {
|
|
230
|
+
throw new Error("'reftype' and 'reftable_name' must be set if 'is_fkey' is true.");
|
|
231
|
+
}
|
|
232
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
224
233
|
const { getState } = require("../db/state");
|
|
225
|
-
return `${getState().types[this.reftype].sql_name} references ${schema}"${sqlsanitize(this.reftable_name)}" ("${this.refname}")`;
|
|
234
|
+
return `${getState().types[this.reftype].sql_name} references ${schema}"${(0, internal_1.sqlsanitize)(this.reftable_name)}" ("${this.refname}")`;
|
|
226
235
|
}
|
|
227
|
-
else {
|
|
236
|
+
else if (this.type && (0, common_types_1.instanceOfType)(this.type) && this.type.sql_name) {
|
|
228
237
|
return this.type.sql_name;
|
|
229
238
|
}
|
|
239
|
+
throw new Error("Unable to get the sql_type");
|
|
230
240
|
}
|
|
231
241
|
/**
|
|
232
242
|
* @type {string}
|
|
@@ -237,31 +247,35 @@ class Field {
|
|
|
237
247
|
if (this.is_fkey)
|
|
238
248
|
return `Key to ${this.reftable_name}`;
|
|
239
249
|
else
|
|
240
|
-
return this.type ? this.type.name : "?";
|
|
250
|
+
return this.type && (0, common_types_1.instanceOfType)(this.type) ? this.type.name : "?";
|
|
241
251
|
}
|
|
242
252
|
/**
|
|
243
253
|
* @type {string}
|
|
244
254
|
*/
|
|
245
255
|
get sql_bare_type() {
|
|
246
256
|
if (this.is_fkey) {
|
|
257
|
+
if (!this.reftype || !this.reftable_name) {
|
|
258
|
+
throw new Error("'reftype' and 'reftable_name' must be set if 'is_fkey' is true.");
|
|
259
|
+
}
|
|
247
260
|
const { getState } = require("../db/state");
|
|
248
261
|
return getState().types[this.reftype].sql_name;
|
|
249
262
|
}
|
|
250
|
-
else {
|
|
263
|
+
else if (this.type && (0, common_types_1.instanceOfType)(this.type) && this.type.sql_name) {
|
|
251
264
|
return this.type.sql_name;
|
|
252
265
|
}
|
|
266
|
+
throw new Error("Unable to get the sql_type");
|
|
253
267
|
}
|
|
254
268
|
/**
|
|
255
269
|
* @returns {Promise<any>}
|
|
256
270
|
*/
|
|
257
271
|
async generate() {
|
|
258
272
|
if (this.is_fkey) {
|
|
259
|
-
const rows = await
|
|
273
|
+
const rows = await db_1.default.select(this.reftable_name, {}, { limit: 1, orderBy: "RANDOM()" });
|
|
260
274
|
if (rows.length === 1)
|
|
261
275
|
return rows[0].id;
|
|
262
276
|
}
|
|
263
277
|
else {
|
|
264
|
-
if (this.type && this.type.contract)
|
|
278
|
+
if ((0, common_types_1.instanceOfType)(this.type) && this.type.contract)
|
|
265
279
|
return this.type.contract(this.attributes).generate();
|
|
266
280
|
}
|
|
267
281
|
}
|
|
@@ -271,19 +285,25 @@ class Field {
|
|
|
271
285
|
*/
|
|
272
286
|
validate(whole_rec) {
|
|
273
287
|
const type = this.is_fkey ? { name: "Key" } : this.type;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
288
|
+
let readval = null;
|
|
289
|
+
if (this.is_fkey) {
|
|
290
|
+
readval = readKey(whole_rec[this.form_name], this);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
let typeObj = this.type;
|
|
294
|
+
readval =
|
|
295
|
+
!type || !typeObj.read
|
|
296
|
+
? whole_rec[this.form_name]
|
|
297
|
+
: typeObj.readFromFormRecord
|
|
298
|
+
? typeObj.readFromFormRecord(whole_rec, this.form_name)
|
|
299
|
+
: typeObj.read(whole_rec[this.form_name], this.attributes);
|
|
300
|
+
}
|
|
281
301
|
if (typeof readval === "undefined" || readval === null)
|
|
282
302
|
if (this.required && this.type !== "File")
|
|
283
|
-
return { error: "Unable to read " + type
|
|
303
|
+
return { error: "Unable to read " + type?.name };
|
|
284
304
|
else
|
|
285
305
|
return { success: null };
|
|
286
|
-
const tyvalres = type && type.validate
|
|
306
|
+
const tyvalres = (0, common_types_1.instanceOfType)(type) && type.validate
|
|
287
307
|
? type.validate(this.attributes || {})(readval)
|
|
288
308
|
: readval;
|
|
289
309
|
if (tyvalres.error)
|
|
@@ -303,7 +323,7 @@ class Field {
|
|
|
303
323
|
* @returns {Field[]}
|
|
304
324
|
*/
|
|
305
325
|
static async find(where, selectopts = { orderBy: "name", nocase: true }) {
|
|
306
|
-
const db_flds = await
|
|
326
|
+
const db_flds = await db_1.default.select("_sc_fields", where, selectopts);
|
|
307
327
|
return db_flds.map((dbf) => new Field(dbf));
|
|
308
328
|
}
|
|
309
329
|
/**
|
|
@@ -311,7 +331,7 @@ class Field {
|
|
|
311
331
|
* @returns {Promise<Field>}
|
|
312
332
|
*/
|
|
313
333
|
static async findOne(where) {
|
|
314
|
-
const db_fld = await
|
|
334
|
+
const db_fld = await db_1.default.selectOne("_sc_fields", where);
|
|
315
335
|
return new Field(db_fld);
|
|
316
336
|
}
|
|
317
337
|
/**
|
|
@@ -319,14 +339,14 @@ class Field {
|
|
|
319
339
|
*/
|
|
320
340
|
async add_unique_constraint() {
|
|
321
341
|
await this.fill_table();
|
|
322
|
-
await
|
|
342
|
+
await db_1.default.add_unique_constraint(this.table?.name, [this.name]);
|
|
323
343
|
}
|
|
324
344
|
/**
|
|
325
345
|
* @returns {Promise<void>}
|
|
326
346
|
*/
|
|
327
347
|
async remove_unique_constraint() {
|
|
328
348
|
await this.fill_table();
|
|
329
|
-
await
|
|
349
|
+
await db_1.default.drop_unique_constraint(this.table?.name, [this.name]);
|
|
330
350
|
}
|
|
331
351
|
/**
|
|
332
352
|
*
|
|
@@ -334,9 +354,12 @@ class Field {
|
|
|
334
354
|
* @returns {Promise<void>}
|
|
335
355
|
*/
|
|
336
356
|
async toggle_not_null(not_null) {
|
|
337
|
-
|
|
357
|
+
if (!this.table) {
|
|
358
|
+
throw new Error("To toogle a not null constraint, 'table' must be set.");
|
|
359
|
+
}
|
|
360
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
338
361
|
await this.fill_table();
|
|
339
|
-
await
|
|
362
|
+
await db_1.default.query(`alter table ${schema}"${(0, internal_1.sqlsanitize)(this.table.name)}" alter column "${(0, internal_1.sqlsanitize)(this.name)}" ${not_null ? "set" : "drop"} not null;`);
|
|
340
363
|
await require("../db/state").getState().refresh_tables();
|
|
341
364
|
}
|
|
342
365
|
/**
|
|
@@ -344,22 +367,27 @@ class Field {
|
|
|
344
367
|
* @returns {Promise<void>}
|
|
345
368
|
*/
|
|
346
369
|
async alter_sql_type(new_field) {
|
|
370
|
+
if (!this.table) {
|
|
371
|
+
throw new Error(`To add the field '${new_field.name}', 'table' must be set.`);
|
|
372
|
+
}
|
|
347
373
|
let new_sql_type = new_field.sql_type;
|
|
348
374
|
let def = "";
|
|
349
|
-
let using = `USING ("${sqlsanitize(this.name)}"::${new_sql_type})`;
|
|
350
|
-
const schema =
|
|
375
|
+
let using = `USING ("${(0, internal_1.sqlsanitize)(this.name)}"::${new_sql_type})`;
|
|
376
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
351
377
|
await this.fill_table();
|
|
352
378
|
if (new_field.primary_key) {
|
|
353
|
-
await
|
|
354
|
-
if (new_field.type
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
379
|
+
await db_1.default.query(`ALTER TABLE ${schema}"${(0, internal_1.sqlsanitize)(this.table.name)}" drop column "${(0, internal_1.sqlsanitize)(this.name)}";`);
|
|
380
|
+
if ((0, common_types_1.instanceOfType)(new_field.type)) {
|
|
381
|
+
if (new_field.type.primaryKey?.sql_type)
|
|
382
|
+
new_sql_type = new_field.type.primaryKey.sql_type;
|
|
383
|
+
if (new_field.type.primaryKey?.default_sql) {
|
|
384
|
+
def = `default ${new_field.type.primaryKey.default_sql}`;
|
|
385
|
+
}
|
|
358
386
|
}
|
|
359
|
-
await
|
|
387
|
+
await db_1.default.query(`ALTER TABLE ${schema}"${(0, internal_1.sqlsanitize)(this.table.name)}" add column "${(0, internal_1.sqlsanitize)(this.name)}" ${new_sql_type} primary key ${def};`);
|
|
360
388
|
}
|
|
361
389
|
else
|
|
362
|
-
await
|
|
390
|
+
await db_1.default.query(`alter table ${schema}"${(0, internal_1.sqlsanitize)(this.table.name)}" alter column "${(0, internal_1.sqlsanitize)(this.name)}" TYPE ${new_sql_type} ${using} ${def};`);
|
|
363
391
|
await require("../db/state").getState().refresh_tables();
|
|
364
392
|
}
|
|
365
393
|
/**
|
|
@@ -376,25 +404,30 @@ class Field {
|
|
|
376
404
|
* @returns {Promise<void>}
|
|
377
405
|
*/
|
|
378
406
|
async update(v) {
|
|
407
|
+
const f = new Field({ ...this, ...v });
|
|
408
|
+
const rename = f.name !== this.name;
|
|
409
|
+
if (rename && !this.table?.name) {
|
|
410
|
+
throw new Error("");
|
|
411
|
+
}
|
|
379
412
|
if (typeof v.is_unique !== "undefined" &&
|
|
380
413
|
!!v.is_unique !== !!this.is_unique) {
|
|
381
414
|
if (v.is_unique && !this.is_unique)
|
|
382
415
|
await this.add_unique_constraint();
|
|
383
416
|
if (!v.is_unique && this.is_unique)
|
|
384
417
|
await this.remove_unique_constraint();
|
|
385
|
-
await
|
|
418
|
+
await db_1.default.update("_sc_fields", { is_unique: v.is_unique }, this.id);
|
|
386
419
|
}
|
|
387
420
|
if (typeof v.required !== "undefined" && !!v.required !== !!this.required)
|
|
388
421
|
await this.toggle_not_null(!!v.required);
|
|
389
|
-
const f = new Field({ ...this, ...v });
|
|
390
422
|
if (f.sql_type !== this.sql_type) {
|
|
391
423
|
await this.alter_sql_type(f);
|
|
392
424
|
}
|
|
393
|
-
if (
|
|
394
|
-
const schema =
|
|
395
|
-
await
|
|
425
|
+
if (rename) {
|
|
426
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
427
|
+
await db_1.default.query(`alter table ${schema}"${(0, internal_1.sqlsanitize)(this.table.name // ensured above
|
|
428
|
+
)}" rename column "${(0, internal_1.sqlsanitize)(this.name)}" TO ${f.name};`);
|
|
396
429
|
}
|
|
397
|
-
await
|
|
430
|
+
await db_1.default.update("_sc_fields", v, this.id);
|
|
398
431
|
Object.entries(v).forEach(([k, v]) => {
|
|
399
432
|
this[k] = v;
|
|
400
433
|
});
|
|
@@ -404,17 +437,18 @@ class Field {
|
|
|
404
437
|
* @type {string}
|
|
405
438
|
*/
|
|
406
439
|
get listKey() {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
440
|
+
if ((0, common_types_1.instanceOfType)(this.type))
|
|
441
|
+
if (this.type.listAs)
|
|
442
|
+
return (r) => this.type.listAs(r[this.name]);
|
|
443
|
+
else if (this.type.showAs)
|
|
444
|
+
return (r) => this.type.showAs(r[this.name]);
|
|
445
|
+
return this.name;
|
|
412
446
|
}
|
|
413
447
|
/**
|
|
414
448
|
* @type {object}
|
|
415
449
|
*/
|
|
416
450
|
get presets() {
|
|
417
|
-
if (this.type && this.type.presets)
|
|
451
|
+
if ((0, common_types_1.instanceOfType)(this.type) && this.type.presets)
|
|
418
452
|
return this.type.presets;
|
|
419
453
|
if (this.type === "Key" && this.reftable_name === "users")
|
|
420
454
|
return { LoggedIn: ({ user }) => user && user.id };
|
|
@@ -432,18 +466,18 @@ class Field {
|
|
|
432
466
|
if (table.ownership_field_id === this.id) {
|
|
433
467
|
throw new InvalidAdminAction(`Cannot delete field ${this.name} as it sets ownership for table ${table.name}`);
|
|
434
468
|
}
|
|
435
|
-
const schema =
|
|
436
|
-
const client =
|
|
469
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
470
|
+
const client = db_1.default.isSQLite ? db_1.default : await db_1.default.getClient();
|
|
437
471
|
await client.query("BEGIN");
|
|
438
|
-
await
|
|
439
|
-
if (!
|
|
440
|
-
await client.query(`alter table ${schema}"${sqlsanitize(table.name)}" drop column "${sqlsanitize(this.name)}"`);
|
|
472
|
+
await db_1.default.deleteWhere("_sc_fields", { id: this.id }, { client });
|
|
473
|
+
if (!db_1.default.isSQLite && (!this.calculated || this.stored)) {
|
|
474
|
+
await client.query(`alter table ${schema}"${(0, internal_1.sqlsanitize)(table.name)}" drop column "${(0, internal_1.sqlsanitize)(this.name)}"`);
|
|
441
475
|
if (table.versioned) {
|
|
442
|
-
await client.query(`alter table ${schema}"${sqlsanitize(table.name)}__history" drop column "${sqlsanitize(this.name)}"`);
|
|
476
|
+
await client.query(`alter table ${schema}"${(0, internal_1.sqlsanitize)(table.name)}__history" drop column "${(0, internal_1.sqlsanitize)(this.name)}"`);
|
|
443
477
|
}
|
|
444
478
|
}
|
|
445
479
|
await client.query("COMMIT");
|
|
446
|
-
if (!
|
|
480
|
+
if (!db_1.default.isSQLite)
|
|
447
481
|
await client.release(true);
|
|
448
482
|
await require("../db/state").getState().refresh_tables();
|
|
449
483
|
}
|
|
@@ -452,10 +486,13 @@ class Field {
|
|
|
452
486
|
* @returns {Promise<void>}
|
|
453
487
|
*/
|
|
454
488
|
async enable_fkey_constraint(table) {
|
|
455
|
-
if (this.is_fkey && !
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
489
|
+
if (this.is_fkey && !db_1.default.isSQLite) {
|
|
490
|
+
if (!this.reftable_name) {
|
|
491
|
+
throw new Error("To enable a foreign key constraint, the 'reftable_name' must be set.");
|
|
492
|
+
}
|
|
493
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
494
|
+
const q = `alter table ${schema}"${(0, internal_1.sqlsanitize)(table.name)}" ADD CONSTRAINT "fkey_${(0, internal_1.sqlsanitize)(table.name)}_${(0, internal_1.sqlsanitize)(this.name)}" FOREIGN KEY ("${(0, internal_1.sqlsanitize)(this.name)}") references ${schema}"${(0, internal_1.sqlsanitize)(this.reftable_name)}" (id)`;
|
|
495
|
+
await db_1.default.query(q);
|
|
459
496
|
}
|
|
460
497
|
}
|
|
461
498
|
/**
|
|
@@ -465,9 +502,9 @@ class Field {
|
|
|
465
502
|
*/
|
|
466
503
|
static async create(fld, bare = false) {
|
|
467
504
|
const f = new Field(fld);
|
|
468
|
-
const schema =
|
|
505
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
469
506
|
const Table = require("./table");
|
|
470
|
-
const is_sqlite =
|
|
507
|
+
const is_sqlite = db_1.default.isSQLite;
|
|
471
508
|
//const tables = await Table.find();
|
|
472
509
|
//console.log({ tables, fld });
|
|
473
510
|
if (f.is_fkey) {
|
|
@@ -484,34 +521,34 @@ class Field {
|
|
|
484
521
|
const table = await Table.findOne({ id: f.table_id });
|
|
485
522
|
if (!f.calculated || f.stored) {
|
|
486
523
|
if (typeof f.attributes.default === "undefined") {
|
|
487
|
-
const q = `alter table ${schema}"${sqlsanitize(table.name)}" add column "${sqlsanitize(f.name)}" ${sql_type} ${f.required ? `not null ${is_sqlite ? 'default ""' : ""}` : ""}`;
|
|
488
|
-
await
|
|
524
|
+
const q = `alter table ${schema}"${(0, internal_1.sqlsanitize)(table.name)}" add column "${(0, internal_1.sqlsanitize)(f.name)}" ${sql_type} ${f.required ? `not null ${is_sqlite ? 'default ""' : ""}` : ""}`;
|
|
525
|
+
await db_1.default.query(q);
|
|
489
526
|
}
|
|
490
527
|
else if (is_sqlite) {
|
|
491
528
|
//warning: not safe but sqlite so we don't care
|
|
492
|
-
const q = `alter table ${schema}"${sqlsanitize(table.name)}" add column "${sqlsanitize(f.name)}" ${sql_type} ${f.required
|
|
529
|
+
const q = `alter table ${schema}"${(0, internal_1.sqlsanitize)(table.name)}" add column "${(0, internal_1.sqlsanitize)(f.name)}" ${sql_type} ${f.required
|
|
493
530
|
? `not null default ${JSON.stringify(f.attributes.default)}`
|
|
494
531
|
: ""}`;
|
|
495
|
-
await
|
|
532
|
+
await db_1.default.query(q);
|
|
496
533
|
}
|
|
497
534
|
else {
|
|
498
|
-
const q = `DROP FUNCTION IF EXISTS add_field_${sqlsanitize(f.name)};
|
|
499
|
-
CREATE FUNCTION add_field_${sqlsanitize(f.name)}(thedef ${f.sql_bare_type}) RETURNS void AS $$
|
|
535
|
+
const q = `DROP FUNCTION IF EXISTS add_field_${(0, internal_1.sqlsanitize)(f.name)};
|
|
536
|
+
CREATE FUNCTION add_field_${(0, internal_1.sqlsanitize)(f.name)}(thedef ${f.sql_bare_type}) RETURNS void AS $$
|
|
500
537
|
BEGIN
|
|
501
|
-
EXECUTE format('alter table ${schema}"${sqlsanitize(table.name)}" add column "${sqlsanitize(f.name)}" ${sql_type} ${f.required ? "not null" : ""} default %L', thedef);
|
|
538
|
+
EXECUTE format('alter table ${schema}"${(0, internal_1.sqlsanitize)(table.name)}" add column "${(0, internal_1.sqlsanitize)(f.name)}" ${sql_type} ${f.required ? "not null" : ""} default %L', thedef);
|
|
502
539
|
END;
|
|
503
540
|
$$ LANGUAGE plpgsql;`;
|
|
504
|
-
await
|
|
505
|
-
await
|
|
541
|
+
await db_1.default.query(q);
|
|
542
|
+
await db_1.default.query(`SELECT add_field_${(0, internal_1.sqlsanitize)(f.name)}($1)`, [
|
|
506
543
|
f.attributes.default,
|
|
507
544
|
]);
|
|
508
545
|
}
|
|
509
546
|
}
|
|
510
|
-
f.id = await
|
|
547
|
+
f.id = await db_1.default.insert("_sc_fields", {
|
|
511
548
|
table_id: f.table_id,
|
|
512
549
|
name: f.name,
|
|
513
550
|
label: f.label,
|
|
514
|
-
type: f.is_fkey ? f.type : f.type
|
|
551
|
+
type: f.is_fkey ? f.type : f.type?.name,
|
|
515
552
|
reftable_name: f.is_fkey ? f.reftable_name : undefined,
|
|
516
553
|
reftype: f.is_fkey ? f.reftype : undefined,
|
|
517
554
|
refname: f.is_fkey ? f.refname : undefined,
|
|
@@ -524,7 +561,7 @@ class Field {
|
|
|
524
561
|
});
|
|
525
562
|
await require("../db/state").getState().refresh_tables();
|
|
526
563
|
if (table.versioned && !f.calculated) {
|
|
527
|
-
await
|
|
564
|
+
await db_1.default.query(`alter table ${schema}"${(0, internal_1.sqlsanitize)(table.name)}__history" add column "${(0, internal_1.sqlsanitize)(f.name)}" ${f.sql_bare_type}`);
|
|
528
565
|
}
|
|
529
566
|
if (f.is_unique && !f.calculated)
|
|
530
567
|
await f.add_unique_constraint();
|
|
@@ -556,64 +593,5 @@ class Field {
|
|
|
556
593
|
return typeattribs;
|
|
557
594
|
}
|
|
558
595
|
}
|
|
559
|
-
Field.contract = {
|
|
560
|
-
variables: {
|
|
561
|
-
name: is.str,
|
|
562
|
-
label: is.str,
|
|
563
|
-
class: is.str,
|
|
564
|
-
postText: is.maybe(is.str),
|
|
565
|
-
sublabel: is.maybe(is.str),
|
|
566
|
-
fieldview: is.maybe(is.str),
|
|
567
|
-
parent_field: is.maybe(is.str),
|
|
568
|
-
reftable_name: is.maybe(is.str),
|
|
569
|
-
validator: is.fun(is.any, is.bool),
|
|
570
|
-
type: is.maybe(is.or(is.eq("Key"), is.eq("File"), is.obj({ name: is.str }))),
|
|
571
|
-
input_type: is.maybe(is.one_of([
|
|
572
|
-
"hidden",
|
|
573
|
-
"file",
|
|
574
|
-
"select",
|
|
575
|
-
"fromtype",
|
|
576
|
-
"search",
|
|
577
|
-
"text",
|
|
578
|
-
"password",
|
|
579
|
-
"section_header",
|
|
580
|
-
"textarea",
|
|
581
|
-
"custom_html",
|
|
582
|
-
"code",
|
|
583
|
-
])),
|
|
584
|
-
is_fkey: is.bool,
|
|
585
|
-
is_unique: is.bool,
|
|
586
|
-
required: is.bool,
|
|
587
|
-
disabled: is.bool,
|
|
588
|
-
id: is.maybe(is.posint),
|
|
589
|
-
attributes: is.obj(),
|
|
590
|
-
table_id: is.maybe(is.posint),
|
|
591
|
-
},
|
|
592
|
-
instance_check: is.and(is.or(is.obj({ type: is.defined }), is.obj({ input_type: is.defined })), is.or(is.obj({ is_fkey: is.eq(false), reftable_name: is.eq(undefined) }), is.obj({ is_fkey: is.eq(true), reftable_name: is.str }))),
|
|
593
|
-
methods: {
|
|
594
|
-
validate: is.fun(is.obj(), is.or(is.obj({ errors: is.str }), is.obj({ success: is.any }))),
|
|
595
|
-
toJson: is.getter(is.obj({ type: is.str })),
|
|
596
|
-
sql_type: is.getter(is.str),
|
|
597
|
-
sql_bare_type: is.getter(is.str),
|
|
598
|
-
form_name: is.getter(is.str),
|
|
599
|
-
listKey: is.getter(is.any),
|
|
600
|
-
presets: is.getter(is.maybe(is.objVals(is.fun(is.obj(), is.any)))),
|
|
601
|
-
delete: is.fun([], is.promise(is.undefined)),
|
|
602
|
-
generate: is.fun([], is.promise(is.any)),
|
|
603
|
-
add_unique_constraint: is.fun([], is.promise(is.undefined)),
|
|
604
|
-
remove_unique_constraint: is.fun([], is.promise(is.undefined)),
|
|
605
|
-
toggle_not_null: is.fun(is.bool, is.promise(is.undefined)),
|
|
606
|
-
fill_table: is.fun([], is.promise(is.undefined)),
|
|
607
|
-
update: is.fun(is.obj(), is.promise(is.undefined)),
|
|
608
|
-
fill_fkey_options: is.fun(is.maybe(is.bool), is.promise()),
|
|
609
|
-
distinct_values: is.fun([], is.promise(is.array(is.obj({ label: is.any, value: is.any })))),
|
|
610
|
-
},
|
|
611
|
-
static_methods: {
|
|
612
|
-
find: is.fun([is.maybe(is.obj()), is.maybe(is.obj())], is.promise(is.array(is.class("Field")))),
|
|
613
|
-
findOne: is.fun(is.obj(), is.promise(is.class("Field"))),
|
|
614
|
-
create: is.fun(is.obj(), is.promise(is.class("Field"))),
|
|
615
|
-
labelToName: is.fun(is.str, is.str),
|
|
616
|
-
},
|
|
617
|
-
};
|
|
618
596
|
module.exports = Field;
|
|
619
597
|
//# sourceMappingURL=field.js.map
|