@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contember/engine-content-api",
3
- "version": "1.2.0-rc.3",
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.3",
14
- "@contember/dic": "^1.2.0-rc.3",
15
- "@contember/logger": "^1.2.0-rc.3",
16
- "@contember/graphql-utils": "^1.2.0-rc.3",
17
- "@contember/schema": "^1.2.0-rc.3",
18
- "@contember/schema-definition": "^1.2.0-rc.3",
19
- "@contember/schema-utils": "^1.2.0-rc.3",
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.3",
26
- "@contember/engine-api-tester": "^1.2.0-rc.3",
27
- "@contember/schema-definition": "^1.2.0-rc.3",
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
- if (!copied) {
16
- result = { ...result }
17
- }
18
- result['not'] = newNot
24
+ write('not', newNot)
19
25
  }
20
26
  } else if (key === 'and' || key === 'or') {
21
- const items: Input.OptionalWhere[] = []
22
- let itemChanged = false
23
- for (const el of value as Input.OptionalWhere[]) {
24
- const newEl = replaceWhere(el, find, replace)
25
- if (newEl !== el) {
26
- itemChanged = true
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
- items.push(newEl)
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 = { authors: { isPublic: { eq: true } } }
99
- const B = { authors: { name: { eq: 'John' } } }
100
- const C = { authors: { name: { eq: 'Jack' } } }
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.Image), A)
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.Image), A)
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.Image), A)
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.Image), A)
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.Image), { and: [A, B] })
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.Image), { or: [A, B] })
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.Image), { id: { always: true } })
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.Image), { id: { never: true } })
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.Image), { not: A })
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.Image), {
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