@saltcorn/data 0.6.1-beta.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/listshowlist.js +24 -10
- package/base-plugin/viewtemplates/room.js +24 -22
- package/base-plugin/viewtemplates/show.js +27 -26
- package/base-plugin/viewtemplates/viewable_fields.js +25 -26
- package/db/db.test.js +0 -154
- package/db/index.js +15 -10
- package/db/state.js +36 -14
- package/models/config.js +7 -1
- package/models/expression.js +37 -25
- package/models/field.js +19 -13
- package/models/file.js +9 -2
- package/models/form.js +7 -6
- package/models/page.js +5 -1
- package/models/table.js +10 -2
- package/models/tenant.js +29 -5
- package/models/view.js +26 -22
- package/package.json +14 -7
- package/plugin-helper.js +31 -11
- package/tests/calc.test.js +22 -0
- package/db/internal.js +0 -302
- package/db/multi-tenant.js +0 -44
- package/db/pg.js +0 -384
- package/db/single-tenant.js +0 -26
- package/db/sqlite.js +0 -297
- package/db/tenants.js +0 -12
package/db/pg.js
DELETED
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PostgreSQL data access layer
|
|
3
|
-
* @category saltcorn-data
|
|
4
|
-
* @module db/pg
|
|
5
|
-
* @subcategory db
|
|
6
|
-
*/
|
|
7
|
-
// TODO move postgresql specific to this module
|
|
8
|
-
const { Pool } = require("pg");
|
|
9
|
-
const copyStreams = require("pg-copy-streams");
|
|
10
|
-
const { promisify } = require("util");
|
|
11
|
-
const { pipeline } = require("stream");
|
|
12
|
-
const { sqlsanitize, mkWhere, mkSelectOptions } = require("./internal");
|
|
13
|
-
const { getConnectObject } = require("./connect");
|
|
14
|
-
const { getTenantSchema } = require("./tenants");
|
|
15
|
-
|
|
16
|
-
var connectObj = getConnectObject();
|
|
17
|
-
|
|
18
|
-
var pool;
|
|
19
|
-
if (connectObj) pool = new Pool(connectObj);
|
|
20
|
-
|
|
21
|
-
var log_sql_enabled = false;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Control Logging sql statements to console
|
|
25
|
-
* @param {boolean} [val = true] - if true then log sql statements to console
|
|
26
|
-
*/
|
|
27
|
-
function set_sql_logging(val = true) {
|
|
28
|
-
log_sql_enabled = val;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Get sql logging state
|
|
33
|
-
* @returns {boolean} if true then sql logging eabled
|
|
34
|
-
*/
|
|
35
|
-
function get_sql_logging() {
|
|
36
|
-
return log_sql_enabled;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Log SQL statement to console
|
|
41
|
-
* @param {string} sql - SQL statement
|
|
42
|
-
* @param {object} [vs] - any additional parameter
|
|
43
|
-
*/
|
|
44
|
-
function sql_log(sql, vs) {
|
|
45
|
-
if (log_sql_enabled)
|
|
46
|
-
if (typeof vs === "undefined") console.log(sql);
|
|
47
|
-
else console.log(sql, vs);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Close database connection
|
|
52
|
-
* @returns {Promise<void>}
|
|
53
|
-
*/
|
|
54
|
-
const close = async () => {
|
|
55
|
-
if (pool) await pool.end();
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Change connection (close connection and open new connection from connObj)
|
|
60
|
-
* @param {object} [connObj = {}] - connection object
|
|
61
|
-
* @returns {Promise<void>}
|
|
62
|
-
*/
|
|
63
|
-
const changeConnection = async (connObj = {}) => {
|
|
64
|
-
await close();
|
|
65
|
-
pool = new Pool(getConnectObject(connObj));
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Execute Select statement
|
|
70
|
-
* @param {string} tbl - table name
|
|
71
|
-
* @param {object} whereObj - where object
|
|
72
|
-
* @param {object} [selectopts = {}] - select options
|
|
73
|
-
* @returns {Promise<*>} return rows
|
|
74
|
-
*/
|
|
75
|
-
const select = async (tbl, whereObj, selectopts = {}) => {
|
|
76
|
-
const { where, values } = mkWhere(whereObj);
|
|
77
|
-
const sql = `SELECT * FROM "${getTenantSchema()}"."${sqlsanitize(
|
|
78
|
-
tbl
|
|
79
|
-
)}" ${where} ${mkSelectOptions(selectopts)}`;
|
|
80
|
-
sql_log(sql, values);
|
|
81
|
-
const tq = await pool.query(sql, values);
|
|
82
|
-
|
|
83
|
-
return tq.rows;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Reset DB Schema using drop schema and recreate it
|
|
88
|
-
* Atterntion! You will lost data after call this function!
|
|
89
|
-
* @param {string} schema - db schema name
|
|
90
|
-
* @returns {Promise<void>} no result
|
|
91
|
-
*/
|
|
92
|
-
const drop_reset_schema = async (schema) => {
|
|
93
|
-
const sql = `DROP SCHEMA IF EXISTS "${schema}" CASCADE;
|
|
94
|
-
CREATE SCHEMA "${schema}";
|
|
95
|
-
GRANT ALL ON SCHEMA "${schema}" TO postgres;
|
|
96
|
-
GRANT ALL ON SCHEMA "${schema}" TO "public" ;
|
|
97
|
-
COMMENT ON SCHEMA "${schema}" IS 'standard public schema';`;
|
|
98
|
-
sql_log(sql);
|
|
99
|
-
|
|
100
|
-
await pool.query(sql);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Get count of rows in table
|
|
105
|
-
* @param {string} - tbl - table name
|
|
106
|
-
* @param {object} - whereObj - where object
|
|
107
|
-
* @returns {Promise<number>} count of tables
|
|
108
|
-
*/
|
|
109
|
-
const count = async (tbl, whereObj) => {
|
|
110
|
-
const { where, values } = mkWhere(whereObj);
|
|
111
|
-
const sql = `SELECT COUNT(*) FROM "${getTenantSchema()}"."${sqlsanitize(
|
|
112
|
-
tbl
|
|
113
|
-
)}" ${where}`;
|
|
114
|
-
sql_log(sql, values);
|
|
115
|
-
const tq = await pool.query(sql, values);
|
|
116
|
-
|
|
117
|
-
return parseInt(tq.rows[0].count);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Get version of PostgreSQL
|
|
122
|
-
* @param {boolean} short - if true return short version info else full version info
|
|
123
|
-
* @returns {Promise<string>} returns version
|
|
124
|
-
*/
|
|
125
|
-
const getVersion = async (short) => {
|
|
126
|
-
const sql = `SELECT version();`;
|
|
127
|
-
sql_log(sql);
|
|
128
|
-
const tq = await pool.query(sql);
|
|
129
|
-
const v = tq.rows[0].version;
|
|
130
|
-
if (short) {
|
|
131
|
-
const ws = v.split(" ");
|
|
132
|
-
return ws[1];
|
|
133
|
-
}
|
|
134
|
-
return v;
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Delete rows in table
|
|
139
|
-
* @param {string} tbl - table name
|
|
140
|
-
* @param {object} whereObj - where object
|
|
141
|
-
* @param {object} [opts = {}]
|
|
142
|
-
* @returns {Promise<object[]>} result of delete execution
|
|
143
|
-
*/
|
|
144
|
-
const deleteWhere = async (tbl, whereObj, opts = {}) => {
|
|
145
|
-
const { where, values } = mkWhere(whereObj);
|
|
146
|
-
const sql = `delete FROM "${getTenantSchema()}"."${sqlsanitize(
|
|
147
|
-
tbl
|
|
148
|
-
)}" ${where}`;
|
|
149
|
-
sql_log(sql, values);
|
|
150
|
-
|
|
151
|
-
const tq = await (opts.client || pool).query(sql, values);
|
|
152
|
-
|
|
153
|
-
return tq.rows;
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Insert rows into table
|
|
158
|
-
* @param {string} tbl - table name
|
|
159
|
-
* @param {object} obj - columns names and data
|
|
160
|
-
* @param {object} [opts = {}] - columns attributes
|
|
161
|
-
* @returns {Promise<string>} returns primary key column or Id column value. If primary key column is not defined then return value of Id column.
|
|
162
|
-
*/
|
|
163
|
-
const insert = async (tbl, obj, opts = {}) => {
|
|
164
|
-
const kvs = Object.entries(obj);
|
|
165
|
-
const fnameList = kvs.map(([k, v]) => `"${sqlsanitize(k)}"`).join();
|
|
166
|
-
var valPosList = [];
|
|
167
|
-
var valList = [];
|
|
168
|
-
const schema = getTenantSchema();
|
|
169
|
-
kvs.forEach(([k, v]) => {
|
|
170
|
-
if (v && v.next_version_by_id) {
|
|
171
|
-
valPosList.push(
|
|
172
|
-
`coalesce((select max(_version) from "${schema}"."${sqlsanitize(
|
|
173
|
-
tbl
|
|
174
|
-
)}" where id=${+v.next_version_by_id}), 0)+1`
|
|
175
|
-
);
|
|
176
|
-
} else {
|
|
177
|
-
valList.push(v);
|
|
178
|
-
valPosList.push(`$${valList.length}`);
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
const sql =
|
|
182
|
-
valPosList.length > 0
|
|
183
|
-
? `insert into "${schema}"."${sqlsanitize(
|
|
184
|
-
tbl
|
|
185
|
-
)}"(${fnameList}) values(${valPosList.join()}) returning ${
|
|
186
|
-
opts.noid ? "*" : opts.pk_name || "id"
|
|
187
|
-
}`
|
|
188
|
-
: `insert into "${schema}"."${sqlsanitize(
|
|
189
|
-
tbl
|
|
190
|
-
)}" DEFAULT VALUES returning ${opts.noid ? "*" : opts.pk_name || "id"}`;
|
|
191
|
-
sql_log(sql, valList);
|
|
192
|
-
const { rows } = await (opts.client || pool).query(sql, valList);
|
|
193
|
-
if (opts.noid) return;
|
|
194
|
-
else return rows[0][opts.pk_name || "id"];
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Update table records
|
|
199
|
-
* @param {string} tbl - table name
|
|
200
|
-
* @param {object} obj - columns names and data
|
|
201
|
-
* @param {number|undefined} id - id of record (primary key column value)
|
|
202
|
-
* @param {object} [opts = {}] - columns attributes
|
|
203
|
-
* @returns {Promise<void>} no result
|
|
204
|
-
*/
|
|
205
|
-
const update = async (tbl, obj, id, opts = {}) => {
|
|
206
|
-
const kvs = Object.entries(obj);
|
|
207
|
-
const assigns = kvs
|
|
208
|
-
.map(([k, v], ix) => `"${sqlsanitize(k)}"=$${ix + 1}`)
|
|
209
|
-
.join();
|
|
210
|
-
var valList = kvs.map(([k, v]) => v);
|
|
211
|
-
// TBD check that is correct - because in insert function opts.noid ? "*" : opts.pk_name || "id"
|
|
212
|
-
//valList.push(id === "undefined"? obj[opts.pk_name]: id);
|
|
213
|
-
valList.push(id === "undefined" ? obj[opts.pk_name || "id"] : id);
|
|
214
|
-
const q = `update "${getTenantSchema()}"."${sqlsanitize(
|
|
215
|
-
tbl
|
|
216
|
-
)}" set ${assigns} where ${opts.pk_name || "id"}=$${kvs.length + 1}`;
|
|
217
|
-
sql_log(q, valList);
|
|
218
|
-
await pool.query(q, valList);
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Select one record
|
|
223
|
-
* @param {srting} tbl - table name
|
|
224
|
-
* @param {object} where - where object
|
|
225
|
-
* @returns {Promise<object>} return first record from sql result
|
|
226
|
-
* @throws {Error}
|
|
227
|
-
*/
|
|
228
|
-
const selectOne = async (tbl, where) => {
|
|
229
|
-
const rows = await select(tbl, where);
|
|
230
|
-
if (rows.length === 0) {
|
|
231
|
-
const w = mkWhere(where);
|
|
232
|
-
throw new Error(`no ${tbl} ${w.where} are ${w.values}`);
|
|
233
|
-
} else return rows[0];
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Select one record or null if no records
|
|
238
|
-
* @param {string} tbl - table name
|
|
239
|
-
* @param {object} where - where object
|
|
240
|
-
* @returns {Promise<null|object>} - null if no record or first record data
|
|
241
|
-
*/
|
|
242
|
-
const selectMaybeOne = async (tbl, where) => {
|
|
243
|
-
const rows = await select(tbl, where);
|
|
244
|
-
if (rows.length === 0) return null;
|
|
245
|
-
else return rows[0];
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Open db connection
|
|
250
|
-
* Only for PG.
|
|
251
|
-
* @returns {Promise<*>} db connection object
|
|
252
|
-
*/
|
|
253
|
-
// TBD Currently this function supported only for PG
|
|
254
|
-
const getClient = async () => await pool.connect();
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Reset sequence
|
|
258
|
-
* Only for PG
|
|
259
|
-
* @param {string} tblname - table name
|
|
260
|
-
* @returns {Promise<void>} no result
|
|
261
|
-
*/
|
|
262
|
-
const reset_sequence = async (tblname) => {
|
|
263
|
-
const sql = `SELECT setval(pg_get_serial_sequence('"${getTenantSchema()}"."${sqlsanitize(
|
|
264
|
-
tblname
|
|
265
|
-
)}"', 'id'), coalesce(max(id),0) + 1, false) FROM "${getTenantSchema()}"."${sqlsanitize(
|
|
266
|
-
tblname
|
|
267
|
-
)}";`;
|
|
268
|
-
await pool.query(sql);
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Add unique constraint
|
|
273
|
-
* @param {string} table_name - table name
|
|
274
|
-
* @param {string[]} field_names - list of columns (members of constraint)
|
|
275
|
-
* @returns {Promise<void>} no result
|
|
276
|
-
*/
|
|
277
|
-
const add_unique_constraint = async (table_name, field_names) => {
|
|
278
|
-
// TBD check that there are no problems with lenght of constraint name
|
|
279
|
-
const sql = `alter table "${getTenantSchema()}"."${sqlsanitize(
|
|
280
|
-
table_name
|
|
281
|
-
)}" add CONSTRAINT "${sqlsanitize(table_name)}_${field_names
|
|
282
|
-
.map((f) => sqlsanitize(f))
|
|
283
|
-
.join("_")}_unique" UNIQUE (${field_names
|
|
284
|
-
.map((f) => `"${sqlsanitize(f)}"`)
|
|
285
|
-
.join(",")});`;
|
|
286
|
-
sql_log(sql);
|
|
287
|
-
await pool.query(sql);
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Drop unique constraint
|
|
292
|
-
* @param {string} table_name - table name
|
|
293
|
-
* @param {string[]} field_names - list of columns (members of constraint)
|
|
294
|
-
* @returns {Promise<void>} no results
|
|
295
|
-
*/
|
|
296
|
-
const drop_unique_constraint = async (table_name, field_names) => {
|
|
297
|
-
// TBD check that there are no problems with lenght of constraint name
|
|
298
|
-
const sql = `alter table "${getTenantSchema()}"."${sqlsanitize(
|
|
299
|
-
table_name
|
|
300
|
-
)}" drop CONSTRAINT "${sqlsanitize(table_name)}_${field_names
|
|
301
|
-
.map((f) => sqlsanitize(f))
|
|
302
|
-
.join("_")}_unique";`;
|
|
303
|
-
sql_log(sql);
|
|
304
|
-
await pool.query(sql);
|
|
305
|
-
};
|
|
306
|
-
/**
|
|
307
|
-
* Copy data from CSV to table?
|
|
308
|
-
* Only for PG
|
|
309
|
-
* @param {object} fileStream - file stream
|
|
310
|
-
* @param {string} tableName - table name
|
|
311
|
-
* @param {string[]} fieldNames - list of columns
|
|
312
|
-
* @param {object} client - db connection
|
|
313
|
-
* @returns {Promise<function>} new Promise
|
|
314
|
-
*/
|
|
315
|
-
const copyFrom1 = (fileStream, tableName, fieldNames, client) => {
|
|
316
|
-
// TBD describe difference between CopyFrom and CopyFrom1
|
|
317
|
-
const quote = (s) => `"${s}"`;
|
|
318
|
-
const sql = `COPY "${sqlsanitize(tableName)}" (${fieldNames
|
|
319
|
-
.map(quote)
|
|
320
|
-
.join(",")}) FROM STDIN CSV HEADER`;
|
|
321
|
-
sql_log(sql);
|
|
322
|
-
|
|
323
|
-
var stream = client.query(copyStreams.from(sql));
|
|
324
|
-
|
|
325
|
-
return new Promise((resolve, reject) => {
|
|
326
|
-
fileStream.on("error", reject);
|
|
327
|
-
stream.on("error", reject);
|
|
328
|
-
stream.on("finish", resolve);
|
|
329
|
-
fileStream.pipe(stream).on("error", reject);
|
|
330
|
-
});
|
|
331
|
-
};
|
|
332
|
-
/**
|
|
333
|
-
* Copy data from CSV to table?
|
|
334
|
-
* Only for PG
|
|
335
|
-
* @param {object} fileStream - file stream
|
|
336
|
-
* @param {string} tableName - table name
|
|
337
|
-
* @param {string[]} fieldNames - list of columns
|
|
338
|
-
* @param {object} client - db connection
|
|
339
|
-
* @returns {Promise<void>} no results
|
|
340
|
-
*/
|
|
341
|
-
const copyFrom = async (fileStream, tableName, fieldNames, client) => {
|
|
342
|
-
// TBD describe difference between CopyFrom and CopyFrom1
|
|
343
|
-
const quote = (s) => `"${s}"`;
|
|
344
|
-
const sql = `COPY "${sqlsanitize(tableName)}" (${fieldNames
|
|
345
|
-
.map(quote)
|
|
346
|
-
.join(",")}) FROM STDIN CSV HEADER`;
|
|
347
|
-
sql_log(sql);
|
|
348
|
-
|
|
349
|
-
const stream = client.query(copyStreams.from(sql));
|
|
350
|
-
return await promisify(pipeline)(fileStream, stream);
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
module.exports = {
|
|
354
|
-
pool,
|
|
355
|
-
/**
|
|
356
|
-
* @param {string} text
|
|
357
|
-
* @param {object} params
|
|
358
|
-
* @returns {object}
|
|
359
|
-
*/
|
|
360
|
-
query: (text, params) => {
|
|
361
|
-
sql_log(text, params);
|
|
362
|
-
return pool.query(text, params);
|
|
363
|
-
},
|
|
364
|
-
select,
|
|
365
|
-
selectOne,
|
|
366
|
-
selectMaybeOne,
|
|
367
|
-
count,
|
|
368
|
-
insert,
|
|
369
|
-
update,
|
|
370
|
-
deleteWhere,
|
|
371
|
-
close,
|
|
372
|
-
sql_log,
|
|
373
|
-
changeConnection,
|
|
374
|
-
set_sql_logging,
|
|
375
|
-
get_sql_logging,
|
|
376
|
-
getClient,
|
|
377
|
-
mkWhere,
|
|
378
|
-
drop_reset_schema,
|
|
379
|
-
add_unique_constraint,
|
|
380
|
-
drop_unique_constraint,
|
|
381
|
-
reset_sequence,
|
|
382
|
-
getVersion,
|
|
383
|
-
copyFrom,
|
|
384
|
-
};
|
package/db/single-tenant.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @category saltcorn-data
|
|
3
|
-
* @module db/single-tenant
|
|
4
|
-
* @subcategory db
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
module.exports = (connObj) => ({
|
|
8
|
-
/**
|
|
9
|
-
* @returns {string}
|
|
10
|
-
*/
|
|
11
|
-
getTenantSchema: () => connObj.default_schema,
|
|
12
|
-
/**
|
|
13
|
-
* @returns {false}
|
|
14
|
-
*/
|
|
15
|
-
is_it_multi_tenant: () => false,
|
|
16
|
-
enable_multi_tenant() {},
|
|
17
|
-
/**
|
|
18
|
-
* @param {*} t
|
|
19
|
-
* @param {function} f
|
|
20
|
-
* @returns {*}
|
|
21
|
-
*/
|
|
22
|
-
runWithTenant(t, f) {
|
|
23
|
-
return f();
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
|
package/db/sqlite.js
DELETED
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SQLite3 data access layer
|
|
3
|
-
* @category saltcorn-data
|
|
4
|
-
* @module db/sqlite
|
|
5
|
-
* @subcategory db
|
|
6
|
-
*/
|
|
7
|
-
// TODO move all sqlite specific to this module
|
|
8
|
-
const sqlite3 = require("sqlite3").verbose();
|
|
9
|
-
const { sqlsanitize, mkWhere, mkSelectOptions } = require("./internal");
|
|
10
|
-
const { getConnectObject } = require("./connect");
|
|
11
|
-
const fs = require("fs").promises;
|
|
12
|
-
const connectObj = getConnectObject(); // was var
|
|
13
|
-
/**
|
|
14
|
-
* Get sqlite path
|
|
15
|
-
* @returns {string}
|
|
16
|
-
*/
|
|
17
|
-
const get_db_filepath = () => {
|
|
18
|
-
if (connectObj.sqlite_path) return connectObj.sqlite_path;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
let current_filepath = get_db_filepath();
|
|
22
|
-
let sqliteDatabase = new sqlite3.Database(current_filepath);
|
|
23
|
-
|
|
24
|
-
let log_sql_enabled = false;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Control Logging sql statements to console
|
|
28
|
-
* @param {boolean} [val = true] - if true then log sql statements to console
|
|
29
|
-
*/
|
|
30
|
-
function set_sql_logging(val = true) {
|
|
31
|
-
log_sql_enabled = val;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Get sql logging state
|
|
36
|
-
* @returns {boolean} if true then sql logging eabled
|
|
37
|
-
*/
|
|
38
|
-
function get_sql_logging() {
|
|
39
|
-
return log_sql_enabled;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Log SQL statement to console
|
|
43
|
-
* @param {string} sql - SQL statement
|
|
44
|
-
* @param {object} [vs] - any additional parameter
|
|
45
|
-
*/
|
|
46
|
-
function sql_log(sql, vs) {
|
|
47
|
-
if (log_sql_enabled)
|
|
48
|
-
if (typeof vs === "undefined") console.log(sql);
|
|
49
|
-
else console.log(sql, vs);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @param {string} sql
|
|
54
|
-
* @param {object} params
|
|
55
|
-
* @returns {Promise<Object[]>}
|
|
56
|
-
*/
|
|
57
|
-
function query(sql, params) {
|
|
58
|
-
sql_log(sql, params);
|
|
59
|
-
return new Promise((resolve, reject) => {
|
|
60
|
-
sqliteDatabase.all(sql, params, function (err, rows) {
|
|
61
|
-
if (err) {
|
|
62
|
-
reject(err);
|
|
63
|
-
} else {
|
|
64
|
-
resolve({ rows });
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Change connection (close connection and open new connection from connObj)
|
|
71
|
-
* @param {object} connObj - connection object
|
|
72
|
-
* @returns {Promise<void>}
|
|
73
|
-
*/
|
|
74
|
-
const changeConnection = async (connObj) => {
|
|
75
|
-
await sqliteDatabase.close();
|
|
76
|
-
current_filepath = connObj.sqlite_path;
|
|
77
|
-
sqliteDatabase = new sqlite3.Database(current_filepath);
|
|
78
|
-
};
|
|
79
|
-
/**
|
|
80
|
-
* Close database connection
|
|
81
|
-
* @returns {Promise<void>}
|
|
82
|
-
*/
|
|
83
|
-
const close = async () => {
|
|
84
|
-
await sqliteDatabase.close();
|
|
85
|
-
};
|
|
86
|
-
/**
|
|
87
|
-
* Execute Select statement
|
|
88
|
-
* @param {string} tbl - table name
|
|
89
|
-
* @param {object} whereObj - where object
|
|
90
|
-
* @param {object} [selectopts = {}] - select options
|
|
91
|
-
* @returns {Promise<*>} return rows
|
|
92
|
-
*/
|
|
93
|
-
const select = async (tbl, whereObj, selectopts = {}) => {
|
|
94
|
-
const { where, values } = mkWhere(whereObj, true);
|
|
95
|
-
const sql = `SELECT * FROM "${sqlsanitize(tbl)}" ${where} ${mkSelectOptions(
|
|
96
|
-
selectopts
|
|
97
|
-
)}`;
|
|
98
|
-
const tq = await query(sql, values);
|
|
99
|
-
|
|
100
|
-
return tq.rows;
|
|
101
|
-
};
|
|
102
|
-
/**
|
|
103
|
-
*
|
|
104
|
-
* @param v
|
|
105
|
-
* @returns {boolean}
|
|
106
|
-
*/
|
|
107
|
-
// TODO Utility function - needs ti be moved out this module
|
|
108
|
-
/**
|
|
109
|
-
* @param {object} v
|
|
110
|
-
* @returns {boolean}
|
|
111
|
-
*/
|
|
112
|
-
const reprAsJson = (v) =>
|
|
113
|
-
typeof v === "object" && v !== null && !(v instanceof Date);
|
|
114
|
-
/**
|
|
115
|
-
* @param {object[]} opts
|
|
116
|
-
* @param {*} opts.k
|
|
117
|
-
* @param {object} opts.v
|
|
118
|
-
* @returns {object}
|
|
119
|
-
*/
|
|
120
|
-
const mkVal = ([k, v]) => (reprAsJson(v) ? JSON.stringify(v) : v);
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Drop unique constraint
|
|
124
|
-
* @param {string} tbl - table name
|
|
125
|
-
* @param {object[]} obj - list of column=value pairs
|
|
126
|
-
* @param {number} id - primary key column value
|
|
127
|
-
* @returns {Promise<void>} no results
|
|
128
|
-
*/
|
|
129
|
-
const update = async (tbl, obj, id) => {
|
|
130
|
-
const kvs = Object.entries(obj);
|
|
131
|
-
const assigns = kvs.map(([k, v], ix) => `"${sqlsanitize(k)}"=?`).join();
|
|
132
|
-
let valList = kvs.map(mkVal);
|
|
133
|
-
valList.push(id);
|
|
134
|
-
const q = `update "${sqlsanitize(tbl)}" set ${assigns} where id=?`;
|
|
135
|
-
await query(q, valList);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Delete rows in table
|
|
140
|
-
* @param {string} tbl - table name
|
|
141
|
-
* @param {object} whereObj - where object
|
|
142
|
-
* @returns {Promise<void>} result of delete execution
|
|
143
|
-
*/
|
|
144
|
-
const deleteWhere = async (tbl, whereObj) => {
|
|
145
|
-
const { where, values } = mkWhere(whereObj, true);
|
|
146
|
-
const sql = `delete FROM "${sqlsanitize(tbl)}" ${where}`;
|
|
147
|
-
|
|
148
|
-
const tq = await query(sql, values);
|
|
149
|
-
};
|
|
150
|
-
/**
|
|
151
|
-
* Insert rows into table
|
|
152
|
-
* @param {string} tbl - table name
|
|
153
|
-
* @param {object} obj - columns names and data
|
|
154
|
-
* @param {object} [opts = {}] - columns attributes
|
|
155
|
-
* @returns {Promise<string>} returns id.
|
|
156
|
-
*/
|
|
157
|
-
const insert = async (tbl, obj, opts = {}) => {
|
|
158
|
-
const kvs = Object.entries(obj);
|
|
159
|
-
const fnameList = kvs.map(([k, v]) => `"${sqlsanitize(k)}"`).join();
|
|
160
|
-
const valPosList = kvs
|
|
161
|
-
.map(([k, v], ix) =>
|
|
162
|
-
v && v.next_version_by_id
|
|
163
|
-
? `coalesce((select max(_version) from "${sqlsanitize(
|
|
164
|
-
tbl
|
|
165
|
-
)}" where id=${+v.next_version_by_id}), 0)+1`
|
|
166
|
-
: reprAsJson(v)
|
|
167
|
-
? "json(?)"
|
|
168
|
-
: "?"
|
|
169
|
-
)
|
|
170
|
-
.join();
|
|
171
|
-
const valList = kvs
|
|
172
|
-
.filter(([k, v]) => !(v && v.next_version_by_id))
|
|
173
|
-
.map(mkVal);
|
|
174
|
-
const sql = `insert into "${sqlsanitize(
|
|
175
|
-
tbl
|
|
176
|
-
)}"(${fnameList}) values(${valPosList})`;
|
|
177
|
-
|
|
178
|
-
await query(sql, valList);
|
|
179
|
-
if (opts.noid) return;
|
|
180
|
-
// TBD Support of primary key column different from id
|
|
181
|
-
const ids = await query("SELECT last_insert_rowid() as id");
|
|
182
|
-
return ids.rows[0].id;
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Select one record
|
|
187
|
-
* @param {string} tbl - table name
|
|
188
|
-
* @param {object} where - where object
|
|
189
|
-
* @throws {Error}
|
|
190
|
-
* @returns {Promise<object>} return first record from sql result
|
|
191
|
-
*/
|
|
192
|
-
const selectOne = async (tbl, where) => {
|
|
193
|
-
const rows = await select(tbl, where);
|
|
194
|
-
if (rows.length === 0) {
|
|
195
|
-
const w = mkWhere(where, true);
|
|
196
|
-
throw new Error(`no ${tbl} ${w.where} are ${w.values}`);
|
|
197
|
-
} else return rows[0];
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Select one record or null if no records
|
|
202
|
-
* @param {string} tbl - table name
|
|
203
|
-
* @param {object} where - where object
|
|
204
|
-
* @returns {Promise<object>} - null if no record or first record data
|
|
205
|
-
*/
|
|
206
|
-
const selectMaybeOne = async (tbl, where) => {
|
|
207
|
-
const rows = await select(tbl, where);
|
|
208
|
-
if (rows.length === 0) return null;
|
|
209
|
-
else return rows[0];
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Get count of rows in table
|
|
214
|
-
* @param {string} tbl - table name
|
|
215
|
-
* @param {object} whereObj - where object
|
|
216
|
-
* @returns {Promise<number>} count of tables
|
|
217
|
-
*/
|
|
218
|
-
const count = async (tbl, whereObj) => {
|
|
219
|
-
const { where, values } = mkWhere(whereObj, true);
|
|
220
|
-
const sql = `SELECT COUNT(*) FROM "${sqlsanitize(tbl)}" ${where}`;
|
|
221
|
-
const tq = await query(sql, values);
|
|
222
|
-
return parseInt(tq.rows[0]["COUNT(*)"]);
|
|
223
|
-
};
|
|
224
|
-
/**
|
|
225
|
-
* Get version of PostgreSQL
|
|
226
|
-
* @returns {Promise<string>} returns version
|
|
227
|
-
*/
|
|
228
|
-
const getVersion = async () => {
|
|
229
|
-
const sql = `SELECT sqlite_version();`;
|
|
230
|
-
sql_log(sql);
|
|
231
|
-
const tq = await query(sql);
|
|
232
|
-
return tq.rows[0]["sqlite_version()"];
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Reset DB Schema using drop schema and recreate it.
|
|
237
|
-
* Attention! You will lost data after call this function!
|
|
238
|
-
* @returns {Promise<void>} no result
|
|
239
|
-
*/
|
|
240
|
-
const drop_reset_schema = async () => {
|
|
241
|
-
await sqliteDatabase.close();
|
|
242
|
-
await fs.unlink(current_filepath);
|
|
243
|
-
sqliteDatabase = new sqlite3.Database(current_filepath);
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Add unique constraint
|
|
248
|
-
* @param {string} table_name - table name
|
|
249
|
-
* @param {string[]} field_names - list of columns (members of constraint)
|
|
250
|
-
* @returns {Promise<void>} no result
|
|
251
|
-
*/
|
|
252
|
-
const add_unique_constraint = async (table_name, field_names) => {
|
|
253
|
-
const sql = `create unique index ${sqlsanitize(
|
|
254
|
-
table_name
|
|
255
|
-
)}_${field_names
|
|
256
|
-
.map((f) => sqlsanitize(f))
|
|
257
|
-
.join("_")}_unique on "${sqlsanitize(table_name)}"(${field_names
|
|
258
|
-
.map((f) => `"${sqlsanitize(f)}"`)
|
|
259
|
-
.join(",")});`;
|
|
260
|
-
sql_log(sql);
|
|
261
|
-
await query(sql);
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Drop unique constraint
|
|
266
|
-
* @param {string} table_name - table name
|
|
267
|
-
* @param {string[]} field_names - list of columns (members of constraint)
|
|
268
|
-
* @returns {Promise<void>} no results
|
|
269
|
-
*/
|
|
270
|
-
const drop_unique_constraint = async (table_name, field_names) => {
|
|
271
|
-
const sql = `drop index ${sqlsanitize(table_name)}_${field_names
|
|
272
|
-
.map((f) => sqlsanitize(f))
|
|
273
|
-
.join("_")}_unique;`;
|
|
274
|
-
sql_log(sql);
|
|
275
|
-
await query(sql);
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
module.exports = {
|
|
279
|
-
sql_log,
|
|
280
|
-
set_sql_logging,
|
|
281
|
-
get_sql_logging,
|
|
282
|
-
sqliteDatabase,
|
|
283
|
-
changeConnection,
|
|
284
|
-
query,
|
|
285
|
-
select,
|
|
286
|
-
selectOne,
|
|
287
|
-
selectMaybeOne,
|
|
288
|
-
insert,
|
|
289
|
-
count,
|
|
290
|
-
close,
|
|
291
|
-
drop_reset_schema,
|
|
292
|
-
update,
|
|
293
|
-
deleteWhere,
|
|
294
|
-
add_unique_constraint,
|
|
295
|
-
drop_unique_constraint,
|
|
296
|
-
getVersion,
|
|
297
|
-
};
|
package/db/tenants.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @category saltcorn-data
|
|
3
|
-
* @module db/tenants
|
|
4
|
-
* @subcategory db
|
|
5
|
-
*/
|
|
6
|
-
const { getConnectObject } = require("./connect");
|
|
7
|
-
|
|
8
|
-
var connectObj = getConnectObject();
|
|
9
|
-
module.exports = connectObj.multi_tenant
|
|
10
|
-
? require("./multi-tenant")(connectObj)
|
|
11
|
-
: require("./single-tenant")(connectObj);
|
|
12
|
-
|