objection 3.5.0 → 3.7.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.
Files changed (41) hide show
  1. package/README.md +3 -3
  2. package/lib/model/AjvValidator.js +33 -10
  3. package/lib/model/modelClone.js +0 -2
  4. package/lib/queryBuilder/InternalOptions.js +2 -0
  5. package/lib/queryBuilder/QueryBuilder.js +56 -10
  6. package/lib/queryBuilder/RelationExpression.js +6 -4
  7. package/lib/queryBuilder/graph/GraphOptions.js +141 -22
  8. package/lib/queryBuilder/graph/GraphUpsert.js +57 -0
  9. package/lib/queryBuilder/graph/insert/GraphInsert.js +2 -0
  10. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +3 -0
  11. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +6 -1
  12. package/lib/queryBuilder/operations/UpdateOperation.js +11 -0
  13. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +3 -1
  14. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +4 -9
  15. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +434 -364
  16. package/lib/queryBuilder/parsers/relationExpressionParser.js +513 -548
  17. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +1 -1
  18. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +4 -7
  19. package/lib/relations/Relation.js +7 -0
  20. package/lib/relations/RelationFindOperation.js +27 -40
  21. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +4 -2
  22. package/lib/relations/belongsToOne/BelongsToOneRelation.js +9 -0
  23. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +41 -13
  24. package/lib/relations/manyToMany/ManyToManyMySqlModifyMixin.js +31 -42
  25. package/lib/relations/manyToMany/ManyToManyRelation.js +15 -18
  26. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +0 -13
  27. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +2 -3
  28. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateMySqlOperation.js +1 -5
  29. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +1 -5
  30. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +9 -0
  31. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +1 -5
  32. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +28 -2
  33. package/lib/utils/identifierMapping.js +8 -17
  34. package/lib/utils/objectUtils.js +109 -2
  35. package/lib/utils/parseFieldExpression.js +10 -3
  36. package/package.json +5 -2
  37. package/typings/objection/index.d.ts +56 -36
  38. package/lib/relations/manyToMany/ManyToManyPostgresModifyMixin.js +0 -27
  39. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelatePostgresOperation.js +0 -16
  40. package/lib/relations/manyToMany/update/ManyToManyUpdatePostgresOperation.js +0 -12
  41. package/lib/utils/clone.js +0 -2329
@@ -15,9 +15,18 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
15
15
  this.joinTablePatchFilterQuery = null;
16
16
  }
17
17
 
