@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.
Files changed (36) hide show
  1. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts.map +1 -1
  2. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js +2 -0
  3. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js.map +1 -1
  4. package/dist/src/mapper/Mapper.d.ts.map +1 -1
  5. package/dist/src/mapper/Mapper.js +2 -4
  6. package/dist/src/mapper/Mapper.js.map +1 -1
  7. package/dist/src/mapper/select/ConditionBuilder.d.ts +1 -1
  8. package/dist/src/mapper/select/ConditionBuilder.d.ts.map +1 -1
  9. package/dist/src/mapper/select/ConditionBuilder.js +5 -5
  10. package/dist/src/mapper/select/ConditionBuilder.js.map +1 -1
  11. package/dist/src/mapper/select/JoinVisitor.js +2 -2
  12. package/dist/src/mapper/select/JoinVisitor.js.map +1 -1
  13. package/dist/src/mapper/select/OrderByBuilder.js +1 -1
  14. package/dist/src/mapper/select/OrderByBuilder.js.map +1 -1
  15. package/dist/src/mapper/select/SelectBuilder.d.ts +1 -1
  16. package/dist/src/mapper/select/SelectBuilder.d.ts.map +1 -1
  17. package/dist/src/mapper/select/SelectBuilder.js +3 -4
  18. package/dist/src/mapper/select/SelectBuilder.js.map +1 -1
  19. package/dist/src/mapper/select/WhereBuilder.d.ts.map +1 -1
  20. package/dist/src/mapper/select/WhereBuilder.js +4 -3
  21. package/dist/src/mapper/select/WhereBuilder.js.map +1 -1
  22. package/dist/src/tsconfig.tsbuildinfo +1 -1
  23. package/dist/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.js.map +1 -1
  24. package/dist/tests/cases/integration/graphQlRequests/query/relations/oneHasMany.test.js +87 -0
  25. package/dist/tests/cases/integration/graphQlRequests/query/relations/oneHasMany.test.js.map +1 -1
  26. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  27. package/package.json +10 -10
  28. package/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.ts +2 -0
  29. package/src/mapper/Mapper.ts +2 -5
  30. package/src/mapper/select/ConditionBuilder.ts +5 -4
  31. package/src/mapper/select/JoinVisitor.ts +2 -2
  32. package/src/mapper/select/OrderByBuilder.ts +1 -1
  33. package/src/mapper/select/SelectBuilder.ts +3 -5
  34. package/src/mapper/select/WhereBuilder.ts +5 -2
  35. package/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.ts +1 -0
  36. 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.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.0",
14
- "@contember/dic": "^1.0.0",
15
- "@contember/engine-common": "^1.0.0",
16
- "@contember/graphql-utils": "^1.0.0",
17
- "@contember/schema": "^1.0.0",
18
- "@contember/schema-utils": "^1.0.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.0",
24
- "@contember/engine-api-tester": "^1.0.0",
25
- "@contember/schema-definition": "^1.0.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
  }
@@ -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
- const selectPromise = selector.select(this, entity, inputWithPredicates, path, groupBy)
124
- const rows = await selector.execute(this.db)
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 = `${sourceAlias}_x_${targetAlias}`
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 = `${sourceAlias}_x_${targetAlias}`
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 async select(
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
- const promise = this.selectInternal(mapper, entity, path, input)
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 async selectInternal(mapper: Mapper, entity: Model.Entity, path: Path, input: ObjectNode) {
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
 
@@ -104,4 +104,5 @@ test('Post by category ids (where many has many owning)', async () => {
104
104
  },
105
105
  })
106
106
  })
107
+
107
108
  test.run()
@@ -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()