@contember/engine-content-api 1.0.0 → 1.0.3
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/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js +2 -0
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js.map +1 -1
- package/dist/src/mapper/Mapper.d.ts.map +1 -1
- package/dist/src/mapper/Mapper.js +2 -4
- package/dist/src/mapper/Mapper.js.map +1 -1
- package/dist/src/mapper/select/ConditionBuilder.d.ts +1 -1
- package/dist/src/mapper/select/ConditionBuilder.d.ts.map +1 -1
- package/dist/src/mapper/select/ConditionBuilder.js +5 -5
- package/dist/src/mapper/select/ConditionBuilder.js.map +1 -1
- package/dist/src/mapper/select/JoinVisitor.js +2 -2
- package/dist/src/mapper/select/JoinVisitor.js.map +1 -1
- package/dist/src/mapper/select/OrderByBuilder.js +1 -1
- package/dist/src/mapper/select/OrderByBuilder.js.map +1 -1
- package/dist/src/mapper/select/SelectBuilder.d.ts +1 -1
- package/dist/src/mapper/select/SelectBuilder.d.ts.map +1 -1
- package/dist/src/mapper/select/SelectBuilder.js +3 -4
- package/dist/src/mapper/select/SelectBuilder.js.map +1 -1
- package/dist/src/mapper/select/WhereBuilder.d.ts.map +1 -1
- package/dist/src/mapper/select/WhereBuilder.js +4 -3
- package/dist/src/mapper/select/WhereBuilder.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/relations/oneHasMany.test.js +87 -0
- package/dist/tests/cases/integration/graphQlRequests/query/relations/oneHasMany.test.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.ts +2 -0
- package/src/mapper/Mapper.ts +2 -5
- package/src/mapper/select/ConditionBuilder.ts +5 -4
- package/src/mapper/select/JoinVisitor.ts +2 -2
- package/src/mapper/select/OrderByBuilder.ts +1 -1
- package/src/mapper/select/SelectBuilder.ts +3 -5
- package/src/mapper/select/WhereBuilder.ts +5 -2
- package/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.ts +1 -0
- package/tests/cases/integration/graphQlRequests/query/relations/oneHasMany.test.ts +89 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/engine-content-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"typings": "dist/src/index.d.ts",
|
|
@@ -10,19 +10,19 @@
|
|
|
10
10
|
"test": "uvu dist/tests/cases/ \\.js$"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@contember/database": "^1.0.
|
|
14
|
-
"@contember/dic": "^1.0.
|
|
15
|
-
"@contember/engine-common": "^1.0.
|
|
16
|
-
"@contember/graphql-utils": "^1.0.
|
|
17
|
-
"@contember/schema": "^1.0.
|
|
18
|
-
"@contember/schema-utils": "^1.0.
|
|
13
|
+
"@contember/database": "^1.0.3",
|
|
14
|
+
"@contember/dic": "^1.0.3",
|
|
15
|
+
"@contember/engine-common": "^1.0.3",
|
|
16
|
+
"@contember/graphql-utils": "^1.0.3",
|
|
17
|
+
"@contember/schema": "^1.0.3",
|
|
18
|
+
"@contember/schema-utils": "^1.0.3",
|
|
19
19
|
"@graphql-tools/schema": "^7.1.5",
|
|
20
20
|
"graphql-tag": "^2.12.5"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@contember/database-tester": "^1.0.
|
|
24
|
-
"@contember/engine-api-tester": "^1.0.
|
|
25
|
-
"@contember/schema-definition": "^1.0.
|
|
23
|
+
"@contember/database-tester": "^1.0.3",
|
|
24
|
+
"@contember/engine-api-tester": "^1.0.3",
|
|
25
|
+
"@contember/schema-definition": "^1.0.3",
|
|
26
26
|
"@graphql-codegen/cli": "^1.15.2",
|
|
27
27
|
"@graphql-codegen/typescript": "^1.15.2",
|
|
28
28
|
"@graphql-codegen/typescript-operations": "^1.15.2",
|
|
@@ -3,6 +3,7 @@ import { FieldMap } from '../EntityFieldsProvider'
|
|
|
3
3
|
import { PaginatedHasManyFieldProviderExtension } from './PaginatedHasManyFieldProvider'
|
|
4
4
|
import { capitalizeFirstLetter } from '../../utils'
|
|
5
5
|
import { PaginatedFieldConfigFactory } from '../../schema/PaginatedFieldConfigFactory'
|
|
6
|
+
import { aliasAwareResolver } from '../../schema'
|
|
6
7
|
|
|
7
8
|
export class PaginatedHasManyFieldProviderVisitor implements
|
|
8
9
|
Model.ColumnVisitor<FieldMap<PaginatedHasManyFieldProviderExtension>>,
|
|
@@ -47,6 +48,7 @@ export class PaginatedHasManyFieldProviderVisitor implements
|
|
|
47
48
|
extensions: {
|
|
48
49
|
relationName: relation.name,
|
|
49
50
|
},
|
|
51
|
+
resolve: aliasAwareResolver,
|
|
50
52
|
},
|
|
51
53
|
}
|
|
52
54
|
}
|
package/src/mapper/Mapper.ts
CHANGED
|
@@ -120,11 +120,8 @@ export class Mapper {
|
|
|
120
120
|
const selector = this.selectBuilderFactory.create(augmentedBuilder, hydrator)
|
|
121
121
|
const filterWithPredicates = this.predicatesInjector.inject(entity, inputWithOrder.args.filter || {})
|
|
122
122
|
const inputWithPredicates = inputWithOrder.withArg('filter', filterWithPredicates)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
await selectPromise
|
|
126
|
-
|
|
127
|
-
return rows
|
|
123
|
+
selector.select(this, entity, inputWithPredicates, path, groupBy)
|
|
124
|
+
return await selector.execute(this.db)
|
|
128
125
|
}
|
|
129
126
|
|
|
130
127
|
public async count(entity: Model.Entity, filter: Input.OptionalWhere) {
|
|
@@ -7,6 +7,7 @@ export class ConditionBuilder {
|
|
|
7
7
|
builder: SqlConditionBuilder,
|
|
8
8
|
tableName: string,
|
|
9
9
|
columnName: string,
|
|
10
|
+
columnType: string,
|
|
10
11
|
condition: Input.Condition<any>,
|
|
11
12
|
): SqlConditionBuilder {
|
|
12
13
|
const keys = Object.keys(condition) as (keyof Required<Input.Condition<any>>)[]
|
|
@@ -27,13 +28,13 @@ export class ConditionBuilder {
|
|
|
27
28
|
param: Exclude<Input.Condition<any>[K], undefined>,
|
|
28
29
|
) => SqlConditionBuilder
|
|
29
30
|
} = {
|
|
30
|
-
and: (builder, expressions) => builder.and(builder2 => expressions.reduce((builder3, expr) => this.build(builder3, tableName, columnName, expr), builder2)),
|
|
31
|
-
or: (builder, expressions) => builder.or(builder2 => expressions.reduce((builder3, expr) => this.build(builder3, tableName, columnName, expr), builder2)),
|
|
32
|
-
not: (builder, expression) => builder.not(builder2 => this.build(builder2, tableName, columnName, expression)),
|
|
31
|
+
and: (builder, expressions) => builder.and(builder2 => expressions.reduce((builder3, expr) => this.build(builder3, tableName, columnName, columnType, expr), builder2)),
|
|
32
|
+
or: (builder, expressions) => builder.or(builder2 => expressions.reduce((builder3, expr) => this.build(builder3, tableName, columnName, columnType, expr), builder2)),
|
|
33
|
+
not: (builder, expression) => builder.not(builder2 => this.build(builder2, tableName, columnName, columnType, expression)),
|
|
33
34
|
eq: (builder, value) => builder.compare(columnIdentifier, Operator.eq, value),
|
|
34
35
|
notEq: (builder, value) => builder.compare(columnIdentifier, Operator.notEq, value),
|
|
35
36
|
isNull: (builder, value) => value ? builder.isNull(columnIdentifier) : builder.not(clause => clause.isNull(columnIdentifier)),
|
|
36
|
-
in: (builder, values) => builder.in(columnIdentifier, values),
|
|
37
|
+
in: (builder, values) => builder.in(columnIdentifier, values, columnType),
|
|
37
38
|
notIn: (builder, values) => builder.not(builder2 => builder2.in(columnIdentifier, values)),
|
|
38
39
|
lt: (builder, value) => builder.compare(columnIdentifier, Operator.lt, value),
|
|
39
40
|
lte: (builder, value) => builder.compare(columnIdentifier, Operator.lte, value),
|
|
@@ -70,7 +70,7 @@ export class JoinVisitor implements Model.RelationByTypeVisitor<JoinDefinition[]
|
|
|
70
70
|
): JoinDefinition[] {
|
|
71
71
|
const sourceAlias = this.path.back().getAlias()
|
|
72
72
|
const targetAlias = this.path.getAlias()
|
|
73
|
-
const joiningAlias =
|
|
73
|
+
const joiningAlias = this.path.back().for('x_' + this.path.getAlias()).getAlias()
|
|
74
74
|
return [
|
|
75
75
|
{
|
|
76
76
|
tableName: relation.joiningTable.tableName,
|
|
@@ -98,7 +98,7 @@ export class JoinVisitor implements Model.RelationByTypeVisitor<JoinDefinition[]
|
|
|
98
98
|
): JoinDefinition[] {
|
|
99
99
|
const sourceAlias = this.path.back().getAlias()
|
|
100
100
|
const targetAlias = this.path.getAlias()
|
|
101
|
-
const joiningAlias =
|
|
101
|
+
const joiningAlias = this.path.back().for('x_' + this.path.getAlias()).getAlias()
|
|
102
102
|
return [
|
|
103
103
|
{
|
|
104
104
|
tableName: targetRelation.joiningTable.tableName,
|
|
@@ -30,7 +30,7 @@ export class OrderByBuilder {
|
|
|
30
30
|
): [SelectBuilder<SelectBuilder.Result>, Orderable] {
|
|
31
31
|
const entries = Object.entries(orderBy)
|
|
32
32
|
if (entries.length !== 1) {
|
|
33
|
-
const fields = entries.join(', ')
|
|
33
|
+
const fields = entries.map(it => it[0]).join(', ')
|
|
34
34
|
throw new UserError('Order by: only one field is expected in each item of order by clause, got: ' + fields)
|
|
35
35
|
}
|
|
36
36
|
if (orderBy._random || orderBy._randomSeeded) {
|
|
@@ -43,14 +43,14 @@ export class SelectBuilder {
|
|
|
43
43
|
return result
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
public
|
|
46
|
+
public select(
|
|
47
47
|
mapper: Mapper,
|
|
48
48
|
entity: Model.Entity,
|
|
49
49
|
input: ObjectNode<Input.ListQueryInput>,
|
|
50
50
|
path: Path,
|
|
51
51
|
groupBy?: string,
|
|
52
52
|
) {
|
|
53
|
-
|
|
53
|
+
this.selectInternal(mapper, entity, path, input)
|
|
54
54
|
const where = input.args.filter
|
|
55
55
|
if (where) {
|
|
56
56
|
this.qb = this.whereBuilder.build(this.qb, entity, path, where)
|
|
@@ -76,11 +76,9 @@ export class SelectBuilder {
|
|
|
76
76
|
}
|
|
77
77
|
this.qb = this.qb.limit(input.args.limit, input.args.offset)
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
await promise
|
|
81
79
|
}
|
|
82
80
|
|
|
83
|
-
private
|
|
81
|
+
private selectInternal(mapper: Mapper, entity: Model.Entity, path: Path, input: ObjectNode) {
|
|
84
82
|
if (!input.fields.find(it => it.name === entity.primary && it.alias === entity.primary)) {
|
|
85
83
|
input = input.withField(new FieldNode(entity.primary, entity.primary, {}))
|
|
86
84
|
}
|
|
@@ -101,6 +101,7 @@ export class WhereBuilder {
|
|
|
101
101
|
conditionBuilder,
|
|
102
102
|
tableName,
|
|
103
103
|
relation.joiningColumn.columnName,
|
|
104
|
+
(targetEntity.fields[targetEntity.primary] as Model.AnyColumn).columnType,
|
|
104
105
|
primaryCondition,
|
|
105
106
|
)
|
|
106
107
|
}
|
|
@@ -114,7 +115,7 @@ export class WhereBuilder {
|
|
|
114
115
|
conditionBuilder = acceptFieldVisitor<SqlConditionBuilder>(this.schema, entity, fieldName, {
|
|
115
116
|
visitColumn: (entity, column) => {
|
|
116
117
|
const subWhere: Input.Condition<Input.ColumnValue> = where[column.name] as Input.Condition<Input.ColumnValue>
|
|
117
|
-
return this.conditionBuilder.build(conditionBuilder, tableName, column.columnName, subWhere)
|
|
118
|
+
return this.conditionBuilder.build(conditionBuilder, tableName, column.columnName, column.columnType, subWhere)
|
|
118
119
|
},
|
|
119
120
|
visitOneHasOneInverse: joinedWhere,
|
|
120
121
|
visitOneHasOneOwning: joinedWhere,
|
|
@@ -198,8 +199,10 @@ export class WhereBuilder {
|
|
|
198
199
|
.select(['junction_', fromColumn])
|
|
199
200
|
const primaryCondition = this.transformWhereToPrimaryCondition(relationWhere, targetEntity.primary)
|
|
200
201
|
if (primaryCondition !== null) {
|
|
202
|
+
const columnType = (targetEntity.fields[targetEntity.primary] as Model.AnyColumn).columnType
|
|
203
|
+
|
|
201
204
|
return augmentedBuilder.where(condition =>
|
|
202
|
-
this.conditionBuilder.build(condition, 'junction_', toColumn, primaryCondition),
|
|
205
|
+
this.conditionBuilder.build(condition, 'junction_', toColumn, columnType, primaryCondition),
|
|
203
206
|
)
|
|
204
207
|
}
|
|
205
208
|
|
|
@@ -416,4 +416,93 @@ test('Posts with paginated comments without count (one has many)', async () => {
|
|
|
416
416
|
})
|
|
417
417
|
})
|
|
418
418
|
|
|
419
|
+
|
|
420
|
+
test('Posts with paginated comments (one has many)', async () => {
|
|
421
|
+
await execute({
|
|
422
|
+
schema: new SchemaBuilder()
|
|
423
|
+
.entity('Post', entity => entity.oneHasMany('comments', relation => relation.target('Comment').ownedBy('post')))
|
|
424
|
+
.entity('Comment', entity => entity.column('content').column('deletedAt', c => c.type(Model.ColumnType.DateTime)))
|
|
425
|
+
.buildSchema(),
|
|
426
|
+
query: GQL`
|
|
427
|
+
query {
|
|
428
|
+
listPost {
|
|
429
|
+
id
|
|
430
|
+
comments: paginateComments(filter: {deletedAt: {isNull: true}}, first: 1) {
|
|
431
|
+
pages: pageInfo {
|
|
432
|
+
count: totalCount
|
|
433
|
+
}
|
|
434
|
+
comments: edges {
|
|
435
|
+
comment: node {
|
|
436
|
+
content
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
`,
|
|
443
|
+
executes: [
|
|
444
|
+
{
|
|
445
|
+
sql: SQL`select
|
|
446
|
+
"root_"."id" as "root_id",
|
|
447
|
+
"root_"."id" as "root_id"
|
|
448
|
+
from "public"."post" as "root_"`,
|
|
449
|
+
response: {
|
|
450
|
+
rows: [{ root_id: testUuid(1) }],
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
sql: SQL`select
|
|
455
|
+
count(*) as "row_count", "root_"."post_id"
|
|
456
|
+
from "public"."comment" as "root_"
|
|
457
|
+
where "root_"."deleted_at" is null and "root_"."post_id" in (?)
|
|
458
|
+
group by "root_"."post_id"`,
|
|
459
|
+
parameters: [testUuid(1)],
|
|
460
|
+
response: {
|
|
461
|
+
rows: [
|
|
462
|
+
{ post_id: testUuid(1), row_count: 5 },
|
|
463
|
+
],
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
sql: SQL`with "data" as
|
|
468
|
+
(select
|
|
469
|
+
"root_"."post_id" as "__grouping_key",
|
|
470
|
+
"root_"."content" as "root_content",
|
|
471
|
+
"root_"."id" as "root_id",
|
|
472
|
+
row_number() over(partition by "root_"."post_id" order by "root_"."id" asc) as "rowNumber_"
|
|
473
|
+
from "public"."comment" as "root_"
|
|
474
|
+
where "root_"."deleted_at" is null
|
|
475
|
+
and "root_"."post_id" in (?)
|
|
476
|
+
order by "root_"."id" asc)
|
|
477
|
+
select "data".* from "data" where "data"."rowNumber_" <= ?`,
|
|
478
|
+
parameters: [testUuid(1), 1],
|
|
479
|
+
response: {
|
|
480
|
+
rows: [
|
|
481
|
+
{ __grouping_key: testUuid(1), root_id: testUuid(3), root_content: 'Lorem ipsum' },
|
|
482
|
+
],
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
],
|
|
486
|
+
return: {
|
|
487
|
+
data: {
|
|
488
|
+
listPost: [
|
|
489
|
+
{
|
|
490
|
+
id: testUuid(1),
|
|
491
|
+
comments: {
|
|
492
|
+
pages: {
|
|
493
|
+
count: 5,
|
|
494
|
+
},
|
|
495
|
+
comments: [
|
|
496
|
+
{
|
|
497
|
+
comment: { content: 'Lorem ipsum' },
|
|
498
|
+
},
|
|
499
|
+
],
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
],
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
})
|
|
506
|
+
})
|
|
507
|
+
|
|
419
508
|
test.run()
|