18
+ get modifiesJoinTable() {
19
+ return this.hasExtraProps;
20
+ }
21
+
18
22
  onAdd(builder, args) {
19
23
  const obj = args[0];
20
24
 
25
+ // The modified rows are known to be related to the owner, so they are
26
+ // filtered by their own ids instead of a subquery that joins the join
27
+ // table. On MySQL, concurrent updates with that subquery deadlock (#135).
28
+ this.skipRelationFilter = builder.internalOptions().skipRelationFilter;
29
+
21
30
  // Copy all extra properties to the `joinTablePatch` object.
22
31
  for (const extra of this.relation.joinTableExtras) {
23
32
  if (extra.aliasProp in obj) {
@@ -42,7 +51,9 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
42
51
  }
43
52
 
44
53
  async onAfter1(builder, result) {
45
- if (this.hasExtraProps) {
54
+ // A query resolved without updating anything, e.g. with `none()`, leaves
55
+ // the join rows untouched too.
56
+ if (this.hasExtraProps && !this.isResolvedWithoutUpdate(builder)) {
46
57
  const joinTableUpdateQuery = this.relation
47
58
  .getJoinModelClass(builder.knex())
48
59
  .query()
@@ -50,7 +61,9 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
50
61
  .patch(this.joinTablePatch);
51
62
 
52
63
  addWhereGroup(joinTableUpdateQuery, () =>
53
- this.applyModifyFilterForJoinTable(joinTableUpdateQuery),
64
+ this.skipRelationFilter
65
+ ? this.applyIdFilterForJoinTable(joinTableUpdateQuery)
66
+ : this.applyModifyFilterForJoinTable(joinTableUpdateQuery),
54
67
  );
55
68
  addWhereGroup(joinTableUpdateQuery, () =>
56
69
  joinTableUpdateQuery.modify(this.relation.joinTableModify),
@@ -63,6 +76,19 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
63
76
  }
64
77
  }
65
78
 
79
+ // Filters the join rows by the ids of the owner and the updated model.
80
+ applyIdFilterForJoinTable(builder) {
81
+ return builder
82
+ .whereInComposite(
83
+ this.relation.joinTableOwnerProp.refs(builder),
84
+ this.owner.getProps(this.relation),
85
+ )
86
+ .whereComposite(
87
+ this.relation.joinTableRelatedProp.refs(builder),
88
+ this.relation.relatedProp.getProps(this.model),
89
+ );
90
+ }
91
+
66
92
  /* istanbul ignore next */
67
93
  applyModifyFilterForRelatedTable(builder) {
68
94
  throw new Error('not implemented');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { isObject, isPlainObject } = require('./objectUtils');
3
+ const { isObject } = require('./objectUtils');
4
4
 
5
5
  // Super fast memoize for single argument functions.
6
6
  function memoize(func) {
@@ -149,9 +149,8 @@ function mapLastPart(mapper, separator) {
149
149
  }
150
150
 
151
151
  // Returns a function that takes an object as an input and maps the object's keys
152
- // using `mapper`, and its values using the optional `valueMapper`. If the input
153
- // is not an object, the input is returned unchanged.
154
- function keyMapper(mapper, valueMapper) {
152
+ // using `mapper`. If the input is not an object, the input is returned unchanged.
153
+ function keyMapper(mapper) {
155
154
  return (obj) => {
156
155
  if (!isObject(obj) || Array.isArray(obj)) {
157
156
  return obj;
@@ -162,7 +161,7 @@ function keyMapper(mapper, valueMapper) {
162
161
 
163
162
  for (let i = 0, l = keys.length; i < l; ++i) {
164
163
  const key = keys[i];
165
- out[mapper(key)] = valueMapper ? valueMapper(obj[key]) : obj[key];
164
+ out[mapper(key)] = obj[key];
166
165
  }
167
166
 
168
167
  return out;
@@ -190,16 +189,10 @@ function snakeCaseMappers(opt = {}) {
190
189
  };
191
190
  }
192
191
 
193
- function knexIdentifierMappers({ parse, format, idSeparator = ':', mapNestedKeys = false } = {}) {
192
+ function knexIdentifierMappers({ parse, format, idSeparator = ':' } = {}) {
194
193
  const formatId = memoize(mapLastPart(format, idSeparator));
195
194
  const parseId = memoize(mapLastPart(parse, idSeparator));
196
195
  const parseKeys = keyMapper(parseId);
197
- // With `mapNestedKeys`, also map the keys of plain objects one level down, as
198
- // in the rows knex returns with its `nestTables: true` option on MySQL:
199
- // `{ tableName: { columnName: value } }`.
200
- const parseRow = mapNestedKeys
201
- ? keyMapper(parseId, (value) => (isPlainObject(value) ? parseKeys(value) : value))
202
- : parseKeys;
203
196
 
204
197
  return {
205
198
  wrapIdentifier(identifier, origWrap) {
@@ -211,12 +204,12 @@ function knexIdentifierMappers({ parse, format, idSeparator = ':', mapNestedKeys
211
204
  const output = new Array(result.length);
212
205
 
213
206
  for (let i = 0, l = result.length; i < l; ++i) {
214
- output[i] = parseRow(result[i]);
207
+ output[i] = parseKeys(result[i]);
215
208
  }
216
209
 
217
210
  return output;
218
211
  } else {
219
- return parseRow(result);
212
+ return parseKeys(result);
220
213
  }
221
214
  },
222
215
  };
@@ -226,11 +219,10 @@ function knexSnakeCaseMappers(opt = {}) {
226
219
  return knexIdentifierMappers({
227
220
  parse: (str) => camelCase(str, opt),
228
221
  format: (str) => snakeCase(str, opt),
229
- mapNestedKeys: opt.mapNestedKeys,
230
222
  });
231
223
  }
232
224
 
233
- function knexIdentifierMapping(colToProp, { mapNestedKeys } = {}) {
225
+ function knexIdentifierMapping(colToProp) {
234
226
  const propToCol = Object.keys(colToProp).reduce((propToCol, column) => {
235
227
  propToCol[colToProp[column]] = column;
236
228
  return propToCol;
@@ -239,7 +231,6 @@ function knexIdentifierMapping(colToProp, { mapNestedKeys } = {}) {
239
231
  return knexIdentifierMappers({
240
232
  parse: (column) => colToProp[column] || column,
241
233
  format: (prop) => propToCol[prop] || prop,
242
- mapNestedKeys,
243
234
  });
244
235
  }
245
236
 
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const { clone, cloneDeep } = require('./clone');
4
3
  const SMALL_ARRAY_SIZE = 10;
5
4
 
6
5
  function isEmpty(item) {
@@ -389,6 +388,115 @@ function mergeMaps(map1, map2) {
389
388
  return map;
390
389
  }
391
390
 
391
+ // Returns the tag of `value` like `Object.prototype.toString()`, but ignores a
392
+ // `Symbol.toStringTag` that can be overwritten, like lodash's `baseGetTag()`.
393
+ // Objects that define a writable tag, like decimal.js numbers, are plain
394
+ // objects then, while built-ins like `URL` keep their own tag.
395
+ function getRawTag(value) {
396
+ const tag = Object.prototype.toString.call(value);
397
+
398
+ if (!(Symbol.toStringTag in value)) {
399
+ return tag;
400
+ }
401
+
402
+ const isOwn = Object.prototype.hasOwnProperty.call(value, Symbol.toStringTag);
403
+ const ownTag = value[Symbol.toStringTag];
404
+
405
+ try {
406
+ value[Symbol.toStringTag] = undefined;
407
+ } catch (err) {
408
+ return tag;
409
+ }
410
+
411
+ const rawTag = Object.prototype.toString.call(value);
412
+
413
+ if (isOwn) {
414
+ value[Symbol.toStringTag] = ownTag;
415
+ } else {
416
+ delete value[Symbol.toStringTag];
417
+ }
418
+
419
+ return rawTag;
420
+ }
421
+
422
+ // Clones `value` deeply, like lodash's `cloneDeep()`: plain objects and class
423
+ // instances keep their prototype and get copies of their own enumerable
424
+ // properties, symbols included. Arrays, dates, regular expressions, maps,
425
+ // sets, buffers, typed arrays and array buffers are copied, circular
426
+ // references are kept. Anything else, like functions, errors and built-ins
427
+ // with internal state like `URL`, is kept as it is.
428
+ function cloneDeep(value, clones = new Map()) {
429
+ if (!isObject(value)) {
430
+ return value;
431
+ } else if (clones.has(value)) {
432
+ return clones.get(value);
433
+ }
434
+
435
+ const Ctor = value.constructor;
436
+ const tag = getRawTag(value);
437
+ let copy;
438
+
439
+ if (tag === '[object Object]') {
440
+ copy = Object.create(Object.getPrototypeOf(value));
441
+ clones.set(value, copy);
442
+
443
+ for (const key of Object.keys(value)) {
444
+ const item = cloneDeep(value[key], clones);
445
+
446
+ if (key === '__proto__') {
447
+ // Assigning it would set the prototype instead of the property.
448
+ Object.defineProperty(copy, key, {
449
+ value: item,
450
+ writable: true,
451
+ enumerable: true,
452
+ configurable: true,
453
+ });
454
+ } else {
455
+ copy[key] = item;
456
+ }
457
+ }
458
+
459
+ for (const symbol of Object.getOwnPropertySymbols(value)) {
460
+ if (Object.prototype.propertyIsEnumerable.call(value, symbol)) {
461
+ copy[symbol] = cloneDeep(value[symbol], clones);
462
+ }
463
+ }
464
+ } else if (tag === '[object Array]') {
465
+ copy = new Ctor(value.length);
466
+ clones.set(value, copy);
467
+
468
+ for (let i = 0, l = value.length; i < l; ++i) {
469
+ copy[i] = cloneDeep(value[i], clones);
470
+ }
471
+ } else if (Buffer.isBuffer(value)) {
472
+ copy = Buffer.from(value);
473
+ } else if (tag === '[object DataView]') {
474
+ copy = new Ctor(value.buffer.slice(0), value.byteOffset, value.byteLength);
475
+ } else if (ArrayBuffer.isView(value)) {
476
+ copy = value.slice();
477
+ } else if (tag === '[object ArrayBuffer]') {
478
+ copy = value.slice(0);
479
+ } else if (tag === '[object Date]') {
480
+ copy = new Ctor(+value);
481
+ } else if (tag === '[object RegExp]') {
482
+ copy = new Ctor(value.source, value.flags);
483
+ copy.lastIndex = value.lastIndex;
484
+ } else if (tag === '[object Map]') {
485
+ copy = new Ctor();
486
+ clones.set(value, copy);
487
+ value.forEach((item, key) => copy.set(key, cloneDeep(item, clones)));
488
+ } else if (tag === '[object Set]') {
489
+ copy = new Ctor();
490
+ clones.set(value, copy);
491
+ value.forEach((item) => copy.add(cloneDeep(item, clones)));
492
+ } else {
493
+ return value;
494
+ }
495
+
496
+ clones.set(value, copy);
497
+ return copy;
498
+ }
499
+
392
500
  module.exports = {
393
501
  isEmpty,
394
502
  isString,
@@ -411,7 +519,6 @@ module.exports = {
411
519
  values,
412
520
  union,
413
521
  chunk,
414
- clone,
415
522
  omit,
416
523
  once,
417
524
  last,
@@ -66,10 +66,17 @@ function toPostgresJsonPath(access) {
66
66
  // `whereIn(ref(...), values)`), so the keys need to be escaped instead: single
67
67
  // quotes are doubled, and `?` is escaped so that knex doesn't read it as a
68
68
  // binding placeholder. Backslashes are always doubled by `toPostgresJsonPath()`,
69
- // so they can't escape the closing quote either.
69
+ // so they can't escape the closing quote either. But knex's Postgres dialect
70
+ // drops all backslashes in front of an escaped `?`, so if the path contains any,
71
+ // an escape string literal is used in which backslashes are written as `\134`.
70
72
  function toPostgresJsonPathLiteral(access) {
71
- const path = toPostgresJsonPath(access).replace(/'/g, "''").replace(/\?/g, '\\?');
72
- return `'${path}'`;
73
+ const path = toPostgresJsonPath(access).replace(/'/g, "''");
74
+
75
+ if (path.includes('\\?')) {
76
+ return `E'${path.replace(/\\/g, '\\134').replace(/\?/g, '\\?')}'`;
77
+ } else {
78
+ return `'${path.replace(/\?/g, '\\?')}'`;
79
+ }
73
80
  }
74
81
 
75
82
  module.exports = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "objection",
3
- "version": "3.5.0",
3
+ "version": "3.7.0",
4
4
  "description": "An SQL-friendly ORM for Node.js",
5
5
  "main": "lib/objection.js",
6
6
  "license": "MIT",
@@ -8,8 +8,11 @@
8
8
  "test": "npm run eslint && mocha --slow 10 --timeout 15000 --reporter spec --recursive tests --exclude \"tests/unit/relations/files/**\" && npm run test:typings",
9
9
  "test:fast": "mocha --slow 10 --timeout 15000 --reporter spec --recursive tests --bail --exclude \"tests/unit/relations/files/**\"",
10
10
  "test:typings": "tsc && prettier --check \"typings/**/*.ts\" \"tests/ts/**/*.ts\"",
11
+ "db:up": "docker compose up -d --wait",
12
+ "db:down": "docker compose down -v",
13
+ "build:parsers": "npx --yes peggy@5.1.0 --format commonjs -o lib/queryBuilder/parsers/jsonFieldExpressionParser.js lib/queryBuilder/parsers/jsonFieldExpressionParser.pegjs && npx --yes peggy@5.1.0 --format commonjs -o lib/queryBuilder/parsers/relationExpressionParser.js lib/queryBuilder/parsers/relationExpressionParser.pegjs && prettier --write \"lib/queryBuilder/parsers/*Parser.js\"",
11
14
  "prettier": "prettier --write \"{examples,lib,tests,testUtils,typings,doc}/**/*.{js,ts}\"",
12
- "eslint": "eslint --format codeframe \"examples/**/*.js\" \"lib/**/*.js\" \"tests/**/*.js\"",
15
+ "eslint": "eslint --format codeframe \"examples/**/*.js\" \"lib/**/*.js\" \"tests/**/*.js\" \"testUtils/**/*.js\" \"*.js\"",
13
16
  "docs:dev": "vitepress dev doc",
14
17
  "docs:build": "vitepress build doc",
15
18
  "docs:preview": "vitepress preview doc"
@@ -374,7 +374,8 @@ declare namespace Objection {
374
374
 
375
375
  /**
376
376
  * Converts the query builder NQB to the same result kind as QB:
377
- * array, single, maybe-single or page.
377
+ * array, single, maybe-single or page. Any other result type, e.g. after
378
+ * `castTo()` or `patch()`, falls back to QB, without narrowing.
378
379
  */
379
380
  type WithResultKind<QB extends AnyQueryBuilder, NQB extends AnyQueryBuilder> = [
380
381
  ResultType<QB>,
@@ -423,7 +424,9 @@ declare namespace Objection {
423
424
  ? I extends Model
424
425
  ? I[] | PartialModelObject<I>[]
425
426
  : Expression<T[K]>
426
- : Expression<T[K]>;
427
+ : NonNullable<T[K]> extends Model
428
+ ? Expression<T[K]> | PartialModelObject<NonNullable<T[K]>> // nullable to-one relations
429
+ : Expression<T[K]>;
427
430
  };
428
431
 
429
432
  /**
@@ -1000,14 +1003,36 @@ declare namespace Objection {
1000
1003
  includeTriggerModifications?: boolean;
1001
1004
  }
1002
1005
 
1006
+ type ReturningColumn = string | Raw | readonly (string | Raw)[];
1007
+
1008
+ /**
1009
+ * The arguments of `returning()`: any number of columns or column arrays,
1010
+ * optionally followed by an options object.
1011
+ */
1012
+ type ReturningArgs =
1013
+ ReturningColumn[] | [ReturningColumn, ...ReturningColumn[], ReturningOptions | undefined];
1014
+
1003
1015
  interface ReturningMethod {
1004
1016
  <QB extends AnyQueryBuilder>(
1005
1017
  this: QB,
1006
- column: string | Raw | (string | Raw)[] | readonly (string | Raw)[],
1007
- options?: ReturningOptions,
1018
+ ...args: ReturningArgs
1008
1019
  ): QB extends NumberQueryBuilder<QB> ? ArrayQueryBuilder<QB> : QB;
1009
1020
  }
1010
1021
 
1022
+ /**
1023
+ * With `returning()`, `relate()` returns the inserted join rows for
1024
+ * many-to-many relations, the updated related rows for has-many relations
1025
+ * and the updated owner rows for belongs-to-one relations. The typings can't
1026
+ * tell these apart, so the rows are typed as `any`.
1027
+ */
1028
+ interface RelateReturningMethod<M extends Model> {
1029
+ (...args: ReturningArgs): QueryBuilder<M, any[]>;
1030
+ }
1031
+
1032
+ type RelateQueryBuilder<QB extends AnyQueryBuilder> = {
1033
+ returning: RelateReturningMethod<ModelType<QB>>;
1034
+ } & NumberQueryBuilder<QB>;
1035
+
1011
1036
  interface TimeoutOptions {
1012
1037
  cancel: boolean;
1013
1038
  }
@@ -1058,8 +1083,9 @@ declare namespace Objection {
1058
1083
  }
1059
1084
 
1060
1085
  export interface InsertGraphOptions {
1061
- relate?: boolean | string[];
1086
+ relate?: boolean | string | string[];
1062
1087
  allowRefs?: boolean;
1088
+ allowMarkers?: boolean;
1063
1089
  }
1064
1090
 
1065
1091
  interface InsertGraphMethod<M extends Model> {
@@ -1077,16 +1103,17 @@ declare namespace Objection {
1077
1103
  }
1078
1104
 
1079
1105
  export interface UpsertGraphOptions {
1080
- relate?: boolean | string[];
1081
- unrelate?: boolean | string[];
1082
- insertMissing?: boolean | string[];
1083
- update?: boolean | string[];
1084
- noInsert?: boolean | string[];
1085
- noUpdate?: boolean | string[];
1086
- noDelete?: boolean | string[];
1087
- noRelate?: boolean | string[];
1088
- noUnrelate?: boolean | string[];
1106
+ relate?: boolean | string | string[];
1107
+ unrelate?: boolean | string | string[];
1108
+ insertMissing?: boolean | string | string[];
1109
+ update?: boolean | string | string[];
1110
+ noInsert?: boolean | string | string[];
1111
+ noUpdate?: boolean | string | string[];
1112
+ noDelete?: boolean | string | string[];
1113
+ noRelate?: boolean | string | string[];
1114
+ noUnrelate?: boolean | string | string[];
1089
1115
  allowRefs?: boolean;
1116
+ allowMarkers?: boolean;
1090
1117
  }
1091
1118
 
1092
1119
  interface UpsertGraphMethod<M extends Model> {
@@ -1386,7 +1413,7 @@ declare namespace Objection {
1386
1413
 
1387
1414
  relate(
1388
1415
  ids: MaybeCompositeId | MaybeCompositeId[] | PartialModelObject<M> | PartialModelObject<M>[],
1389
- ): NumberQueryBuilder<this>;
1416
+ ): RelateQueryBuilder<this>;
1390
1417
 
1391
1418
  unrelate(): NumberQueryBuilder<this>;
1392
1419
  for(ids: ForIdValue | ForIdValue[]): this;
@@ -1718,34 +1745,25 @@ declare namespace Objection {
1718
1745
  constructor(config: AjvConfig);
1719
1746
  }
1720
1747
 
1721
- export interface SnakeCaseMappersOptions {
1748
+ /**
1749
+ * The options shared by `snakeCaseMappers` and `knexSnakeCaseMappers`.
1750
+ */
1751
+ export interface SnakeCaseOptions {
1722
1752
  upperCase?: boolean;
1723
1753
  underscoreBeforeDigits?: boolean;
1724
1754
  underscoreBetweenUppercaseLetters?: boolean;
1725
1755
  noDoubleUnderscores?: boolean;
1756
+ }
1757
+
1758
+ export interface SnakeCaseMappersOptions extends SnakeCaseOptions {
1726
1759
  /**
1727
1760
  * Only convert the column part of field expressions like
1728
1761
  * `jsonColumn:someKey` and keep their JSON keys as written.
1729
- * Only used by `snakeCaseMappers`.
1730
1762
  */
1731
1763
  preserveJsonKeys?: boolean;
1732
- /**
1733
- * Also convert the keys of plain objects one level down in the results,
1734
- * e.g. the rows of knex's `nestTables: true` option on MySQL. Also applies
1735
- * to JSON columns parsed by the driver.
1736
- * Only used by `knexSnakeCaseMappers`.
1737
- */
1738
- mapNestedKeys?: boolean;
1739
1764
  }
1740
1765
 
1741
- export interface KnexIdentifierMappingOptions {
1742
- /**
1743
- * Also convert the keys of plain objects one level down in the results,
1744
- * e.g. the rows of knex's `nestTables: true` option on MySQL. Also applies
1745
- * to JSON columns parsed by the driver.
1746
- */
1747
- mapNestedKeys?: boolean;
1748
- }
1766
+ export interface KnexSnakeCaseMappersOptions extends SnakeCaseOptions {}
1749
1767
 
1750
1768
  export interface ColumnNameMappers {
1751
1769
  parse(json: Pojo): Pojo;
@@ -1762,11 +1780,11 @@ declare namespace Objection {
1762
1780
  }
1763
1781
 
1764
1782
  export interface KnexSnakeCaseMappersFactory {
1765
- (options?: SnakeCaseMappersOptions): KnexMappers;
1783
+ (options?: KnexSnakeCaseMappersOptions): KnexMappers;
1766
1784
  }
1767
1785
 
1768
1786
  export interface KnexIdentifierMappingFactory {
1769
- (colToProp: Record<string, string>, options?: KnexIdentifierMappingOptions): KnexMappers;
1787
+ (colToProp: Record<string, string>): KnexMappers;
1770
1788
  }
1771
1789
 
1772
1790
  export type ValidationErrorType =
@@ -2040,14 +2058,16 @@ declare namespace Objection {
2040
2058
  static bindKnex<M>(this: M, trxOrKnex: TransactionOrKnex): M;
2041
2059
  static bindTransaction<M>(this: M, trxOrKnex: TransactionOrKnex): M;
2042
2060
 
2043
- static fetchGraph<M extends Model, const E extends RelationExpression<M>>(
2061
+ // E defaults to `string` so that `fetchGraph<Person>(...)` still compiles,
2062
+ // without narrowing, as TypeScript doesn't infer the remaining arguments.
2063
+ static fetchGraph<M extends Model, const E extends RelationExpression<M> = string>(
2044
2064
  this: ConstructorType<M>,
2045
2065
  modelOrObject: PartialModelObject<M>,
2046
2066
  expression: E,
2047
2067
  options?: FetchGraphOptions,
2048
2068
  ): SingleQueryBuilder<WithGraphModelQueryBuilder<M, E>>;
2049
2069
 
2050
- static fetchGraph<M extends Model, const E extends RelationExpression<M>>(
2070
+ static fetchGraph<M extends Model, const E extends RelationExpression<M> = string>(
2051
2071
  this: ConstructorType<M>,
2052
2072
  modelOrObject: PartialModelObject<M>[],
2053
2073
  expression: E,
@@ -1,27 +0,0 @@
1
- 'use strict';
2
-
3
- const { ManyToManyModifyMixin } = require('./ManyToManyModifyMixin');
4
-
5
- // Like `ManyToManySqliteModifyMixin`, this identifies the join rows to modify
6
- // by their physical row id, so that only the join rows that match the filters
7
- // are modified (#1853). `tableoid` makes `ctid` unique for partitioned tables.
8
- const ManyToManyPostgresModifyMixin = (Operation) => {
9
- return class extends ManyToManyModifyMixin(Operation) {
10
- applyModifyFilterForJoinTable(builder) {
11
- const joinTableOwnerRefs = this.relation.joinTableOwnerProp.refs(builder);
12
- const tableRef = builder.tableRefFor(this.relation.getJoinModelClass(builder));
13
- const rowIdRefs = [`${tableRef}.tableoid`, `${tableRef}.ctid`];
14
-
15
- const ownerValues = this.owner.getProps(this.relation);
16
- const subquery = this.modifyFilterSubquery.clone().select(rowIdRefs);
17
-
18
- return builder
19
- .whereInComposite(rowIdRefs, subquery)
20
- .whereInComposite(joinTableOwnerRefs, ownerValues);
21
- }
22
- };
23
- };
24
-
25
- module.exports = {
26
- ManyToManyPostgresModifyMixin,
27
- };
@@ -1,16 +0,0 @@
1
- 'use strict';
2
-
3
- const { ManyToManyUnrelateOperationBase } = require('./ManyToManyUnrelateOperationBase');
4
- const { ManyToManyPostgresModifyMixin } = require('../ManyToManyPostgresModifyMixin');
5
-
6
- class ManyToManyUnrelatePostgresOperation extends ManyToManyPostgresModifyMixin(
7
- ManyToManyUnrelateOperationBase,
8
- ) {
9
- get modifyMainQuery() {
10
- return false;
11
- }
12
- }
13
-
14
- module.exports = {
15
- ManyToManyUnrelatePostgresOperation,
16
- };
@@ -1,12 +0,0 @@
1
- 'use strict';
2
-
3
- const { ManyToManyUpdateOperationBase } = require('./ManyToManyUpdateOperationBase');
4
- const { ManyToManyPostgresModifyMixin } = require('../ManyToManyPostgresModifyMixin');
5
-
6
- class ManyToManyUpdatePostgresOperation extends ManyToManyPostgresModifyMixin(
7
- ManyToManyUpdateOperationBase,
8
- ) {}
9
-
10
- module.exports = {
11
- ManyToManyUpdatePostgresOperation,
12
- };