@contember/engine-content-api 1.2.0-alpha.11 → 1.2.0-alpha.13
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/acl/EvaluatedPredicateReplacer.d.ts +2 -2
- package/dist/src/acl/EvaluatedPredicateReplacer.d.ts.map +1 -1
- package/dist/src/acl/EvaluatedPredicateReplacer.js.map +1 -1
- package/dist/src/acl/PredicateFactory.d.ts +9 -3
- package/dist/src/acl/PredicateFactory.d.ts.map +1 -1
- package/dist/src/acl/PredicateFactory.js +42 -24
- package/dist/src/acl/PredicateFactory.js.map +1 -1
- package/dist/src/acl/PredicatesInjector.d.ts.map +1 -1
- package/dist/src/acl/PredicatesInjector.js +1 -0
- package/dist/src/acl/PredicatesInjector.js.map +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.js +31 -27
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.js.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.js +18 -14
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.js.map +1 -1
- package/dist/src/mapper/JunctionTableManager.js.map +1 -1
- package/dist/src/mapper/Mapper.js +3 -3
- package/dist/src/mapper/Mapper.js.map +1 -1
- package/dist/src/mapper/MapperContainer.d.ts.map +1 -1
- package/dist/src/mapper/MapperContainer.js +2 -2
- package/dist/src/mapper/MapperContainer.js.map +1 -1
- package/dist/src/mapper/delete/DeleteExecutor.js +1 -1
- package/dist/src/mapper/delete/DeleteExecutor.js.map +1 -1
- package/dist/src/mapper/insert/InsertBuilder.d.ts +1 -1
- package/dist/src/mapper/insert/InsertBuilder.d.ts.map +1 -1
- package/dist/src/mapper/insert/InsertBuilder.js.map +1 -1
- package/dist/src/mapper/select/RelationFetcher.js +1 -1
- package/dist/src/mapper/select/RelationFetcher.js.map +1 -1
- package/dist/src/mapper/select/SelectBuilder.d.ts +3 -1
- package/dist/src/mapper/select/SelectBuilder.d.ts.map +1 -1
- package/dist/src/mapper/select/SelectBuilder.js +50 -12
- package/dist/src/mapper/select/SelectBuilder.js.map +1 -1
- package/dist/src/mapper/select/SelectExecutionHandler.d.ts +15 -4
- package/dist/src/mapper/select/SelectExecutionHandler.d.ts.map +1 -1
- package/dist/src/mapper/select/SelectHydrator.d.ts +3 -2
- package/dist/src/mapper/select/SelectHydrator.d.ts.map +1 -1
- package/dist/src/mapper/select/SelectHydrator.js +4 -5
- package/dist/src/mapper/select/SelectHydrator.js.map +1 -1
- package/dist/src/mapper/select/WhereBuilder.d.ts +5 -3
- package/dist/src/mapper/select/WhereBuilder.d.ts.map +1 -1
- package/dist/src/mapper/select/WhereBuilder.js +47 -8
- package/dist/src/mapper/select/WhereBuilder.js.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts +1 -0
- package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitor.js +118 -91
- package/dist/src/mapper/select/handlers/FieldsVisitor.js.map +1 -1
- package/dist/src/mapper/select/handlers/MetaHandler.d.ts.map +1 -1
- package/dist/src/mapper/select/handlers/MetaHandler.js +6 -11
- package/dist/src/mapper/select/handlers/MetaHandler.js.map +1 -1
- package/dist/src/mapper/select/optimizer/WhereOptimizer.d.ts +5 -1
- package/dist/src/mapper/select/optimizer/WhereOptimizer.d.ts.map +1 -1
- package/dist/src/mapper/select/optimizer/WhereOptimizer.js +10 -3
- package/dist/src/mapper/select/optimizer/WhereOptimizer.js.map +1 -1
- package/dist/src/mapper/select/optimizer/WhereReplacer.d.ts +1 -1
- package/dist/src/mapper/select/optimizer/WhereReplacer.d.ts.map +1 -1
- package/dist/src/mapper/select/optimizer/WhereReplacer.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/acl/differentRowAndFieldPredicate.test.js +51 -4
- package/dist/tests/cases/integration/graphQlRequests/query/acl/differentRowAndFieldPredicate.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.js +26 -25
- package/dist/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.js +9 -6
- package/dist/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/acl/rowPredicateSubset.test.d.ts +2 -0
- package/dist/tests/cases/integration/graphQlRequests/query/acl/rowPredicateSubset.test.d.ts.map +1 -0
- package/dist/tests/cases/integration/graphQlRequests/query/acl/rowPredicateSubset.test.js +109 -0
- package/dist/tests/cases/integration/graphQlRequests/query/acl/rowPredicateSubset.test.js.map +1 -0
- package/dist/tests/cases/integration/graphQlRequests/query/graphqlFeatures/alias.test.js +9 -13
- package/dist/tests/cases/integration/graphQlRequests/query/graphqlFeatures/alias.test.js.map +1 -1
- package/dist/tests/cases/unit/predicatesInjector.test.js +31 -3
- package/dist/tests/cases/unit/predicatesInjector.test.js.map +1 -1
- package/dist/tests/cases/unit/whereBuilder.test.d.ts +2 -0
- package/dist/tests/cases/unit/whereBuilder.test.d.ts.map +1 -0
- package/dist/tests/cases/unit/whereBuilder.test.js +75 -0
- package/dist/tests/cases/unit/whereBuilder.test.js.map +1 -0
- package/dist/tests/cases/unit/whereOptimizer.test.js +24 -21
- package/dist/tests/cases/unit/whereOptimizer.test.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/acl/EvaluatedPredicateReplacer.ts +4 -4
- package/src/acl/PredicateFactory.ts +59 -36
- package/src/acl/PredicatesInjector.ts +2 -1
- package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.ts +5 -5
- package/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.ts +5 -5
- package/src/mapper/JunctionTableManager.ts +3 -3
- package/src/mapper/Mapper.ts +3 -3
- package/src/mapper/MapperContainer.ts +2 -1
- package/src/mapper/delete/DeleteExecutor.ts +1 -1
- package/src/mapper/insert/InsertBuilder.ts +2 -2
- package/src/mapper/select/RelationFetcher.ts +1 -1
- package/src/mapper/select/SelectBuilder.ts +69 -13
- package/src/mapper/select/SelectExecutionHandler.ts +15 -8
- package/src/mapper/select/SelectHydrator.ts +13 -7
- package/src/mapper/select/WhereBuilder.ts +58 -11
- package/src/mapper/select/handlers/FieldsVisitor.ts +53 -67
- package/src/mapper/select/handlers/MetaHandler.ts +6 -17
- package/src/mapper/select/optimizer/WhereOptimizer.ts +25 -13
- package/src/mapper/select/optimizer/WhereReplacer.ts +4 -4
- package/tests/cases/integration/graphQlRequests/query/acl/differentRowAndFieldPredicate.test.ts +54 -4
- package/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.ts +26 -25
- package/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.ts +9 -6
- package/tests/cases/integration/graphQlRequests/query/acl/rowPredicateSubset.test.ts +104 -0
- package/tests/cases/integration/graphQlRequests/query/graphqlFeatures/alias.test.ts +9 -13
- package/tests/cases/unit/predicatesInjector.test.ts +37 -7
- package/tests/cases/unit/whereBuilder.test.ts +84 -0
- package/tests/cases/unit/whereOptimizer.test.ts +20 -17
|
@@ -90,17 +90,20 @@ test('querying post + author name', async () => {
|
|
|
90
90
|
},
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
|
-
sql: SQL`
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
sql: SQL`SELECT
|
|
94
|
+
"root_"."id" AS "root_id",
|
|
95
|
+
"root_country"."name" IN (?) AS "root___predicate_countryPredicate",
|
|
96
|
+
"root_"."name" AS "root_name",
|
|
97
|
+
"root_"."id" AS "root_id"
|
|
98
|
+
FROM "public"."author" AS "root_"
|
|
99
|
+
LEFT JOIN "public"."country" AS "root_country" ON "root_"."country_id" = "root_country"."id"
|
|
100
|
+
WHERE "root_"."id" IN (?, ?)`,
|
|
99
101
|
parameters: ['Czechia', testUuid(3), testUuid(4)],
|
|
100
102
|
response: {
|
|
101
103
|
rows: [
|
|
102
104
|
{
|
|
103
105
|
root_id: testUuid(3),
|
|
106
|
+
root___predicate_countryPredicate: true,
|
|
104
107
|
root_name: 'John',
|
|
105
108
|
},
|
|
106
109
|
],
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { SchemaDefinition as def, AclDefinition as acl, createSchema } from '@contember/schema-definition'
|
|
2
|
+
import { Acl } from '@contember/schema'
|
|
3
|
+
import { test } from 'vitest'
|
|
4
|
+
import { execute } from '../../../../../src/test'
|
|
5
|
+
import { GQL, SQL } from '../../../../../src/tags'
|
|
6
|
+
import { testUuid } from '../../../../../src/testUuid'
|
|
7
|
+
import { PermissionFactory } from '../../../../../../src'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
namespace RowPredicateSubset {
|
|
11
|
+
export const readerRole = acl.createRole('reader')
|
|
12
|
+
@acl.allow(readerRole, {
|
|
13
|
+
when: {
|
|
14
|
+
isPublished: { eq: true },
|
|
15
|
+
},
|
|
16
|
+
read: ['isPublished', 'isUnlocked', 'title'],
|
|
17
|
+
})
|
|
18
|
+
@acl.allow(readerRole, {
|
|
19
|
+
when: {
|
|
20
|
+
and: [
|
|
21
|
+
{ isUnlocked: { eq: true } },
|
|
22
|
+
{ isPublished: { eq: true } },
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
read: ['content'],
|
|
26
|
+
})
|
|
27
|
+
export class Article {
|
|
28
|
+
isPublished = def.boolColumn()
|
|
29
|
+
isUnlocked = def.boolColumn()
|
|
30
|
+
title = def.stringColumn()
|
|
31
|
+
content = def.stringColumn()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
test('row level predicate includes main predicate', async () => {
|
|
38
|
+
const schema = createSchema(RowPredicateSubset)
|
|
39
|
+
|
|
40
|
+
const permissions = new PermissionFactory(schema.model).create(schema.acl, ['reader'])
|
|
41
|
+
|
|
42
|
+
await execute({
|
|
43
|
+
schema: schema.model,
|
|
44
|
+
permissions: permissions,
|
|
45
|
+
variables: {},
|
|
46
|
+
query: GQL`
|
|
47
|
+
query {
|
|
48
|
+
listArticle {
|
|
49
|
+
id
|
|
50
|
+
title
|
|
51
|
+
content
|
|
52
|
+
}
|
|
53
|
+
}`,
|
|
54
|
+
executes: [
|
|
55
|
+
{
|
|
56
|
+
sql: SQL`SELECT
|
|
57
|
+
"root_"."id" AS "root_id",
|
|
58
|
+
TRUE AS "root___predicate_isPublished_eq_true",
|
|
59
|
+
"root_"."title" AS "root_title",
|
|
60
|
+
"root_"."is_unlocked" = ? AS "root___predicate_and_isUnlocked_eq_true_isPubl",
|
|
61
|
+
"root_"."content" AS "root_content"
|
|
62
|
+
FROM "public"."article" AS "root_"
|
|
63
|
+
WHERE "root_"."is_published" = ?`,
|
|
64
|
+
parameters: [true, true],
|
|
65
|
+
response: {
|
|
66
|
+
rows: [
|
|
67
|
+
{
|
|
68
|
+
root_id: testUuid(1),
|
|
69
|
+
root___predicate_isPublished_eq_true: true,
|
|
70
|
+
root_title: 'Hello',
|
|
71
|
+
root___predicate_and_isUnlocked_eq_true_isPubl: false,
|
|
72
|
+
root_content: 'Foo bar',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
root_id: testUuid(2),
|
|
76
|
+
root___predicate_isPublished_eq_true: true,
|
|
77
|
+
root_title: 'Hello 2',
|
|
78
|
+
root___predicate_and_isUnlocked_eq_true_isPubl: true,
|
|
79
|
+
root_content: 'Lorem ipsum',
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
return: {
|
|
86
|
+
data: {
|
|
87
|
+
listArticle: [
|
|
88
|
+
{
|
|
89
|
+
id: testUuid(1),
|
|
90
|
+
title: 'Hello',
|
|
91
|
+
content: null,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: testUuid(2),
|
|
95
|
+
title: 'Hello 2',
|
|
96
|
+
content: 'Lorem ipsum',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
|
|
@@ -77,15 +77,13 @@ test('aliases', async () => {
|
|
|
77
77
|
}`,
|
|
78
78
|
executes: [
|
|
79
79
|
{
|
|
80
|
-
sql: SQL`
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
"root_"."id" as "root_id"
|
|
88
|
-
from "public"."author" as "root_"`,
|
|
80
|
+
sql: SQL`SELECT
|
|
81
|
+
"root_"."id" AS "root_idx",
|
|
82
|
+
"root_"."name" AS "root_name1",
|
|
83
|
+
"root_"."name" AS "root_name2",
|
|
84
|
+
"root_"."name" = ? AS "root___predicate_name_eq",
|
|
85
|
+
"root_"."id" AS "root_id"
|
|
86
|
+
FROM "public"."author" AS "root_"`,
|
|
89
87
|
parameters: ['John'],
|
|
90
88
|
response: {
|
|
91
89
|
rows: [
|
|
@@ -94,9 +92,7 @@ test('aliases', async () => {
|
|
|
94
92
|
root_idx: testUuid(1),
|
|
95
93
|
root_name1: 'John',
|
|
96
94
|
root_name2: 'John',
|
|
97
|
-
|
|
98
|
-
root_meta_name1_readable2: true,
|
|
99
|
-
root_meta_name1_updatable1: false,
|
|
95
|
+
root___predicate_name_eq: true,
|
|
100
96
|
},
|
|
101
97
|
],
|
|
102
98
|
},
|
|
@@ -111,7 +107,7 @@ test('aliases', async () => {
|
|
|
111
107
|
name1: {
|
|
112
108
|
readable1: true,
|
|
113
109
|
readable2: true,
|
|
114
|
-
updatable1:
|
|
110
|
+
updatable1: true,
|
|
115
111
|
},
|
|
116
112
|
},
|
|
117
113
|
name1: 'John',
|
|
@@ -5,6 +5,8 @@ import { describe, it, assert } from 'vitest'
|
|
|
5
5
|
import { PermissionsFactory } from '@contember/engine-system-api/dist/src/model'
|
|
6
6
|
import { WhereOptimizer } from '../../../src/mapper/select/optimizer/WhereOptimizer'
|
|
7
7
|
import { ConditionOptimizer } from '../../../src/mapper/select/optimizer/ConditionOptimizer'
|
|
8
|
+
import { acceptFieldVisitor } from '@contember/schema-utils'
|
|
9
|
+
import { testUuid } from '@contember/engine-api-tester'
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
|
|
@@ -157,14 +159,14 @@ namespace DeepFilterModel {
|
|
|
157
159
|
|
|
158
160
|
|
|
159
161
|
describe('predicates injector elimination', () => {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const permissions = new PermissionFactory(schema.model).create(schema.acl, ['reader'])
|
|
162
|
+
const schema = createSchema(DeepFilterModel)
|
|
163
|
+
const permissions = new PermissionFactory(schema.model).create(schema.acl, ['reader'])
|
|
163
164
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
const injector = new PredicatesInjector(
|
|
166
|
+
schema.model,
|
|
167
|
+
new PredicateFactory(permissions, schema.model, new VariableInjector(schema.model, {})),
|
|
168
|
+
)
|
|
169
|
+
it('eliminates predicates in where', () => {
|
|
168
170
|
const injected = injector.inject(schema.model.entities.Article, {
|
|
169
171
|
coverPhoto: { image: { tags: { label: { eq: 'foo' } } } },
|
|
170
172
|
})
|
|
@@ -173,4 +175,32 @@ describe('predicates injector elimination', () => {
|
|
|
173
175
|
|
|
174
176
|
assert.deepStrictEqual(result, { and: [{ coverPhoto: { image: { tags: { label: { eq: 'foo' } } } } }, { isPublished: { eq: true } }] })
|
|
175
177
|
})
|
|
178
|
+
|
|
179
|
+
it('eliminate back referencing predicate', () => {
|
|
180
|
+
const relation = acceptFieldVisitor(schema.model, schema.model.entities.Article, 'coverPhoto', {
|
|
181
|
+
visitColumn: () => {
|
|
182
|
+
throw new Error()
|
|
183
|
+
},
|
|
184
|
+
visitRelation: ctx => ctx,
|
|
185
|
+
})
|
|
186
|
+
const injected = injector.inject(schema.model.entities.ImageUse, {
|
|
187
|
+
articles: { id: { in: [testUuid(1)] } },
|
|
188
|
+
}, relation)
|
|
189
|
+
|
|
190
|
+
assert.deepStrictEqual(injected, {
|
|
191
|
+
and: [
|
|
192
|
+
{
|
|
193
|
+
articles: {
|
|
194
|
+
and: [
|
|
195
|
+
{ id: { in: [testUuid(1)] } },
|
|
196
|
+
{ id: { always: true } },
|
|
197
|
+
],
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
articles: { id: { always: true } },
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
})
|
|
205
|
+
})
|
|
176
206
|
})
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, it, assert } from 'vitest'
|
|
2
|
+
import { ConditionOptimizer } from '../../../src/mapper/select/optimizer/ConditionOptimizer'
|
|
3
|
+
import { createSchema, SchemaDefinition as def } from '@contember/schema-definition'
|
|
4
|
+
import { WhereOptimizer } from '../../../src/mapper/select/optimizer/WhereOptimizer'
|
|
5
|
+
import { ConditionBuilder, JoinBuilder, PathFactory, WhereBuilder } from '../../../src/mapper'
|
|
6
|
+
import { Compiler, SelectBuilder } from '@contember/database'
|
|
7
|
+
import { Input, Schema } from '@contember/schema'
|
|
8
|
+
|
|
9
|
+
namespace WhereBuilderModel {
|
|
10
|
+
export class Author {
|
|
11
|
+
name = def.stringColumn()
|
|
12
|
+
isPublic = def.boolColumn().notNull()
|
|
13
|
+
articles = def.oneHasMany(Article, 'author')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class Article {
|
|
17
|
+
title = def.stringColumn()
|
|
18
|
+
isPublic = def.boolColumn().notNull()
|
|
19
|
+
author = def.manyHasOne(Author, 'articles')
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const createWhere = (schema: Schema, where: Input.Where) => {
|
|
24
|
+
const pathFactory = new PathFactory()
|
|
25
|
+
const joinBuilder = new JoinBuilder(schema.model)
|
|
26
|
+
const conditionBuilder = new ConditionBuilder()
|
|
27
|
+
const whereOptimizer = new WhereOptimizer(schema.model, new ConditionOptimizer())
|
|
28
|
+
const whereBuilder = new WhereBuilder(schema.model, joinBuilder, conditionBuilder, pathFactory, whereOptimizer)
|
|
29
|
+
|
|
30
|
+
const qb = SelectBuilder.create()
|
|
31
|
+
.from('author', 'root_')
|
|
32
|
+
|
|
33
|
+
return whereBuilder.build(qb, schema.model.entities.Author, pathFactory.create([]), where).options.where.compile().sql
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('where builder', () => {
|
|
37
|
+
it('where on has-many relation with AND outside', () => {
|
|
38
|
+
const schema = createSchema(WhereBuilderModel)
|
|
39
|
+
const where = createWhere(schema, {
|
|
40
|
+
and: [
|
|
41
|
+
{
|
|
42
|
+
articles: { isPublic: { eq: true } },
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
articles: { title: { eq: 'Hello' } },
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
})
|
|
49
|
+
assert.equal(
|
|
50
|
+
where,
|
|
51
|
+
' where exists (select 1 from "__SCHEMA__"."article" as "sub_" where "root_"."id" = "sub_"."author_id" and "sub_"."is_public" = ?) and exists (select 1 from "__SCHEMA__"."article" as "sub_" where "root_"."id" = "sub_"."author_id" and "sub_"."title" = ?)',
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('where on has-many relation with AND inside', () => {
|
|
56
|
+
const schema = createSchema(WhereBuilderModel)
|
|
57
|
+
const where = createWhere(schema, {
|
|
58
|
+
articles: {
|
|
59
|
+
and: [
|
|
60
|
+
{ isPublic: { eq: true } },
|
|
61
|
+
{ title: { eq: 'Hello' } },
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
assert.equal(
|
|
66
|
+
where,
|
|
67
|
+
' where exists (select 1 from "__SCHEMA__"."article" as "sub_" where "root_"."id" = "sub_"."author_id" and "sub_"."is_public" = ? and "sub_"."title" = ?)',
|
|
68
|
+
)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
it('where on has-many relation with isNull', () => {
|
|
73
|
+
const schema = createSchema(WhereBuilderModel)
|
|
74
|
+
const where = createWhere(schema, {
|
|
75
|
+
articles: {
|
|
76
|
+
id: { isNull: true },
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
assert.equal(
|
|
80
|
+
where,
|
|
81
|
+
' where exists (select 1 from (select "root_"."id") as "sub2_" left join "__SCHEMA__"."article" as "sub_" on "sub2_"."id" = "sub_"."author_id" where "sub_"."id" is null)',
|
|
82
|
+
)
|
|
83
|
+
})
|
|
84
|
+
})
|
|
@@ -200,14 +200,15 @@ describe('where optimized', () => {
|
|
|
200
200
|
describe('remove id predicates', () => {
|
|
201
201
|
|
|
202
202
|
it('remove ID predicate when traversing from a relation - always', () => {
|
|
203
|
-
|
|
204
|
-
image: { id: { isNull: false } },
|
|
205
|
-
}, model.entities.Author, [acceptFieldVisitor(model, 'Image', 'authors', {
|
|
203
|
+
const relationPath = [acceptFieldVisitor(model, 'Image', 'authors', {
|
|
206
204
|
visitColumn: () => {
|
|
207
205
|
throw new Error()
|
|
208
206
|
},
|
|
209
207
|
visitRelation: context => context,
|
|
210
|
-
})]
|
|
208
|
+
})]
|
|
209
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
210
|
+
image: { id: { isNull: false } },
|
|
211
|
+
}, model.entities.Author, { relationPath }), {
|
|
211
212
|
id: { always: true },
|
|
212
213
|
})
|
|
213
214
|
})
|
|
@@ -216,12 +217,12 @@ describe('where optimized', () => {
|
|
|
216
217
|
it('remove ID predicate when traversing from a relation - never', () => {
|
|
217
218
|
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
218
219
|
image: { id: { isNull: true } },
|
|
219
|
-
}, model.entities.Author, [acceptFieldVisitor(model, 'Image', 'authors', {
|
|
220
|
+
}, model.entities.Author, { relationPath: [acceptFieldVisitor(model, 'Image', 'authors', {
|
|
220
221
|
visitColumn: () => {
|
|
221
222
|
throw new Error()
|
|
222
223
|
},
|
|
223
224
|
visitRelation: context => context,
|
|
224
|
-
})]), {
|
|
225
|
+
})] }), {
|
|
225
226
|
id: { never: true },
|
|
226
227
|
})
|
|
227
228
|
})
|
|
@@ -229,28 +230,27 @@ describe('where optimized', () => {
|
|
|
229
230
|
it('remove ID predicate when traversing in where', () => {
|
|
230
231
|
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
231
232
|
authors: { image: { id: { isNull: false } } },
|
|
232
|
-
}, model.entities.Image
|
|
233
|
+
}, model.entities.Image), {
|
|
233
234
|
id: { always: true },
|
|
234
235
|
})
|
|
235
236
|
})
|
|
236
237
|
|
|
237
238
|
it('do not remove ID predicate when traversing from a has-many relation', () => {
|
|
238
|
-
|
|
239
|
-
authors: { id: { isNull: false } },
|
|
240
|
-
}, model.entities.Image, [acceptFieldVisitor(model, 'Author', 'image', {
|
|
239
|
+
const relationPath = [acceptFieldVisitor(model, 'Author', 'image', {
|
|
241
240
|
visitColumn: () => {
|
|
242
241
|
throw new Error()
|
|
243
242
|
},
|
|
244
243
|
visitRelation: context => context,
|
|
245
|
-
})]
|
|
244
|
+
})]
|
|
245
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
246
|
+
authors: { id: { isNull: false } },
|
|
247
|
+
}, model.entities.Image, { relationPath }), {
|
|
246
248
|
authors: { id: { isNull: false } },
|
|
247
249
|
})
|
|
248
250
|
})
|
|
249
251
|
|
|
250
252
|
it('do not remove ID predicate when traversing from a nested has-many relation', () => {
|
|
251
|
-
|
|
252
|
-
articles: { author: { id: { isNull: false } } },
|
|
253
|
-
}, model.entities.Image, [
|
|
253
|
+
const relationPath = [
|
|
254
254
|
acceptFieldVisitor(model, 'Author', 'articles', {
|
|
255
255
|
visitColumn: () => {
|
|
256
256
|
throw new Error()
|
|
@@ -263,7 +263,10 @@ describe('where optimized', () => {
|
|
|
263
263
|
},
|
|
264
264
|
visitRelation: context => context,
|
|
265
265
|
}),
|
|
266
|
-
]
|
|
266
|
+
]
|
|
267
|
+
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
268
|
+
articles: { author: { id: { isNull: false } } },
|
|
269
|
+
}, model.entities.Image, { relationPath }), {
|
|
267
270
|
articles: { author: { id: { isNull: false } } },
|
|
268
271
|
})
|
|
269
272
|
})
|
|
@@ -271,7 +274,7 @@ describe('where optimized', () => {
|
|
|
271
274
|
it('do not remove ID predicate when traversing in where over has-many relation', () => {
|
|
272
275
|
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
273
276
|
image: { authors: { id: { isNull: false } } },
|
|
274
|
-
}, model.entities.Author
|
|
277
|
+
}, model.entities.Author), {
|
|
275
278
|
image: { authors: { id: { isNull: false } } },
|
|
276
279
|
})
|
|
277
280
|
})
|
|
@@ -280,7 +283,7 @@ describe('where optimized', () => {
|
|
|
280
283
|
it('do not remove ID predicate when traversing in where over has-many relation - nested', () => {
|
|
281
284
|
assert.deepStrictEqual(whereOptimizer.optimize({
|
|
282
285
|
image: { authors: { image: { id: { isNull: false } } } },
|
|
283
|
-
}, model.entities.Author
|
|
286
|
+
}, model.entities.Author), {
|
|
284
287
|
image: { authors: { image: { id: { isNull: false } } } },
|
|
285
288
|
})
|
|
286
289
|
})
|