@sap/cds 5.4.6 → 5.5.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/CHANGELOG.md +208 -2
- package/apis/ql.d.ts +17 -15
- package/app/index.js +1 -1
- package/bin/build/buildTaskEngine.js +26 -42
- package/bin/build/buildTaskFactory.js +6 -10
- package/bin/build/buildTaskHandler.js +2 -4
- package/bin/build/buildTaskProvider.js +3 -1
- package/bin/build/buildTaskProviderFactory.js +9 -15
- package/bin/build/constants.js +15 -3
- package/bin/build/index.js +5 -4
- package/bin/build/mtaUtil.js +8 -11
- package/bin/build/provider/buildTaskHandlerEdmx.js +63 -6
- package/bin/build/provider/buildTaskHandlerInternal.js +2 -34
- package/bin/build/provider/buildTaskProviderInternal.js +16 -42
- package/bin/build/provider/fiori/index.js +13 -24
- package/bin/build/provider/hana/2migration.js +17 -15
- package/bin/build/provider/hana/2tabledata.js +52 -48
- package/bin/build/provider/hana/index.js +27 -25
- package/bin/build/provider/hana/migrationtable.js +91 -67
- package/bin/build/provider/java-cf/index.js +14 -24
- package/bin/build/provider/mtx/index.js +12 -14
- package/bin/build/provider/node-cf/index.js +18 -32
- package/bin/cds.js +5 -5
- package/bin/serve.js +29 -23
- package/bin/version.js +0 -1
- package/lib/compile/etc/_localized.js +4 -9
- package/lib/compile/for/sql.js +5 -2
- package/lib/compile/parse.js +25 -17
- package/lib/compile/to/srvinfo.js +2 -1
- package/lib/connect/bindings.js +2 -1
- package/lib/connect/index.js +48 -49
- package/lib/core/classes.js +1 -1
- package/lib/core/reflect.js +10 -2
- package/lib/deploy.js +26 -23
- package/lib/env/defaults.js +13 -6
- package/lib/env/index.js +73 -78
- package/lib/env/requires.js +38 -19
- package/lib/index.js +9 -10
- package/lib/lazy.js +2 -2
- package/lib/log/index.js +33 -45
- package/lib/log/service/index.js +2 -2
- package/lib/ql/CREATE.js +14 -9
- package/lib/ql/DELETE.js +6 -5
- package/lib/ql/DROP.js +12 -9
- package/lib/ql/INSERT.js +40 -16
- package/lib/ql/Query.js +67 -40
- package/lib/ql/SELECT.js +162 -127
- package/lib/ql/UPDATE.js +74 -42
- package/lib/ql/Whereable.js +77 -87
- package/lib/ql/index.js +36 -24
- package/lib/ql/parse.js +35 -0
- package/lib/req/context.js +44 -8
- package/lib/req/locale.js +7 -7
- package/lib/serve/Service-api.js +21 -14
- package/lib/serve/Service-dispatch.js +28 -12
- package/lib/serve/Transaction.js +22 -10
- package/lib/serve/index.js +16 -11
- package/lib/utils/axios.js +23 -16
- package/lib/utils/data.js +35 -0
- package/lib/utils/tests.js +27 -18
- package/libx/_runtime/audit/generic/personal/access.js +81 -0
- package/libx/_runtime/audit/generic/personal/constants.js +4 -0
- package/libx/_runtime/audit/generic/personal/index.js +50 -0
- package/libx/_runtime/audit/generic/personal/modification.js +138 -0
- package/libx/_runtime/audit/generic/personal/utils.js +186 -0
- package/libx/_runtime/audit/utils/v2.js +10 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +5 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +5 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +5 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +2 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +4 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +7 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +59 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +11 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +6 -10
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +3 -46
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +2 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/createToCQN.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/deleteToCQN.js +4 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectHelper.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +16 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityType.js +6 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/format/RepresentationKind.js +4 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/OdataRequest.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +15 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/OperationValidator.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +8 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +6 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +12 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +1 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +7 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +14 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +13 -13
- package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +2 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +2 -2
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +2 -4
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +4 -2
- package/libx/_runtime/cds-services/services/Service.js +40 -5
- package/libx/_runtime/cds-services/services/utils/columns.js +13 -7
- package/libx/_runtime/cds-services/services/utils/compareJson.js +88 -4
- package/libx/_runtime/cds-services/services/utils/differ.js +24 -6
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +2 -2
- package/libx/_runtime/common/composition/data.js +44 -55
- package/libx/_runtime/common/composition/delete.js +97 -71
- package/libx/_runtime/common/composition/index.js +2 -1
- package/libx/_runtime/common/composition/insert.js +34 -11
- package/libx/_runtime/common/composition/tree.js +119 -92
- package/libx/_runtime/common/composition/update.js +4 -1
- package/libx/_runtime/common/composition/utils.js +1 -3
- package/libx/_runtime/common/constants/draft.js +12 -1
- package/libx/_runtime/common/generic/auth.js +6 -22
- package/libx/_runtime/common/generic/crud.js +14 -13
- package/libx/_runtime/common/generic/input.js +23 -26
- package/libx/_runtime/common/generic/put.js +1 -1
- package/libx/_runtime/common/generic/sorting.js +16 -16
- package/libx/_runtime/common/i18n/index.js +1 -1
- package/libx/_runtime/common/i18n/messages.properties +4 -0
- package/libx/_runtime/common/utils/backlinks.js +12 -5
- package/libx/_runtime/common/utils/cqn.js +6 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +102 -101
- package/libx/_runtime/common/utils/csn.js +47 -4
- package/libx/_runtime/common/utils/data.js +0 -37
- package/libx/_runtime/common/utils/enrichWithKeysFromWhere.js +1 -1
- package/libx/_runtime/common/utils/entityFromCqn.js +7 -24
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +39 -7
- package/libx/_runtime/common/utils/generateOnCond.js +11 -12
- package/libx/_runtime/common/utils/onlyKeysRemain.js +10 -0
- package/libx/_runtime/common/utils/path.js +35 -0
- package/libx/_runtime/common/utils/postProcessing.js +86 -0
- package/libx/_runtime/common/utils/quotingStyles.js +37 -26
- package/libx/_runtime/common/utils/resolveView.js +223 -171
- package/libx/_runtime/common/utils/rewriteAsterisk.js +46 -26
- package/libx/_runtime/common/utils/structured.js +6 -12
- package/libx/_runtime/common/utils/template.js +10 -5
- package/libx/_runtime/common/utils/templateDelimiter.js +1 -0
- package/libx/_runtime/common/utils/templateProcessor.js +22 -30
- package/libx/_runtime/common/utils/union.js +31 -0
- package/libx/_runtime/common/utils/unionCqnTemplate.js +184 -0
- package/libx/_runtime/db/Service.js +1 -1
- package/libx/_runtime/db/data-conversion/timestamp.js +2 -9
- package/libx/_runtime/db/expand/expandCQNToJoin.js +204 -297
- package/libx/_runtime/db/expand/index.js +3 -3
- package/libx/_runtime/db/expand/rawToExpanded.js +36 -7
- package/libx/_runtime/db/generic/index.js +1 -1
- package/libx/_runtime/db/generic/input.js +5 -7
- package/libx/_runtime/db/generic/integrity.js +1 -1
- package/libx/_runtime/db/generic/rewrite.js +2 -10
- package/libx/_runtime/db/generic/update.js +13 -5
- package/libx/_runtime/db/generic/virtual.js +22 -58
- package/libx/_runtime/db/query/delete.js +7 -4
- package/libx/_runtime/db/query/insert.js +6 -4
- package/libx/_runtime/db/query/read.js +13 -20
- package/libx/_runtime/db/query/run.js +4 -1
- package/libx/_runtime/db/query/update.js +5 -4
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +35 -2
- package/libx/_runtime/db/sql-builder/FunctionBuilder.js +17 -2
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +6 -5
- package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +10 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +35 -24
- package/libx/_runtime/db/sql-builder/UpdateBuilder.js +14 -4
- package/libx/_runtime/db/sql-builder/arrayed.js +4 -0
- package/libx/_runtime/db/utils/deep.js +8 -0
- package/libx/_runtime/db/utils/generateAliases.js +2 -1
- package/libx/_runtime/fiori/generic/activate.js +19 -15
- package/libx/_runtime/fiori/generic/before.js +3 -11
- package/libx/_runtime/fiori/generic/cancel.js +1 -1
- package/libx/_runtime/fiori/generic/delete.js +3 -1
- package/libx/_runtime/fiori/generic/edit.js +12 -2
- package/libx/_runtime/fiori/generic/new.js +5 -5
- package/libx/_runtime/fiori/generic/patch.js +0 -18
- package/libx/_runtime/fiori/generic/read.js +241 -189
- package/libx/_runtime/fiori/utils/delete.js +36 -7
- package/libx/_runtime/fiori/utils/handler.js +43 -44
- package/libx/_runtime/fiori/utils/where.js +30 -15
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +4 -6
- package/libx/_runtime/hana/execute.js +2 -2
- package/libx/_runtime/hana/localized.js +4 -4
- package/libx/_runtime/hana/pool.js +29 -14
- package/libx/_runtime/hana/search2cqn4sql.js +2 -1
- package/libx/_runtime/hana/searchToContains.js +18 -14
- package/libx/_runtime/index.js +0 -5
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +13 -5
- package/libx/_runtime/messaging/common-utils/naming-conventions.js +4 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +31 -19
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -2
- package/libx/_runtime/messaging/enterprise-messaging.js +6 -4
- package/libx/_runtime/messaging/service.js +7 -6
- package/libx/_runtime/odata/cqn2odata.js +110 -43
- package/libx/_runtime/odata/index.js +26 -48
- package/libx/_runtime/odata/odata2cqn.js +1 -6154
- package/libx/_runtime/odata/odata2cqn.pegjs +559 -0
- package/libx/_runtime/odata/readToCqn.js +94 -64
- package/libx/_runtime/remote/Service.js +74 -21
- package/libx/_runtime/remote/cqn2odata/index.js +1 -5
- package/libx/_runtime/remote/utils/client.js +24 -101
- package/libx/_runtime/remote/utils/dataConversion.js +27 -12
- package/libx/_runtime/sqlite/Service.js +3 -5
- package/libx/_runtime/sqlite/execute.js +23 -24
- package/libx/_runtime/sqlite/localized.js +12 -7
- package/libx/_runtime/types/api.js +10 -0
- package/package.json +1 -1
- package/server.js +16 -2
- package/lib/ql/grammar.pegjs +0 -208
- package/lib/ql/parser.js +0 -1
- package/lib/ql/rt/DELETE.js +0 -29
- package/lib/ql/rt/INSERT.js +0 -23
- package/lib/ql/rt/Query.js +0 -84
- package/lib/ql/rt/SELECT.js +0 -174
- package/lib/ql/rt/UPDATE.js +0 -119
- package/lib/ql/rt/_helpers.js +0 -91
- package/lib/ql/rt/index.js +0 -32
- package/libx/_runtime/audit/generic/personal.js +0 -260
- package/libx/_runtime/cds-services/statements/BaseStatement.js +0 -72
- package/libx/_runtime/cds-services/statements/Create.js +0 -57
- package/libx/_runtime/cds-services/statements/Delete.js +0 -33
- package/libx/_runtime/cds-services/statements/Drop.js +0 -42
- package/libx/_runtime/cds-services/statements/Insert.js +0 -201
- package/libx/_runtime/cds-services/statements/Select.js +0 -826
- package/libx/_runtime/cds-services/statements/Update.js +0 -181
- package/libx/_runtime/cds-services/statements/Where.js +0 -726
- package/libx/_runtime/cds-services/statements/index.js +0 -25
- package/libx/_runtime/common/generic/resolve-mock.js +0 -9
package/lib/ql/SELECT.js
CHANGED
|
@@ -1,87 +1,120 @@
|
|
|
1
|
-
const Whereable = require('./Whereable'), { parse,
|
|
2
|
-
const
|
|
1
|
+
const Whereable = require('./Whereable'), { parse, predicate4 } = Whereable
|
|
2
|
+
const defaults = global.cds.env.sql
|
|
3
|
+
|
|
3
4
|
|
|
4
5
|
module.exports = class SELECT extends Whereable {
|
|
5
6
|
|
|
6
|
-
static
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
static _api() {
|
|
8
|
+
const $ = Object.assign
|
|
9
|
+
return $((..._) => new this()._select_or_from(..._), {
|
|
10
|
+
one: $((...x) => new this({one:true})._select_or_from(...x),{
|
|
11
|
+
columns: (..._) => new this({one:true}).columns(..._),
|
|
12
|
+
from: (..._) => new this({one:true}).from(..._),
|
|
13
|
+
}),
|
|
14
|
+
distinct: $((...x) => new this({distinct:true})._select_or_from(...x),{
|
|
15
|
+
columns: (..._) => new this({distinct:true}).columns(..._),
|
|
16
|
+
from: (..._) => new this({distinct:true}).from(..._),
|
|
17
|
+
}),
|
|
18
|
+
columns: (..._) => new this().columns(..._),
|
|
19
|
+
from: (..._) => new this().from(..._),
|
|
15
20
|
})
|
|
16
21
|
}
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return this
|
|
23
|
+
_select_or_from (cols, ...more) { // srv.read`title`.from`Books` or srv.read`Books` ?
|
|
24
|
+
if (!cols) return this
|
|
25
|
+
else if (is_number(cols)) return this.columns(...arguments) //> numbers can't be from
|
|
26
|
+
else if (cols.name) return this.from (...arguments) //> clearly a from
|
|
27
|
+
else if (cols.raw) { // tagged template string
|
|
28
|
+
if (cols[0].startsWith('from ')) { // SELECT`from ...`, with an arbitrary long CQL tail...
|
|
29
|
+
Object.assign (this.SELECT, SELECT_(' ',arguments))
|
|
30
|
+
return this
|
|
31
|
+
} else if (cols[0][0] === '{') { // SELECT`{a,b}`... -> it's columns
|
|
32
|
+
let {columns:c} = SELECT_('from X', arguments)
|
|
33
|
+
return this._add('columns',c)
|
|
34
|
+
} else { // SELECT`Foo` -> ambiguous -> try parsing as columns...
|
|
35
|
+
let {columns:c} = SELECT_('from X {', arguments, '}')
|
|
36
|
+
if (c.length > 1 || !c[0].ref) return this._add('columns',c)
|
|
37
|
+
// else cols = c[0] //> goes on below...
|
|
38
|
+
}
|
|
39
|
+
} else { // SELECT('Foo'|'*',[...]|(foo)=>{})
|
|
40
|
+
if (cols === '*') return this.columns(...arguments)
|
|
41
|
+
const c = _columns_or_not (cols)
|
|
42
|
+
if (c) return this._add('columns',c)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// return a proxy assuming it's a from and switching to
|
|
46
|
+
// columns on a subsequent call of .from, if any.
|
|
47
|
+
const {SELECT:_} = this, {one} = _
|
|
48
|
+
return Object.defineProperties (this.from (cols, ...more), {
|
|
49
|
+
from: { configurable:true, value:(...args) => { delete this.from
|
|
50
|
+
if (!one) delete _.one; delete _.columns; delete _.where
|
|
51
|
+
return this.from (...args) .columns (cols, ...more)
|
|
52
|
+
}}
|
|
53
|
+
})
|
|
21
54
|
}
|
|
22
|
-
|
|
23
|
-
|
|
55
|
+
|
|
56
|
+
columns (...cols) {
|
|
57
|
+
if (cols[0]) this._add ('columns', _columns(cols))
|
|
24
58
|
return this
|
|
25
59
|
}
|
|
26
60
|
|
|
27
|
-
from(
|
|
28
|
-
this.
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
61
|
+
from (target, second, third) {
|
|
62
|
+
this.SELECT.from = target === '*' || this._target_ref4 (...arguments)
|
|
63
|
+
if (!target.raw && second) {
|
|
64
|
+
const cols = _columns_or_not (second)
|
|
65
|
+
cols ? this._add('columns',cols) : this.byKey(second)
|
|
32
66
|
if (third) this.columns(third)
|
|
33
67
|
}
|
|
34
68
|
return this
|
|
35
69
|
}
|
|
36
70
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return this
|
|
71
|
+
fullJoin (other, as) { return this.join (other, as, 'full') }
|
|
72
|
+
leftJoin (other, as) { return this.join (other, as, 'left') }
|
|
73
|
+
rightJoin (other, as) { return this.join (other, as, 'right') }
|
|
74
|
+
innerJoin (other, as) { return this.join (other, as, 'inner') }
|
|
75
|
+
join (other, as, kind='inner') {
|
|
76
|
+
const [, target, alias = as] = /(\S+)(?:\s+(?:as)?\s+(\S+))?/i.exec(other)
|
|
77
|
+
const ref = { ref: [target] }
|
|
78
|
+
if (alias) ref.as = alias
|
|
79
|
+
this.SELECT.from = { join:kind, args: [this.SELECT.from, ref] }
|
|
80
|
+
return Object.defineProperty(this, '_where_or_having', { value: 'on', configurable: true })
|
|
47
81
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
82
|
+
on (...args) {
|
|
83
|
+
if (!this.SELECT.from || !this.SELECT.from.join)
|
|
84
|
+
throw new Error(`Invalid call of "SELECT.on()" without prior call of "SELECT.join()"`)
|
|
85
|
+
return this._where (args,'and','on')
|
|
51
86
|
}
|
|
52
87
|
|
|
53
|
-
|
|
54
|
-
this.
|
|
55
|
-
return this
|
|
88
|
+
having(...x) {
|
|
89
|
+
return this._where (x,'and','having')
|
|
56
90
|
}
|
|
57
91
|
|
|
58
|
-
groupBy(...
|
|
59
|
-
|
|
60
|
-
|
|
92
|
+
groupBy (...args) {
|
|
93
|
+
if (!args[0]) return this
|
|
94
|
+
const cqn = args[0].raw ? SELECT_('from X group by', args).groupBy : args.map(parse.expr)
|
|
95
|
+
return this._add('groupBy',cqn)
|
|
61
96
|
}
|
|
62
97
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return this
|
|
98
|
+
orderBy (...args) {
|
|
99
|
+
if (!args[0]) return this
|
|
100
|
+
return this._add('orderBy',_order_by(args))
|
|
66
101
|
}
|
|
67
102
|
|
|
68
|
-
|
|
69
|
-
this.
|
|
103
|
+
limit (rows, offset) {
|
|
104
|
+
if (is_number(rows) || rows) this.SELECT.limit = rows.rows ? rows : { rows: {val:rows} }
|
|
105
|
+
if (is_number(offset)) this.SELECT.limit.offset = { val: offset }
|
|
70
106
|
return this
|
|
71
107
|
}
|
|
72
108
|
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
109
|
+
forUpdate ({ of, wait = defaults.lock_acquire_timeout || -1 } = {}) {
|
|
110
|
+
const sfu = this.SELECT.forUpdate = {}
|
|
111
|
+
if (of) sfu.of = of.map (c => ({ref:c.split('.')}))
|
|
112
|
+
if (wait >= 0) sfu.wait = wait
|
|
76
113
|
return this
|
|
77
114
|
}
|
|
78
115
|
|
|
79
|
-
|
|
80
|
-
return this.
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
foreach(callback) {
|
|
84
|
-
return this.then((rows) => rows.map(callback))
|
|
116
|
+
foreach (callback) {
|
|
117
|
+
return this.then(rows => rows.map(callback))
|
|
85
118
|
}
|
|
86
119
|
|
|
87
120
|
valueOf() {
|
|
@@ -89,89 +122,91 @@ module.exports = class SELECT extends Whereable {
|
|
|
89
122
|
}
|
|
90
123
|
}
|
|
91
124
|
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
return typeof x === 'string' ? parse.column(x) : {val:x}
|
|
125
|
+
|
|
126
|
+
const _columns = (args) => {
|
|
127
|
+
if (args[0].raw) {
|
|
128
|
+
if (args[0][0] === '{') return SELECT_('from X ',args).columns
|
|
129
|
+
else return SELECT_('from X {',args,'}').columns
|
|
130
|
+
} else return _columns_or_not(args[0]) || args.map(_column_expr)
|
|
100
131
|
}
|
|
101
132
|
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
104
|
-
if (
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
133
|
+
const _columns_or_not = (x) => {
|
|
134
|
+
if (typeof x === 'function') return _projection4(x)
|
|
135
|
+
if (typeof x === 'string' && x[0] === '{') return parse.cql('SELECT from X '+ x).SELECT.columns
|
|
136
|
+
if (Array.isArray(x)) return x.map(_column_expr)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const _column_expr = (x) => {
|
|
140
|
+
if (is_cqn(x)) return x
|
|
141
|
+
if (typeof x === 'string') return parse.column(x)
|
|
142
|
+
if (typeof x === 'object') for (let one in x) return Object.assign(parse.expr(one),{as:x[one]})
|
|
143
|
+
else return {val:x}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const _projection4 = (fn) => {
|
|
147
|
+
const columns=[]; fn (new Proxy (fn,{
|
|
148
|
+
apply: (_, __, args) => { // handle top-level projections such as (foo)=>{ foo('*') }
|
|
149
|
+
if (!args.length) return columns.push('*')
|
|
150
|
+
let [x] = Array.isArray(args[0]) ? args[0] : args
|
|
151
|
+
columns.push (x === '*' || x === '.*' ? '*' : is_cqn(x) ? x : {ref:[x]})
|
|
152
|
+
return { as: (alias) => (x.as = alias) }
|
|
153
|
+
},
|
|
154
|
+
get: (_, p) => { // handle top-level paths like (foo)=>{ foo.bar }
|
|
155
|
+
const col = {ref:[p]}; columns.push(col)
|
|
156
|
+
const nested = new Proxy(fn,{ // handle n-fold paths like (foo)=>{ foo.bar.car }
|
|
117
157
|
get: (_, p) => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
},
|
|
141
|
-
})
|
|
158
|
+
if (p === 'where') return (x) => ((col.where = predicate4([x])), nested)
|
|
159
|
+
if (p === 'as') return (alias) => ((col.as = alias), nested)
|
|
160
|
+
else return col.ref.push(p), nested
|
|
161
|
+
},
|
|
162
|
+
apply: (_, __, args) => { // handle nested projections e.g. (foo)=>{ foo.bar (b=>{ ... }) }
|
|
163
|
+
const [a, b] = args
|
|
164
|
+
if (!a) col.expand = ['*']
|
|
165
|
+
else if (a.raw) {
|
|
166
|
+
if (a[0] === '*') col.expand = ['*']
|
|
167
|
+
else if (a[0] === '.*') col.inline = ['*']
|
|
168
|
+
else {
|
|
169
|
+
let {columns} = SELECT_(col.ref[col.ref.length-1] +' ', args, ' from X')
|
|
170
|
+
Object.assign (col, columns[0])
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if (Array.isArray(a)) col.expand = _columns(a)
|
|
174
|
+
else if (a === '*') col.expand = ['*']
|
|
175
|
+
else if (a === '.*') col.inline = ['*']
|
|
176
|
+
else {
|
|
177
|
+
let x = (col[/^\(?_\b/.test(a) ? 'inline' : 'expand'] = _projection4(a))
|
|
178
|
+
if (b && b.levels) while (--b.levels) x.push({ ...col, expand: (x = [...x]) })
|
|
179
|
+
}
|
|
142
180
|
return nested
|
|
143
181
|
},
|
|
144
182
|
})
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
183
|
+
return nested
|
|
184
|
+
},
|
|
185
|
+
}))
|
|
186
|
+
return columns
|
|
148
187
|
}
|
|
149
188
|
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const order = parse.expr(each)
|
|
157
|
-
all.push(order)
|
|
158
|
-
const ad = arg[each]
|
|
159
|
-
order[ad === 1 ? 'asc' : ad === -1 ? 'desc' : ad] = true
|
|
189
|
+
const _order_by = (args) => {
|
|
190
|
+
if (args[0].raw) return SELECT_('from X order by', args).orderBy
|
|
191
|
+
if (Array.isArray(args[0])) args = args[0]
|
|
192
|
+
const cqn=[], _add = (ref,ad) => {
|
|
193
|
+
const obx = parse.expr(ref); cqn.push(obx)
|
|
194
|
+
if (ad) obx.sort = ad == 1 ? 'asc' : ad == -1 ? 'desc' : ad
|
|
160
195
|
}
|
|
161
|
-
return all
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// e.g. .orderBy ('x asc','y desc')
|
|
165
|
-
const _order_by_fluid = (args) => {
|
|
166
|
-
const all = []
|
|
167
196
|
for (let each of args) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (each.endsWith(' desc')) order.desc = true
|
|
197
|
+
if (each.ref) cqn.push(each)
|
|
198
|
+
else if (typeof each === 'string') _add (...each.split(' '))
|
|
199
|
+
else for (let ref in each) _add (ref, each[ref])
|
|
172
200
|
}
|
|
173
|
-
return
|
|
201
|
+
return cqn
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const {CQL} = parse, SELECT_ = (prefix, [ strings, ...more ], suffix) => {
|
|
205
|
+
const tts = [...strings]; tts.raw = true
|
|
206
|
+
if (prefix) tts[0] = `SELECT ${prefix} ${tts[0]}`
|
|
207
|
+
if (suffix) tts[tts.length-1] += ` ${suffix}`
|
|
208
|
+
return CQL(tts,...more).SELECT
|
|
174
209
|
}
|
|
175
210
|
|
|
176
|
-
const
|
|
177
|
-
const
|
|
211
|
+
const is_cqn = x => x === undefined || x === '*' || x.val !== undefined || x.xpr || x.ref || x.list || x.func || x.SELECT
|
|
212
|
+
const is_number = x => !isNaN(x)
|
package/lib/ql/UPDATE.js
CHANGED
|
@@ -1,65 +1,97 @@
|
|
|
1
|
-
const Whereable = require('./Whereable')
|
|
2
|
-
const
|
|
3
|
-
const is_array = Array.isArray
|
|
4
|
-
const $ = Object.assign
|
|
1
|
+
const Whereable = require('./Whereable')
|
|
2
|
+
const { parse } = require('../index')
|
|
5
3
|
|
|
6
4
|
module.exports = class UPDATE extends Whereable {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
|
|
6
|
+
static _api() {
|
|
7
|
+
return Object.assign ((..._) => (new this).entity(..._), {
|
|
8
|
+
entity: (..._) => (new this).entity(..._),
|
|
10
9
|
})
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
entity(e, key) {
|
|
14
|
-
this.
|
|
12
|
+
entity (e, key) {
|
|
13
|
+
this.UPDATE.entity = this._target_name4 (e)
|
|
15
14
|
if (key) this.byKey(key)
|
|
16
15
|
return this
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
this.
|
|
18
|
+
data (d) {
|
|
19
|
+
this.UPDATE.data = d
|
|
21
20
|
return this
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
this.
|
|
26
|
-
return this
|
|
23
|
+
set (...args) { // .set() is an alias for .with()
|
|
24
|
+
return this.with (...args)
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
with (...args) {
|
|
28
|
+
if (args.length === 0) return this
|
|
29
|
+
|
|
30
|
+
// A tagged template string with a single expression, e.g. .with `my.stock -= 1`
|
|
31
|
+
if (args[0].raw) {
|
|
32
|
+
let [lhs,op,...rhs] = parse.CXL(...args).xpr || this._expected `${{args}} to contain expressions of form 'column = <expr>'`
|
|
33
|
+
_add (this, lhs.ref.join('.'), op, ...rhs)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Alternating expr fragment / values args, e.g. .with ('my.stock -=',1, 'lastOrder =', '$now')
|
|
37
|
+
else if (args.length > 1) {
|
|
38
|
+
for (let i = 0; i < args.length; ++i) {
|
|
39
|
+
const [, col, op] = /\s*([\w.]+)\s*([%*+-]?=)/.exec(args[i])
|
|
40
|
+
_add (this, col, op, { val: args[++i] })
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// A single string with comma-separated expressions, e.g. .with ('my.stock -= 1, lastOrder = $now')
|
|
45
|
+
else if (typeof args[0] === 'string') {
|
|
46
|
+
for (let each of _comma_separated_exprs(args[0])) {
|
|
47
|
+
let [lhs,op,...rhs] = parse.expr(each).xpr || this._expected `${{args}} to contain expressions of form 'column = <expr>'`
|
|
48
|
+
_add (this, lhs.ref.join('.'), op, ...rhs)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
33
51
|
|
|
34
|
-
|
|
35
|
-
|
|
52
|
+
// A column - value / expr object, e.g. .with ({ stock:{'-=':1}, lastOrder:{'=':'$now'} })
|
|
53
|
+
else if (typeof args[0] === 'object') {
|
|
54
|
+
const o = args[0]
|
|
55
|
+
for (let col in o) {
|
|
56
|
+
let op = '=', v = o[col]
|
|
57
|
+
if (typeof v === 'object' && !(v === null || v.map || v.pipe || v instanceof Buffer || v instanceof Date)) {
|
|
58
|
+
let o = Object.keys(v)[0] || this._expected `${{v}} to be an object with an operator as single key`
|
|
59
|
+
if (o in operators) v = v[op=o]
|
|
60
|
+
}
|
|
61
|
+
_add (this, col, op, v && (v.val !== undefined || v.ref || v.xpr || v.func || v.SELECT) ? v : {val:v})
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return this
|
|
36
66
|
}
|
|
37
67
|
}
|
|
38
68
|
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
return _set
|
|
69
|
+
|
|
70
|
+
const _add = (q, col, op, ...xpr) => {
|
|
71
|
+
const {UPDATE} = q, v =
|
|
72
|
+
op === '=' ? xpr.length === 1 ? xpr[0] : { xpr } :
|
|
73
|
+
op in operators ? { xpr: [ {ref:[col]}, op[0], ...xpr] } :
|
|
74
|
+
q._expected `${{op}} to be one of ${Object.keys(operators)}`
|
|
75
|
+
if ('val' in v) (UPDATE.data || (UPDATE.data={}))[col] = v.val
|
|
76
|
+
else (UPDATE.with || (UPDATE.with={}))[col] = v
|
|
49
77
|
}
|
|
50
78
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
79
|
+
const _comma_separated_exprs = (s) => {
|
|
80
|
+
let all=[], start=0, scope=0, close, stack = [close]
|
|
81
|
+
for (let i=0; i < s.length; ++i) {
|
|
82
|
+
const c = s[i]
|
|
83
|
+
if (c === "'") while (i < s.length) { if (s[++i] === "'") {
|
|
84
|
+
if (s[i+1] === "'") ++i // double '' is a quoted '
|
|
85
|
+
else break
|
|
86
|
+
}}
|
|
87
|
+
else if (c === ',' && scope === 0) { all.push(s.slice(start,i)); start = i+1 }
|
|
88
|
+
else if (c === '(') { scope++; stack.unshift(close = ')') }
|
|
89
|
+
else if (c === '[') { scope++; stack.unshift(close = ']') }
|
|
90
|
+
else if (c === '{') { scope++; stack.unshift(close = '}') }
|
|
91
|
+
else if (c === close) { scope--; stack.shift(); close = stack[0] }
|
|
57
92
|
}
|
|
58
|
-
|
|
93
|
+
all.push(s.slice(start))
|
|
94
|
+
return all
|
|
59
95
|
}
|
|
60
96
|
|
|
61
|
-
const
|
|
62
|
-
if (op === '-=') return { xpr: [parse.expr(lhs), '-', parse.expr(rhs)] }
|
|
63
|
-
if (op === '+=') return { xpr: [parse.expr(lhs), '+', parse.expr(rhs)] }
|
|
64
|
-
else return parse.expr(rhs) || {val:rhs}
|
|
65
|
-
}
|
|
97
|
+
const operators = { '=':1, '-=':2, '+=':2, '*=':2, '/=':2, '%=':2 }
|