orange-orm 4.8.0 → 4.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.browser.mjs +4355 -3529
- package/dist/index.mjs +5185 -3581
- package/docs/changelog.md +7 -1
- package/package.json +1 -1
- package/src/applyPatch.js +67 -45
- package/src/bunPg/newTransaction.js +18 -0
- package/src/bunPg/wrapCommand.js +148 -0
- package/src/bunSqlite/newTransaction.js +18 -0
- package/src/bunSqlite/wrapCommand.js +30 -0
- package/src/bunSqlite/wrapQuery.js +1 -1
- package/src/d1/newTransaction.js +18 -0
- package/src/d1/wrapCommand.js +34 -0
- package/src/mssql/newTransaction.js +19 -0
- package/src/mssql/wrapCommand.js +129 -0
- package/src/mySql/newTransaction.js +18 -0
- package/src/mySql/wrapCommand.js +22 -0
- package/src/nodeSqlite/newTransaction.js +18 -0
- package/src/nodeSqlite/wrapCommand.js +34 -0
- package/src/oracle/newTransaction.js +18 -0
- package/src/oracle/wrapCommand.js +37 -0
- package/src/patchTable.js +111 -17
- package/src/pg/newTransaction.js +18 -0
- package/src/pg/wrapCommand.js +31 -0
- package/src/pglite/newTransaction.js +18 -0
- package/src/pglite/wrapCommand.js +30 -0
- package/src/sap/newTransaction.js +18 -0
- package/src/sqlite3/newTransaction.js +18 -0
- package/src/sqlite3/wrapCommand.js +23 -0
- package/src/table/commands/delete/newSingleCommand.js +3 -3
- package/src/table/commands/delete/singleCommand/newSingleCommandCore.js +112 -3
- package/src/table/commands/newDeleteCommand.js +3 -3
- package/src/table/commands/newRow.js +2 -2
- package/src/table/commands/newUpdateCommand.js +52 -2
- package/src/table/commands/newUpdateCommandCore.js +307 -4
- package/src/table/executeQueries/executeChanges.js +3 -3
- package/src/table/executeQueries/executeCommand.js +8 -0
- package/src/table/executeQueries/negotiateNullParams.js +26 -0
- package/src/table/executeQueries/resolveExecuteCommand.js +28 -0
- package/src/table/executeQueries/resolveExecuteQuery.js +1 -23
- package/src/table/isJsonUpdateSupported.js +5 -0
- package/src/table/resultToRows/decodeDbRow.js +13 -7
- package/src/table/resultToRows/delete.js +43 -2
- package/src/table/resultToRows/newDecodeDbRow.js +1 -7
- package/src/table.js +62 -0
- package/src/tedious/newTransaction.js +18 -0
- package/src/tedious/wrapCommand.js +121 -0
- package/src/validateDeleteAllowed.js +27 -10
- package/src/patchRow.js +0 -13
- package/src/table/insertDefault.js +0 -88
- package/src/validateDeleteConflict.js +0 -98
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const getSessionSingleton = require('../getSessionSingleton');
|
|
2
|
+
const negotiateNullParams = require('./negotiateNullParams');
|
|
2
3
|
|
|
3
4
|
function resolveExecuteQuery(context, query) {
|
|
4
5
|
return resolve;
|
|
@@ -22,29 +23,6 @@ function resolveExecuteQuery(context, query) {
|
|
|
22
23
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
function negotiateNullParams(query) {
|
|
26
|
-
if (query && query.parameters && query.parameters.length > 0 && (query.parameters.filter(x => x === null || x === undefined).length > 0)) {
|
|
27
|
-
var splitted = query.sql().split('?');
|
|
28
|
-
var sql = '';
|
|
29
|
-
var parameters = [];
|
|
30
|
-
var lastIndex = splitted.length - 1;
|
|
31
|
-
for (var i = 0; i < lastIndex; i++) {
|
|
32
|
-
if (query.parameters[i] === null || query.parameters[i] === undefined)
|
|
33
|
-
sql += splitted[i] + 'null';
|
|
34
|
-
else {
|
|
35
|
-
sql += splitted[i] + '?';
|
|
36
|
-
parameters.push(query.parameters[i]);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
sql += splitted[lastIndex];
|
|
40
|
-
return {
|
|
41
|
-
sql: () => sql,
|
|
42
|
-
parameters
|
|
43
|
-
};
|
|
44
26
|
|
|
45
|
-
}
|
|
46
|
-
else
|
|
47
|
-
return query;
|
|
48
|
-
}
|
|
49
27
|
|
|
50
28
|
module.exports = resolveExecuteQuery;
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
var newDecodeDbRow = require('./newDecodeDbRow');
|
|
2
2
|
|
|
3
3
|
function decodeDbRow(context, span, table, dbRow, shouldValidate, isInsert) {
|
|
4
|
-
var
|
|
4
|
+
var decodeCache = span._decodeDbRowCache;
|
|
5
|
+
if (!decodeCache) {
|
|
6
|
+
decodeCache = {};
|
|
7
|
+
Object.defineProperty(span, '_decodeDbRowCache', {
|
|
8
|
+
enumerable: false,
|
|
9
|
+
get: function() {
|
|
10
|
+
return decodeCache;
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
var cacheKey = (shouldValidate ? 'v' : 'nv') + (isInsert ? ':i' : ':u');
|
|
15
|
+
var decode = decodeCache[cacheKey];
|
|
5
16
|
if (!decode) {
|
|
6
17
|
let aliases = new Set();
|
|
7
18
|
if (span.columns)
|
|
@@ -12,12 +23,7 @@ function decodeDbRow(context, span, table, dbRow, shouldValidate, isInsert) {
|
|
|
12
23
|
if (aliases.size === 0)
|
|
13
24
|
aliases = undefined;
|
|
14
25
|
decode = newDecodeDbRow(table, dbRow, aliases, shouldValidate, isInsert);
|
|
15
|
-
|
|
16
|
-
enumerable: false,
|
|
17
|
-
get: function() {
|
|
18
|
-
return decode;
|
|
19
|
-
},
|
|
20
|
-
});
|
|
26
|
+
decodeCache[cacheKey] = decode;
|
|
21
27
|
}
|
|
22
28
|
return decode(context, dbRow);
|
|
23
29
|
}
|
|
@@ -14,11 +14,25 @@ function _delete(context, row, strategy, table) {
|
|
|
14
14
|
args.push(row[primary.alias]);
|
|
15
15
|
});
|
|
16
16
|
var filter = newPrimaryKeyFilter.apply(null, args);
|
|
17
|
-
var
|
|
17
|
+
var concurrencyState = row._concurrencyState;
|
|
18
|
+
delete row._concurrencyState;
|
|
19
|
+
var cmds = newDeleteCommand(context, [], table, filter, strategy, relations, concurrencyState);
|
|
18
20
|
cmds.forEach(function(cmd) {
|
|
19
21
|
pushCommand(context, cmd);
|
|
20
22
|
});
|
|
21
23
|
var cmd = cmds[0];
|
|
24
|
+
var concurrencySummary = summarizeConcurrency(concurrencyState);
|
|
25
|
+
if (concurrencySummary.hasConcurrency) {
|
|
26
|
+
var deleteCmd = cmds[cmds.length - 1];
|
|
27
|
+
deleteCmd.onResult = function(result) {
|
|
28
|
+
var rowCount = extractRowCount(result);
|
|
29
|
+
if (rowCount === undefined)
|
|
30
|
+
return;
|
|
31
|
+
if (rowCount === 0 && concurrencySummary.hasOptimistic) {
|
|
32
|
+
throw new Error('The row was changed by another user.');
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
22
36
|
if (table._emitChanged.callbacks.length > 0) {
|
|
23
37
|
cmd.disallowCompress = true;
|
|
24
38
|
var dto = createDto(table, row);
|
|
@@ -28,4 +42,31 @@ function _delete(context, row, strategy, table) {
|
|
|
28
42
|
|
|
29
43
|
}
|
|
30
44
|
|
|
31
|
-
|
|
45
|
+
function summarizeConcurrency(concurrencyState) {
|
|
46
|
+
const summary = { hasConcurrency: false, hasOptimistic: false };
|
|
47
|
+
if (!concurrencyState || !concurrencyState.columns)
|
|
48
|
+
return summary;
|
|
49
|
+
for (let name in concurrencyState.columns) {
|
|
50
|
+
const state = concurrencyState.columns[name];
|
|
51
|
+
if (!state)
|
|
52
|
+
continue;
|
|
53
|
+
const strategy = state.concurrency || 'optimistic';
|
|
54
|
+
if (strategy === 'overwrite')
|
|
55
|
+
continue;
|
|
56
|
+
summary.hasConcurrency = true;
|
|
57
|
+
if (strategy === 'optimistic')
|
|
58
|
+
summary.hasOptimistic = true;
|
|
59
|
+
}
|
|
60
|
+
return summary;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function extractRowCount(result) {
|
|
64
|
+
if (Array.isArray(result) && typeof result[0].rowsAffected === 'number')
|
|
65
|
+
return result[0].rowsAffected;
|
|
66
|
+
if (!result || typeof result !== 'object')
|
|
67
|
+
return;
|
|
68
|
+
if (typeof result.rowsAffected === 'number')
|
|
69
|
+
return result.rowsAffected;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = _delete;
|
|
@@ -7,7 +7,6 @@ let _delete = require('./delete');
|
|
|
7
7
|
let newObject = require('../../newObject');
|
|
8
8
|
let toDto = require('./toDto');
|
|
9
9
|
let createDto = require('./toDto/createDto');
|
|
10
|
-
let patchRow = require('../../patchRow');
|
|
11
10
|
let onChange = require('@lroal/on-change');
|
|
12
11
|
let flags = require('../../flags');
|
|
13
12
|
let tryGetSessionContext = require('../tryGetSessionContext');
|
|
@@ -78,7 +77,7 @@ function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert)
|
|
|
78
77
|
return negotiateNull(this[intName]);
|
|
79
78
|
},
|
|
80
79
|
set: function(value) {
|
|
81
|
-
if (column.onChange && (this[intName] !== null && this[intName] !== undefined) && typeof value === 'object') {
|
|
80
|
+
if (column.onChange && (this[intName] !== null && this[intName] !== undefined) && value && typeof value === 'object') {
|
|
82
81
|
if (this[intName] === onChange.target(value))
|
|
83
82
|
return;
|
|
84
83
|
this._proxies[name] = column.onChange(value, () => {
|
|
@@ -198,11 +197,6 @@ function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert)
|
|
|
198
197
|
|
|
199
198
|
Row.prototype.deleteCascade = Row.prototype.cascadeDelete;
|
|
200
199
|
|
|
201
|
-
Row.prototype.patch = async function(patches, options) {
|
|
202
|
-
await patchRow(this._context, table, this, patches, options);
|
|
203
|
-
return this;
|
|
204
|
-
};
|
|
205
|
-
|
|
206
200
|
function decodeDbRow(context, row) {
|
|
207
201
|
for (let i = 0; i < numberOfColumns; i++) {
|
|
208
202
|
let index = offset + i;
|
package/src/table.js
CHANGED
|
@@ -17,6 +17,8 @@ const cascadeDelete = require('./table/cascadeDelete');
|
|
|
17
17
|
const patchTable = require('./patchTable');
|
|
18
18
|
const newEmitEvent = require('./emitEvent');
|
|
19
19
|
const hostLocal = require('./hostLocal');
|
|
20
|
+
const getSessionSingleton = require('./table/getSessionSingleton');
|
|
21
|
+
const isJsonUpdateSupported = require('./table/isJsonUpdateSupported');
|
|
20
22
|
// const getTSDefinition = require('./getTSDefinition'); //todo: unused ?
|
|
21
23
|
const where = require('./table/where');
|
|
22
24
|
const aggregate = require('./table/aggregate');
|
|
@@ -141,6 +143,55 @@ function _new(tableName) {
|
|
|
141
143
|
return insert.apply(null, args);
|
|
142
144
|
};
|
|
143
145
|
|
|
146
|
+
table.updateWithConcurrency = function(context, options, row, property, value, oldValue, patchInfo) {
|
|
147
|
+
options = options || {};
|
|
148
|
+
const columnOptions = inferColumnOptions(options, property);
|
|
149
|
+
const concurrency = columnOptions.concurrency || 'optimistic';
|
|
150
|
+
const column = table[property];
|
|
151
|
+
|
|
152
|
+
if (patchInfo && column && column.tsType === 'JSONColumn' && Array.isArray(patchInfo.path) && patchInfo.path.length > 1) {
|
|
153
|
+
const engine = getSessionSingleton(context, 'engine');
|
|
154
|
+
if (isJsonUpdateSupported(engine)) {
|
|
155
|
+
const jsonPath = patchInfo.path.slice(1);
|
|
156
|
+
const jsonUpdateState = row._jsonUpdateState || {};
|
|
157
|
+
const columnState = jsonUpdateState[property] || { patches: [] };
|
|
158
|
+
columnState.patches.push({
|
|
159
|
+
path: jsonPath,
|
|
160
|
+
op: patchInfo.op,
|
|
161
|
+
value: patchInfo.value,
|
|
162
|
+
oldValue: patchInfo.oldValue
|
|
163
|
+
});
|
|
164
|
+
jsonUpdateState[property] = columnState;
|
|
165
|
+
row._jsonUpdateState = jsonUpdateState;
|
|
166
|
+
if (concurrency !== 'overwrite') {
|
|
167
|
+
const state = row._concurrencyState || { columns: {} };
|
|
168
|
+
const columnConcurrency = state.columns[property] || {};
|
|
169
|
+
columnConcurrency.concurrency = concurrency;
|
|
170
|
+
columnConcurrency.paths = columnConcurrency.paths || [];
|
|
171
|
+
columnConcurrency.paths.push({
|
|
172
|
+
path: jsonPath,
|
|
173
|
+
oldValue: patchInfo.oldValue
|
|
174
|
+
});
|
|
175
|
+
delete columnConcurrency.oldValue;
|
|
176
|
+
state.columns[property] = columnConcurrency;
|
|
177
|
+
row._concurrencyState = state;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else if (concurrency !== 'overwrite') {
|
|
181
|
+
const state = row._concurrencyState || { columns: {} };
|
|
182
|
+
const fullOldValue = Object.prototype.hasOwnProperty.call(patchInfo, 'fullOldValue') ? patchInfo.fullOldValue : oldValue;
|
|
183
|
+
state.columns[property] = { oldValue: fullOldValue, concurrency };
|
|
184
|
+
row._concurrencyState = state;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else if (concurrency !== 'overwrite') {
|
|
188
|
+
const state = row._concurrencyState || { columns: {} };
|
|
189
|
+
state.columns[property] = { oldValue, concurrency };
|
|
190
|
+
row._concurrencyState = state;
|
|
191
|
+
}
|
|
192
|
+
row[property] = value;
|
|
193
|
+
};
|
|
194
|
+
|
|
144
195
|
table.delete = _delete.bind(null, table);
|
|
145
196
|
table.cascadeDelete = function(context, ...rest) {
|
|
146
197
|
const args = [context, table, ...rest];
|
|
@@ -174,4 +225,15 @@ function _new(tableName) {
|
|
|
174
225
|
return table;
|
|
175
226
|
}
|
|
176
227
|
|
|
228
|
+
function inferColumnOptions(defaults, property) {
|
|
229
|
+
const parent = {};
|
|
230
|
+
if (!defaults)
|
|
231
|
+
return parent;
|
|
232
|
+
if ('readonly' in defaults)
|
|
233
|
+
parent.readonly = defaults.readonly;
|
|
234
|
+
if ('concurrency' in defaults)
|
|
235
|
+
parent.concurrency = defaults.concurrency;
|
|
236
|
+
return { ...parent, ...(defaults[property] || {}) };
|
|
237
|
+
}
|
|
238
|
+
|
|
177
239
|
module.exports = _new;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var wrapQuery = require('./wrapQuery');
|
|
2
|
+
var wrapCommand = require('./wrapCommand');
|
|
2
3
|
var encodeBoolean = require('./encodeBoolean');
|
|
3
4
|
var deleteFromSql = require('./deleteFromSql');
|
|
4
5
|
var selectForUpdateSql = require('./selectForUpdateSql');
|
|
@@ -65,6 +66,22 @@ function newResolveTransaction(domain, pool, { readonly = false } = {}) {
|
|
|
65
66
|
callback(e);
|
|
66
67
|
}
|
|
67
68
|
});
|
|
69
|
+
},
|
|
70
|
+
executeCommand: function(query, callback) {
|
|
71
|
+
pool.connect((err, client, done) => {
|
|
72
|
+
if (err) {
|
|
73
|
+
return callback(err);
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
wrapCommand(domain, client)(query, (err, res) => {
|
|
77
|
+
done();
|
|
78
|
+
callback(err, res);
|
|
79
|
+
});
|
|
80
|
+
} catch (e) {
|
|
81
|
+
done();
|
|
82
|
+
callback(e);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
68
85
|
}
|
|
69
86
|
};
|
|
70
87
|
domain.rdb = rdb;
|
|
@@ -81,6 +98,7 @@ function newResolveTransaction(domain, pool, { readonly = false } = {}) {
|
|
|
81
98
|
return;
|
|
82
99
|
}
|
|
83
100
|
client.executeQuery = wrapQuery(domain, client);
|
|
101
|
+
client.executeCommand = wrapCommand(domain, client);
|
|
84
102
|
rdb.dbClient = client;
|
|
85
103
|
rdb.dbClientDone = done;
|
|
86
104
|
domain.rdb = rdb;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
var log = require('../table/log');
|
|
2
|
+
|
|
3
|
+
function wrapCommand(_context, connection) {
|
|
4
|
+
let CachedRequest = null;
|
|
5
|
+
let CachedTypes = null;
|
|
6
|
+
|
|
7
|
+
return runQuery;
|
|
8
|
+
|
|
9
|
+
function runQuery(query, onCompleted) {
|
|
10
|
+
if (!CachedRequest || !CachedTypes) {
|
|
11
|
+
import('tedious')
|
|
12
|
+
.then(({ Request, TYPES }) => {
|
|
13
|
+
CachedRequest = Request;
|
|
14
|
+
CachedTypes = TYPES;
|
|
15
|
+
doQuery(query, onCompleted);
|
|
16
|
+
})
|
|
17
|
+
.catch((err) => onCompleted(extractError(err), { rowsAffected: 0 }));
|
|
18
|
+
} else {
|
|
19
|
+
doQuery(query, onCompleted);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function doQuery(query, onCompleted) {
|
|
24
|
+
log.emitQuery({ sql: query.sql(), parameters: query.parameters });
|
|
25
|
+
const sql = replaceParamChar(query.sql(), query.parameters);
|
|
26
|
+
|
|
27
|
+
if (sql.length < 18 && query.parameters.length === 0) {
|
|
28
|
+
if (sql === 'BEGIN TRANSACTION') {
|
|
29
|
+
connection.beginTransaction((err) => {
|
|
30
|
+
if (err) return onCompleted(extractError(err), { rowsAffected: 0 });
|
|
31
|
+
return onCompleted(null, { rowsAffected: 0 });
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
} else if (sql === 'COMMIT') {
|
|
35
|
+
connection.commitTransaction((err) => {
|
|
36
|
+
if (err) return onCompleted(extractError(err), { rowsAffected: 0 });
|
|
37
|
+
return onCompleted(null, { rowsAffected: 0 });
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
} else if (sql === 'ROLLBACK') {
|
|
41
|
+
connection.rollbackTransaction((err) => {
|
|
42
|
+
if (err) return onCompleted(extractError(err), { rowsAffected: 0 });
|
|
43
|
+
return onCompleted(null, { rowsAffected: 0 });
|
|
44
|
+
});
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let affectedRows = 0;
|
|
50
|
+
|
|
51
|
+
var request = new CachedRequest(sql, onInnerCompleted);
|
|
52
|
+
addParameters(request, query.parameters, CachedTypes);
|
|
53
|
+
|
|
54
|
+
request.on('doneInProc', (rowCount) => {
|
|
55
|
+
if (typeof rowCount === 'number') affectedRows += rowCount;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
request.on('doneProc', (rowCount) => {
|
|
59
|
+
if (typeof rowCount === 'number') affectedRows += rowCount;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
request.on('done', (rowCount) => {
|
|
63
|
+
if (typeof rowCount === 'number') affectedRows += rowCount;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
connection.execSql(request);
|
|
67
|
+
|
|
68
|
+
function onInnerCompleted(err) {
|
|
69
|
+
if (err) return onCompleted(extractError(err), { rowsAffected: 0 });
|
|
70
|
+
return onCompleted(null, { rowsAffected: affectedRows });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function extractError(e) {
|
|
76
|
+
if (e && e.errors) {
|
|
77
|
+
return e.errors[0];
|
|
78
|
+
} else {
|
|
79
|
+
return e;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function replaceParamChar(sql, params) {
|
|
84
|
+
if (params.length === 0) return sql;
|
|
85
|
+
var splitted = sql.split('?');
|
|
86
|
+
sql = '';
|
|
87
|
+
var lastIndex = splitted.length - 1;
|
|
88
|
+
for (var i = 0; i < lastIndex; i++) {
|
|
89
|
+
sql += splitted[i] + '@' + i;
|
|
90
|
+
}
|
|
91
|
+
sql += splitted[lastIndex];
|
|
92
|
+
return sql;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function addParameters(request, params, TYPES) {
|
|
96
|
+
const res = [];
|
|
97
|
+
for (let i = 0; i < params.length; i++) {
|
|
98
|
+
const p = [`${i}`, toType(params[i]), params[i]];
|
|
99
|
+
request.addParameter.apply(request, p);
|
|
100
|
+
res.push(p);
|
|
101
|
+
}
|
|
102
|
+
return res;
|
|
103
|
+
|
|
104
|
+
function toType(p) {
|
|
105
|
+
if (typeof p === 'string') return TYPES.VarChar;
|
|
106
|
+
else if (Number.isInteger(p)) {
|
|
107
|
+
if (p >= -2147483648 && p <= 2147483647) {
|
|
108
|
+
return TYPES.Int;
|
|
109
|
+
} else {
|
|
110
|
+
return TYPES.BigInt;
|
|
111
|
+
}
|
|
112
|
+
} else if (typeof p === 'number') return TYPES.Money;
|
|
113
|
+
else if (p instanceof Date && !isNaN(p)) return TYPES.Date;
|
|
114
|
+
else if (Array.isArray(p)) return TYPES.NVarChar;
|
|
115
|
+
else if (Buffer.isBuffer(p)) return TYPES.VarBinary;
|
|
116
|
+
else if (typeof p === 'object' && p instanceof Object) return TYPES.NVarChar;
|
|
117
|
+
else throw new Error('Unknown data type');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = wrapCommand;
|
|
@@ -5,12 +5,14 @@ async function validateDeleteAllowed({ row, options, table }) {
|
|
|
5
5
|
e.status = 405;
|
|
6
6
|
throw e;
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
if (!hasReadonlyTrue(options))
|
|
9
|
+
return;
|
|
10
|
+
for (let p in options) {
|
|
11
|
+
if (isManyRelation(p, table)) {
|
|
12
12
|
const childTable = table[p]._relation.childTable;
|
|
13
13
|
const childOptions = inferOptions(options, p);
|
|
14
|
+
if (!hasReadonlyTrue(childOptions))
|
|
15
|
+
continue;
|
|
14
16
|
const children = await row[p];
|
|
15
17
|
for (let i = 0; i < children.length; i++) {
|
|
16
18
|
const childRow = children[i];
|
|
@@ -19,22 +21,22 @@ async function validateDeleteAllowed({ row, options, table }) {
|
|
|
19
21
|
}
|
|
20
22
|
else if (isOneRelation(p, table)) {
|
|
21
23
|
const childOptions = inferOptions(options, p);
|
|
24
|
+
if (!hasReadonlyTrue(childOptions))
|
|
25
|
+
continue;
|
|
22
26
|
const childTable = table[p]._relation.childTable;
|
|
23
27
|
let childRow = await row[p];
|
|
24
28
|
await validateDeleteAllowed({ row: childRow, options: childOptions, table: childTable });
|
|
25
29
|
}
|
|
30
|
+
}
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
function isColumn(name, table) {
|
|
29
|
-
return table[name] && table[name].equal;
|
|
30
|
-
}
|
|
31
33
|
|
|
32
34
|
function isManyRelation(name, table) {
|
|
33
|
-
return table[name] && table[name]._relation.isMany;
|
|
35
|
+
return table[name] && table[name]._relation && table[name]._relation.isMany;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
function isOneRelation(name, table) {
|
|
37
|
-
return table[name] && table[name]._relation.isOne;
|
|
39
|
+
return table[name] && table[name]._relation && table[name]._relation.isOne;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
function inferOptions(defaults, property) {
|
|
@@ -46,4 +48,19 @@ function inferOptions(defaults, property) {
|
|
|
46
48
|
return {...parent, ...(defaults[property] || {})};
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
function hasReadonlyTrue(options) {
|
|
52
|
+
if (!options || options !== Object(options))
|
|
53
|
+
return false;
|
|
54
|
+
if (options.readonly === true)
|
|
55
|
+
return true;
|
|
56
|
+
for (let p in options) {
|
|
57
|
+
const value = options[p];
|
|
58
|
+
if (!value || value !== Object(value))
|
|
59
|
+
continue;
|
|
60
|
+
if (hasReadonlyTrue(value))
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = validateDeleteAllowed;
|
package/src/patchRow.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
let patchTable = require('./patchTable');
|
|
2
|
-
|
|
3
|
-
function patchRow(context, table, row, patches, options) {
|
|
4
|
-
patches = JSON.parse(JSON.stringify(patches));
|
|
5
|
-
let pkName = table._primaryColumns[0].alias;
|
|
6
|
-
let id = row[pkName];
|
|
7
|
-
for (let i = 0; i < patches.length; i++) {
|
|
8
|
-
patches[i].path = '/' + id + patches[i].path;
|
|
9
|
-
}
|
|
10
|
-
return patchTable(context, table, patches, options);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
module.exports = patchRow;
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
let getSessionContext = require('./getSessionContext');
|
|
2
|
-
let executeQueries = require('./executeQueries');
|
|
3
|
-
let newRow = require('./commands/newRow');
|
|
4
|
-
let newInsertCommand = require('./commands/newInsertCommand');
|
|
5
|
-
let newInsertCommandCore = require('./commands/newInsertCommandCore');
|
|
6
|
-
let newGetLastInsertedCommand = require('./commands/newGetLastInsertedCommand');
|
|
7
|
-
let pushCommand = require('./commands/pushCommand');
|
|
8
|
-
|
|
9
|
-
function insert({table, options}, arg) {
|
|
10
|
-
if (Array.isArray(arg)) {
|
|
11
|
-
let all = [];
|
|
12
|
-
for (let i = 0; i < arg.length; i++) {
|
|
13
|
-
all.push(insert(table, arg[i]));
|
|
14
|
-
}
|
|
15
|
-
return Promise.all(all);
|
|
16
|
-
}
|
|
17
|
-
let args = [table].slice.call(arguments);
|
|
18
|
-
let row = newRow.apply(null, args);
|
|
19
|
-
let hasPrimary = getHasPrimary(table, row);
|
|
20
|
-
if (hasPrimary)
|
|
21
|
-
row = table._cache.tryAdd(row);
|
|
22
|
-
let cmd = newInsertCommand(newInsertCommandCore, table, row, options);
|
|
23
|
-
|
|
24
|
-
pushCommand(cmd);
|
|
25
|
-
expand(table, row);
|
|
26
|
-
Object.defineProperty(row, 'then', {
|
|
27
|
-
value: then,
|
|
28
|
-
writable: true,
|
|
29
|
-
enumerable: false,
|
|
30
|
-
configurable: true
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
let selectCmd;
|
|
34
|
-
if (getSessionContext().lastInsertedIsSeparate) {
|
|
35
|
-
selectCmd = newGetLastInsertedCommand(table, row, cmd);
|
|
36
|
-
pushCommand(selectCmd);
|
|
37
|
-
selectCmd.onResult = onResult;
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
cmd.onResult = onResult;
|
|
41
|
-
cmd.disallowCompress = true;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return row;
|
|
45
|
-
function then(fn,efn) {
|
|
46
|
-
delete row.then;
|
|
47
|
-
return executeQueries([]).then(() => fn(row), efn);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function onResult([result]) {
|
|
51
|
-
row.hydrate(result);
|
|
52
|
-
if (!hasPrimary)
|
|
53
|
-
row = table._cache.tryAdd(row);
|
|
54
|
-
table._cache.tryAdd(row);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function expand(table, row) {
|
|
59
|
-
let relationName;
|
|
60
|
-
let visitor = {};
|
|
61
|
-
visitor.visitJoin = function() { };
|
|
62
|
-
|
|
63
|
-
visitor.visitMany = function() {
|
|
64
|
-
row.expand(relationName);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
visitor.visitOne = function() {
|
|
68
|
-
row.expand(relationName);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
for (relationName in table._relations) {
|
|
72
|
-
let relation = table._relations[relationName];
|
|
73
|
-
relation.accept(visitor);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function getHasPrimary(table, row) {
|
|
79
|
-
for (let i = 0; i < table._primaryColumns.length; i++) {
|
|
80
|
-
let column = table._primaryColumns[i];
|
|
81
|
-
if (row[column.alias] === null)
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
return true;
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
module.exports = insert;
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/* eslint-disable */
|
|
3
|
-
const toCompareObject = require('./toCompareObject');
|
|
4
|
-
|
|
5
|
-
async function validateDeleteConflict({ row, oldValue, options, table }) {
|
|
6
|
-
for (let p in oldValue) {
|
|
7
|
-
if (isColumn(p, table)) {
|
|
8
|
-
const option = inferOptions(options, p);
|
|
9
|
-
let strategy = option.concurrency || 'optimistic';
|
|
10
|
-
if ((strategy === 'optimistic')) {
|
|
11
|
-
try {
|
|
12
|
-
const column = table[p];
|
|
13
|
-
if (column?.tsType === 'DateColumn') {
|
|
14
|
-
assertDatesEqual(oldValue[p], toCompareObject(row[p]));
|
|
15
|
-
}
|
|
16
|
-
else
|
|
17
|
-
assertDeepEqual(oldValue[p], toCompareObject(row[p]));
|
|
18
|
-
}
|
|
19
|
-
catch (e) {
|
|
20
|
-
throw new Error(`The field ${p} was changed by another user. Expected ${inspect(oldValue[p])}, but was ${inspect(row[p])}.`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
else if (isManyRelation(p, table)) {
|
|
25
|
-
const childTable = table[p]._relation.childTable;
|
|
26
|
-
for (let name in oldValue[p]) {
|
|
27
|
-
if (name === '__patchType')
|
|
28
|
-
continue;
|
|
29
|
-
let childRow = await childTable.tryGetById.apply(null, JSON.parse(name));
|
|
30
|
-
if (!childRow)
|
|
31
|
-
throw new Error(`${p} with id ${name} was deleted by another user`);
|
|
32
|
-
if (! await validateDeleteConflict({ row: childRow, oldValue: oldValue[p][name], options: inferOptions(options, p), table: childTable }))
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
else if (isOneRelation(p, table)) {
|
|
37
|
-
const childTable = table[p]._relation.childTable;
|
|
38
|
-
let childRow = await row[p];
|
|
39
|
-
if (!childRow)
|
|
40
|
-
throw new Error(`${p} was deleted by another user`);
|
|
41
|
-
if (! await validateDeleteConflict({ row: childRow, oldValue: oldValue[p], options: inferOptions(options, p), table: childTable }))
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function isColumn(name, table) {
|
|
50
|
-
return table[name] && table[name].equal;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function isManyRelation(name, table) {
|
|
54
|
-
return table[name] && table[name]._relation.isMany;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function isOneRelation(name, table) {
|
|
58
|
-
return table[name] && table[name]._relation.isOne;
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function inferOptions(defaults, property) {
|
|
63
|
-
const parent = {};
|
|
64
|
-
if ('readonly' in defaults)
|
|
65
|
-
parent.readonly = defaults.readonly;
|
|
66
|
-
if ('concurrency' in defaults)
|
|
67
|
-
parent.concurrency = defaults.concurrency;
|
|
68
|
-
return {...parent, ...(defaults[property] || {})};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function assertDatesEqual(date1, date2) {
|
|
72
|
-
if (date1 && date2) {
|
|
73
|
-
const parts1 = date1.split('T');
|
|
74
|
-
const time1parts = (parts1[1] || '').split(/[-+.]/);
|
|
75
|
-
const parts2 = date2.split('T');
|
|
76
|
-
const time2parts = (parts2[1] || '').split(/[-+.]/);
|
|
77
|
-
while (time1parts.length !== time2parts.length) {
|
|
78
|
-
if (time1parts.length > time2parts.length)
|
|
79
|
-
time1parts.pop();
|
|
80
|
-
else if (time1parts.length < time2parts.length)
|
|
81
|
-
time2parts.pop();
|
|
82
|
-
}
|
|
83
|
-
date1 = `${parts1[0]}T${time1parts[0]}`;
|
|
84
|
-
date2 = `${parts2[0]}T${time2parts[0]}`;
|
|
85
|
-
}
|
|
86
|
-
assertDeepEqual(date1, date2);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function assertDeepEqual(a, b) {
|
|
90
|
-
if (JSON.stringify(a) !== JSON.stringify(b))
|
|
91
|
-
throw new Error('A, b are not equal');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function inspect(obj) {
|
|
95
|
-
return JSON.stringify(obj, null, 2);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
module.exports = validateDeleteConflict;
|