objection 3.1.5 → 3.3.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 (69) hide show
  1. package/README.md +16 -16
  2. package/lib/model/AjvValidator.js +173 -18
  3. package/lib/model/Model.js +3 -1
  4. package/lib/model/graph/ModelGraphNode.js +12 -0
  5. package/lib/model/modelToJson.js +2 -1
  6. package/lib/queryBuilder/QueryBuilder.js +339 -47
  7. package/lib/queryBuilder/QueryBuilderOperationSupport.js +5 -0
  8. package/lib/queryBuilder/ReferenceBuilder.js +5 -3
  9. package/lib/queryBuilder/RelationExpression.js +21 -9
  10. package/lib/queryBuilder/StaticHookArguments.js +12 -1
  11. package/lib/queryBuilder/graph/GraphFetcher.js +3 -1
  12. package/lib/queryBuilder/graph/GraphOptions.js +21 -2
  13. package/lib/queryBuilder/graph/GraphUpsert.js +52 -0
  14. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +20 -14
  15. package/lib/queryBuilder/graph/insert/DeferredRelationGraphInsertAction.js +57 -0
  16. package/lib/queryBuilder/graph/insert/GraphInsert.js +113 -8
  17. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +10 -1
  18. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +15 -3
  19. package/lib/queryBuilder/join/JoinResultParser.js +22 -0
  20. package/lib/queryBuilder/join/RelationJoiner.js +71 -5
  21. package/lib/queryBuilder/operations/DelegateOperation.js +4 -0
  22. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +7 -1
  23. package/lib/queryBuilder/operations/InsertGraphOperation.js +2 -2
  24. package/lib/queryBuilder/operations/InsertOperation.js +121 -12
  25. package/lib/queryBuilder/operations/NoneOperation.js +37 -0
  26. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +5 -0
  27. package/lib/queryBuilder/operations/QueryBuilderOperation.js +4 -0
  28. package/lib/queryBuilder/operations/ReturningOperation.js +28 -3
  29. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +20 -0
  30. package/lib/queryBuilder/operations/UpdateOperation.js +3 -2
  31. package/lib/queryBuilder/operations/UpsertGraphOperation.js +5 -0
  32. package/lib/queryBuilder/operations/WhereGroupOperation.js +41 -0
  33. package/lib/queryBuilder/operations/eager/EagerOperation.js +7 -5
  34. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +4 -2
  35. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +9 -20
  36. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasPostgresOperation.js +3 -3
  37. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectPostgresOperation.js +1 -1
  38. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +45 -32
  39. package/lib/queryBuilder/operations/select/Selection.js +95 -4
  40. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +6 -0
  41. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +5 -1
  42. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +9 -0
  43. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +81 -43
  44. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.pegjs +5 -4
  45. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +9 -0
  46. package/lib/queryBuilder/whereGroups.js +125 -0
  47. package/lib/relations/Relation.js +5 -2
  48. package/lib/relations/RelationProperty.js +7 -3
  49. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +1 -0
  50. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +5 -0
  51. package/lib/relations/hasMany/HasManyRelateOperation.js +6 -2
  52. package/lib/relations/hasMany/HasManyUnrelateOperation.js +5 -2
  53. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +26 -3
  54. package/lib/relations/manyToMany/ManyToManyMySqlModifyMixin.js +66 -0
  55. package/lib/relations/manyToMany/ManyToManyPostgresModifyMixin.js +27 -0
  56. package/lib/relations/manyToMany/ManyToManyRelation.js +70 -48
  57. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +6 -0
  58. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateMySqlOperation.js +16 -0
  59. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +5 -1
  60. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelatePostgresOperation.js +16 -0
  61. package/lib/relations/manyToMany/update/ManyToManyUpdateMySqlOperation.js +12 -0
  62. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +8 -2
  63. package/lib/relations/manyToMany/update/ManyToManyUpdatePostgresOperation.js +12 -0
  64. package/lib/utils/deprecate.js +6 -0
  65. package/lib/utils/identifierMapping.js +23 -3
  66. package/lib/utils/objectUtils.js +9 -5
  67. package/lib/utils/parseFieldExpression.js +28 -0
  68. package/package.json +22 -14
  69. package/typings/objection/index.d.ts +339 -68
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ const { ManyToManyUpdateOperationBase } = require('./ManyToManyUpdateOperationBase');
4
+ const { ManyToManyMySqlModifyMixin } = require('../ManyToManyMySqlModifyMixin');
5
+
6
+ class ManyToManyUpdateMySqlOperation extends ManyToManyMySqlModifyMixin(
7
+ ManyToManyUpdateOperationBase,
8
+ ) {}
9
+
10
+ module.exports = {
11
+ ManyToManyUpdateMySqlOperation,
12
+ };
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { UpdateOperation } = require('../../../queryBuilder/operations/UpdateOperation');
4
+ const { addWhereGroup } = require('../../../queryBuilder/whereGroups');
4
5
 
