@abedmurrar/objection 4.0.0-beta.2 → 4.0.0-beta.4
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/lib/queryBuilder/FunctionBuilder.js +35 -31
- package/lib/queryBuilder/JoinBuilder.js +46 -45
- package/lib/queryBuilder/RawBuilder.js +15 -13
- package/lib/queryBuilder/ReferenceBuilder.js +25 -23
- package/lib/queryBuilder/RelationExpression.js +59 -19
- package/lib/queryBuilder/ValueBuilder.js +20 -19
- package/lib/queryBuilder/expressions.js +8 -18
- package/lib/queryBuilder/functions/mysql.js +18 -42
- package/lib/queryBuilder/join/JoinResultColumn.js +6 -4
- package/lib/queryBuilder/join/JoinResultParser.js +10 -8
- package/lib/queryBuilder/join/RelationJoiner.js +40 -35
- package/lib/queryBuilder/join/TableNode.js +7 -5
- package/lib/queryBuilder/join/TableTree.js +13 -9
- package/lib/queryBuilder/join/utils.js +8 -8
- package/package.json +1 -1
|
@@ -1,15 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DuplicateRelationError = exports.RelationExpressionParseError = exports.RelationExpression = void 0;
|
|
37
|
+
const parser = __importStar(require("./parsers/relationExpressionParser"));
|
|
38
|
+
const objectUtils_1 = require("../utils/objectUtils");
|
|
39
|
+
const RelationDoesNotExistError_1 = require("../model/RelationDoesNotExistError");
|
|
5
40
|
class RelationExpressionParseError extends Error {
|
|
6
41
|
}
|
|
42
|
+
exports.RelationExpressionParseError = RelationExpressionParseError;
|
|
7
43
|
class DuplicateRelationError extends RelationExpressionParseError {
|
|
8
44
|
constructor(relationName) {
|
|
9
45
|
super();
|
|
10
46
|
this.relationName = relationName;
|
|
11
47
|
}
|
|
12
48
|
}
|
|
49
|
+
exports.DuplicateRelationError = DuplicateRelationError;
|
|
13
50
|
class RelationExpression {
|
|
14
51
|
constructor(node = newNode(), recursionDepth = 0) {
|
|
15
52
|
this.node = node;
|
|
@@ -18,7 +55,7 @@ class RelationExpression {
|
|
|
18
55
|
// Create a relation expression from a string, a pojo or another
|
|
19
56
|
// RelationExpression instance.
|
|
20
57
|
static create(expr) {
|
|
21
|
-
if (isObject(expr)) {
|
|
58
|
+
if ((0, objectUtils_1.isObject)(expr)) {
|
|
22
59
|
if (expr.isObjectionRelationExpression) {
|
|
23
60
|
return expr;
|
|
24
61
|
}
|
|
@@ -26,7 +63,7 @@ class RelationExpression {
|
|
|
26
63
|
return new RelationExpression(normalizeNode(expr));
|
|
27
64
|
}
|
|
28
65
|
}
|
|
29
|
-
else if (isString(expr)) {
|
|
66
|
+
else if ((0, objectUtils_1.isString)(expr)) {
|
|
30
67
|
if (expr.trim().length === 0) {
|
|
31
68
|
return new RelationExpression();
|
|
32
69
|
}
|
|
@@ -58,7 +95,7 @@ class RelationExpression {
|
|
|
58
95
|
}
|
|
59
96
|
}
|
|
60
97
|
get maxRecursionDepth() {
|
|
61
|
-
if (isNumber(this.node.$recursive)) {
|
|
98
|
+
if ((0, objectUtils_1.isNumber)(this.node.$recursive)) {
|
|
62
99
|
return this.node.$recursive;
|
|
63
100
|
}
|
|
64
101
|
else {
|
|
@@ -143,7 +180,7 @@ class RelationExpression {
|
|
|
143
180
|
const node = this.node[childName];
|
|
144
181
|
const relation = modelClass.getRelationUnsafe(node.$relation);
|
|
145
182
|
if (!relation) {
|
|
146
|
-
throw new RelationDoesNotExistError(node.$relation);
|
|
183
|
+
throw new RelationDoesNotExistError_1.RelationDoesNotExistError(node.$relation);
|
|
147
184
|
}
|
|
148
185
|
const childExpr = new RelationExpression(node);
|
|
149
186
|
cb(childExpr, relation);
|
|
@@ -156,6 +193,7 @@ class RelationExpression {
|
|
|
156
193
|
clone() {
|
|
157
194
|
return new RelationExpression(cloneNode(this.node), this.recursionDepth);
|
|
158
195
|
}
|
|
196
|
+
// `null` for an empty expression.
|
|
159
197
|
toString() {
|
|
160
198
|
return toString(this.node);
|
|
161
199
|
}
|
|
@@ -166,6 +204,7 @@ class RelationExpression {
|
|
|
166
204
|
return this.toPojo();
|
|
167
205
|
}
|
|
168
206
|
}
|
|
207
|
+
exports.RelationExpression = RelationExpression;
|
|
169
208
|
const parseCache = new Map();
|
|
170
209
|
function parse(str) {
|
|
171
210
|
const cachedNode = parseCache.get(str);
|
|
@@ -194,10 +233,12 @@ function getChildNames(node) {
|
|
|
194
233
|
}
|
|
195
234
|
function toString(node) {
|
|
196
235
|
const childNames = node.$childNames;
|
|
197
|
-
let childExpr = childNames
|
|
236
|
+
let childExpr = childNames
|
|
237
|
+
.map((childName) => node[childName])
|
|
238
|
+
.map(toString);
|
|
198
239
|
let str = node.$relation;
|
|
199
240
|
if (node.$recursive) {
|
|
200
|
-
if (isNumber(node.$recursive)) {
|
|
241
|
+
if ((0, objectUtils_1.isNumber)(node.$recursive)) {
|
|
201
242
|
str += '.^' + node.$recursive;
|
|
202
243
|
}
|
|
203
244
|
else {
|
|
@@ -277,8 +318,10 @@ function normalizeNode(node = null, name = null, allRecusive = false) {
|
|
|
277
318
|
$childNames: normalizeChildNames(node),
|
|
278
319
|
};
|
|
279
320
|
for (const childName of normalized.$childNames) {
|
|
321
|
+
// `node` isn't null here, since a null node has no child names.
|
|
280
322
|
const childNode = node[childName];
|
|
281
|
-
if (isObject(childNode) || childNode === true) {
|
|
323
|
+
if ((0, objectUtils_1.isObject)(childNode) || childNode === true) {
|
|
324
|
+
// `true` is a node without any properties, like `{}`.
|
|
282
325
|
normalized[childName] = normalizeNode(childNode, childName);
|
|
283
326
|
}
|
|
284
327
|
}
|
|
@@ -312,6 +355,7 @@ function findExpressionsAtPath(target, path, results) {
|
|
|
312
355
|
}
|
|
313
356
|
else {
|
|
314
357
|
for (const childName of path.node.$childNames) {
|
|
358
|
+
// Not null, since `childName` is a child of `path`.
|
|
315
359
|
const pathChild = path.childExpression(childName);
|
|
316
360
|
const targetChild = target.childExpression(childName);
|
|
317
361
|
if (targetChild) {
|
|
@@ -325,13 +369,13 @@ function mergeNodes(node1, node2) {
|
|
|
325
369
|
const node = {
|
|
326
370
|
$name: node1.$name,
|
|
327
371
|
$relation: node1.$relation,
|
|
328
|
-
$modify: union(node1.$modify, node2.$modify),
|
|
372
|
+
$modify: (0, objectUtils_1.union)(node1.$modify, node2.$modify),
|
|
329
373
|
$recursive: mergeRecursion(node1.$recursive, node2.$recursive),
|
|
330
374
|
$allRecursive: node1.$allRecursive || node2.$allRecursive,
|
|
331
375
|
$childNames: null,
|
|
332
376
|
};
|
|
333
377
|
if (!node.$recursive && !node.$allRecursive) {
|
|
334
|
-
node.$childNames = union(node1.$childNames, node2.$childNames);
|
|
378
|
+
node.$childNames = (0, objectUtils_1.union)(node1.$childNames, node2.$childNames);
|
|
335
379
|
for (const childName of node.$childNames) {
|
|
336
380
|
const child1 = node1[childName];
|
|
337
381
|
const child2 = node2[childName];
|
|
@@ -346,13 +390,14 @@ function mergeNodes(node1, node2) {
|
|
|
346
390
|
else {
|
|
347
391
|
node.$childNames = [];
|
|
348
392
|
}
|
|
393
|
+
// `$childNames` was set above.
|
|
349
394
|
return node;
|
|
350
395
|
}
|
|
351
396
|
function mergeRecursion(rec1, rec2) {
|
|
352
397
|
if (rec1 === true || rec2 === true) {
|
|
353
398
|
return true;
|
|
354
399
|
}
|
|
355
|
-
else if (isNumber(rec1) && isNumber(rec2)) {
|
|
400
|
+
else if ((0, objectUtils_1.isNumber)(rec1) && (0, objectUtils_1.isNumber)(rec2)) {
|
|
356
401
|
return Math.max(rec1, rec2);
|
|
357
402
|
}
|
|
358
403
|
else {
|
|
@@ -366,8 +411,3 @@ Object.defineProperties(RelationExpression.prototype, {
|
|
|
366
411
|
value: true,
|
|
367
412
|
},
|
|
368
413
|
});
|
|
369
|
-
module.exports = {
|
|
370
|
-
RelationExpression,
|
|
371
|
-
RelationExpressionParseError,
|
|
372
|
-
DuplicateRelationError,
|
|
373
|
-
};
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ValueBuilder = void 0;
|
|
4
|
+
exports.val = val;
|
|
5
|
+
const objectUtils_1 = require("../utils/objectUtils");
|
|
6
|
+
const buildUtils_1 = require("../utils/buildUtils");
|
|
7
|
+
const knexUtils_1 = require("../utils/knexUtils");
|
|
8
|
+
const mysqlJsonPath_1 = require("../utils/mysqlJsonPath");
|
|
9
|
+
const expressions_1 = require("./expressions");
|
|
7
10
|
class ValueBuilder {
|
|
8
11
|
constructor(value) {
|
|
9
12
|
this._value = value;
|
|
10
13
|
this._cast = null;
|
|
11
14
|
// Cast objects and arrays to json by default.
|
|
12
|
-
this._toJson = isObject(value);
|
|
15
|
+
this._toJson = (0, objectUtils_1.isObject)(value);
|
|
13
16
|
this._toArray = false;
|
|
14
17
|
this._alias = null;
|
|
15
18
|
}
|
|
@@ -67,29 +70,30 @@ class ValueBuilder {
|
|
|
67
70
|
sql = '?';
|
|
68
71
|
}
|
|
69
72
|
else if (this._toArray) {
|
|
70
|
-
const values = asArray(this._value);
|
|
71
|
-
bindings.push(...values.map((it) => buildArg(it, builder)));
|
|
73
|
+
const values = (0, objectUtils_1.asArray)(this._value);
|
|
74
|
+
bindings.push(...values.map((it) => (0, buildUtils_1.buildArg)(it, builder)));
|
|
72
75
|
sql = `ARRAY[${values.map(() => '?').join(', ')}]`;
|
|
73
76
|
}
|
|
74
77
|
else {
|
|
78
|
+
// A value of the user, which knex binds as it is.
|
|
75
79
|
bindings.push(this._value);
|
|
76
80
|
sql = '?';
|
|
77
81
|
}
|
|
78
82
|
const knex = builder.unsafeKnex();
|
|
79
|
-
const mysql = isMySql(knex);
|
|
83
|
+
const mysql = (0, knexUtils_1.isMySql)(knex);
|
|
80
84
|
if (this._toJson && !this._cast && mysql) {
|
|
81
85
|
// MySQL compares strings and JSON values as strings, so `{}` is never
|
|
82
86
|
// equal to a JSON column without the cast. Postgres casts it implicitly.
|
|
83
|
-
sql = toJsonSql(sql, knex);
|
|
87
|
+
sql = (0, mysqlJsonPath_1.toJsonSql)(sql, knex);
|
|
84
88
|
}
|
|
85
89
|
else if (this._cast && mysql) {
|
|
86
|
-
const type = toMySqlCastType(this._cast);
|
|
90
|
+
const type = (0, mysqlJsonPath_1.toMySqlCastType)(this._cast);
|
|
87
91
|
// MySQL can't cast to a boolean.
|
|
88
|
-
if (isBooleanType(this._cast)) {
|
|
92
|
+
if ((0, mysqlJsonPath_1.isBooleanType)(this._cast)) {
|
|
89
93
|
sql = `(${sql} <> 0)`;
|
|
90
94
|
}
|
|
91
95
|
else if (type === 'JSON') {
|
|
92
|
-
sql = toJsonSql(sql, knex);
|
|
96
|
+
sql = (0, mysqlJsonPath_1.toJsonSql)(sql, knex);
|
|
93
97
|
}
|
|
94
98
|
else {
|
|
95
99
|
sql = `CAST(${sql} AS ${type})`;
|
|
@@ -105,11 +109,8 @@ class ValueBuilder {
|
|
|
105
109
|
return [sql, bindings];
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
|
-
|
|
112
|
+
exports.ValueBuilder = ValueBuilder;
|
|
113
|
+
(0, expressions_1.addExpressionMethods)(ValueBuilder.prototype);
|
|
109
114
|
function val(val) {
|
|
110
115
|
return new ValueBuilder(val);
|
|
111
116
|
}
|
|
112
|
-
module.exports = {
|
|
113
|
-
ValueBuilder,
|
|
114
|
-
val,
|
|
115
|
-
};
|
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// Person.ref('age').gte(18).as('isAdult')
|
|
7
|
-
// Pet.ref('order').plus(1)
|
|
8
|
-
// Person.ref('firstName').isNotBlank().or(Person.ref('lastName').isNotBlank())
|
|
9
|
-
//
|
|
10
|
-
// Every method returns a new `FunctionBuilder`. The sql is wrapped in parentheses,
|
|
11
|
-
// so expressions can be nested without thinking about operator precedence. The
|
|
12
|
-
// arguments are bindings like the arguments of `fn()`: strings are values and
|
|
13
|
-
// columns are passed with `ref()` or `Model.ref()`.
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addExpressionMethods = addExpressionMethods;
|
|
4
|
+
exports.expression = expression;
|
|
5
|
+
const objectUtils_1 = require("../utils/objectUtils");
|
|
14
6
|
const COMPARISONS = {
|
|
15
7
|
eq: '=',
|
|
16
8
|
ne: '<>',
|
|
@@ -98,7 +90,9 @@ function createLogic(first, rest, operator) {
|
|
|
98
90
|
return expression(`(${conditions.map(() => '?').join(` ${operator} `)})`, conditions);
|
|
99
91
|
}
|
|
100
92
|
function isSubquery(value) {
|
|
101
|
-
return (isObject(value) &&
|
|
93
|
+
return ((0, objectUtils_1.isObject)(value) &&
|
|
94
|
+
(value.isObjectionQueryBuilderBase ||
|
|
95
|
+
typeof value.toSQL === 'function'));
|
|
102
96
|
}
|
|
103
97
|
function expression(sql, args) {
|
|
104
98
|
// Required here because `FunctionBuilder` itself gets these methods.
|
|
@@ -115,7 +109,3 @@ function addExpressionMethods(prototype) {
|
|
|
115
109
|
});
|
|
116
110
|
}
|
|
117
111
|
}
|
|
118
|
-
module.exports = {
|
|
119
|
-
addExpressionMethods,
|
|
120
|
-
expression,
|
|
121
|
-
};
|
|
@@ -1,35 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
// name the name of the helper: `fn.dateFormat()`
|
|
8
|
-
// sql the name of the SQL function: `DATE_FORMAT`
|
|
9
|
-
// params the parameters, as TypeScript
|
|
10
|
-
// result the type of the result, as TypeScript
|
|
11
|
-
// options `json`: the arguments that are JSON documents. Objects and arrays
|
|
12
|
-
// passed to them are cast to JSON. An array of indexes,
|
|
13
|
-
// 'all', or 'even' (0, 2, 4, ...) / 'odd' (1, 3, 5, ...).
|
|
14
|
-
// `portable`: the function works the same on postgres, so it
|
|
15
|
-
// isn't limited to MySQL.
|
|
16
|
-
// `build`: a function that builds the sql for functions with
|
|
17
|
-
// keywords in their syntax, like `TIMESTAMPDIFF(DAY, ?, ?)`.
|
|
18
|
-
// `aggregate`: the function is an aggregate that `filter()` works
|
|
19
|
-
// with. `true` when every argument is aggregated, or a
|
|
20
|
-
// function that returns how many of the first arguments are.
|
|
21
|
-
// `window`: the function is a window function, which needs `over()`.
|
|
22
|
-
//
|
|
23
|
-
// The arguments are bindings, so strings are values. Columns are passed with
|
|
24
|
-
// `ref()` or `Model.ref()`.
|
|
25
|
-
//
|
|
26
|
-
// The typings in `typings/objection/index.d.ts` are generated from this list
|
|
27
|
-
// with `node scripts/generate-fn-typings.js`.
|
|
28
|
-
//
|
|
29
|
-
// Not included: spatial functions, operators, `CASE`, `JSON_TABLE()`, internal functions and functions
|
|
30
|
-
// that are deprecated (`JSON_MERGE()`, `FOUND_ROWS()`, `VALUES()`,
|
|
31
|
-
// `MASTER_POS_WAIT()`) or that need a component (`VALIDATE_PASSWORD_STRENGTH()`).
|
|
32
|
-
// `fn('NAME', ...args)` calls any function.
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TIMESTAMP_UNITS = exports.INTERVAL_UNITS = exports.MARIADB_UNSUPPORTED = exports.FUNCTIONS = void 0;
|
|
4
|
+
exports.buildOrderBy = buildOrderBy;
|
|
5
|
+
const ReferenceBuilder_1 = require("../ReferenceBuilder");
|
|
33
6
|
const STR = 'string | null';
|
|
34
7
|
const NUM = 'number | null';
|
|
35
8
|
const DEC = 'FnNumeric | null';
|
|
@@ -66,7 +39,9 @@ const INTERVAL_UNITS = [
|
|
|
66
39
|
'DAY_HOUR',
|
|
67
40
|
'YEAR_MONTH',
|
|
68
41
|
];
|
|
42
|
+
exports.INTERVAL_UNITS = INTERVAL_UNITS;
|
|
69
43
|
const TIMESTAMP_UNITS = INTERVAL_UNITS.slice(0, 9);
|
|
44
|
+
exports.TIMESTAMP_UNITS = TIMESTAMP_UNITS;
|
|
70
45
|
const CAST_TYPE = /^((BINARY|CHAR|NCHAR)(\(\d+\))?( CHARACTER SET \w+)?|DATE|(DATETIME|TIME)(\(\d\))?|DECIMAL(\(\d+(, ?\d+)?\))?|DOUBLE|FLOAT(\(\d+\))?|JSON|REAL|(SIGNED|UNSIGNED)( INTEGER)?|YEAR)$/i;
|
|
71
46
|
const CHARSET = /^\w+$/;
|
|
72
47
|
const MATCH_MODES = {
|
|
@@ -540,6 +515,7 @@ const FUNCTIONS = [
|
|
|
540
515
|
{ json: [0, 1], build: buildMemberOf },
|
|
541
516
|
],
|
|
542
517
|
];
|
|
518
|
+
exports.FUNCTIONS = FUNCTIONS;
|
|
543
519
|
// Builders for the functions with keywords in their syntax. They return
|
|
544
520
|
// `[sql, args]`. Keywords are checked against lists, since they can't be bindings.
|
|
545
521
|
function buildDateAdd(name, sql, [date, amount, unit]) {
|
|
@@ -592,6 +568,7 @@ function buildTrim(name, sql, [str, options = {}]) {
|
|
|
592
568
|
}
|
|
593
569
|
}
|
|
594
570
|
function buildChar(name, sql, [codes, options = {}]) {
|
|
571
|
+
// `codes`, `columns` and `exprs` below are arrays after the first line.
|
|
595
572
|
codes = Array.isArray(codes) ? codes : [codes];
|
|
596
573
|
const placeholders = codes.map(() => '?').join(', ');
|
|
597
574
|
if (options.using === undefined) {
|
|
@@ -612,7 +589,10 @@ function buildMatch(name, sql, [columns, search, options = {}]) {
|
|
|
612
589
|
}
|
|
613
590
|
mode = ` ${mode}`;
|
|
614
591
|
}
|
|
615
|
-
return [
|
|
592
|
+
return [
|
|
593
|
+
`MATCH(${columns.map(() => '?').join(', ')}) AGAINST(?${mode})`,
|
|
594
|
+
[...columns, search],
|
|
595
|
+
];
|
|
616
596
|
}
|
|
617
597
|
function buildCountDistinct(name, sql, exprs) {
|
|
618
598
|
return [`COUNT(DISTINCT ${exprs.map(() => '?').join(', ')})`, exprs];
|
|
@@ -653,7 +633,7 @@ function buildOrderBy(name, orderBy) {
|
|
|
653
633
|
return [sql, args];
|
|
654
634
|
}
|
|
655
635
|
function toColumn(column) {
|
|
656
|
-
return typeof column === 'string' ? ref(column) : column;
|
|
636
|
+
return typeof column === 'string' ? (0, ReferenceBuilder_1.ref)(column) : column;
|
|
657
637
|
}
|
|
658
638
|
function buildNtile(name, sql, [buckets]) {
|
|
659
639
|
return [`NTILE(${integer(name, 'buckets', buckets, 1)})`, []];
|
|
@@ -751,12 +731,8 @@ const MARIADB_UNSUPPORTED = {
|
|
|
751
731
|
regexpInstr: MAX_ARGS(2),
|
|
752
732
|
regexpSubstr: MAX_ARGS(2),
|
|
753
733
|
regexpReplace: MAX_ARGS(3),
|
|
754
|
-
jsonValue: (args) => args[2] && args[2].returning !== undefined
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
FUNCTIONS,
|
|
758
|
-
MARIADB_UNSUPPORTED,
|
|
759
|
-
buildOrderBy,
|
|
760
|
-
INTERVAL_UNITS,
|
|
761
|
-
TIMESTAMP_UNITS,
|
|
734
|
+
jsonValue: (args) => args[2] && args[2].returning !== undefined
|
|
735
|
+
? "can't use the returning option on MariaDB"
|
|
736
|
+
: null,
|
|
762
737
|
};
|
|
738
|
+
exports.MARIADB_UNSUPPORTED = MARIADB_UNSUPPORTED;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JoinResultColumn = void 0;
|
|
2
4
|
class JoinResultColumn {
|
|
5
|
+
// The arguments are the properties of the column.
|
|
3
6
|
constructor({ columnAlias, tableNode, name }) {
|
|
4
7
|
this.columnAlias = columnAlias;
|
|
5
8
|
this.tableNode = tableNode;
|
|
6
9
|
this.name = name;
|
|
7
10
|
}
|
|
8
11
|
static create({ tableTree, columnAlias }) {
|
|
12
|
+
// The column aliases of the joined query are those of the table tree.
|
|
9
13
|
const tableNode = tableTree.getNodeForColumnAlias(columnAlias);
|
|
10
14
|
return new JoinResultColumn({
|
|
11
15
|
columnAlias,
|
|
@@ -14,6 +18,4 @@ class JoinResultColumn {
|
|
|
14
18
|
});
|
|
15
19
|
}
|
|
16
20
|
}
|
|
17
|
-
|
|
18
|
-
JoinResultColumn,
|
|
19
|
-
};
|
|
21
|
+
exports.JoinResultColumn = JoinResultColumn;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JoinResultParser = void 0;
|
|
4
|
+
const JoinResultColumn_1 = require("./JoinResultColumn");
|
|
5
|
+
const objectUtils_1 = require("../../utils/objectUtils");
|
|
4
6
|
class JoinResultParser {
|
|
5
7
|
constructor({ tableTree, omitColumnAliases = [] }) {
|
|
6
8
|
this.tableTree = tableTree;
|
|
@@ -54,6 +56,8 @@ class JoinResultParser {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
const model = tableNode.modelClass.fromDatabaseJson(row);
|
|
59
|
+
// The child nodes and the node of a parent model always have a relation
|
|
60
|
+
// and a relation property.
|
|
57
61
|
for (const childNode of tableNode.childNodes) {
|
|
58
62
|
if (childNode.relation.isOneToOne()) {
|
|
59
63
|
model[childNode.relationProperty] = null;
|
|
@@ -80,12 +84,13 @@ class JoinResultParser {
|
|
|
80
84
|
}
|
|
81
85
|
_createColumns(row) {
|
|
82
86
|
const columns = Object.keys(row)
|
|
83
|
-
.map((columnAlias) => JoinResultColumn.create({ tableTree: this.tableTree, columnAlias }))
|
|
87
|
+
.map((columnAlias) => JoinResultColumn_1.JoinResultColumn.create({ tableTree: this.tableTree, columnAlias }))
|
|
84
88
|
// The omitted columns are filtered here once instead of for every model.
|
|
85
89
|
.filter((column) => !this.omitColumnAliases.has(column.columnAlias));
|
|
86
|
-
return groupBy(columns, getTableNode);
|
|
90
|
+
return (0, objectUtils_1.groupBy)(columns, getTableNode);
|
|
87
91
|
}
|
|
88
92
|
}
|
|
93
|
+
exports.JoinResultParser = JoinResultParser;
|
|
89
94
|
function getTableNode(column) {
|
|
90
95
|
return column.tableNode;
|
|
91
96
|
}
|
|
@@ -101,6 +106,3 @@ function createChildMaps(tableNode) {
|
|
|
101
106
|
}
|
|
102
107
|
return maps;
|
|
103
108
|
}
|
|
104
|
-
module.exports = {
|
|
105
|
-
JoinResultParser,
|
|
106
|
-
};
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RelationJoiner = void 0;
|
|
4
|
+
const objectUtils_1 = require("../../utils/objectUtils");
|
|
5
|
+
const Selection_1 = require("../operations/select/Selection");
|
|
6
|
+
const createModifier_1 = require("../../utils/createModifier");
|
|
7
|
+
const promiseUtils_1 = require("../../utils/promiseUtils");
|
|
8
|
+
const modelConcurrency_1 = require("../../model/modelConcurrency");
|
|
9
|
+
const ValidationError_1 = require("../../model/ValidationError");
|
|
10
|
+
const TableTree_1 = require("./TableTree");
|
|
11
|
+
const JoinResultParser_1 = require("./JoinResultParser");
|
|
12
|
+
const utils_1 = require("./utils");
|
|
11
13
|
/**
|
|
12
14
|
* Given a relation expression, builds a query using joins to fetch it.
|
|
13
15
|
*/
|
|
@@ -47,8 +49,8 @@ class RelationJoiner {
|
|
|
47
49
|
fetchColumnInfo(builder) {
|
|
48
50
|
const tableTree = this._getTableTree(builder);
|
|
49
51
|
const allModelClasses = new Set(tableTree.nodes.map((node) => node.modelClass));
|
|
50
|
-
return
|
|
51
|
-
concurrency: getReadConcurrency(this.rootModelClass, builder.unsafeKnex()),
|
|
52
|
+
return (0, promiseUtils_1.map)(Array.from(allModelClasses), (modelClass) => modelClass.fetchTableMetadata({ parentBuilder: builder }), {
|
|
53
|
+
concurrency: (0, modelConcurrency_1.getReadConcurrency)(this.rootModelClass, builder.unsafeKnex()),
|
|
52
54
|
});
|
|
53
55
|
}
|
|
54
56
|
build(builder, buildSelects = true) {
|
|
@@ -62,7 +64,7 @@ class RelationJoiner {
|
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
parseResult(builder, flatRows) {
|
|
65
|
-
const parser = JoinResultParser.create({
|
|
67
|
+
const parser = JoinResultParser_1.JoinResultParser.create({
|
|
66
68
|
tableTree: this._getTableTree(builder),
|
|
67
69
|
omitColumnAliases: this.internalSelections.map((it) => it.alias),
|
|
68
70
|
});
|
|
@@ -71,7 +73,7 @@ class RelationJoiner {
|
|
|
71
73
|
_getTableTree(builder) {
|
|
72
74
|
if (!this.tableTree) {
|
|
73
75
|
// Create the table tree lazily.
|
|
74
|
-
this.tableTree = TableTree.create({
|
|
76
|
+
this.tableTree = TableTree_1.TableTree.create({
|
|
75
77
|
rootModelClass: this.rootModelClass,
|
|
76
78
|
rootTableAlias: builder.tableRef(),
|
|
77
79
|
expression: this.expression,
|
|
@@ -80,7 +82,7 @@ class RelationJoiner {
|
|
|
80
82
|
}
|
|
81
83
|
return this.tableTree;
|
|
82
84
|
}
|
|
83
|
-
_buildJoinsForNode({ builder, tableNode, userSelectQueries }) {
|
|
85
|
+
_buildJoinsForNode({ builder, tableNode, userSelectQueries, }) {
|
|
84
86
|
const subqueryToJoin = createSubqueryToJoin({
|
|
85
87
|
builder,
|
|
86
88
|
tableNode,
|
|
@@ -107,13 +109,14 @@ class RelationJoiner {
|
|
|
107
109
|
this._buildJoinsForNode({ builder, tableNode: childNode, userSelectQueries });
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
|
-
_buildSelects({ builder, tableNode, userSelectQueries }) {
|
|
112
|
+
_buildSelects({ builder, tableNode, userSelectQueries, }) {
|
|
111
113
|
const { selections, internalSelections } = getSelectionsForNode({
|
|
112
114
|
builder,
|
|
113
115
|
tableNode,
|
|
114
116
|
userSelectQueries,
|
|
115
117
|
});
|
|
116
118
|
for (const selection of selections) {
|
|
119
|
+
// The selections that are added here all have an alias.
|
|
117
120
|
checkAliasLength(tableNode.modelClass, selection.name);
|
|
118
121
|
}
|
|
119
122
|
// Save the selections that were added internally (not by the user)
|
|
@@ -123,6 +126,7 @@ class RelationJoiner {
|
|
|
123
126
|
builder.select(selectionsToStrings(selections));
|
|
124
127
|
}
|
|
125
128
|
}
|
|
129
|
+
exports.RelationJoiner = RelationJoiner;
|
|
126
130
|
function defaultOptions() {
|
|
127
131
|
return {
|
|
128
132
|
joinOperation: 'leftJoin',
|
|
@@ -131,11 +135,11 @@ function defaultOptions() {
|
|
|
131
135
|
aliases: {},
|
|
132
136
|
};
|
|
133
137
|
}
|
|
134
|
-
function createSubqueryToJoin({ builder, tableNode, modifiers }) {
|
|
138
|
+
function createSubqueryToJoin({ builder, tableNode, modifiers, }) {
|
|
135
139
|
const { relation, expression, modelClass } = tableNode;
|
|
136
140
|
const modifierQuery = modelClass.query().childQueryOf(builder);
|
|
137
141
|
for (const modifierName of expression.node.$modify) {
|
|
138
|
-
const modifier = createModifier({
|
|
142
|
+
const modifier = (0, createModifier_1.createModifier)({
|
|
139
143
|
modifier: modifierName,
|
|
140
144
|
modelClass,
|
|
141
145
|
modifiers,
|
|
@@ -146,7 +150,7 @@ function createSubqueryToJoin({ builder, tableNode, modifiers }) {
|
|
|
146
150
|
catch (err) {
|
|
147
151
|
if (err instanceof modelClass.ModifierNotFoundError) {
|
|
148
152
|
throw modelClass.createValidationError({
|
|
149
|
-
type: ValidationErrorType.RelationExpression,
|
|
153
|
+
type: ValidationError_1.ValidationErrorType.RelationExpression,
|
|
150
154
|
message: `could not find modifier "${modifierName}" for relation "${relation.name}"`,
|
|
151
155
|
});
|
|
152
156
|
}
|
|
@@ -157,19 +161,20 @@ function createSubqueryToJoin({ builder, tableNode, modifiers }) {
|
|
|
157
161
|
}
|
|
158
162
|
return modifierQuery;
|
|
159
163
|
}
|
|
160
|
-
function ensureIdAndRelationPropsAreSelected({ builder, tableNode }) {
|
|
164
|
+
function ensureIdAndRelationPropsAreSelected({ builder, tableNode, }) {
|
|
161
165
|
const tableRef = builder.tableRef();
|
|
162
166
|
const cols = [
|
|
163
167
|
...builder.modelClass().getIdColumnArray(),
|
|
164
168
|
...tableNode.relation.relatedProp.cols,
|
|
165
169
|
...tableNode.childNodes.reduce((cols, childNode) => [...cols, ...childNode.relation.ownerProp.cols], []),
|
|
166
170
|
];
|
|
167
|
-
const selectStrings = uniqBy(cols)
|
|
171
|
+
const selectStrings = (0, objectUtils_1.uniqBy)(cols)
|
|
168
172
|
.filter((col) => !builder.hasSelectionAs(col, col))
|
|
169
173
|
.map((col) => `${tableRef}.${col}`);
|
|
170
174
|
return builder.select(selectStrings);
|
|
171
175
|
}
|
|
172
|
-
function getSelectionsForNode({ builder, tableNode, userSelectQueries }) {
|
|
176
|
+
function getSelectionsForNode({ builder, tableNode, userSelectQueries, }) {
|
|
177
|
+
// Every node has a query: `build()` and `_buildJoinsForNode()` add them.
|
|
173
178
|
const userSelectQuery = userSelectQueries.get(tableNode);
|
|
174
179
|
const userSelections = userSelectQuery.findAllSelections();
|
|
175
180
|
const userSelectedAllColumns = isSelectAllSelectionSet(userSelections);
|
|
@@ -189,6 +194,7 @@ function getSelectionsForNode({ builder, tableNode, userSelectQueries }) {
|
|
|
189
194
|
else {
|
|
190
195
|
const idSelections = getIdSelectionsForNode({ tableNode });
|
|
191
196
|
for (const idSelection of idSelections) {
|
|
197
|
+
// The id selections have a column.
|
|
192
198
|
if (!userSelectQuery.hasSelectionAs(idSelection.column, idSelection.column)) {
|
|
193
199
|
selections.push(idSelection);
|
|
194
200
|
internalSelections.push(idSelection);
|
|
@@ -205,29 +211,31 @@ function getSelectionsForNode({ builder, tableNode, userSelectQueries }) {
|
|
|
205
211
|
internalSelections,
|
|
206
212
|
};
|
|
207
213
|
}
|
|
208
|
-
function mapUserSelectionsFromSubqueryToMainQuery({ userSelections, tableNode }) {
|
|
214
|
+
function mapUserSelectionsFromSubqueryToMainQuery({ userSelections, tableNode, }) {
|
|
209
215
|
return userSelections.filter(isNotSelectAll).map((selection) => {
|
|
210
|
-
|
|
216
|
+
// A user selection that isn't `*` has a name.
|
|
217
|
+
return new Selection_1.Selection(tableNode.alias, selection.name, tableNode.getColumnAliasForColumn(selection.name));
|
|
211
218
|
});
|
|
212
219
|
}
|
|
213
|
-
function getJoinTableExtraSelectionsForNode({ builder, tableNode }) {
|
|
220
|
+
function getJoinTableExtraSelectionsForNode({ builder, tableNode, }) {
|
|
214
221
|
return tableNode.relation.joinTableExtras.map((extra) => {
|
|
215
|
-
|
|
222
|
+
// A many to many relation, which has a join table.
|
|
223
|
+
return new Selection_1.Selection(tableNode.getJoinTableAlias(builder), extra.joinTableCol, tableNode.getColumnAliasForColumn(extra.aliasCol));
|
|
216
224
|
});
|
|
217
225
|
}
|
|
218
|
-
function getAllColumnSelectionsForNode({ builder, tableNode }) {
|
|
226
|
+
function getAllColumnSelectionsForNode({ builder, tableNode, }) {
|
|
219
227
|
const table = builder.tableNameFor(tableNode.modelClass);
|
|
220
228
|
const tableMeta = tableNode.modelClass.tableMetadata({ table });
|
|
221
229
|
if (!tableMeta) {
|
|
222
230
|
throw new Error(`table metadata has not been fetched for table '${table}'. Are you trying to call toKnexQuery() for a withGraphJoined query? To make sure the table metadata is fetched see the objection.initialize function.`);
|
|
223
231
|
}
|
|
224
232
|
return tableMeta.columns.map((columnName) => {
|
|
225
|
-
return new Selection(tableNode.alias, columnName, tableNode.getColumnAliasForColumn(columnName));
|
|
233
|
+
return new Selection_1.Selection(tableNode.alias, columnName, tableNode.getColumnAliasForColumn(columnName));
|
|
226
234
|
});
|
|
227
235
|
}
|
|
228
236
|
function getIdSelectionsForNode({ tableNode }) {
|
|
229
237
|
return tableNode.modelClass.getIdColumnArray().map((columnName) => {
|
|
230
|
-
return new Selection(tableNode.alias, columnName, tableNode.getColumnAliasForColumn(columnName));
|
|
238
|
+
return new Selection_1.Selection(tableNode.alias, columnName, tableNode.getColumnAliasForColumn(columnName));
|
|
231
239
|
});
|
|
232
240
|
}
|
|
233
241
|
function selectionsToStrings(selections) {
|
|
@@ -246,13 +254,10 @@ function isSelectAllSelectionSet(selections) {
|
|
|
246
254
|
return selections.length === 0 || selections.some(isSelectAll);
|
|
247
255
|
}
|
|
248
256
|
function checkAliasLength(modelClass, alias) {
|
|
249
|
-
if (alias.length > ID_LENGTH_LIMIT) {
|
|
257
|
+
if (alias.length > utils_1.ID_LENGTH_LIMIT) {
|
|
250
258
|
throw modelClass.createValidationError({
|
|
251
|
-
type: ValidationErrorType.RelationExpression,
|
|
252
|
-
message: `identifier ${alias} is over ${ID_LENGTH_LIMIT} characters long and would be truncated by the database engine.`,
|
|
259
|
+
type: ValidationError_1.ValidationErrorType.RelationExpression,
|
|
260
|
+
message: `identifier ${alias} is over ${utils_1.ID_LENGTH_LIMIT} characters long and would be truncated by the database engine.`,
|
|
253
261
|
});
|
|
254
262
|
}
|
|
255
263
|
}
|
|
256
|
-
module.exports = {
|
|
257
|
-
RelationJoiner,
|
|
258
|
-
};
|