@contember/engine-content-api 1.2.0-rc.3 → 1.2.0-rc.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/dist/src/mapper/select/optimizer/WhereOptimizer.d.ts.map +1 -1
- package/dist/src/mapper/select/optimizer/WhereOptimizer.js +3 -1
- package/dist/src/mapper/select/optimizer/WhereOptimizer.js.map +1 -1
- package/dist/src/mapper/select/optimizer/WhereReplacer.d.ts +3 -1
- package/dist/src/mapper/select/optimizer/WhereReplacer.d.ts.map +1 -1
- package/dist/src/mapper/select/optimizer/WhereReplacer.js +42 -18
- package/dist/src/mapper/select/optimizer/WhereReplacer.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/cases/unit/whereOptimizer.test.js +114 -13
- package/dist/tests/cases/unit/whereOptimizer.test.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -11
- package/src/mapper/select/optimizer/WhereOptimizer.ts +3 -1
- package/src/mapper/select/optimizer/WhereReplacer.ts +45 -18
- package/tests/cases/unit/whereOptimizer.test.ts +120 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/engine-content-api",
|
|
3
|
-
"version": "1.2.0-rc.
|
|
3
|
+
"version": "1.2.0-rc.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"typings": "dist/src/index.d.ts",
|
|
@@ -10,21 +10,21 @@
|
|
|
10
10
|
"test": "vitest --no-threads"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@contember/database": "^1.2.0-rc.
|
|
14
|
-
"@contember/dic": "^1.2.0-rc.
|
|
15
|
-
"@contember/logger": "^1.2.0-rc.
|
|
16
|
-
"@contember/graphql-utils": "^1.2.0-rc.
|
|
17
|
-
"@contember/schema": "^1.2.0-rc.
|
|
18
|
-
"@contember/schema-definition": "^1.2.0-rc.
|
|
19
|
-
"@contember/schema-utils": "^1.2.0-rc.
|
|
13
|
+
"@contember/database": "^1.2.0-rc.4",
|
|
14
|
+
"@contember/dic": "^1.2.0-rc.4",
|
|
15
|
+
"@contember/logger": "^1.2.0-rc.4",
|
|
16
|
+
"@contember/graphql-utils": "^1.2.0-rc.4",
|
|
17
|
+
"@contember/schema": "^1.2.0-rc.4",
|
|
18
|
+
"@contember/schema-definition": "^1.2.0-rc.4",
|
|
19
|
+
"@contember/schema-utils": "^1.2.0-rc.4",
|
|
20
20
|
"@graphql-tools/schema": "^8.3.5",
|
|
21
21
|
"fast-deep-equal": "^3.1.3",
|
|
22
22
|
"graphql-tag": "^2.12.5"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@contember/database-tester": "^1.2.0-rc.
|
|
26
|
-
"@contember/engine-api-tester": "^1.2.0-rc.
|
|
27
|
-
"@contember/schema-definition": "^1.2.0-rc.
|
|
25
|
+
"@contember/database-tester": "^1.2.0-rc.4",
|
|
26
|
+
"@contember/engine-api-tester": "^1.2.0-rc.4",
|
|
27
|
+
"@contember/schema-definition": "^1.2.0-rc.4",
|
|
28
28
|
"@graphql-codegen/cli": "^2.6.2",
|
|
29
29
|
"@graphql-codegen/typescript": "^2.5.1",
|
|
30
30
|
"@graphql-codegen/typescript-operations": "^2.4.2",
|
|
@@ -140,7 +140,9 @@ export class WhereOptimizer {
|
|
|
140
140
|
const a = result[j]
|
|
141
141
|
const b = result[i]
|
|
142
142
|
if (i !== j && typeof a !== 'boolean' && typeof b !== 'boolean') {
|
|
143
|
-
const elResult = replaceWhere(a, b, { [entity.primary]: replacement }
|
|
143
|
+
const elResult = replaceWhere(a, b, { [entity.primary]: replacement }, {
|
|
144
|
+
replaceSubOperands: true,
|
|
145
|
+
})
|
|
144
146
|
if (elResult !== a) {
|
|
145
147
|
if (!copied) {
|
|
146
148
|
result = [...result]
|
|
@@ -1,39 +1,66 @@
|
|
|
1
1
|
import { Input, Writable } from '@contember/schema'
|
|
2
2
|
import deepEqual from 'fast-deep-equal'
|
|
3
3
|
|
|
4
|
-
export const replaceWhere = (subject: Input.OptionalWhere, find: Input.OptionalWhere, replace: Input.OptionalWhere): Input.OptionalWhere => {
|
|
4
|
+
export const replaceWhere = (subject: Input.OptionalWhere, find: Input.OptionalWhere, replace: Input.OptionalWhere, opts: { replaceSubOperands?: boolean } = {}): Input.OptionalWhere => {
|
|
5
5
|
if (deepEqual(subject, find)) {
|
|
6
6
|
return replace
|
|
7
7
|
}
|
|
8
8
|
let result: Writable<Input.OptionalWhere> = subject
|
|
9
9
|
let copied = false
|
|
10
|
+
// copy on write to preserve referential integrity, when nothing has changed
|
|
11
|
+
const write = <T extends string>(key: T, value: Input.OptionalWhere[T]) => {
|
|
12
|
+
if (!copied) {
|
|
13
|
+
result = { ...result }
|
|
14
|
+
copied = true
|
|
15
|
+
}
|
|
16
|
+
result[key] = value
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
for (const key in subject) {
|
|
11
20
|
const value = subject[key]
|
|
12
21
|
if (key === 'not') {
|
|
13
|
-
const newNot = replaceWhere(value as Input.OptionalWhere, find, replace)
|
|
22
|
+
const newNot = replaceWhere(value as Input.OptionalWhere, find, replace, opts)
|
|
14
23
|
if (newNot !== value) {
|
|
15
|
-
|
|
16
|
-
result = { ...result }
|
|
17
|
-
}
|
|
18
|
-
result['not'] = newNot
|
|
24
|
+
write('not', newNot)
|
|
19
25
|
}
|
|
20
26
|
} else if (key === 'and' || key === 'or') {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
const operands = value as Input.OptionalWhere[]
|
|
28
|
+
const subOperandsToFind = opts.replaceSubOperands && Object.keys(find).length === 1 && find[key] ? (find[key] as Input.OptionalWhere[]) : null
|
|
29
|
+
if (subOperandsToFind !== null && containsAllOperands(operands, subOperandsToFind)) {
|
|
30
|
+
write(key, [replace])
|
|
31
|
+
} else {
|
|
32
|
+
const items: Input.OptionalWhere[] = []
|
|
33
|
+
let itemChanged = false
|
|
34
|
+
for (const el of operands) {
|
|
35
|
+
const newEl = replaceWhere(el, find, replace, opts)
|
|
36
|
+
if (newEl !== el) {
|
|
37
|
+
itemChanged = true
|
|
38
|
+
}
|
|
39
|
+
items.push(newEl)
|
|
27
40
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (itemChanged) {
|
|
31
|
-
if (!copied) {
|
|
32
|
-
result = { ...result }
|
|
41
|
+
if (itemChanged) {
|
|
42
|
+
write(key, items)
|
|
33
43
|
}
|
|
34
|
-
result[key] = items
|
|
35
44
|
}
|
|
45
|
+
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
48
|
return result
|
|
39
49
|
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
const containsAllOperands = (subjectOperands: Input.OptionalWhere[], findOperands: Input.OptionalWhere[]): boolean => {
|
|
53
|
+
for (const op1 of findOperands) {
|
|
54
|
+
let found = false
|
|
55
|
+
for (const op2 of subjectOperands) {
|
|
56
|
+
if (deepEqual(op1, op2)) {
|
|
57
|
+
found = true
|
|
58
|
+
break
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!found) {
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
@@ -95,9 +95,11 @@ describe('where optimized', () => {
|
|
|
95
95
|
})
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
const A = {
|
|
99
|
-
const B = {
|
|
100
|
-
const C = {
|
|
98
|
+
const A = { name: { eq: 'A' } }
|
|
99
|
+
const B = { name: { eq: 'B' } }
|
|
100
|
+
const C = { name: { eq: 'C' } }
|
|
101
|
+
const D = { name: { eq: 'D' } }
|
|
102
|
+
const E = { name: { eq: 'E' } }
|
|
101
103
|
|
|
102
104
|
it('minimize: A || (A && B) => A', () => {
|
|
103
105
|
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
@@ -105,7 +107,7 @@ describe('where optimized', () => {
|
|
|
105
107
|
A,
|
|
106
108
|
{ and: [A, B] },
|
|
107
109
|
],
|
|
108
|
-
}, model.entities.
|
|
110
|
+
}, model.entities.Author), A)
|
|
109
111
|
})
|
|
110
112
|
|
|
111
113
|
it('minimize: (A && B) || A => A', () => {
|
|
@@ -114,7 +116,7 @@ describe('where optimized', () => {
|
|
|
114
116
|
{ and: [A, B] },
|
|
115
117
|
A,
|
|
116
118
|
],
|
|
117
|
-
}, model.entities.
|
|
119
|
+
}, model.entities.Author), A)
|
|
118
120
|
})
|
|
119
121
|
|
|
120
122
|
it('minimize: A && (A || B) => A', () => {
|
|
@@ -123,7 +125,7 @@ describe('where optimized', () => {
|
|
|
123
125
|
A,
|
|
124
126
|
{ or: [A, B] },
|
|
125
127
|
],
|
|
126
|
-
}, model.entities.
|
|
128
|
+
}, model.entities.Author), A)
|
|
127
129
|
})
|
|
128
130
|
|
|
129
131
|
it('minimize: (A || B) && A => A', () => {
|
|
@@ -132,7 +134,7 @@ describe('where optimized', () => {
|
|
|
132
134
|
{ or: [A, B] },
|
|
133
135
|
A,
|
|
134
136
|
],
|
|
135
|
-
}, model.entities.
|
|
137
|
+
}, model.entities.Author), A)
|
|
136
138
|
})
|
|
137
139
|
|
|
138
140
|
it('minimize: A && (!A || B) => A && B', () => {
|
|
@@ -141,7 +143,7 @@ describe('where optimized', () => {
|
|
|
141
143
|
A,
|
|
142
144
|
{ or: [{ not: A }, B] },
|
|
143
145
|
],
|
|
144
|
-
}, model.entities.
|
|
146
|
+
}, model.entities.Author), { and: [A, B] })
|
|
145
147
|
})
|
|
146
148
|
|
|
147
149
|
it('minimize: A || (!A && B) => A || B', () => {
|
|
@@ -150,7 +152,7 @@ describe('where optimized', () => {
|
|
|
150
152
|
A,
|
|
151
153
|
{ and: [{ not: A }, B] },
|
|
152
154
|
],
|
|
153
|
-
}, model.entities.
|
|
155
|
+
}, model.entities.Author), { or: [A, B] })
|
|
154
156
|
})
|
|
155
157
|
|
|
156
158
|
|
|
@@ -160,7 +162,7 @@ describe('where optimized', () => {
|
|
|
160
162
|
A,
|
|
161
163
|
{ not: A },
|
|
162
164
|
],
|
|
163
|
-
}, model.entities.
|
|
165
|
+
}, model.entities.Author), { id: { always: true } })
|
|
164
166
|
})
|
|
165
167
|
|
|
166
168
|
it('minimize: A && !A => 0', () => {
|
|
@@ -169,7 +171,7 @@ describe('where optimized', () => {
|
|
|
169
171
|
A,
|
|
170
172
|
{ not: A },
|
|
171
173
|
],
|
|
172
|
-
}, model.entities.
|
|
174
|
+
}, model.entities.Author), { id: { never: true } })
|
|
173
175
|
})
|
|
174
176
|
|
|
175
177
|
it('minimize: !A && !A => !A', () => {
|
|
@@ -178,7 +180,7 @@ describe('where optimized', () => {
|
|
|
178
180
|
{ not: A },
|
|
179
181
|
{ not: A },
|
|
180
182
|
],
|
|
181
|
-
}, model.entities.
|
|
183
|
+
}, model.entities.Author), { not: A })
|
|
182
184
|
})
|
|
183
185
|
|
|
184
186
|
|
|
@@ -188,7 +190,7 @@ describe('where optimized', () => {
|
|
|
188
190
|
{ and: [A, B] },
|
|
189
191
|
{ and: [A, C] },
|
|
190
192
|
],
|
|
191
|
-
}, model.entities.
|
|
193
|
+
}, model.entities.Author), {
|
|
192
194
|
or: [
|
|
193
195
|
{ and: [A, B] },
|
|
194
196
|
{ and: [A, C] },
|
|
@@ -196,6 +198,111 @@ describe('where optimized', () => {
|
|
|
196
198
|
})
|
|
197
199
|
})
|
|
198
200
|
|
|
201
|
+
it('minimize: (A || B) && (A || B || C) => A || B', () => {
|
|
202
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
203
|
+
and: [
|
|
204
|
+
{
|
|
205
|
+
or: [A, B],
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
or: [A, B, C],
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
}, model.entities.Author), { or: [A, B] })
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('not minimize: (A || B) && (A || C)', () => {
|
|
215
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
216
|
+
and: [
|
|
217
|
+
{
|
|
218
|
+
or: [A, B],
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
or: [A, C],
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
}, model.entities.Author), { and: [{ or: [A, B] }, { or: [A, C] }] })
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
it('minimize: (A && B) || (A && B && C) => A && B', () => {
|
|
228
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
229
|
+
or: [
|
|
230
|
+
{
|
|
231
|
+
and: [A, B],
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
and: [A, B, C],
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
}, model.entities.Author), { and: [A, B] })
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('minimize: (A && B) || (A && B) || (A && B) => A && B', () => {
|
|
241
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
242
|
+
or: [
|
|
243
|
+
{
|
|
244
|
+
and: [A, B],
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
and: [A, B],
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
and: [A, B],
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
}, model.entities.Author), { and: [A, B] })
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
it('minimize: (a && b) || (a && b && c) || (a && c) => (a && b) || (a && c)', () => {
|
|
257
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
258
|
+
or: [
|
|
259
|
+
{
|
|
260
|
+
and: [A, B],
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
and: [A, B, C],
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
and: [A, C],
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
}, model.entities.Author), {
|
|
270
|
+
or: [
|
|
271
|
+
{
|
|
272
|
+
and: [A, B],
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
and: [A, C],
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
it('minimize: (a && b) || (c && (d || (a && b && e))) => (a && b) || (c && d)', () => {
|
|
282
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
283
|
+
or: [
|
|
284
|
+
{
|
|
285
|
+
and: [A, B],
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
and: [C, { or: [D, { and: [A, B, E] }] }],
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
}, model.entities.Author), { or: [{ and: [A, B] }, { and: [C, D] }] })
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
it('minimize: (a || b) && (c || (d && (a || b || e))) => (A || B) && (C || D)', () => {
|
|
295
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
296
|
+
and: [
|
|
297
|
+
{
|
|
298
|
+
or: [A, B],
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
or: [C, { and: [D, { or: [A, B, E] }] }],
|
|
302
|
+
},
|
|
303
|
+
],
|
|
304
|
+
}, model.entities.Author), { and: [{ or: [A, B] }, { or: [C, D] }] })
|
|
305
|
+
})
|
|
199
306
|
|
|
200
307
|
describe('remove id predicates', () => {
|
|
201
308
|
|