5
6
  class ManyToManyUpdateOperationBase extends UpdateOperation {
6
7
  constructor(name, opt) {
@@ -44,9 +45,14 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
44
45
  .childQueryOf(builder)
45
46
  .patch(this.joinTablePatch);
46
47
 
47
- await this.applyModifyFilterForJoinTable(joinTableUpdateQuery).modify(
48
- this.relation.joinTableModify,
48
+ addWhereGroup(joinTableUpdateQuery, () =>
49
+ this.applyModifyFilterForJoinTable(joinTableUpdateQuery),
49
50
  );
51
+ addWhereGroup(joinTableUpdateQuery, () =>
52
+ joinTableUpdateQuery.modify(this.relation.joinTableModify),
53
+ );
54
+
55
+ await joinTableUpdateQuery;
50
56
  return result;
51
57
  } else {
52
58
  return result;
@@ -0,0 +1,12 @@
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
+ };
@@ -10,6 +10,12 @@ function deprecate(message) {
10
10
  }
11
11
  }
12
12
 
13
+ // Only meant for tests that need to see a deprecation message again.
14
+ function resetDeprecations() {
15
+ LOGGED_DEPRECATIONS.clear();
16
+ }
17
+
13
18
  module.exports = {
14
19
  deprecate,
20
+ resetDeprecations,
15
21
  };
@@ -27,6 +27,7 @@ function snakeCase(
27
27
  upperCase = false,
28
28
  underscoreBeforeDigits = false,
29
29
  underscoreBetweenUppercaseLetters = false,
30
+ noDoubleUnderscores = false,
30
31
  } = {},
31
32
  ) {
32
33
  if (str.length === 0) {
@@ -48,11 +49,16 @@ function snakeCase(
48
49
  const lowerChar = lower[i];
49
50
  const prevLowerChar = lower[i - 1];
50
51
 
52
+ // If noDoubleUnderscores is true, never insert an underscore directly
53
+ // after an existing one (e.g. "foo_1" stays "foo_1" instead of becoming
54
+ // "foo__1" when underscoreBeforeDigits is true).
55
+ const canInsertUnderscore = !noDoubleUnderscores || prevChar !== '_';
56
+
51
57
  // If underScoreBeforeDigits is true then, well, insert an underscore
52
58
  // before digits :). Only the first digit gets an underscore if
53
59
  // there are multiple.
54
60
  if (underscoreBeforeDigits && isDigit(char) && !isDigit(prevChar)) {
55
- out += '_' + char;
61
+ out += canInsertUnderscore ? '_' + char : char;
56
62
  continue;
57
63
  }
58
64
 
@@ -65,7 +71,7 @@ function snakeCase(
65
71
  // If underscoreBetweenUppercaseLetters is true, we always place an underscore
66
72
  // before consecutive uppercase letters (e.g. "fooBAR" becomes "foo_b_a_r").
67
73
  // Otherwise, we don't (e.g. "fooBAR" becomes "foo_bar").
68
- if (underscoreBetweenUppercaseLetters || !prevCharacterIsUppercase) {
74
+ if (canInsertUnderscore && (underscoreBetweenUppercaseLetters || !prevCharacterIsUppercase)) {
69
75
  out += '_' + lowerChar;
70
76
  } else {
71
77
  out += lowerChar;
@@ -162,10 +168,24 @@ function keyMapper(mapper) {
162
168
  };
163
169
  }
164
170
 
171
+ // Returns a function that only calls `mapper` for the part of the input string
172
+ // before the first `separator`, and leaves the rest untouched. For field
173
+ // expressions like `jsonColumn:some.jsonPath` this maps the column but keeps
174
+ // the json path as is. Column names can't contain `:`, so the first one marks
175
+ // the boundary.
176
+ function mapFirstPart(mapper, separator) {
177
+ return (str) => {
178
+ const idx = str.indexOf(separator);
179
+ return idx === -1 ? mapper(str) : mapper(str.slice(0, idx)) + str.slice(idx);
180
+ };
181
+ }
182
+
165
183
  function snakeCaseMappers(opt = {}) {
184
+ const format = (str) => snakeCase(str, opt);
185
+
166
186
  return {
167
187
  parse: keyMapper(memoize((str) => camelCase(str, opt))),
168
- format: keyMapper(memoize((str) => snakeCase(str, opt))),
188
+ format: keyMapper(memoize(opt.preserveJsonKeys ? mapFirstPart(format, ':') : format)),
169
189
  };
170
190
  }
171
191
 
@@ -123,13 +123,17 @@ function union(arr1, arr2) {
123
123
  }
124
124
 
125
125
  function unionSmall(arr1, arr2) {
126
- const all = arr1.slice();
126
+ const all = [];
127
127
 
128
- for (let i = 0, l = arr2.length; i < l; ++i) {
129
- const item = arr2[i];
128
+ for (let i = 0, l = arr1.length; i < l; ++i) {
129
+ if (all.indexOf(arr1[i]) === -1) {
130
+ all.push(arr1[i]);
131
+ }
132
+ }
130
133
 
131
- if (all.indexOf(item) === -1) {
132
- all.push(item);
134
+ for (let i = 0, l = arr2.length; i < l; ++i) {
135
+ if (all.indexOf(arr2[i]) === -1) {
136
+ all.push(arr2[i]);
133
137
  }
134
138
  }
135
139
 
@@ -46,6 +46,34 @@ function freezeParsedExpr(parsedExpr) {
46
46
  return parsedExpr;
47
47
  }
48
48
 
49
+ // Formats the json path of a parsed field expression as a Postgres text array
50
+ // literal, e.g. `{a,"",b}`. Keys that would otherwise be misread (empty keys,
51
+ // keys with whitespace, delimiters, quotes or backslashes and `NULL`) are
52
+ // double-quoted, with quotes and backslashes escaped.
53
+ function toPostgresJsonPath(access) {
54
+ const keys = access.map(({ ref }) => {
55
+ const key = String(ref);
56
+ return key === '' || /[{}",\\\s]/.test(key) || key.toUpperCase() === 'NULL'
57
+ ? `"${key.replace(/["\\]/g, '\\$&')}"`
58
+ : key;
59
+ });
60
+ return `{${keys.join(',')}}`;
61
+ }
62
+
63
+ // Formats the json path of a parsed field expression as a quoted string literal
64
+ // to be used in raw knex SQL, e.g. `'{a,b}'`. The path can't be passed as a
65
+ // binding, as knex doesn't keep the order of bindings in raw columns (e.g. in
66
+ // `whereIn(ref(...), values)`), so the keys need to be escaped instead: single
67
+ // quotes are doubled, and `?` is escaped so that knex doesn't read it as a
68
+ // binding placeholder. Backslashes are always doubled by `toPostgresJsonPath()`,
69
+ // so they can't escape the closing quote either.
70
+ function toPostgresJsonPathLiteral(access) {
71
+ const path = toPostgresJsonPath(access).replace(/'/g, "''").replace(/\?/g, '\\?');
72
+ return `'${path}'`;
73
+ }
74
+
49
75
  module.exports = {
50
76
  parseFieldExpression,
77
+ toPostgresJsonPath,
78
+ toPostgresJsonPathLiteral,
51
79
  };
package/package.json CHANGED
@@ -1,17 +1,18 @@
1
1
  {
2
2
  "name": "objection",
3
- "version": "3.1.5",
3
+ "version": "3.3.0",
4
4
  "description": "An SQL-friendly ORM for Node.js",
5
5
  "main": "lib/objection.js",
6
6
  "license": "MIT",
7
7
  "scripts": {
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
- "test:typings": "tsc",
10
+ "test:typings": "tsc && prettier --check \"typings/**/*.ts\" \"tests/ts/**/*.ts\"",
11
11
  "prettier": "prettier --write \"{examples,lib,tests,testUtils,typings,doc}/**/*.{js,ts}\"",
12
12
  "eslint": "eslint --format codeframe \"examples/**/*.js\" \"lib/**/*.js\" \"tests/**/*.js\"",
13
- "docs:dev": "vuepress dev doc",
14
- "docs:build": "vuepress build doc"
13
+ "docs:dev": "vitepress dev doc",
14
+ "docs:build": "vitepress build doc",
15
+ "docs:preview": "vitepress preview doc"
15
16
  },
16
17
  "publishConfig": {
17
18
  "tag": "latest"
@@ -30,8 +31,12 @@
30
31
  ],
31
32
  "repository": {
32
33
  "type": "git",
33
- "url": "git://github.com/vincit/objection.js.git"
34
+ "url": "git+https://github.com/ditojs/objection.git"
34
35
  },
36
+ "bugs": {
37
+ "url": "https://github.com/ditojs/objection/issues"
38
+ },
39
+ "homepage": "https://ditojs.github.io/objection/",
35
40
  "engines": {
36
41
  "node": ">=14.0.0"
37
42
  },
@@ -54,27 +59,30 @@
54
59
  "types": "./typings/objection/index.d.ts",
55
60
  "dependencies": {
56
61
  "ajv": "^8.17.1",
57
- "ajv-formats": "^2.1.1",
62
+ "ajv-formats": "^3.0.1",
58
63
  "db-errors": "^0.2.3"
59
64
  },
60
65
  "peerDependencies": {
61
66
  "knex": ">=1.0.1"
62
67
  },
63
68
  "devDependencies": {
64
- "@types/node": "^22.7.0",
69
+ "@types/node": "^22.15.3",
70
+ "bluebird": "^3.7.2",
65
71
  "chai": "^4.3.10",
66
72
  "chai-subset": "^1.6.0",
67
73
  "eslint": "^8.54.0",
68
74
  "eslint-formatter-codeframe": "^7.32.1",
69
- "eslint-plugin-prettier": "^5.2.1",
75
+ "eslint-plugin-prettier": "^5.3.1",
70
76
  "expect.js": "^0.3.1",
71
- "knex": "^3.1.0",
72
- "mocha": "^10.7.3",
77
+ "knex": "^3.3.0",
78
+ "lodash": "^4.18.1",
79
+ "mocha": "^11.2.2",
73
80
  "mysql": "^2.18.1",
74
- "pg": "^8.13.0",
75
- "prettier": "3.3.3",
81
+ "pg": "^8.15.6",
82
+ "prettier": "3.9.9",
76
83
  "sqlite3": "^5.1.7",
77
- "typescript": ">=5.6.2",
78
- "vuepress": "1.9.10"
84
+ "typescript": ">=5.8.3",
85
+ "uuid": "^9.0.1",
86
+ "vitepress": "1.6.4"
79
87
  }
80
88
  }