orange-orm 5.3.6 → 5.4.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/dist/index.mjs CHANGED
@@ -270,6 +270,8 @@ export interface ${name}Strategy {
270
270
  offset?: number;
271
271
  orderBy?: Array<${orderByColumns(table)}> | ${orderByColumns(table)};
272
272
  where?: (table: ${name}TableBase) => RawFilter;
273
+ forUpdate?: boolean;
274
+ skipLocked?: boolean;
273
275
  }
274
276
 
275
277
  ${otherConcurrency}
@@ -1837,7 +1839,7 @@ function requireExecutePath () {
1837
1839
 
1838
1840
  async function replace(subject, strategy = { insertAndForget: true }) {
1839
1841
  validateStrategy(table, strategy);
1840
- const refinedStrategy = objectToStrategy(subject, {}, table);
1842
+ const refinedStrategy = withLockingStrategy(objectToStrategy(subject, {}, table), strategy);
1841
1843
  const JSONFilter2 = {
1842
1844
  path: 'getManyDto',
1843
1845
  args: [subject, refinedStrategy]
@@ -1854,7 +1856,7 @@ function requireExecutePath () {
1854
1856
 
1855
1857
  async function update(subject, whereStrategy, strategy = { insertAndForget: true }) {
1856
1858
  validateStrategy(table, strategy);
1857
- const refinedWhereStrategy = objectToStrategy(subject, whereStrategy, table);
1859
+ const refinedWhereStrategy = withLockingStrategy(objectToStrategy(subject, whereStrategy, table), strategy);
1858
1860
  const JSONFilter2 = {
1859
1861
  path: 'getManyDto',
1860
1862
  args: [null, refinedWhereStrategy]
@@ -1874,6 +1876,43 @@ function requireExecutePath () {
1874
1876
  return changed;
1875
1877
  }
1876
1878
 
1879
+ function withLockingStrategy(fetchStrategy, strategy) {
1880
+ const lockStrategy = extractLockingStrategy(strategy);
1881
+ if (!lockStrategy)
1882
+ return fetchStrategy;
1883
+ return mergeLockingStrategy(fetchStrategy, lockStrategy);
1884
+ }
1885
+
1886
+ function extractLockingStrategy(strategy) {
1887
+ if (!strategy || typeof strategy !== 'object')
1888
+ return;
1889
+ const result = {};
1890
+ if (strategy.forUpdate)
1891
+ result.forUpdate = strategy.forUpdate;
1892
+ if (strategy.skipLocked)
1893
+ result.skipLocked = strategy.skipLocked;
1894
+ for (let name in strategy) {
1895
+ if (name === 'where' || name === 'orderBy' || name === 'limit' || name === 'offset' || name === 'forUpdate' || name === 'skipLocked')
1896
+ continue;
1897
+ const child = extractLockingStrategy(strategy[name]);
1898
+ if (child)
1899
+ result[name] = child;
1900
+ }
1901
+ return Object.keys(result).length > 0 ? result : undefined;
1902
+ }
1903
+
1904
+ function mergeLockingStrategy(fetchStrategy, lockStrategy) {
1905
+ const result = { ...fetchStrategy };
1906
+ for (let name in lockStrategy) {
1907
+ const value = lockStrategy[name];
1908
+ if (name === 'forUpdate' || name === 'skipLocked')
1909
+ result[name] = value;
1910
+ else
1911
+ result[name] = mergeLockingStrategy(result[name] && typeof result[name] === 'object' ? result[name] : {}, value);
1912
+ }
1913
+ return result;
1914
+ }
1915
+
1877
1916
  function objectToStrategy(object, whereStrategy, table, strategy = {}) {
1878
1917
  strategy = { ...whereStrategy, ...strategy };
1879
1918
  if (Array.isArray(object)) {
@@ -2695,7 +2734,7 @@ function requireHostLocal () {
2695
2734
  || beforeCommit
2696
2735
  || afterCommit
2697
2736
  || afterRollback);
2698
- if (!hasTransactionHooks && readonlyOps.includes(body.path))
2737
+ if (!hasTransactionHooks && readonlyOps.includes(body.path) && !hasLockingStrategy(body))
2699
2738
  await db.transaction({ readonly: true }, fn);
2700
2739
  else {
2701
2740
  await db.transaction(async (context) => {
@@ -2729,6 +2768,24 @@ function requireHostLocal () {
2729
2768
  result = await executePath(context, options);
2730
2769
  }
2731
2770
  }
2771
+
2772
+ function hasLockingStrategy(body) {
2773
+ if (!body || !body.args)
2774
+ return false;
2775
+ return hasLockingStrategyCore(body.args[1]);
2776
+ }
2777
+
2778
+ function hasLockingStrategyCore(strategy) {
2779
+ if (!strategy || typeof strategy !== 'object')
2780
+ return false;
2781
+ if (strategy.forUpdate || strategy.skipLocked)
2782
+ return true;
2783
+ for (let name in strategy) {
2784
+ if (name !== 'where' && hasLockingStrategyCore(strategy[name]))
2785
+ return true;
2786
+ }
2787
+ return false;
2788
+ }
2732
2789
  async function query() {
2733
2790
  let args = arguments;
2734
2791
  let result;
@@ -3594,7 +3651,7 @@ function requireClient () {
3594
3651
  return false;
3595
3652
  if (Object.keys(value).length === 0)
3596
3653
  return true;
3597
- if ('where' in value || 'orderBy' in value || 'limit' in value || 'offset' in value)
3654
+ if ('where' in value || 'orderBy' in value || 'limit' in value || 'offset' in value || 'forUpdate' in value || 'skipLocked' in value)
3598
3655
  return true;
3599
3656
  for (let key in value) {
3600
3657
  const v = value[key];
@@ -3844,6 +3901,7 @@ function requireClient () {
3844
3901
 
3845
3902
  function proxifyArray(array, strategy, fast) {
3846
3903
  let _array = array;
3904
+ const storedStrategy = toStoredFetchStrategy(strategy);
3847
3905
  if (_reactive)
3848
3906
  array = _reactive(array);
3849
3907
  let handler = {
@@ -3871,17 +3929,17 @@ function requireClient () {
3871
3929
  };
3872
3930
 
3873
3931
  let watcher = onChange(array, () => {
3874
- rootMap.set(array, { json: cloneFromDb(array, fast), strategy, originalArray: [...array] });
3932
+ rootMap.set(array, { json: cloneFromDb(array, fast), strategy: storedStrategy, originalArray: [...array] });
3875
3933
  });
3876
3934
  let innerProxy = new Proxy(watcher, handler);
3877
- if (strategy !== undefined) {
3878
- const { limit, ...cleanStrategy } = { ...strategy };
3879
- fetchingStrategyMap.set(array, cleanStrategy);
3935
+ if (storedStrategy !== undefined) {
3936
+ fetchingStrategyMap.set(array, storedStrategy);
3880
3937
  }
3881
3938
  return innerProxy;
3882
3939
  }
3883
3940
 
3884
3941
  function proxifyRow(row, strategy, fast) {
3942
+ const storedStrategy = toStoredFetchStrategy(strategy);
3885
3943
  let handler = {
3886
3944
  get(_target, property,) {
3887
3945
  if (property === 'save' || property === 'saveChanges') //call server then acceptChanges
@@ -3906,10 +3964,10 @@ function requireClient () {
3906
3964
 
3907
3965
  };
3908
3966
  let watcher = onChange(row, () => {
3909
- rootMap.set(row, { json: cloneFromDb(row, fast), strategy });
3967
+ rootMap.set(row, { json: cloneFromDb(row, fast), strategy: storedStrategy });
3910
3968
  });
3911
3969
  let innerProxy = new Proxy(watcher, handler);
3912
- fetchingStrategyMap.set(row, strategy);
3970
+ fetchingStrategyMap.set(row, storedStrategy);
3913
3971
  return innerProxy;
3914
3972
  }
3915
3973
 
@@ -4000,7 +4058,7 @@ function requireClient () {
4000
4058
  let insertedPositions = getInsertedRowsPosition(array);
4001
4059
  let { changed, strategy: newStrategy } = await p;
4002
4060
  copyIntoArray(changed, array, [...insertedPositions, ...updatedPositions]);
4003
- rootMap.set(array, { json: cloneFromDb(array), strategy: newStrategy, originalArray: [...array] });
4061
+ rootMap.set(array, { json: cloneFromDb(array), strategy: toStoredFetchStrategy(newStrategy), originalArray: [...array] });
4004
4062
  }
4005
4063
 
4006
4064
  async function patch(patch, concurrencyOptions, strategy) {
@@ -4062,8 +4120,7 @@ function requireClient () {
4062
4120
  let context = rootMap.get(obj);
4063
4121
  if (context?.strategy !== undefined) {
4064
4122
  // @ts-ignore
4065
- let { limit, ...strategy } = { ...context.strategy };
4066
- return strategy;
4123
+ return toStoredFetchStrategy(context.strategy);
4067
4124
  }
4068
4125
  }
4069
4126
  }
@@ -4073,9 +4130,24 @@ function requireClient () {
4073
4130
  return strategy;
4074
4131
  else if (fetchingStrategyMap.get(obj) !== undefined) {
4075
4132
  // @ts-ignore
4076
- const { limit, ...strategy } = { ...fetchingStrategyMap.get(obj) };
4133
+ return toStoredFetchStrategy(fetchingStrategyMap.get(obj));
4134
+ }
4135
+ }
4136
+
4137
+ function toStoredFetchStrategy(strategy) {
4138
+ if (strategy === undefined || strategy === null || typeof strategy !== 'object')
4077
4139
  return strategy;
4140
+ if (Array.isArray(strategy))
4141
+ return strategy.map(toStoredFetchStrategy);
4142
+ const cleanStrategy = { ...strategy };
4143
+ delete cleanStrategy.limit;
4144
+ delete cleanStrategy.forUpdate;
4145
+ delete cleanStrategy.skipLocked;
4146
+ for (let name in cleanStrategy) {
4147
+ if (name !== 'where' && cleanStrategy[name] && typeof cleanStrategy[name] === 'object')
4148
+ cleanStrategy[name] = toStoredFetchStrategy(cleanStrategy[name]);
4078
4149
  }
4150
+ return cleanStrategy;
4079
4151
  }
4080
4152
 
4081
4153
  function clearChangesArray(array) {
@@ -4166,8 +4238,9 @@ function requireClient () {
4166
4238
  array.splice(i + offset, 1);
4167
4239
  offset--;
4168
4240
  }
4169
- rootMap.set(array, { json: cloneFromDb(array), strategy, originalArray: [...array] });
4170
- fetchingStrategyMap.set(array, strategy);
4241
+ const storedStrategy = toStoredFetchStrategy(strategy);
4242
+ rootMap.set(array, { json: cloneFromDb(array), strategy: storedStrategy, originalArray: [...array] });
4243
+ fetchingStrategyMap.set(array, storedStrategy);
4171
4244
  }
4172
4245
 
4173
4246
  async function deleteRow(row, options) {
@@ -4201,7 +4274,7 @@ function requireClient () {
4201
4274
  let adapter = netAdapter(url, tableName, { http: httpInterceptor, tableOptions });
4202
4275
  let { changed, strategy: newStrategy } = await adapter.patch(body);
4203
4276
  copyInto(changed, [row]);
4204
- rootMap.set(row, { json: cloneFromDb(row), strategy: newStrategy });
4277
+ rootMap.set(row, { json: cloneFromDb(row), strategy: toStoredFetchStrategy(newStrategy) });
4205
4278
  }
4206
4279
 
4207
4280
  async function refreshRow(row, strategy) {
@@ -4225,8 +4298,9 @@ function requireClient () {
4225
4298
  for (let p in rows[0]) {
4226
4299
  row[p] = rows[0][p];
4227
4300
  }
4228
- rootMap.set(row, { json: cloneFromDb(row), strategy });
4229
- fetchingStrategyMap.set(row, strategy);
4301
+ const storedStrategy = toStoredFetchStrategy(strategy);
4302
+ rootMap.set(row, { json: cloneFromDb(row), strategy: storedStrategy });
4303
+ fetchingStrategyMap.set(row, storedStrategy);
4230
4304
  }
4231
4305
 
4232
4306
  function acceptChangesRow(row) {
@@ -6732,8 +6806,8 @@ function requireNewPrimaryKeyFilter () {
6732
6806
  var primaryColumns = table._primaryColumns;
6733
6807
  var key = arguments[2];
6734
6808
  var filter = primaryColumns[0].equal(context, key);
6735
- for (var i = 2; i < primaryColumns.length; i++) {
6736
- key = arguments[i+1];
6809
+ for (var i = 1; i < primaryColumns.length; i++) {
6810
+ key = arguments[i + 2];
6737
6811
  var colFilter = primaryColumns[i].equal(context, key);
6738
6812
  filter = filter.and(context, colFilter);
6739
6813
  }
@@ -6870,6 +6944,89 @@ function requireNewColumnSql () {
6870
6944
  return newColumnSql;
6871
6945
  }
6872
6946
 
6947
+ var lockSql;
6948
+ var hasRequiredLockSql;
6949
+
6950
+ function requireLockSql () {
6951
+ if (hasRequiredLockSql) return lockSql;
6952
+ hasRequiredLockSql = 1;
6953
+ const getSessionSingleton = requireGetSessionSingleton();
6954
+
6955
+ function selectLockSql(context, span, alias, exclusive) {
6956
+ const lock = collectSelectLock(span, alias, exclusive);
6957
+ if (!hasLock(lock))
6958
+ return '';
6959
+ const encode = getSessionSingleton(context, 'selectForUpdateSql');
6960
+ if (!encode)
6961
+ return '';
6962
+ return encode(context, lock);
6963
+ }
6964
+
6965
+ function tableHintSql(context, span, exclusive) {
6966
+ const lock = spanToLock(span, exclusive);
6967
+ if (!hasLock(lock))
6968
+ return '';
6969
+ const encode = getSessionSingleton(context, 'selectForUpdateSql');
6970
+ if (!encode || !encode.tableHint)
6971
+ return '';
6972
+ return encode.tableHint(context, lock);
6973
+ }
6974
+
6975
+ function collectSelectLock(span, alias, exclusive) {
6976
+ const lock = {
6977
+ aliases: [],
6978
+ forUpdate: Boolean(exclusive),
6979
+ skipLocked: false
6980
+ };
6981
+ collect(span, alias, lock);
6982
+ if (exclusive && lock.aliases.indexOf(alias) === -1)
6983
+ lock.aliases.unshift(alias);
6984
+ return lock;
6985
+ }
6986
+
6987
+ function collect(span, alias, lock) {
6988
+ if (!span)
6989
+ return;
6990
+ if (span.forUpdate) {
6991
+ lock.forUpdate = true;
6992
+ lock.aliases.push(alias);
6993
+ }
6994
+ if (span.skipLocked)
6995
+ lock.skipLocked = true;
6996
+
6997
+ if (!span.legs)
6998
+ return;
6999
+ const visitor = {};
7000
+ visitor.visitJoin = visitJoinedLeg;
7001
+ visitor.visitOne = visitJoinedLeg;
7002
+ visitor.visitMany = function() {};
7003
+
7004
+ function visitJoinedLeg(leg) {
7005
+ collect(leg.span, alias + leg.name, lock);
7006
+ }
7007
+
7008
+ span.legs.forEach(leg => leg.accept(visitor));
7009
+ }
7010
+
7011
+ function spanToLock(span, exclusive) {
7012
+ return {
7013
+ aliases: [],
7014
+ forUpdate: Boolean(exclusive || span?.forUpdate),
7015
+ skipLocked: Boolean(span?.skipLocked)
7016
+ };
7017
+ }
7018
+
7019
+ function hasLock(lock) {
7020
+ return Boolean(lock.forUpdate || lock.skipLocked);
7021
+ }
7022
+
7023
+ lockSql = {
7024
+ selectLockSql,
7025
+ tableHintSql
7026
+ };
7027
+ return lockSql;
7028
+ }
7029
+
6873
7030
  var newShallowJoinSql;
6874
7031
  var hasRequiredNewShallowJoinSql;
6875
7032
 
@@ -6878,10 +7035,12 @@ function requireNewShallowJoinSql () {
6878
7035
  hasRequiredNewShallowJoinSql = 1;
6879
7036
  const newJoinCore = requireNewShallowJoinSqlCore();
6880
7037
  const getSessionSingleton = requireGetSessionSingleton();
7038
+ const lockSql = requireLockSql();
6881
7039
 
6882
- function _new(context, rightTable, leftColumns, rightColumns, leftAlias, rightAlias, filter) {
7040
+ function _new(context, rightTable, leftColumns, rightColumns, leftAlias, rightAlias, filter, span) {
6883
7041
  const quote = getSessionSingleton(context, 'quote');
6884
- const sql = ' JOIN ' + quote(rightTable._dbName) + ' ' + quote(rightAlias) + ' ON (';
7042
+ const tableHint = lockSql.tableHintSql(context, span);
7043
+ const sql = ' JOIN ' + quote(rightTable._dbName) + ' ' + quote(rightAlias) + tableHint + ' ON (';
6885
7044
  const joinCore = newJoinCore(context, rightTable, leftColumns, rightColumns, leftAlias, rightAlias, filter);
6886
7045
  return joinCore.prepend(sql).append(')');
6887
7046
  }
@@ -6901,7 +7060,7 @@ function requireJoinLegToShallowJoinSql () {
6901
7060
  function toJoinSql(context,leg,alias,childAlias) {
6902
7061
  var columns = leg.columns;
6903
7062
  var childTable = leg.span.table;
6904
- return newShallowJoinSql(context,childTable,columns,childTable._primaryColumns,alias,childAlias,leg.span.where).prepend(' LEFT');
7063
+ return newShallowJoinSql(context,childTable,columns,childTable._primaryColumns,alias,childAlias,leg.span.where,leg.span).prepend(' LEFT');
6905
7064
  }
6906
7065
 
6907
7066
  joinLegToShallowJoinSql = toJoinSql;
@@ -6937,7 +7096,7 @@ function requireOneLegToShallowJoinSql () {
6937
7096
  var parentTable = leg.table;
6938
7097
  var columns = leg.columns;
6939
7098
  var childTable = leg.span.table;
6940
- return newShallowJoinSql(context,childTable,parentTable._primaryColumns,columns,alias,childAlias, leg.span.where).prepend(' LEFT');
7099
+ return newShallowJoinSql(context,childTable,parentTable._primaryColumns,columns,alias,childAlias, leg.span.where,leg.span).prepend(' LEFT');
6941
7100
  }
6942
7101
 
6943
7102
  oneLegToShallowJoinSql = toJoinSql;
@@ -7057,26 +7216,6 @@ function requireNegotiateLimit () {
7057
7216
  return negotiateLimit_1;
7058
7217
  }
7059
7218
 
7060
- var negotiateExclusive_1;
7061
- var hasRequiredNegotiateExclusive;
7062
-
7063
- function requireNegotiateExclusive () {
7064
- if (hasRequiredNegotiateExclusive) return negotiateExclusive_1;
7065
- hasRequiredNegotiateExclusive = 1;
7066
- var getSessionSingleton = requireGetSessionSingleton();
7067
-
7068
- function negotiateExclusive(context, table, alias, _exclusive) {
7069
- if (table._exclusive || _exclusive) {
7070
- var encode = getSessionSingleton(context, 'selectForUpdateSql');
7071
- return encode(context, alias);
7072
- }
7073
- return '';
7074
- }
7075
-
7076
- negotiateExclusive_1 = negotiateExclusive;
7077
- return negotiateExclusive_1;
7078
- }
7079
-
7080
7219
  var newSingleQuery$1;
7081
7220
  var hasRequiredNewSingleQuery$1;
7082
7221
 
@@ -7087,23 +7226,25 @@ function requireNewSingleQuery$1 () {
7087
7226
  var newJoinSql = requireNewJoinSql();
7088
7227
  var newWhereSql = requireNewWhereSql();
7089
7228
  var negotiateLimit = requireNegotiateLimit();
7090
- var negotiateExclusive = requireNegotiateExclusive();
7229
+ var lockSql = requireLockSql();
7091
7230
  var newParameterized = requireNewParameterized();
7092
7231
  var quote = requireQuote$6();
7093
7232
 
7094
7233
  function _new(context, table, filter, span, alias, innerJoin, orderBy, limit, offset, exclusive) {
7095
7234
 
7096
7235
  var name = quote(context, table._dbName);
7236
+ var quotedAlias = quote(context, alias);
7097
7237
  var columnSql = newColumnSql(context, table, span, alias);
7098
7238
  var joinSql = newJoinSql(context, span, alias);
7099
7239
  var whereSql = newWhereSql(context, table, filter, alias);
7100
7240
  var safeLimit = negotiateLimit(limit);
7101
- var exclusiveClause = negotiateExclusive(table, alias, exclusive);
7102
- return newParameterized('select' + safeLimit + ' ' + columnSql + ' from ' + name + ' ' + quote(context, alias))
7241
+ var lockClause = lockSql.selectLockSql(context, span, alias, exclusive);
7242
+ var tableHint = lockSql.tableHintSql(context, span, exclusive);
7243
+ return newParameterized('select' + safeLimit + ' ' + columnSql + ' from ' + name + ' ' + quotedAlias + tableHint)
7103
7244
  .append(innerJoin)
7104
7245
  .append(joinSql)
7105
7246
  .append(whereSql)
7106
- .append(orderBy + offset + exclusiveClause);
7247
+ .append(orderBy + offset + lockClause);
7107
7248
  }
7108
7249
 
7109
7250
  newSingleQuery$1 = _new;
@@ -7369,7 +7510,7 @@ function requireNewUpdateCommandCore () {
7369
7510
  const encoded = encodeJsonValue(pathState.oldValue, column);
7370
7511
  const jsonPath = buildJsonPath(pathState.path);
7371
7512
  const columnExpr = buildJsonExtractExpression(quote(column._dbName), jsonPath, pathState.oldValue);
7372
- command = appendJsonPathComparison(columnExpr, encoded);
7513
+ command = appendJsonPathComparison(columnExpr, encoded, pathState.oldValue);
7373
7514
  }
7374
7515
  }
7375
7516
  else {
@@ -7429,7 +7570,12 @@ function requireNewUpdateCommandCore () {
7429
7570
  return command;
7430
7571
  }
7431
7572
 
7432
- function appendJsonPathComparison(columnExpr, encoded) {
7573
+ function appendJsonPathComparison(columnExpr, encoded, oldValue) {
7574
+ if (oldValue === undefined) {
7575
+ command = command.append(separator).append(columnExpr).append(' IS NULL');
7576
+ separator = ' AND ';
7577
+ return command;
7578
+ }
7433
7579
  if (engine === 'pg') {
7434
7580
  command = command.append(separator).append(columnExpr).append(' IS NOT DISTINCT FROM ').append(encoded);
7435
7581
  }
@@ -9413,46 +9559,14 @@ function requireGetMany () {
9413
9559
  return resultToRows(context, span,result);
9414
9560
  }
9415
9561
 
9416
- getMany.exclusive = function(table,filter,strategy) {
9417
- return getManyCore(table,filter,strategy,true);
9562
+ getMany.exclusive = function(context,table,filter,strategy) {
9563
+ return getManyCore(context,table,filter,strategy,true);
9418
9564
  };
9419
9565
 
9420
9566
  getMany_1 = getMany;
9421
9567
  return getMany_1;
9422
9568
  }
9423
9569
 
9424
- var tryGetFirstFromDb;
9425
- var hasRequiredTryGetFirstFromDb;
9426
-
9427
- function requireTryGetFirstFromDb () {
9428
- if (hasRequiredTryGetFirstFromDb) return tryGetFirstFromDb;
9429
- hasRequiredTryGetFirstFromDb = 1;
9430
- var getMany = requireGetMany();
9431
-
9432
- function tryGet(context, table, filter, strategy) {
9433
- strategy = setLimit(strategy);
9434
- return getMany(context, table, filter, strategy).then(filterRows);
9435
- }
9436
-
9437
- function filterRows(rows) {
9438
- if (rows.length > 0)
9439
- return rows[0];
9440
- return null;
9441
- }
9442
-
9443
- tryGet.exclusive = function(context, table, filter, strategy) {
9444
- strategy = setLimit(strategy);
9445
- return getMany.exclusive(context, table, filter, strategy).then(filterRows);
9446
- };
9447
-
9448
- function setLimit(strategy) {
9449
- return {...strategy, ...{limit: 1}};
9450
- }
9451
-
9452
- tryGetFirstFromDb = tryGet;
9453
- return tryGetFirstFromDb;
9454
- }
9455
-
9456
9570
  var extractStrategy;
9457
9571
  var hasRequiredExtractStrategy;
9458
9572
 
@@ -9477,25 +9591,31 @@ function requireTryGetFromDbById () {
9477
9591
  if (hasRequiredTryGetFromDbById) return tryGetFromDbById;
9478
9592
  hasRequiredTryGetFromDbById = 1;
9479
9593
  var newPrimaryKeyFilter = requireNewPrimaryKeyFilter();
9480
- var tryGetFirstFromDb = requireTryGetFirstFromDb();
9594
+ var getMany = requireGetMany();
9481
9595
  var extractStrategy = requireExtractStrategy();
9482
9596
 
9483
9597
  function tryGet(context) {
9484
9598
  var filter = newPrimaryKeyFilter.apply(null, arguments);
9485
9599
  var table = arguments[1];
9486
9600
  var strategy = extractStrategy.apply(null, arguments);
9487
- return tryGetFirstFromDb(context, table, filter, strategy);
9601
+ return getMany(context, table, filter, strategy).then(filterRows);
9488
9602
  }
9489
9603
 
9490
9604
  tryGet.exclusive = function tryGet(context) {
9491
9605
  var filter = newPrimaryKeyFilter.apply(null, arguments);
9492
9606
  var table = arguments[1];
9493
9607
  var strategy = extractStrategy.apply(null, arguments);
9494
- return tryGetFirstFromDb.exclusive(context, table, filter, strategy);
9608
+ return getMany.exclusive(context, table, filter, strategy).then(filterRows);
9495
9609
 
9496
9610
 
9497
9611
  };
9498
9612
 
9613
+ function filterRows(rows) {
9614
+ if (rows.length > 0)
9615
+ return rows[0];
9616
+ return null;
9617
+ }
9618
+
9499
9619
  tryGetFromDbById = tryGet;
9500
9620
  return tryGetFromDbById;
9501
9621
  }
@@ -11709,18 +11829,22 @@ function requireNewSingleQuery () {
11709
11829
  var newJoinSql = requireNewJoinSql();
11710
11830
  var newParameterized = requireNewParameterized();
11711
11831
  var getSessionSingleton = requireGetSessionSingleton();
11832
+ var lockSql = requireLockSql();
11712
11833
 
11713
11834
  function _new(context,table,filter,span, alias,orderBy,limit,offset,distinct = false) {
11714
11835
  var quote = getSessionSingleton(context, 'quote');
11715
11836
  var name = quote(table._dbName);
11837
+ var quotedAlias = quote(alias);
11716
11838
  var columnSql = newColumnSql(context,table,span,alias,true);
11717
11839
  var joinSql = newJoinSql(context, span, alias);
11718
11840
  var whereSql = newWhereSql(context,table,filter,alias);
11719
11841
  if (limit)
11720
11842
  limit = limit + ' ';
11721
11843
  const selectClause = distinct ? 'select distinct ' : 'select ';
11844
+ const lockClause = lockSql.selectLockSql(context, span, alias);
11845
+ const tableHint = lockSql.tableHintSql(context, span);
11722
11846
 
11723
- return newParameterized(selectClause + limit + columnSql + ' from ' + name + ' ' + quote(alias)).append(joinSql).append(whereSql).append(orderBy + offset);
11847
+ return newParameterized(selectClause + limit + columnSql + ' from ' + name + ' ' + quotedAlias + tableHint).append(joinSql).append(whereSql).append(orderBy + offset + lockClause);
11724
11848
 
11725
11849
  }
11726
11850
 
@@ -12178,6 +12302,38 @@ function requireTryGetById () {
12178
12302
  return tryGetById;
12179
12303
  }
12180
12304
 
12305
+ var tryGetFirstFromDb;
12306
+ var hasRequiredTryGetFirstFromDb;
12307
+
12308
+ function requireTryGetFirstFromDb () {
12309
+ if (hasRequiredTryGetFirstFromDb) return tryGetFirstFromDb;
12310
+ hasRequiredTryGetFirstFromDb = 1;
12311
+ var getMany = requireGetMany();
12312
+
12313
+ function tryGet(context, table, filter, strategy) {
12314
+ strategy = setLimit(strategy);
12315
+ return getMany(context, table, filter, strategy).then(filterRows);
12316
+ }
12317
+
12318
+ function filterRows(rows) {
12319
+ if (rows.length > 0)
12320
+ return rows[0];
12321
+ return null;
12322
+ }
12323
+
12324
+ tryGet.exclusive = function(context, table, filter, strategy) {
12325
+ strategy = setLimit(strategy);
12326
+ return getMany.exclusive(context, table, filter, strategy).then(filterRows);
12327
+ };
12328
+
12329
+ function setLimit(strategy) {
12330
+ return {...strategy, ...{limit: 1}};
12331
+ }
12332
+
12333
+ tryGetFirstFromDb = tryGet;
12334
+ return tryGetFirstFromDb;
12335
+ }
12336
+
12181
12337
  var newRowCache_1;
12182
12338
  var hasRequiredNewRowCache;
12183
12339
 
@@ -12698,29 +12854,34 @@ function requireApplyPatch () {
12698
12854
 
12699
12855
  }
12700
12856
 
12701
- // function assertDatesEqual(date1, date2) {
12702
- // if (date1 && date2) {
12703
- // const parts1 = date1.split('T');
12704
- // const time1parts = (parts1[1] || '').split(/[-+.]/);
12705
- // const parts2 = date2.split('T');
12706
- // const time2parts = (parts2[1] || '').split(/[-+.]/);
12707
- // while (time1parts.length !== time2parts.length) {
12708
- // if (time1parts.length > time2parts.length)
12709
- // time1parts.pop();
12710
- // else if (time1parts.length < time2parts.length)
12711
- // time2parts.pop();
12712
- // }
12713
- // date1 = `${parts1[0]}T${time1parts[0]}`;
12714
- // date2 = `${parts2[0]}T${time2parts[0]}`;
12715
- // }
12716
- // assertDeepEqual(date1, date2);
12717
- // }
12718
-
12719
12857
  function assertDeepEqual(a, b) {
12720
- if (JSON.stringify(a) !== JSON.stringify(b))
12858
+ if (!deepEqual(a, b))
12721
12859
  throw new Error('A, b are not equal');
12722
12860
  }
12723
12861
 
12862
+ function deepEqual(a, b) {
12863
+ if (a === b) return true;
12864
+ if (a && b && typeof a === 'object' && typeof b === 'object') {
12865
+ if (Array.isArray(a)) {
12866
+ if (!Array.isArray(b) || a.length !== b.length) return false;
12867
+ for (let i = 0; i < a.length; i++) {
12868
+ if (!deepEqual(a[i], b[i])) return false;
12869
+ }
12870
+ return true;
12871
+ }
12872
+ if (Array.isArray(b)) return false;
12873
+
12874
+ const keysA = Object.keys(a);
12875
+ const keysB = Object.keys(b);
12876
+ if (keysA.length !== keysB.length) return false;
12877
+ for (const key of keysA) {
12878
+ if (!Object.prototype.hasOwnProperty.call(b, key) || !deepEqual(a[key], b[key])) return false;
12879
+ }
12880
+ return true;
12881
+ }
12882
+ return false;
12883
+ }
12884
+
12724
12885
  applyPatch_1 = applyPatch;
12725
12886
  return applyPatch_1;
12726
12887
  }
@@ -12845,6 +13006,7 @@ function requirePatchTable () {
12845
13006
  const engine = getSessionSingleton(context, 'engine');
12846
13007
  options = cleanOptions(options);
12847
13008
  strategy = JSON.parse(JSON.stringify(strategy || {}));
13009
+ await lockTouchedRows();
12848
13010
  let changed = new Set();
12849
13011
  for (let i = 0; i < patches.length; i++) {
12850
13012
  let patch = { path: undefined, value: undefined, op: undefined };
@@ -12864,14 +13026,28 @@ function requirePatchTable () {
12864
13026
  }
12865
13027
  if (strategy['insertAndForget'])
12866
13028
  return {
12867
- changed: [], strategy
13029
+ changed: [], strategy: stripLockingStrategy(strategy)
12868
13030
  };
12869
- return { changed: await toDtos(changed), strategy };
13031
+ return { changed: await toDtos(changed), strategy: stripLockingStrategy(strategy) };
12870
13032
 
12871
13033
 
12872
13034
  async function toDtos(set) {
12873
13035
  set = [...set];
12874
- const result = await table.getManyDto(context, set, strategy);
13036
+ const result = await table.getManyDto(context, set, stripLockingStrategy(strategy));
13037
+ return result;
13038
+ }
13039
+
13040
+ function stripLockingStrategy(strategy) {
13041
+ if (!strategy || typeof strategy !== 'object')
13042
+ return strategy;
13043
+ if (Array.isArray(strategy))
13044
+ return strategy.map(stripLockingStrategy);
13045
+ const result = {};
13046
+ for (let name in strategy) {
13047
+ if (name === 'forUpdate' || name === 'skipLocked')
13048
+ continue;
13049
+ result[name] = stripLockingStrategy(strategy[name]);
13050
+ }
12875
13051
  return result;
12876
13052
  }
12877
13053
 
@@ -12882,6 +13058,54 @@ function requirePatchTable () {
12882
13058
  return [property];
12883
13059
  }
12884
13060
 
13061
+ async function lockTouchedRows() {
13062
+ if (!hasLockingStrategy(strategy))
13063
+ return;
13064
+ const keys = [];
13065
+ const keySet = new Set();
13066
+ for (let i = 0; i < patches.length; i++) {
13067
+ const patch = patches[i];
13068
+ const path = patch.path.split('/').slice(1);
13069
+ if (path.length === 0)
13070
+ continue;
13071
+ if (patch.op === 'add' && path.length === 1)
13072
+ continue;
13073
+ const key = toKey(path[0]);
13074
+ if (isTemporaryKey(key))
13075
+ continue;
13076
+ const keyString = JSON.stringify(key);
13077
+ if (keySet.has(keyString))
13078
+ continue;
13079
+ keySet.add(keyString);
13080
+ keys.push(key);
13081
+ }
13082
+ for (let i = 0; i < keys.length; i++) {
13083
+ const row = await table.tryGetById.apply(null, [context, ...keys[i], strategy]);
13084
+ if (!row)
13085
+ throw new Error(`Row ${table._dbName} with id ${keys[i]} was not found.`);
13086
+ }
13087
+ }
13088
+
13089
+ function hasLockingStrategy(strategy) {
13090
+ if (!strategy || typeof strategy !== 'object')
13091
+ return false;
13092
+ if (strategy.forUpdate || strategy.skipLocked)
13093
+ return true;
13094
+ for (let name in strategy) {
13095
+ if (name !== 'where' && hasLockingStrategy(strategy[name]))
13096
+ return true;
13097
+ }
13098
+ return false;
13099
+ }
13100
+
13101
+ function isTemporaryKey(key) {
13102
+ for (let i = 0; i < key.length; i++) {
13103
+ if (typeof key[i] === 'string' && key[i].indexOf('~') === 0)
13104
+ return true;
13105
+ }
13106
+ return false;
13107
+ }
13108
+
12885
13109
  async function add({ path, value, op, oldValue, strategy, options }, table, row, parentRow, relation) {
12886
13110
  let property = path[0];
12887
13111
  path = path.slice(1);
@@ -14525,16 +14749,23 @@ function requireDeleteFromSql$5 () {
14525
14749
  return deleteFromSql_1$5;
14526
14750
  }
14527
14751
 
14528
- var selectForUpdateSql$5;
14752
+ var selectForUpdateSql$4;
14529
14753
  var hasRequiredSelectForUpdateSql$5;
14530
14754
 
14531
14755
  function requireSelectForUpdateSql$5 () {
14532
- if (hasRequiredSelectForUpdateSql$5) return selectForUpdateSql$5;
14756
+ if (hasRequiredSelectForUpdateSql$5) return selectForUpdateSql$4;
14533
14757
  hasRequiredSelectForUpdateSql$5 = 1;
14534
- selectForUpdateSql$5 = function(_alias) {
14535
- return ' FOR UPDATE';
14758
+ selectForUpdateSql$4 = function(_context, lock) {
14759
+ if (typeof lock === 'string')
14760
+ lock = { forUpdate: true };
14761
+ let sql = '';
14762
+ if (lock.forUpdate)
14763
+ sql += ' FOR UPDATE';
14764
+ if (lock.skipLocked)
14765
+ sql += ' SKIP LOCKED';
14766
+ return sql;
14536
14767
  };
14537
- return selectForUpdateSql$5;
14768
+ return selectForUpdateSql$4;
14538
14769
  }
14539
14770
 
14540
14771
  var lastInsertedSql_1$4;
@@ -16549,18 +16780,28 @@ function requireDeleteFromSql$4 () {
16549
16780
  return deleteFromSql_1$4;
16550
16781
  }
16551
16782
 
16552
- var selectForUpdateSql$4;
16783
+ var selectForUpdateSql$3;
16553
16784
  var hasRequiredSelectForUpdateSql$4;
16554
16785
 
16555
16786
  function requireSelectForUpdateSql$4 () {
16556
- if (hasRequiredSelectForUpdateSql$4) return selectForUpdateSql$4;
16787
+ if (hasRequiredSelectForUpdateSql$4) return selectForUpdateSql$3;
16557
16788
  hasRequiredSelectForUpdateSql$4 = 1;
16558
16789
  const quote = requireQuote$6();
16559
16790
 
16560
- selectForUpdateSql$4 = function(alias) {
16561
- return ' FOR UPDATE OF ' + quote(alias);
16791
+ selectForUpdateSql$3 = function(context, lock) {
16792
+ if (typeof lock === 'string')
16793
+ lock = { aliases: [lock], forUpdate: true };
16794
+ let sql = '';
16795
+ if (lock.forUpdate) {
16796
+ sql = ' FOR UPDATE';
16797
+ if (lock.aliases && lock.aliases.length > 0)
16798
+ sql += ' OF ' + lock.aliases.map(alias => quote(context, alias)).join(', ');
16799
+ }
16800
+ if (lock.skipLocked)
16801
+ sql += ' SKIP LOCKED';
16802
+ return sql;
16562
16803
  };
16563
- return selectForUpdateSql$4;
16804
+ return selectForUpdateSql$3;
16564
16805
  }
16565
16806
 
16566
16807
  var limitAndOffset_1$4;
@@ -18527,18 +18768,18 @@ function requireDeleteFromSql$3 () {
18527
18768
  return deleteFromSql_1$3;
18528
18769
  }
18529
18770
 
18530
- var selectForUpdateSql$3;
18771
+ var selectForUpdateSql$2;
18531
18772
  var hasRequiredSelectForUpdateSql$3;
18532
18773
 
18533
18774
  function requireSelectForUpdateSql$3 () {
18534
- if (hasRequiredSelectForUpdateSql$3) return selectForUpdateSql$3;
18775
+ if (hasRequiredSelectForUpdateSql$3) return selectForUpdateSql$2;
18535
18776
  hasRequiredSelectForUpdateSql$3 = 1;
18536
- const quote = requireQuote$6();
18537
-
18538
- selectForUpdateSql$3 = function(context, alias) {
18539
- return ' FOR UPDATE OF ' + quote(context, alias);
18777
+ selectForUpdateSql$2 = function(_context, lock) {
18778
+ if (lock)
18779
+ throw new Error('select for update is not supported by SQLite');
18780
+ return '';
18540
18781
  };
18541
- return selectForUpdateSql$3;
18782
+ return selectForUpdateSql$2;
18542
18783
  }
18543
18784
 
18544
18785
  var lastInsertedSql_1$2;
@@ -20684,18 +20925,31 @@ function requireDeleteFromSql$2 () {
20684
20925
  return deleteFromSql_1$2;
20685
20926
  }
20686
20927
 
20687
- var selectForUpdateSql$2;
20928
+ var selectForUpdateSql_1;
20688
20929
  var hasRequiredSelectForUpdateSql$2;
20689
20930
 
20690
20931
  function requireSelectForUpdateSql$2 () {
20691
- if (hasRequiredSelectForUpdateSql$2) return selectForUpdateSql$2;
20932
+ if (hasRequiredSelectForUpdateSql$2) return selectForUpdateSql_1;
20692
20933
  hasRequiredSelectForUpdateSql$2 = 1;
20693
- const quote = requireQuote$6();
20934
+ function selectForUpdateSql() {
20935
+ return '';
20936
+ }
20694
20937
 
20695
- selectForUpdateSql$2 = function(alias) {
20696
- return ' FOR UPDATE OF ' + quote(alias);
20938
+ selectForUpdateSql.tableHint = function(_context, lock) {
20939
+ const hints = [];
20940
+ if (lock.forUpdate)
20941
+ hints.push('UPDLOCK');
20942
+ if (lock.skipLocked) {
20943
+ hints.push('READPAST');
20944
+ hints.push('ROWLOCK');
20945
+ }
20946
+ if (hints.length === 0)
20947
+ return '';
20948
+ return ' WITH (' + hints.join(', ') + ')';
20697
20949
  };
20698
- return selectForUpdateSql$2;
20950
+
20951
+ selectForUpdateSql_1 = selectForUpdateSql;
20952
+ return selectForUpdateSql_1;
20699
20953
  }
20700
20954
 
20701
20955
  var limitAndOffset_1$2;
@@ -22271,10 +22525,10 @@ var hasRequiredSelectForUpdateSql$1;
22271
22525
  function requireSelectForUpdateSql$1 () {
22272
22526
  if (hasRequiredSelectForUpdateSql$1) return selectForUpdateSql$1;
22273
22527
  hasRequiredSelectForUpdateSql$1 = 1;
22274
- const quote = requireQuote$6();
22275
-
22276
- selectForUpdateSql$1 = function(alias) {
22277
- return ' FOR UPDATE OF ' + quote(alias);
22528
+ selectForUpdateSql$1 = function(_context, lock) {
22529
+ if (lock)
22530
+ throw new Error('select for update is not supported by SAP ASE');
22531
+ return '';
22278
22532
  };
22279
22533
  return selectForUpdateSql$1;
22280
22534
  }
@@ -22994,10 +23248,15 @@ var hasRequiredSelectForUpdateSql;
22994
23248
  function requireSelectForUpdateSql () {
22995
23249
  if (hasRequiredSelectForUpdateSql) return selectForUpdateSql;
22996
23250
  hasRequiredSelectForUpdateSql = 1;
22997
- const quote = requireQuote$6();
22998
-
22999
- selectForUpdateSql = function(alias) {
23000
- return ' FOR UPDATE OF ' + quote(alias);
23251
+ selectForUpdateSql = function(_context, lock) {
23252
+ if (typeof lock === 'string')
23253
+ lock = { forUpdate: true };
23254
+ let sql = '';
23255
+ if (lock.forUpdate)
23256
+ sql = ' FOR UPDATE';
23257
+ if (lock.skipLocked)
23258
+ sql += ' SKIP LOCKED';
23259
+ return sql;
23001
23260
  };
23002
23261
  return selectForUpdateSql;
23003
23262
  }