@sap/cds-compiler 6.1.0 → 6.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.
- package/CHANGELOG.md +78 -0
- package/bin/cdsc.js +17 -6
- package/bin/cdsse.js +1 -1
- package/bin/cdsv2m.js +1 -1
- package/lib/api/main.js +29 -7
- package/lib/api/options.js +1 -1
- package/lib/base/builtins.js +9 -0
- package/lib/base/keywords.js +1 -1
- package/lib/base/message-registry.js +41 -10
- package/lib/base/messages.js +13 -6
- package/lib/base/model.js +1 -1
- package/lib/base/optionProcessorHelper.js +7 -2
- package/lib/checks/assocOutsideService.js +17 -30
- package/lib/checks/checkForTypes.js +0 -18
- package/lib/checks/checkPathsInStoredCalcElement.js +2 -1
- package/lib/checks/featureFlags.js +4 -1
- package/lib/checks/onConditions.js +2 -2
- package/lib/checks/queryNoDbArtifacts.js +16 -15
- package/lib/checks/types.js +1 -1
- package/lib/checks/utils.js +30 -6
- package/lib/checks/validator.js +4 -5
- package/lib/compiler/assert-consistency.js +3 -1
- package/lib/compiler/base.js +1 -1
- package/lib/compiler/builtins.js +1 -1
- package/lib/compiler/checks.js +85 -39
- package/lib/compiler/define.js +24 -5
- package/lib/compiler/extend.js +1 -1
- package/lib/compiler/finalize-parse-cdl.js +9 -1
- package/lib/compiler/generate.js +4 -4
- package/lib/compiler/index.js +88 -6
- package/lib/compiler/lsp-api.js +2 -0
- package/lib/compiler/populate.js +8 -8
- package/lib/compiler/propagator.js +1 -1
- package/lib/compiler/resolve.js +22 -21
- package/lib/compiler/shared.js +6 -6
- package/lib/compiler/tweak-assocs.js +53 -31
- package/lib/compiler/utils.js +9 -16
- package/lib/compiler/xpr-rewrite.js +2 -2
- package/lib/gen/BaseParser.js +35 -29
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +1424 -1430
- package/lib/gen/Dictionary.json +1 -2
- package/lib/gen/cdlKeywords.json +26 -0
- package/lib/inspect/inspectPropagation.js +1 -1
- package/lib/json/from-csn.js +2 -2
- package/lib/json/to-csn.js +1 -1
- package/lib/language/multiLineStringParser.js +1 -1
- package/lib/model/cloneCsn.js +1 -0
- package/lib/model/csnRefs.js +9 -4
- package/lib/model/csnUtils.js +67 -2
- package/lib/optionProcessor.js +9 -9
- package/lib/parsers/AstBuildingParser.js +28 -26
- package/lib/parsers/identifiers.js +2 -30
- package/lib/render/toCdl.js +73 -13
- package/lib/render/toSql.js +127 -108
- package/lib/render/utils/common.js +4 -2
- package/lib/render/utils/sql.js +67 -0
- package/lib/transform/addTenantFields.js +4 -4
- package/lib/transform/db/assertUnique.js +2 -1
- package/lib/transform/db/associations.js +37 -1
- package/lib/transform/db/assocsToQueries/transformExists.js +21 -32
- package/lib/transform/db/assocsToQueries/utils.js +1 -1
- package/lib/transform/db/cdsPersistence.js +1 -1
- package/lib/transform/db/expansion.js +37 -36
- package/lib/transform/db/killAnnotations.js +1 -0
- package/lib/transform/db/processSqlServices.js +20 -2
- package/lib/transform/draft/db.js +20 -20
- package/lib/transform/draft/odata.js +38 -40
- package/lib/transform/effective/associations.js +1 -1
- package/lib/transform/effective/flattening.js +40 -47
- package/lib/transform/effective/main.js +6 -4
- package/lib/transform/forOdata.js +201 -92
- package/lib/transform/forRelationalDB.js +151 -142
- package/lib/transform/localized.js +116 -109
- package/lib/transform/odata/adaptAnnotationRefs.js +21 -16
- package/lib/transform/odata/createForeignKeys.js +73 -70
- package/lib/transform/odata/flattening.js +216 -200
- package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +47 -45
- package/lib/transform/odata/toFinalBaseType.js +40 -39
- package/lib/transform/odata/typesExposure.js +151 -133
- package/lib/transform/odata/utils.js +7 -6
- package/lib/transform/parseExpr.js +165 -162
- package/lib/transform/transformUtils.js +184 -551
- package/lib/transform/translateAssocsToJoins.js +511 -596
- package/lib/transform/tupleExpansion.js +495 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
- package/lib/utils/moduleResolve.js +1 -1
- package/package.json +2 -2
- package/lib/base/cleanSymbols.js +0 -17
- package/lib/checks/nonexpandableStructured.js +0 -39
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
|
|
3
|
-
'use strict'
|
|
3
|
+
'use strict';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* parseExpr() accepts any JSON object and tries to convert a token stream expression
|
|
@@ -49,20 +49,19 @@ function parseExpr(xpr, state = { array: true, nary: false }) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function Cast(xpr, state) {
|
|
52
|
-
if(xpr != null && !state.array) {
|
|
53
|
-
if(Array.isArray(xpr))
|
|
52
|
+
if (xpr != null && !state.array) {
|
|
53
|
+
if (Array.isArray(xpr))
|
|
54
54
|
return xpr.map(x => Cast(x, state));
|
|
55
|
-
if(typeof xpr === 'object') {
|
|
55
|
+
if (typeof xpr === 'object') {
|
|
56
56
|
const castKeys = Object.keys(xpr).filter(k => k !== 'cast');
|
|
57
|
-
if(xpr.cast != null && castKeys.length === 1)
|
|
58
|
-
return {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
57
|
+
if (xpr.cast != null && castKeys.length === 1)
|
|
58
|
+
return { cast: [ xpr.cast, { [castKeys[0]]: xpr[castKeys[0]] } ] };
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
for (const n in xpr) {
|
|
62
|
+
// xpr could be an array with polluted prototype
|
|
63
|
+
if (Object.hasOwnProperty.call(xpr, n))
|
|
64
|
+
xpr[n] = Cast(xpr[n], state);
|
|
66
65
|
}
|
|
67
66
|
}
|
|
68
67
|
}
|
|
@@ -70,26 +69,26 @@ function parseExpr(xpr, state = { array: true, nary: false }) {
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
function CaseWhen(xpr) {
|
|
73
|
-
if(Array.isArray(xpr))
|
|
72
|
+
if (Array.isArray(xpr))
|
|
74
73
|
recurseIntoCases();
|
|
75
|
-
}
|
|
76
|
-
return [xpr, 0, Array.isArray(xpr) ? xpr.length : 1];
|
|
77
74
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
return [ xpr, 0, Array.isArray(xpr) ? xpr.length : 1 ];
|
|
76
|
+
|
|
77
|
+
function recurseIntoCases(casePos = -1, lvl = -1) {
|
|
78
|
+
for (let c = casePos + 1; c < xpr.length; c++) {
|
|
79
|
+
if (xpr[c] === 'case')
|
|
80
|
+
recurseIntoCases(c, lvl + 1);
|
|
83
81
|
}
|
|
84
|
-
if(lvl > -1) {
|
|
82
|
+
if (lvl > -1) {
|
|
85
83
|
let endPos = casePos;
|
|
86
|
-
while(xpr[endPos] !== 'end' && endPos < xpr.length)
|
|
87
|
-
|
|
84
|
+
while (xpr[endPos] !== 'end' && endPos < xpr.length)
|
|
85
|
+
endPos++;
|
|
86
|
+
if (xpr[endPos] === 'end') {
|
|
88
87
|
const caseTree = rewriteCaseBlock(casePos, endPos);
|
|
89
|
-
if(casePos === 0 && endPos === xpr.length-1)
|
|
88
|
+
if (casePos === 0 && endPos === xpr.length - 1)
|
|
90
89
|
xpr = caseTree;
|
|
91
90
|
else
|
|
92
|
-
xpr.splice(casePos, endPos-casePos+1, caseTree);
|
|
91
|
+
xpr.splice(casePos, endPos - casePos + 1, caseTree);
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
}
|
|
@@ -100,197 +99,201 @@ function parseExpr(xpr, state = { array: true, nary: false }) {
|
|
|
100
99
|
* @return {Array|object}
|
|
101
100
|
*/
|
|
102
101
|
function rewriteCaseBlock(casePos, endPos) {
|
|
103
|
-
const caseTree = state.array ? [ 'case' ] : {
|
|
102
|
+
const caseTree = state.array ? [ 'case' ] : { case: [] };
|
|
104
103
|
|
|
105
104
|
let elsePos = endPos;
|
|
106
105
|
let whenPos = casePos;
|
|
107
106
|
|
|
108
|
-
while(xpr[elsePos] !== 'else' && elsePos > casePos)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
while (xpr[elsePos] !== 'else' && elsePos > casePos)
|
|
108
|
+
elsePos--;
|
|
109
|
+
let elseCond;
|
|
110
|
+
if (xpr[elsePos] === 'else') {
|
|
111
|
+
elseCond = xpr.slice(elsePos + 1, endPos);
|
|
112
112
|
endPos = elsePos;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
while(xpr[whenPos] !== 'when' && whenPos < endPos)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
while (xpr[whenPos] !== 'when' && whenPos < endPos)
|
|
116
|
+
whenPos++;
|
|
117
|
+
if (xpr[whenPos] === 'when' && whenPos - (casePos + 1) >= 1) {
|
|
118
|
+
const caseExpr = xpr.slice(casePos + 1, whenPos);
|
|
119
|
+
if (state.array)
|
|
119
120
|
caseTree.push(caseExpr);
|
|
120
121
|
else
|
|
121
122
|
caseTree.case.push(caseExpr.length === 1 ? caseExpr[0] : caseExpr);
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
while(xpr[whenPos] === 'when') {
|
|
125
|
-
const when = {
|
|
126
|
-
if(state.array)
|
|
125
|
+
while (xpr[whenPos] === 'when') {
|
|
126
|
+
const when = { when: [] };
|
|
127
|
+
if (state.array)
|
|
127
128
|
caseTree.push('when');
|
|
128
129
|
else
|
|
129
130
|
caseTree.case.push(when);
|
|
130
131
|
|
|
131
|
-
let thenPos = whenPos+1;
|
|
132
|
-
while(xpr[thenPos] !== 'then' && thenPos < endPos)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
let thenPos = whenPos + 1;
|
|
133
|
+
while (xpr[thenPos] !== 'then' && thenPos < endPos)
|
|
134
|
+
thenPos++;
|
|
135
|
+
if (xpr[thenPos] === 'then') {
|
|
136
|
+
const whenExpr = xpr.slice(whenPos + 1, thenPos);
|
|
137
|
+
if (state.array)
|
|
136
138
|
caseTree.push(whenExpr);
|
|
137
139
|
else
|
|
138
140
|
when.when.push(whenExpr.length === 1 ? whenExpr[0] : whenExpr);
|
|
139
141
|
}
|
|
140
142
|
|
|
141
|
-
whenPos = thenPos+1;
|
|
142
|
-
while(xpr[whenPos] !== 'when' && whenPos < endPos)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
whenPos = thenPos + 1;
|
|
144
|
+
while (xpr[whenPos] !== 'when' && whenPos < endPos)
|
|
145
|
+
whenPos++;
|
|
146
|
+
if (xpr[whenPos] === 'when' || whenPos === endPos) {
|
|
147
|
+
const then = xpr.slice(thenPos + 1, whenPos);
|
|
148
|
+
if (state.array)
|
|
146
149
|
caseTree.push('then', then);
|
|
147
150
|
else
|
|
148
151
|
when.when.push(then.length === 1 ? then[0] : then);
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
|
-
if(elseCond) {
|
|
152
|
-
if(state.array)
|
|
154
|
+
if (elseCond) {
|
|
155
|
+
if (state.array)
|
|
153
156
|
caseTree.push('else', elseCond);
|
|
154
157
|
else
|
|
155
|
-
|
|
158
|
+
caseTree.case.push(elseCond.length === 1 ? elseCond[0] : elseCond);
|
|
156
159
|
}
|
|
157
|
-
if(state.array)
|
|
160
|
+
if (state.array)
|
|
158
161
|
caseTree.push('end');
|
|
159
162
|
return caseTree;
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
|
|
163
166
|
function conditionOR(xpr, s, e, state) {
|
|
164
|
-
return binaryExpr(xpr, ['or'], conditionAnd, s, e, state);
|
|
167
|
+
return binaryExpr(xpr, [ 'or' ], conditionAnd, s, e, state);
|
|
165
168
|
}
|
|
166
169
|
|
|
167
170
|
function conditionAnd(xpr, s, e, state) {
|
|
168
171
|
return binaryExpr(xpr, (xpr, s, e) => {
|
|
169
|
-
let a = s-1;
|
|
172
|
+
let a = s - 1;
|
|
170
173
|
let b;
|
|
171
174
|
do {
|
|
172
175
|
b = false;
|
|
173
|
-
for(a++; xpr[a] !== 'and' && a < e; a++) {
|
|
174
|
-
if(xpr[a] === 'between')
|
|
176
|
+
for (a++; xpr[a] !== 'and' && a < e; a++) {
|
|
177
|
+
if (xpr[a] === 'between')
|
|
175
178
|
b = true;
|
|
176
179
|
}
|
|
177
|
-
} while(b && a < e)
|
|
180
|
+
} while (b && a < e);
|
|
178
181
|
|
|
179
|
-
if(!b && a < e)
|
|
180
|
-
return [1, a]
|
|
181
|
-
|
|
182
|
-
return [1, -1];
|
|
182
|
+
if (!b && a < e)
|
|
183
|
+
return [ 1, a ];
|
|
184
|
+
return [ 1, -1 ];
|
|
183
185
|
}, conditionTerm, s, e, state);
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
function conditionTerm(xpr, s, e, state) {
|
|
187
|
-
if(Array.isArray(xpr)) {
|
|
188
|
-
if(xpr.length >= 3 && xpr[s+1] === 'is') {
|
|
189
|
+
if (Array.isArray(xpr)) {
|
|
190
|
+
if (xpr.length >= 3 && xpr[s + 1] === 'is') {
|
|
189
191
|
const isnull = conditionOR(xpr[s], 0, 0, state);
|
|
190
|
-
if(xpr[s+2] === 'null')
|
|
191
|
-
return state.array ? [ isnull, 'is', 'null' ] :
|
|
192
|
-
else if(xpr[s+2] === 'not' && xpr[s+3] === 'null')
|
|
193
|
-
return state.array ? [ isnull, 'is', 'not', 'null' ] : {
|
|
192
|
+
if (xpr[s + 2] === 'null')
|
|
193
|
+
return state.array ? [ isnull, 'is', 'null' ] : { isNull: isnull };
|
|
194
|
+
else if (xpr[s + 2] === 'not' && xpr[s + 3] === 'null')
|
|
195
|
+
return state.array ? [ isnull, 'is', 'not', 'null' ] : { isNotNull: isnull };
|
|
194
196
|
}
|
|
195
|
-
if(xpr[s] === 'not') {
|
|
196
|
-
const
|
|
197
|
-
return state.array ? [ 'not',
|
|
197
|
+
if (xpr[s] === 'not') {
|
|
198
|
+
const not = conditionTerm(xpr, s + 1, e, state);
|
|
199
|
+
return state.array ? [ 'not', not ] : { not };
|
|
198
200
|
}
|
|
199
|
-
if(xpr[s] === 'exists') {
|
|
200
|
-
const exists = conditionTerm(xpr, s+1, e, state)
|
|
201
|
-
return state.array ? [ 'exists', exists ] : {
|
|
201
|
+
if (xpr[s] === 'exists') {
|
|
202
|
+
const exists = conditionTerm(xpr, s + 1, e, state);
|
|
203
|
+
return state.array ? [ 'exists', exists ] : { exists };
|
|
202
204
|
}
|
|
203
205
|
}
|
|
204
206
|
return compareTerm(xpr, s, e, state);
|
|
205
207
|
}
|
|
206
208
|
|
|
207
209
|
function compareTerm(xpr, s, e, state) {
|
|
208
|
-
if(Array.isArray(xpr)) {
|
|
210
|
+
if (Array.isArray(xpr)) {
|
|
209
211
|
let i = s;
|
|
210
212
|
let not = false;
|
|
211
213
|
let between;
|
|
212
|
-
while(i < e && xpr[i] !== 'between')
|
|
214
|
+
while (i < e && xpr[i] !== 'between')
|
|
215
|
+
i++;
|
|
213
216
|
const b = i < e ? i : -1;
|
|
214
|
-
while(i < e && xpr[i] !== 'and')
|
|
217
|
+
while (i < e && xpr[i] !== 'and')
|
|
218
|
+
i++;
|
|
215
219
|
const a = i < e ? i : -1;
|
|
216
|
-
if(b >= 0) {
|
|
220
|
+
if (b >= 0) {
|
|
217
221
|
const token = [ 'between' ];
|
|
218
|
-
not = (xpr[b-1] === 'not');
|
|
219
|
-
if(not)
|
|
220
|
-
token.splice(0,0, 'not');
|
|
221
|
-
const expr = expression(xpr, s, not ? b-1 : b, state);
|
|
222
|
+
not = (xpr[b - 1] === 'not');
|
|
223
|
+
if (not)
|
|
224
|
+
token.splice(0, 0, 'not');
|
|
225
|
+
const expr = expression(xpr, s, not ? b - 1 : b, state);
|
|
222
226
|
between = state.array
|
|
223
227
|
? [ expr, ...token ]
|
|
224
|
-
: {
|
|
225
|
-
if(a >= 0) {
|
|
226
|
-
const lower = expression(xpr, b+1, a, state);
|
|
227
|
-
const upper = expression(xpr, a+1, e, state);
|
|
228
|
-
if(state.array)
|
|
228
|
+
: { between: [ expr ] };
|
|
229
|
+
if (a >= 0) {
|
|
230
|
+
const lower = expression(xpr, b + 1, a, state);
|
|
231
|
+
const upper = expression(xpr, a + 1, e, state);
|
|
232
|
+
if (state.array)
|
|
229
233
|
between.push(lower, 'and', upper);
|
|
230
|
-
else
|
|
234
|
+
else
|
|
231
235
|
between.between.push(lower, upper);
|
|
232
|
-
}
|
|
233
236
|
}
|
|
234
237
|
else {
|
|
235
|
-
const unspec = expression(xpr, b+1, e, state);
|
|
236
|
-
if(state.array)
|
|
238
|
+
const unspec = expression(xpr, b + 1, e, state);
|
|
239
|
+
if (state.array)
|
|
237
240
|
between.push(unspec);
|
|
238
241
|
else
|
|
239
242
|
between.between.push(unspec);
|
|
240
243
|
}
|
|
241
|
-
if(not && !state.array)
|
|
242
|
-
between = {
|
|
243
|
-
|
|
244
|
+
if (not && !state.array)
|
|
245
|
+
between = { not: between };
|
|
246
|
+
|
|
244
247
|
return between;
|
|
245
248
|
}
|
|
246
249
|
}
|
|
247
250
|
return binaryExpr(xpr, (xpr, s, e) => {
|
|
248
|
-
const token = ['=', '<>', '>', '>=', '<', '<=', '==', '!=', 'like', 'in'];
|
|
249
|
-
while(s < e && !token.includes(xpr[s]))
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
const token = [ '=', '<>', '>', '>=', '<', '<=', '==', '!=', 'like', 'in' ];
|
|
252
|
+
while (s < e && !token.includes(xpr[s]))
|
|
253
|
+
s++;
|
|
254
|
+
if (s < e) {
|
|
255
|
+
if (xpr[s - 1] === 'not' && (xpr[s] === 'in' || xpr[s] === 'like'))
|
|
256
|
+
return [ 2, s - 1 ];
|
|
257
|
+
return [ 1, s ];
|
|
255
258
|
}
|
|
256
|
-
return [1, -1];
|
|
259
|
+
return [ 1, -1 ];
|
|
257
260
|
}, expression, s, e, state);
|
|
258
261
|
}
|
|
259
262
|
|
|
260
263
|
function expression(xpr, s, e, state) {
|
|
261
|
-
return binaryExpr(xpr, ['||'], exprAddSub, s, e, state);
|
|
264
|
+
return binaryExpr(xpr, [ '||' ], exprAddSub, s, e, state);
|
|
262
265
|
}
|
|
263
266
|
|
|
264
267
|
function exprAddSub(xpr, s, e, state) {
|
|
265
268
|
return binaryExpr(xpr, (xpr, s, e) => {
|
|
266
269
|
const skips = [ '+', '-', '*', '/' ];
|
|
267
270
|
let found = false;
|
|
268
|
-
let p=s;
|
|
269
|
-
while(!found && p < e) {
|
|
270
|
-
found = ((xpr[p] === '+' || xpr[p] === '-') && p > s && !skips.includes(xpr[p-1]) && p < e);
|
|
271
|
-
if(!found)
|
|
271
|
+
let p = s;
|
|
272
|
+
while (!found && p < e) {
|
|
273
|
+
found = ((xpr[p] === '+' || xpr[p] === '-') && p > s && !skips.includes(xpr[p - 1]) && p < e);
|
|
274
|
+
if (!found)
|
|
275
|
+
p++;
|
|
272
276
|
}
|
|
273
|
-
if(found)
|
|
274
|
-
return [1, p];
|
|
275
|
-
return [1, -1];
|
|
277
|
+
if (found)
|
|
278
|
+
return [ 1, p ];
|
|
279
|
+
return [ 1, -1 ];
|
|
276
280
|
}, exprMulDiv, s, e, state);
|
|
277
281
|
}
|
|
278
282
|
|
|
279
283
|
function exprMulDiv(xpr, s, e, state) {
|
|
280
|
-
return binaryExpr(xpr, ['*', '/'], (state.array ? unary : dot), s, e, state);
|
|
284
|
+
return binaryExpr(xpr, [ '*', '/' ], (state.array ? unary : dot), s, e, state);
|
|
281
285
|
}
|
|
282
286
|
|
|
283
287
|
function dot(xpr, s, e, state) {
|
|
284
|
-
return binaryExpr(xpr, ['.'], unary, s, e, state);
|
|
288
|
+
return binaryExpr(xpr, [ '.' ], unary, s, e, state);
|
|
285
289
|
}
|
|
286
290
|
|
|
287
291
|
function unary(xpr, s, e, state) {
|
|
288
|
-
if(Array.isArray(xpr)) {
|
|
289
|
-
if(xpr[s] === '+' || xpr[s] === '-' || (!state.array && xpr[s] === 'new')) {
|
|
290
|
-
if(state.array)
|
|
291
|
-
return [ xpr[s], unary(xpr, s+1, e, state) ];
|
|
292
|
-
|
|
293
|
-
return { [xpr[s]]: unary(xpr, s+1, e, state) };
|
|
292
|
+
if (Array.isArray(xpr)) {
|
|
293
|
+
if (xpr[s] === '+' || xpr[s] === '-' || (!state.array && xpr[s] === 'new')) {
|
|
294
|
+
if (state.array)
|
|
295
|
+
return [ xpr[s], unary(xpr, s + 1, e, state) ];
|
|
296
|
+
return { [xpr[s]]: unary(xpr, s + 1, e, state) };
|
|
294
297
|
}
|
|
295
298
|
}
|
|
296
299
|
return terminal(xpr, s, e, state);
|
|
@@ -298,39 +301,40 @@ function parseExpr(xpr, state = { array: true, nary: false }) {
|
|
|
298
301
|
function terminal(xpr, s, e, state) {
|
|
299
302
|
const csnarray = [
|
|
300
303
|
'ref', 'args', 'columns', 'keys', 'expand', 'inline',
|
|
301
|
-
'requires', 'extensions', 'includes', 'excluding'
|
|
304
|
+
'requires', 'extensions', 'includes', 'excluding',
|
|
302
305
|
];
|
|
303
306
|
const xprarray = [
|
|
304
|
-
'xpr', 'on', 'where', 'orderBy', 'groupBy', 'having'
|
|
307
|
+
'xpr', 'on', 'where', 'orderBy', 'groupBy', 'having',
|
|
308
|
+
];
|
|
305
309
|
|
|
306
|
-
if(Array.isArray(xpr) && xpr.length > 0) {
|
|
307
|
-
if(e-s <= 1 && state.anno === 0
|
|
308
|
-
return parseExprInt(xpr[e-1], state);
|
|
309
|
-
|
|
310
|
-
return xpr.slice(s, e).map(ix => parseExprInt(ix, state));
|
|
310
|
+
if (Array.isArray(xpr) && xpr.length > 0) {
|
|
311
|
+
if (e - s <= 1 && state.anno === 0 && typeof xpr[e - 1] !== 'string')
|
|
312
|
+
return parseExprInt(xpr[e - 1], state);
|
|
313
|
+
return xpr.slice(s, e).map(ix => parseExprInt(ix, state));
|
|
311
314
|
}
|
|
312
315
|
if (typeof xpr === 'object') {
|
|
313
316
|
// if(xpr?.func && funkyfuncs.includes(xpr?.func))
|
|
314
317
|
// return xpr;
|
|
315
|
-
for(const n in xpr) {
|
|
318
|
+
for (const n in xpr) {
|
|
316
319
|
// xpr could be an array with polluted prototype
|
|
317
320
|
if (!Object.hasOwnProperty.call(xpr, n))
|
|
318
321
|
continue;
|
|
319
322
|
const x = xpr[n];
|
|
320
323
|
const isAnno = n[0] === '@' && isSimpleAnnoValue(x);
|
|
321
|
-
if(isAnno)
|
|
324
|
+
if (isAnno)
|
|
322
325
|
state.anno++;
|
|
323
|
-
if(Array.isArray(x)) {
|
|
324
|
-
if(csnarray.includes(n) || state.anno !== 0)
|
|
326
|
+
if (Array.isArray(x)) {
|
|
327
|
+
if (csnarray.includes(n) || state.anno !== 0)
|
|
325
328
|
xpr[n] = x.map(ix => parseExprInt(ix, state));
|
|
326
|
-
else if(xprarray.includes(n) && x.length === 1)
|
|
329
|
+
else if (xprarray.includes(n) && x.length === 1)
|
|
327
330
|
xpr[n] = x.map(ix => parseExprInt(ix, state));
|
|
328
331
|
else
|
|
329
332
|
xpr[n] = parseExprInt(x, state);
|
|
330
333
|
}
|
|
331
|
-
else
|
|
334
|
+
else {
|
|
332
335
|
xpr[n] = parseExprInt(x, state);
|
|
333
|
-
|
|
336
|
+
}
|
|
337
|
+
if (isAnno)
|
|
334
338
|
state.anno--;
|
|
335
339
|
}
|
|
336
340
|
}
|
|
@@ -341,63 +345,62 @@ function parseExpr(xpr, state = { array: true, nary: false }) {
|
|
|
341
345
|
const naryExpr = [];
|
|
342
346
|
let not = false;
|
|
343
347
|
if (Array.isArray(xpr)) {
|
|
344
|
-
let [tl, p] = findToken(s, e);
|
|
348
|
+
let [ tl, p ] = findToken(s, e);
|
|
345
349
|
if (p >= 0) {
|
|
346
350
|
let lhs = next(xpr, s, p, state);
|
|
347
351
|
naryExpr.push(lhs);
|
|
348
|
-
let op = xpr.slice(p, p+tl);
|
|
349
|
-
s = p+tl;
|
|
350
|
-
[tl, p] = findToken(s, e);
|
|
351
|
-
while(p >= 0) {
|
|
352
|
+
let op = xpr.slice(p, p + tl);
|
|
353
|
+
s = p + tl;
|
|
354
|
+
[ tl, p ] = findToken(s, e);
|
|
355
|
+
while (p >= 0) {
|
|
352
356
|
const rhs = next(xpr, s, p, state);
|
|
353
357
|
naryExpr.push(...op, rhs);
|
|
354
|
-
if(state.array)
|
|
358
|
+
if (state.array) {
|
|
355
359
|
lhs = [ lhs, ...op, rhs ];
|
|
360
|
+
}
|
|
356
361
|
else {
|
|
357
362
|
not = op.length > 1 && op[0] === 'not';
|
|
358
|
-
if(not)
|
|
363
|
+
if (not)
|
|
359
364
|
op = op.slice(1);
|
|
360
365
|
lhs = (not
|
|
361
|
-
|
|
362
|
-
|
|
366
|
+
? { not: { [op.join('')]: [ lhs, rhs ] } }
|
|
367
|
+
: { [op.join('')]: [ lhs, rhs ] });
|
|
363
368
|
}
|
|
364
|
-
op = xpr.slice(p, p+tl);
|
|
365
|
-
s = p+tl;
|
|
366
|
-
[tl, p] = findToken(s, e);
|
|
369
|
+
op = xpr.slice(p, p + tl);
|
|
370
|
+
s = p + tl;
|
|
371
|
+
[ tl, p ] = findToken(s, e);
|
|
367
372
|
}
|
|
368
373
|
|
|
369
374
|
let rhs = next(xpr, s, e, state);
|
|
370
|
-
if(Array.isArray(rhs) && rhs.length === 0)
|
|
375
|
+
if (Array.isArray(rhs) && rhs.length === 0)
|
|
371
376
|
rhs = undefined;
|
|
372
377
|
naryExpr.push(...op, rhs);
|
|
373
378
|
|
|
374
379
|
if (state.array)
|
|
375
|
-
return (state.nary ? naryExpr : [ lhs, ...op, rhs ])
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
380
|
+
return (state.nary ? naryExpr : [ lhs, ...op, rhs ]);
|
|
381
|
+
|
|
382
|
+
not = op.length > 1 && op[0] === 'not';
|
|
383
|
+
if (not)
|
|
384
|
+
op = op.slice(1);
|
|
385
|
+
return (not
|
|
386
|
+
? { not: { [op.join('')]: [ lhs, rhs ] } }
|
|
387
|
+
: { [op.join('')]: [ lhs, rhs ] });
|
|
385
388
|
}
|
|
386
389
|
}
|
|
387
390
|
return next(xpr, s, e, state);
|
|
388
391
|
|
|
389
392
|
function findToken(s, e) {
|
|
390
|
-
if(typeof token === 'function')
|
|
393
|
+
if (typeof token === 'function')
|
|
391
394
|
return token(xpr, s, e);
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
395
|
+
|
|
396
|
+
while (s < e && !token.includes(xpr[s]))
|
|
397
|
+
s++;
|
|
398
|
+
if (s < e)
|
|
399
|
+
return [ 1, s ];
|
|
400
|
+
|
|
401
|
+
return [ 1, -1 ];
|
|
398
402
|
}
|
|
399
403
|
}
|
|
400
|
-
|
|
401
404
|
}
|
|
402
405
|
|
|
403
406
|
function isSimpleAnnoValue(val) {
|