@abedmurrar/objection 0.0.0-stage → 4.0.0-beta.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/LICENSE +23 -0
- package/README.md +105 -2
- package/lib/index.mjs +6 -0
- package/lib/initialize.js +11 -0
- package/lib/model/AjvValidator.js +278 -0
- package/lib/model/Model.js +772 -0
- package/lib/model/ModifierNotFoundError.js +10 -0
- package/lib/model/NotFoundError.js +19 -0
- package/lib/model/RelationDoesNotExistError.js +11 -0
- package/lib/model/ValidationError.js +46 -0
- package/lib/model/Validator.js +20 -0
- package/lib/model/getModel.js +7 -0
- package/lib/model/graph/ModelGraph.js +60 -0
- package/lib/model/graph/ModelGraphBuilder.js +188 -0
- package/lib/model/graph/ModelGraphEdge.js +40 -0
- package/lib/model/graph/ModelGraphNode.js +201 -0
- package/lib/model/inheritModel.js +19 -0
- package/lib/model/modelBindKnex.js +69 -0
- package/lib/model/modelClone.js +102 -0
- package/lib/model/modelColPropMap.js +24 -0
- package/lib/model/modelConcurrency.js +24 -0
- package/lib/model/modelId.js +57 -0
- package/lib/model/modelJsonAttributes.js +72 -0
- package/lib/model/modelParseRelations.js +83 -0
- package/lib/model/modelQueryProps.js +116 -0
- package/lib/model/modelSet.js +116 -0
- package/lib/model/modelTableMetadata.js +71 -0
- package/lib/model/modelToJson.js +157 -0
- package/lib/model/modelUtils.js +40 -0
- package/lib/model/modelValidate.js +40 -0
- package/lib/model/modelValues.js +113 -0
- package/lib/model/modelVisitor.js +34 -0
- package/lib/objection.js +89 -0
- package/lib/queryBuilder/FunctionBuilder.js +291 -0
- package/lib/queryBuilder/InternalOptions.js +24 -0
- package/lib/queryBuilder/JoinBuilder.js +124 -0
- package/lib/queryBuilder/QueryBuilder.js +1136 -0
- package/lib/queryBuilder/QueryBuilderBase.js +666 -0
- package/lib/queryBuilder/QueryBuilderContext.js +20 -0
- package/lib/queryBuilder/QueryBuilderContextBase.js +26 -0
- package/lib/queryBuilder/QueryBuilderOperationSupport.js +484 -0
- package/lib/queryBuilder/QueryBuilderUserContext.js +25 -0
- package/lib/queryBuilder/RawBuilder.js +78 -0
- package/lib/queryBuilder/ReferenceBuilder.js +246 -0
- package/lib/queryBuilder/RelationExpression.js +373 -0
- package/lib/queryBuilder/StaticHookArguments.js +122 -0
- package/lib/queryBuilder/ValueBuilder.js +115 -0
- package/lib/queryBuilder/expressions.js +121 -0
- package/lib/queryBuilder/functions/mysql.js +762 -0
- package/lib/queryBuilder/graph/GraphAction.js +54 -0
- package/lib/queryBuilder/graph/GraphData.js +12 -0
- package/lib/queryBuilder/graph/GraphFetcher.js +155 -0
- package/lib/queryBuilder/graph/GraphNodeDbExistence.js +146 -0
- package/lib/queryBuilder/graph/GraphOperation.js +21 -0
- package/lib/queryBuilder/graph/GraphOptions.js +165 -0
- package/lib/queryBuilder/graph/GraphUpsert.js +231 -0
- package/lib/queryBuilder/graph/delete/GraphDelete.js +15 -0
- package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +56 -0
- package/lib/queryBuilder/graph/insert/GraphInsert.js +116 -0
- package/lib/queryBuilder/graph/insert/GraphInsertAction.js +183 -0
- package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +70 -0
- package/lib/queryBuilder/graph/patch/GraphPatch.js +15 -0
- package/lib/queryBuilder/graph/patch/GraphPatchAction.js +205 -0
- package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +26 -0
- package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +96 -0
- package/lib/queryBuilder/join/JoinResultColumn.js +19 -0
- package/lib/queryBuilder/join/JoinResultParser.js +106 -0
- package/lib/queryBuilder/join/RelationJoiner.js +258 -0
- package/lib/queryBuilder/join/TableNode.js +136 -0
- package/lib/queryBuilder/join/TableTree.js +69 -0
- package/lib/queryBuilder/join/utils.js +19 -0
- package/lib/queryBuilder/operations/DelegateOperation.js +101 -0
- package/lib/queryBuilder/operations/DeleteOperation.js +47 -0
- package/lib/queryBuilder/operations/FindByIdOperation.js +29 -0
- package/lib/queryBuilder/operations/FindByIdsOperation.js +23 -0
- package/lib/queryBuilder/operations/FindOperation.js +147 -0
- package/lib/queryBuilder/operations/FirstOperation.js +22 -0
- package/lib/queryBuilder/operations/FromOperation.js +91 -0
- package/lib/queryBuilder/operations/InsertAndFetchOperation.js +38 -0
- package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +35 -0
- package/lib/queryBuilder/operations/InsertGraphOperation.js +87 -0
- package/lib/queryBuilder/operations/InsertOperation.js +173 -0
- package/lib/queryBuilder/operations/InstanceDeleteOperation.js +37 -0
- package/lib/queryBuilder/operations/InstanceFindOperation.js +17 -0
- package/lib/queryBuilder/operations/InstanceInsertOperation.js +20 -0
- package/lib/queryBuilder/operations/InstanceUpdateOperation.js +45 -0
- package/lib/queryBuilder/operations/JoinRelatedOperation.js +83 -0
- package/lib/queryBuilder/operations/KnexOperation.js +11 -0
- package/lib/queryBuilder/operations/MergeOperation.js +43 -0
- package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +173 -0
- package/lib/queryBuilder/operations/OnBuildKnexOperation.js +23 -0
- package/lib/queryBuilder/operations/OnBuildOperation.js +23 -0
- package/lib/queryBuilder/operations/OnErrorOperation.js +23 -0
- package/lib/queryBuilder/operations/QueryBuilderOperation.js +258 -0
- package/lib/queryBuilder/operations/RangeOperation.js +37 -0
- package/lib/queryBuilder/operations/RelateOperation.js +20 -0
- package/lib/queryBuilder/operations/ReturningOperation.js +24 -0
- package/lib/queryBuilder/operations/RunAfterOperation.js +23 -0
- package/lib/queryBuilder/operations/RunBeforeOperation.js +23 -0
- package/lib/queryBuilder/operations/UnrelateOperation.js +18 -0
- package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +63 -0
- package/lib/queryBuilder/operations/UpdateOperation.js +130 -0
- package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +35 -0
- package/lib/queryBuilder/operations/UpsertGraphOperation.js +47 -0
- package/lib/queryBuilder/operations/WhereCompositeOperation.js +48 -0
- package/lib/queryBuilder/operations/WhereInOperation.js +46 -0
- package/lib/queryBuilder/operations/eager/EagerOperation.js +46 -0
- package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +41 -0
- package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +10 -0
- package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +227 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +29 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +37 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +30 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +33 -0
- package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +155 -0
- package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +135 -0
- package/lib/queryBuilder/operations/select/SelectOperation.js +50 -0
- package/lib/queryBuilder/operations/select/Selection.js +112 -0
- package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +84 -0
- package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +90 -0
- package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +95 -0
- package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +787 -0
- package/lib/queryBuilder/parsers/relationExpressionParser.js +930 -0
- package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +17 -0
- package/lib/queryBuilder/transformations/QueryTransformation.js +9 -0
- package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +57 -0
- package/lib/queryBuilder/transformations/index.js +9 -0
- package/lib/queryBuilder/whereScopes.js +199 -0
- package/lib/relations/Relation.js +317 -0
- package/lib/relations/RelationDeleteOperation.js +23 -0
- package/lib/relations/RelationFindOperation.js +116 -0
- package/lib/relations/RelationInsertOperation.js +25 -0
- package/lib/relations/RelationOwner.js +199 -0
- package/lib/relations/RelationProperty.js +207 -0
- package/lib/relations/RelationUpdateOperation.js +23 -0
- package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +18 -0
- package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +33 -0
- package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +39 -0
- package/lib/relations/belongsToOne/BelongsToOneRelation.js +45 -0
- package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +46 -0
- package/lib/relations/hasMany/HasManyInsertOperation.js +45 -0
- package/lib/relations/hasMany/HasManyRelateOperation.js +48 -0
- package/lib/relations/hasMany/HasManyRelation.js +41 -0
- package/lib/relations/hasMany/HasManyUnrelateOperation.js +26 -0
- package/lib/relations/hasOne/HasOneRelation.js +10 -0
- package/lib/relations/hasOneThrough/HasOneThroughRelation.js +10 -0
- package/lib/relations/manyToMany/ManyToManyModifyMixin.js +82 -0
- package/lib/relations/manyToMany/ManyToManyRelation.js +405 -0
- package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +29 -0
- package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +8 -0
- package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +20 -0
- package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +8 -0
- package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +82 -0
- package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +40 -0
- package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +64 -0
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +11 -0
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +27 -0
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +11 -0
- package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +8 -0
- package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +65 -0
- package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +8 -0
- package/lib/transaction.js +66 -0
- package/lib/utils/assert.js +19 -0
- package/lib/utils/buildUtils.js +19 -0
- package/lib/utils/classUtils.js +9 -0
- package/lib/utils/cloneDeep.js +365 -0
- package/lib/utils/createModifier.js +37 -0
- package/lib/utils/deprecate.js +11 -0
- package/lib/utils/identifierMapping.js +188 -0
- package/lib/utils/internalPropUtils.js +7 -0
- package/lib/utils/knexUtils.js +81 -0
- package/lib/utils/mixin.js +18 -0
- package/lib/utils/mysqlJsonPath.js +70 -0
- package/lib/utils/normalizeIds.js +127 -0
- package/lib/utils/objectUtils.js +314 -0
- package/lib/utils/parseFieldExpression.js +73 -0
- package/lib/utils/postgresJsonPath.js +96 -0
- package/lib/utils/promiseUtils/after.js +14 -0
- package/lib/utils/promiseUtils/afterReturn.js +14 -0
- package/lib/utils/promiseUtils/index.js +15 -0
- package/lib/utils/promiseUtils/isPromise.js +8 -0
- package/lib/utils/promiseUtils/map.js +96 -0
- package/lib/utils/promiseUtils/mapAfterAllReturn.js +23 -0
- package/lib/utils/promiseUtils/try.js +19 -0
- package/lib/utils/resolveModel.js +104 -0
- package/lib/utils/tmpColumnUtils.js +7 -0
- package/package.json +113 -4
- package/typings/objection/index.d.mts +362 -0
- package/typings/objection/index.d.ts +4131 -0
- package/typings/objection/relation-expression.d.ts +237 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { asArray } = require('../utils/objectUtils');
|
|
3
|
+
const BUILDER_SYMBOL = Symbol();
|
|
4
|
+
// The static hooks of `Model`, which do nothing. Queries skip creating the
|
|
5
|
+
// arguments and calling the hook when a model class hasn't overridden it.
|
|
6
|
+
const defaultStaticHooks = new WeakSet();
|
|
7
|
+
function markDefaultStaticHook(hook) {
|
|
8
|
+
defaultStaticHooks.add(hook);
|
|
9
|
+
}
|
|
10
|
+
function hasStaticHook(modelClass, hookName) {
|
|
11
|
+
return !defaultStaticHooks.has(modelClass[hookName]);
|
|
12
|
+
}
|
|
13
|
+
class StaticHookArguments {
|
|
14
|
+
constructor({ builder, result = null }) {
|
|
15
|
+
// The builder should never be accessed through the arguments.
|
|
16
|
+
// Hide it as well as possible to discourage people from
|
|
17
|
+
// digging it out.
|
|
18
|
+
Object.defineProperty(this, BUILDER_SYMBOL, {
|
|
19
|
+
value: builder,
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(this, 'result', {
|
|
22
|
+
value: asArray(result),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
static create(args) {
|
|
26
|
+
return new StaticHookArguments(args);
|
|
27
|
+
}
|
|
28
|
+
get asFindQuery() {
|
|
29
|
+
return () => {
|
|
30
|
+
return this[BUILDER_SYMBOL].toFindQuery().clearWithGraphFetched().runAfter(asArray);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
get context() {
|
|
34
|
+
return this[BUILDER_SYMBOL].context();
|
|
35
|
+
}
|
|
36
|
+
get transaction() {
|
|
37
|
+
return this[BUILDER_SYMBOL].unsafeKnex();
|
|
38
|
+
}
|
|
39
|
+
get relation() {
|
|
40
|
+
const op = this[BUILDER_SYMBOL].findOperation(hasRelation);
|
|
41
|
+
if (op) {
|
|
42
|
+
return getRelation(op);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
get modelOptions() {
|
|
49
|
+
const op = this[BUILDER_SYMBOL].findOperation(hasModelOptions);
|
|
50
|
+
if (op) {
|
|
51
|
+
return getModelOptions(op);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
get items() {
|
|
58
|
+
const op = this[BUILDER_SYMBOL].findOperation(hasItems);
|
|
59
|
+
if (op) {
|
|
60
|
+
return asArray(getItems(op));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
get inputItems() {
|
|
67
|
+
const op = this[BUILDER_SYMBOL].findOperation(hasInputItems);
|
|
68
|
+
if (op) {
|
|
69
|
+
return asArray(getInputItems(op));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
get cancelQuery() {
|
|
76
|
+
const args = this;
|
|
77
|
+
return (cancelValue) => {
|
|
78
|
+
const builder = this[BUILDER_SYMBOL];
|
|
79
|
+
if (cancelValue === undefined) {
|
|
80
|
+
if (builder.isInsert()) {
|
|
81
|
+
cancelValue = args.inputItems;
|
|
82
|
+
}
|
|
83
|
+
else if (builder.isFind()) {
|
|
84
|
+
cancelValue = [];
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
cancelValue = 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
builder.resolve(cancelValue);
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function getRelation(op) {
|
|
95
|
+
return op.relation;
|
|
96
|
+
}
|
|
97
|
+
function hasRelation(op) {
|
|
98
|
+
return !!getRelation(op);
|
|
99
|
+
}
|
|
100
|
+
function getModelOptions(op) {
|
|
101
|
+
return op.modelOptions;
|
|
102
|
+
}
|
|
103
|
+
function hasModelOptions(op) {
|
|
104
|
+
return !!getModelOptions(op);
|
|
105
|
+
}
|
|
106
|
+
function getItems(op) {
|
|
107
|
+
return op.instance || (op.owner && op.owner.isModels && op.owner.modelArray);
|
|
108
|
+
}
|
|
109
|
+
function hasItems(op) {
|
|
110
|
+
return !!getItems(op);
|
|
111
|
+
}
|
|
112
|
+
function getInputItems(op) {
|
|
113
|
+
return op.models || op.model;
|
|
114
|
+
}
|
|
115
|
+
function hasInputItems(op) {
|
|
116
|
+
return !!getInputItems(op);
|
|
117
|
+
}
|
|
118
|
+
module.exports = {
|
|
119
|
+
StaticHookArguments,
|
|
120
|
+
markDefaultStaticHook,
|
|
121
|
+
hasStaticHook,
|
|
122
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { asArray, isObject } = require('../utils/objectUtils');
|
|
3
|
+
const { buildArg } = require('../utils/buildUtils');
|
|
4
|
+
const { isMySql } = require('../utils/knexUtils');
|
|
5
|
+
const { toMySqlCastType, isBooleanType, toJsonSql } = require('../utils/mysqlJsonPath');
|
|
6
|
+
const { addExpressionMethods } = require('./expressions');
|
|
7
|
+
class ValueBuilder {
|
|
8
|
+
constructor(value) {
|
|
9
|
+
this._value = value;
|
|
10
|
+
this._cast = null;
|
|
11
|
+
// Cast objects and arrays to json by default.
|
|
12
|
+
this._toJson = isObject(value);
|
|
13
|
+
this._toArray = false;
|
|
14
|
+
this._alias = null;
|
|
15
|
+
}
|
|
16
|
+
get cast() {
|
|
17
|
+
return this._cast;
|
|
18
|
+
}
|
|
19
|
+
castText() {
|
|
20
|
+
return this.castTo('text');
|
|
21
|
+
}
|
|
22
|
+
castInt() {
|
|
23
|
+
return this.castTo('integer');
|
|
24
|
+
}
|
|
25
|
+
castBigInt() {
|
|
26
|
+
return this.castTo('bigint');
|
|
27
|
+
}
|
|
28
|
+
castFloat() {
|
|
29
|
+
return this.castTo('float');
|
|
30
|
+
}
|
|
31
|
+
castDecimal() {
|
|
32
|
+
return this.castTo('decimal');
|
|
33
|
+
}
|
|
34
|
+
castReal() {
|
|
35
|
+
return this.castTo('real');
|
|
36
|
+
}
|
|
37
|
+
castBool() {
|
|
38
|
+
return this.castTo('boolean');
|
|
39
|
+
}
|
|
40
|
+
castJson() {
|
|
41
|
+
this._toArray = false;
|
|
42
|
+
this._toJson = true;
|
|
43
|
+
this._cast = 'jsonb';
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
castTo(sqlType) {
|
|
47
|
+
this._cast = sqlType;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
asArray() {
|
|
51
|
+
this._toJson = false;
|
|
52
|
+
this._toArray = true;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
as(alias) {
|
|
56
|
+
this._alias = alias;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
toKnexRaw(builder) {
|
|
60
|
+
return builder.knex().raw(...this._createRawArgs(builder));
|
|
61
|
+
}
|
|
62
|
+
_createRawArgs(builder) {
|
|
63
|
+
let sql = null;
|
|
64
|
+
const bindings = [];
|
|
65
|
+
if (this._toJson) {
|
|
66
|
+
bindings.push(JSON.stringify(this._value));
|
|
67
|
+
sql = '?';
|
|
68
|
+
}
|
|
69
|
+
else if (this._toArray) {
|
|
70
|
+
const values = asArray(this._value);
|
|
71
|
+
bindings.push(...values.map((it) => buildArg(it, builder)));
|
|
72
|
+
sql = `ARRAY[${values.map(() => '?').join(', ')}]`;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
bindings.push(this._value);
|
|
76
|
+
sql = '?';
|
|
77
|
+
}
|
|
78
|
+
const knex = builder.unsafeKnex();
|
|
79
|
+
const mysql = isMySql(knex);
|
|
80
|
+
if (this._toJson && !this._cast && mysql) {
|
|
81
|
+
// MySQL compares strings and JSON values as strings, so `{}` is never
|
|
82
|
+
// equal to a JSON column without the cast. Postgres casts it implicitly.
|
|
83
|
+
sql = toJsonSql(sql, knex);
|
|
84
|
+
}
|
|
85
|
+
else if (this._cast && mysql) {
|
|
86
|
+
const type = toMySqlCastType(this._cast);
|
|
87
|
+
// MySQL can't cast to a boolean.
|
|
88
|
+
if (isBooleanType(this._cast)) {
|
|
89
|
+
sql = `(${sql} <> 0)`;
|
|
90
|
+
}
|
|
91
|
+
else if (type === 'JSON') {
|
|
92
|
+
sql = toJsonSql(sql, knex);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
sql = `CAST(${sql} AS ${type})`;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (this._cast) {
|
|
99
|
+
sql = `CAST(${sql} AS ${this._cast})`;
|
|
100
|
+
}
|
|
101
|
+
if (this._alias) {
|
|
102
|
+
bindings.push(this._alias);
|
|
103
|
+
sql = `${sql} as ??`;
|
|
104
|
+
}
|
|
105
|
+
return [sql, bindings];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
addExpressionMethods(ValueBuilder.prototype);
|
|
109
|
+
function val(val) {
|
|
110
|
+
return new ValueBuilder(val);
|
|
111
|
+
}
|
|
112
|
+
module.exports = {
|
|
113
|
+
ValueBuilder,
|
|
114
|
+
val,
|
|
115
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { isObject } = require('../utils/objectUtils');
|
|
3
|
+
// Comparison, logic and arithmetic methods for `ref()`, `val()`, `fn()` and
|
|
4
|
+
// `raw()`, so that expressions can be written without raw sql:
|
|
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()`.
|
|
14
|
+
const COMPARISONS = {
|
|
15
|
+
eq: '=',
|
|
16
|
+
ne: '<>',
|
|
17
|
+
gt: '>',
|
|
18
|
+
gte: '>=',
|
|
19
|
+
lt: '<',
|
|
20
|
+
lte: '<=',
|
|
21
|
+
};
|
|
22
|
+
const ARITHMETIC = {
|
|
23
|
+
plus: '+',
|
|
24
|
+
minus: '-',
|
|
25
|
+
times: '*',
|
|
26
|
+
div: '/',
|
|
27
|
+
};
|
|
28
|
+
const methods = {
|
|
29
|
+
// `eq(null)` and `ne(null)` are `IS NULL` and `IS NOT NULL`, like `where(col, null)`.
|
|
30
|
+
eq(value) {
|
|
31
|
+
return value === null ? this.isNull() : expression('(? = ?)', [this, value]);
|
|
32
|
+
},
|
|
33
|
+
ne(value) {
|
|
34
|
+
return value === null ? this.isNotNull() : expression('(? <> ?)', [this, value]);
|
|
35
|
+
},
|
|
36
|
+
in(values) {
|
|
37
|
+
return createIn(this, values, 'IN');
|
|
38
|
+
},
|
|
39
|
+
notIn(values) {
|
|
40
|
+
return createIn(this, values, 'NOT IN');
|
|
41
|
+
},
|
|
42
|
+
like(pattern) {
|
|
43
|
+
return expression('(? LIKE ?)', [this, pattern]);
|
|
44
|
+
},
|
|
45
|
+
between(min, max) {
|
|
46
|
+
return expression('(? BETWEEN ? AND ?)', [this, min, max]);
|
|
47
|
+
},
|
|
48
|
+
isNull() {
|
|
49
|
+
return expression('(? IS NULL)', [this]);
|
|
50
|
+
},
|
|
51
|
+
isNotNull() {
|
|
52
|
+
return expression('(? IS NOT NULL)', [this]);
|
|
53
|
+
},
|
|
54
|
+
// NULL, an empty string or a string of only spaces.
|
|
55
|
+
isBlank() {
|
|
56
|
+
return expression("(COALESCE(TRIM(?), '') = '')", [this]);
|
|
57
|
+
},
|
|
58
|
+
isNotBlank() {
|
|
59
|
+
return expression("(COALESCE(TRIM(?), '') <> '')", [this]);
|
|
60
|
+
},
|
|
61
|
+
and(...conditions) {
|
|
62
|
+
return createLogic(this, conditions, 'AND');
|
|
63
|
+
},
|
|
64
|
+
or(...conditions) {
|
|
65
|
+
return createLogic(this, conditions, 'OR');
|
|
66
|
+
},
|
|
67
|
+
not() {
|
|
68
|
+
return expression('(NOT ?)', [this]);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
for (const [name, operator] of Object.entries(COMPARISONS)) {
|
|
72
|
+
if (!methods[name]) {
|
|
73
|
+
methods[name] = function (value) {
|
|
74
|
+
return expression(`(? ${operator} ?)`, [this, value]);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const [name, operator] of Object.entries(ARITHMETIC)) {
|
|
79
|
+
methods[name] = function (value) {
|
|
80
|
+
return expression(`(? ${operator} ?)`, [this, value]);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function createIn(left, values, operator) {
|
|
84
|
+
if (isSubquery(values)) {
|
|
85
|
+
return expression(`(? ${operator} ?)`, [left, values]);
|
|
86
|
+
}
|
|
87
|
+
if (!Array.isArray(values)) {
|
|
88
|
+
throw new Error(`${operator.toLowerCase()}() takes an array or a subquery.`);
|
|
89
|
+
}
|
|
90
|
+
if (values.length === 0) {
|
|
91
|
+
// Like knex's `whereIn(col, [])`.
|
|
92
|
+
return expression(operator === 'IN' ? '(1 = 0)' : '(1 = 1)', []);
|
|
93
|
+
}
|
|
94
|
+
return expression(`(? ${operator} (${values.map(() => '?').join(', ')}))`, [left, ...values]);
|
|
95
|
+
}
|
|
96
|
+
function createLogic(first, rest, operator) {
|
|
97
|
+
const conditions = [first, ...rest];
|
|
98
|
+
return expression(`(${conditions.map(() => '?').join(` ${operator} `)})`, conditions);
|
|
99
|
+
}
|
|
100
|
+
function isSubquery(value) {
|
|
101
|
+
return (isObject(value) && (value.isObjectionQueryBuilderBase || typeof value.toSQL === 'function'));
|
|
102
|
+
}
|
|
103
|
+
function expression(sql, args) {
|
|
104
|
+
// Required here because `FunctionBuilder` itself gets these methods.
|
|
105
|
+
const { FunctionBuilder } = require('./FunctionBuilder');
|
|
106
|
+
return new FunctionBuilder(sql, args);
|
|
107
|
+
}
|
|
108
|
+
function addExpressionMethods(prototype) {
|
|
109
|
+
for (const [name, method] of Object.entries(methods)) {
|
|
110
|
+
Object.defineProperty(prototype, name, {
|
|
111
|
+
configurable: true,
|
|
112
|
+
enumerable: false,
|
|
113
|
+
writable: true,
|
|
114
|
+
value: method,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
module.exports = {
|
|
119
|
+
addExpressionMethods,
|
|
120
|
+
expression,
|
|
121
|
+
};
|