@contember/engine-content-api 1.3.6 → 1.4.0-alpha.2
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/ExecutionContainer.d.ts +4 -4
- package/dist/src/ExecutionContainer.d.ts.map +1 -1
- package/dist/src/ExecutionContainer.js +5 -2
- package/dist/src/ExecutionContainer.js.map +1 -1
- package/dist/src/extensions/EntityFieldsProvider.d.ts +1 -1
- package/dist/src/extensions/EntityFieldsProvider.d.ts.map +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.d.ts +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.d.ts.map +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.js +12 -2
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.js.map +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.d.ts +16 -9
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.d.ts.map +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.js +21 -13
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.js.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.d.ts +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.d.ts.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.js +8 -2
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.js.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts +16 -9
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js +17 -12
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js.map +1 -1
- package/dist/src/introspection/IntrospectionSchemaDefinitionFactory.d.ts +2 -0
- package/dist/src/introspection/IntrospectionSchemaDefinitionFactory.d.ts.map +1 -1
- package/dist/src/introspection/IntrospectionSchemaDefinitionFactory.js +18 -14
- package/dist/src/introspection/IntrospectionSchemaDefinitionFactory.js.map +1 -1
- package/dist/src/introspection/index.d.ts +1 -2
- package/dist/src/introspection/index.d.ts.map +1 -1
- package/dist/src/introspection/index.js +4 -4
- package/dist/src/introspection/index.js.map +1 -1
- package/dist/src/mapper/ErrorUtils.d.ts +3 -3
- package/dist/src/mapper/ErrorUtils.d.ts.map +1 -1
- package/dist/src/mapper/ErrorUtils.js +2 -2
- package/dist/src/mapper/ErrorUtils.js.map +1 -1
- package/dist/src/mapper/Mapper.d.ts +2 -3
- package/dist/src/mapper/Mapper.d.ts.map +1 -1
- package/dist/src/mapper/Mapper.js +1 -1
- package/dist/src/mapper/Mapper.js.map +1 -1
- package/dist/src/mapper/MapperFactory.d.ts +3 -3
- package/dist/src/mapper/MapperFactory.d.ts.map +1 -1
- package/dist/src/mapper/MapperFactory.js.map +1 -1
- package/dist/src/mapper/Result.d.ts +2 -2
- package/dist/src/mapper/Result.d.ts.map +1 -1
- package/dist/src/mapper/Result.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/Inserter.d.ts +3 -2
- package/dist/src/mapper/insert/Inserter.d.ts.map +1 -1
- package/dist/src/mapper/insert/Inserter.js.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts +3 -5
- package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitor.js +8 -4
- package/dist/src/mapper/select/handlers/FieldsVisitor.js.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitorFactory.d.ts +3 -5
- package/dist/src/mapper/select/handlers/FieldsVisitorFactory.d.ts.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitorFactory.js +3 -4
- package/dist/src/mapper/select/handlers/FieldsVisitorFactory.js.map +1 -1
- package/dist/src/mapper/update/Updater.d.ts +2 -2
- package/dist/src/mapper/update/Updater.d.ts.map +1 -1
- package/dist/src/mapper/update/Updater.js.map +1 -1
- package/dist/src/resolvers/MutationResolver.d.ts +3 -2
- package/dist/src/resolvers/MutationResolver.d.ts.map +1 -1
- package/dist/src/resolvers/MutationResolver.js +20 -18
- package/dist/src/resolvers/MutationResolver.js.map +1 -1
- package/dist/src/schema/EntityTypeProvider.d.ts.map +1 -1
- package/dist/src/schema/EntityTypeProvider.js +23 -26
- package/dist/src/schema/EntityTypeProvider.js.map +1 -1
- package/dist/src/schema/GraphQlSchemaBuilder.d.ts.map +1 -1
- package/dist/src/schema/GraphQlSchemaBuilder.js +3 -1
- package/dist/src/schema/GraphQlSchemaBuilder.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/cases/integration/graphQlDb/update/deferedConstraints.test.js +1 -1
- package/dist/tests/cases/integration/graphQlDb/update/deferedConstraints.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.d.ts +2 -0
- package/dist/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.d.ts.map +1 -0
- package/dist/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.js +170 -0
- package/dist/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.js.map +1 -0
- package/dist/tests/src/test.js +1 -1
- package/dist/tests/src/test.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/graphql.codegen.yml +1 -1
- package/package.json +12 -13
- package/src/ExecutionContainer.ts +13 -6
- package/src/extensions/EntityFieldsProvider.ts +1 -1
- package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.ts +12 -5
- package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.ts +33 -24
- package/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.ts +8 -5
- package/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.ts +28 -17
- package/src/introspection/IntrospectionSchemaDefinitionFactory.ts +22 -14
- package/src/introspection/index.ts +1 -2
- package/src/mapper/ErrorUtils.ts +8 -7
- package/src/mapper/Mapper.ts +4 -4
- package/src/mapper/MapperFactory.ts +3 -3
- package/src/mapper/Result.ts +2 -3
- package/src/mapper/delete/DeleteExecutor.ts +1 -1
- package/src/mapper/insert/Inserter.ts +3 -2
- package/src/mapper/select/handlers/FieldsVisitor.ts +9 -5
- package/src/mapper/select/handlers/FieldsVisitorFactory.ts +3 -6
- package/src/mapper/update/Updater.ts +3 -2
- package/src/resolvers/MutationResolver.ts +29 -22
- package/src/schema/EntityTypeProvider.ts +32 -41
- package/src/schema/GraphQlSchemaBuilder.ts +3 -1
- package/tests/cases/integration/graphQlDb/update/deferedConstraints.test.ts +1 -1
- package/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.ts +169 -0
- package/tests/cases/integration/graphQlSchema/schema-acl-allowed.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-acl-create-only.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-acl-restricted-create.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-acl-restricted-delete.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-acl-restricted-update.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-acl.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-aliased-type.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-basic.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-bug-66.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-custom-primary.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-has-many-reduction.gql +1 -0
- package/tests/cases/integration/graphQlSchema/schema-new-builder.gql +1 -0
- package/tests/src/test.ts +3 -3
- package/dist/src/introspection/content-schema.graphql.d.ts +0 -4
- package/dist/src/introspection/content-schema.graphql.d.ts.map +0 -1
- package/dist/src/introspection/content-schema.graphql.js +0 -113
- package/dist/src/introspection/content-schema.graphql.js.map +0 -1
- package/src/introspection/content-schema.graphql.ts +0 -113
package/graphql.codegen.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/engine-content-api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0-alpha.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"typings": "dist/src/index.d.ts",
|
|
@@ -13,20 +13,19 @@
|
|
|
13
13
|
"test": "vitest --dir ./tests/cases --no-threads"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@contember/database": "1.
|
|
17
|
-
"@contember/dic": "1.
|
|
18
|
-
"@contember/graphql-utils": "1.
|
|
19
|
-
"@contember/logger": "1.
|
|
20
|
-
"@contember/schema": "1.
|
|
21
|
-
"@contember/schema-definition": "1.
|
|
22
|
-
"@contember/schema-utils": "1.
|
|
23
|
-
"fast-deep-equal": "^3.1.3"
|
|
24
|
-
"graphql-tag": "^2.12.5"
|
|
16
|
+
"@contember/database": "1.4.0-alpha.2",
|
|
17
|
+
"@contember/dic": "1.4.0-alpha.2",
|
|
18
|
+
"@contember/graphql-utils": "1.4.0-alpha.2",
|
|
19
|
+
"@contember/logger": "1.4.0-alpha.2",
|
|
20
|
+
"@contember/schema": "1.4.0-alpha.2",
|
|
21
|
+
"@contember/schema-definition": "1.4.0-alpha.2",
|
|
22
|
+
"@contember/schema-utils": "1.4.0-alpha.2",
|
|
23
|
+
"fast-deep-equal": "^3.1.3"
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
|
-
"@contember/database-tester": "1.
|
|
28
|
-
"@contember/engine-api-tester": "1.
|
|
29
|
-
"@contember/schema-definition": "1.
|
|
26
|
+
"@contember/database-tester": "1.4.0-alpha.2",
|
|
27
|
+
"@contember/engine-api-tester": "1.4.0-alpha.2",
|
|
28
|
+
"@contember/schema-definition": "1.4.0-alpha.2",
|
|
30
29
|
"@graphql-codegen/cli": "^2.6.2",
|
|
31
30
|
"@graphql-codegen/typescript": "^2.5.1",
|
|
32
31
|
"@graphql-codegen/typescript-operations": "^2.4.2",
|
|
@@ -27,8 +27,8 @@ import {
|
|
|
27
27
|
} from './mapper'
|
|
28
28
|
import { Builder } from '@contember/dic'
|
|
29
29
|
import { Acl, Model, Schema } from '@contember/schema'
|
|
30
|
-
import { Client, SelectBuilder as DbSelectBuilder } from '@contember/database'
|
|
31
|
-
import { Providers
|
|
30
|
+
import { Client, DatabaseMetadata, SelectBuilder as DbSelectBuilder } from '@contember/database'
|
|
31
|
+
import { Providers } from '@contember/schema-utils'
|
|
32
32
|
import { PaginatedHasManyExecutionHandler } from './extensions/paginatedHasMany/PaginatedHasManyExecutionHandler'
|
|
33
33
|
import { PaginatedHasManyFieldProvider } from './extensions/paginatedHasMany/PaginatedHasManyFieldProvider'
|
|
34
34
|
import { WhereOptimizer } from './mapper/select/optimizer/WhereOptimizer'
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
|
|
45
45
|
export type ExecutionContainerArgs = {
|
|
46
46
|
schema: Schema & { id: number }
|
|
47
|
-
schemaDatabaseMetadata:
|
|
47
|
+
schemaDatabaseMetadata: DatabaseMetadata
|
|
48
48
|
db: Client
|
|
49
49
|
identityId: string
|
|
50
50
|
identityVariables: Acl.VariablesMap
|
|
@@ -107,13 +107,20 @@ export class ExecutionContainerFactory {
|
|
|
107
107
|
.addService('whereOptimized', ({ schema }) =>
|
|
108
108
|
new WhereOptimizer(schema.model, new ConditionOptimizer()))
|
|
109
109
|
.addService('whereBuilder', ({ joinBuilder, conditionBuilder, pathFactory, whereOptimized, schema }) =>
|
|
110
|
-
new WhereBuilder(
|
|
110
|
+
new WhereBuilder(
|
|
111
|
+
schema.model,
|
|
112
|
+
joinBuilder,
|
|
113
|
+
conditionBuilder,
|
|
114
|
+
pathFactory,
|
|
115
|
+
whereOptimized,
|
|
116
|
+
(schema.settings.content?.useExistsInHasManyFilter ?? schema.settings.useExistsInHasManyFilter) === true,
|
|
117
|
+
))
|
|
111
118
|
.addService('orderByBuilder', ({ joinBuilder, schema }) =>
|
|
112
119
|
new OrderByBuilder(schema.model, joinBuilder))
|
|
113
120
|
.addService('relationFetcher', ({ whereBuilder, orderByBuilder, predicatesInjector, pathFactory }) =>
|
|
114
121
|
new RelationFetcher(whereBuilder, orderByBuilder, predicatesInjector, pathFactory))
|
|
115
|
-
.addService('fieldsVisitorFactory', ({ relationFetcher, predicateFactory,
|
|
116
|
-
new FieldsVisitorFactory(
|
|
122
|
+
.addService('fieldsVisitorFactory', ({ relationFetcher, predicateFactory, schema }) =>
|
|
123
|
+
new FieldsVisitorFactory(relationFetcher, predicateFactory, schema.settings.content ?? {}))
|
|
117
124
|
.addService('metaHandler', ({ whereBuilder, predicateFactory }) =>
|
|
118
125
|
new MetaHandler(whereBuilder, predicateFactory))
|
|
119
126
|
.addService('uniqueWhereExpander', ({ schema }) =>
|
|
@@ -2,7 +2,7 @@ import { GraphQLFieldConfig } from 'graphql'
|
|
|
2
2
|
import { Model } from '@contember/schema'
|
|
3
3
|
|
|
4
4
|
export interface EntityFieldsProvider<ExtensionArg extends object = {}> {
|
|
5
|
-
getFields(entity: Model.Entity, accessibleFields:
|
|
5
|
+
getFields(entity: Model.Entity, accessibleFields: Model.AnyField[]): FieldMap<ExtensionArg>
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export type FieldMap<ExtensionArg extends object> = {
|
|
@@ -11,11 +11,18 @@ export class HasManyToHasOneReducer implements EntityFieldsProvider<HasManyToHas
|
|
|
11
11
|
private readonly visitor: HasManyToHasOneRelationReducerFieldVisitor,
|
|
12
12
|
) {}
|
|
13
13
|
|
|
14
|
-
getFields(entity: Model.Entity,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
|
|
14
|
+
getFields(entity: Model.Entity, accessibleFields: Model.AnyField[]): FieldMap<HasManyToHasOneReducerExtension> {
|
|
15
|
+
const fieldMap: FieldMap<HasManyToHasOneReducerExtension> = {}
|
|
16
|
+
for (const field of accessibleFields) {
|
|
17
|
+
if (field.type !== Model.RelationType.OneHasMany) {
|
|
18
|
+
continue
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (const [name, resultField] of acceptFieldVisitor(this.schema, entity, field, this.visitor)) {
|
|
22
|
+
fieldMap[name] = resultField
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return fieldMap
|
|
19
26
|
}
|
|
20
27
|
}
|
|
21
28
|
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { GraphQLInputObjectType, GraphQLNonNull } from 'graphql'
|
|
2
2
|
import { Acl, Model } from '@contember/schema'
|
|
3
|
-
import {
|
|
4
|
-
aliasAwareResolver,
|
|
5
|
-
EntityTypeProvider,
|
|
6
|
-
FieldAccessVisitor,
|
|
7
|
-
GqlTypeName,
|
|
8
|
-
WhereTypeProvider,
|
|
9
|
-
} from '../../schema'
|
|
3
|
+
import { aliasAwareResolver, EntityTypeProvider, FieldAccessVisitor, GqlTypeName, WhereTypeProvider } from '../../schema'
|
|
10
4
|
import { acceptFieldVisitor } from '@contember/schema-utils'
|
|
11
5
|
import { Authorizator } from '../../acl'
|
|
12
6
|
import { getFieldsForUniqueWhere } from '../../utils'
|
|
13
|
-
import { HasManyToHasOneReducerExtension } from './HasManyToHasOneReducer'
|
|
14
|
-
import {
|
|
7
|
+
import { HasManyToHasOneReducer, HasManyToHasOneReducerExtension } from './HasManyToHasOneReducer'
|
|
8
|
+
import { GraphQLFieldConfig } from 'graphql'
|
|
9
|
+
|
|
10
|
+
type Result = [
|
|
11
|
+
string,
|
|
12
|
+
GraphQLFieldConfig<any, any> & {
|
|
13
|
+
extensions: HasManyToHasOneReducerExtension
|
|
14
|
+
}
|
|
15
|
+
]
|
|
15
16
|
|
|
16
17
|
export class HasManyToHasOneRelationReducerFieldVisitor implements
|
|
17
|
-
Model.ColumnVisitor<
|
|
18
|
-
Model.RelationByTypeVisitor<
|
|
18
|
+
Model.ColumnVisitor<Result[]>,
|
|
19
|
+
Model.RelationByTypeVisitor<Result[]> {
|
|
19
20
|
|
|
20
21
|
constructor(
|
|
21
22
|
private readonly schema: Model.Schema,
|
|
@@ -25,32 +26,32 @@ export class HasManyToHasOneRelationReducerFieldVisitor implements
|
|
|
25
26
|
) {}
|
|
26
27
|
|
|
27
28
|
public visitColumn() {
|
|
28
|
-
return
|
|
29
|
+
return []
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
public visitOneHasOneOwning() {
|
|
32
|
-
return
|
|
33
|
+
return []
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
public visitOneHasOneInverse() {
|
|
36
|
-
return
|
|
37
|
+
return []
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
public visitManyHasOne() {
|
|
40
|
-
return
|
|
41
|
+
return []
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
public visitManyHasManyInverse() {
|
|
44
|
-
return
|
|
45
|
+
return []
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
public visitManyHasManyOwning() {
|
|
48
|
-
return
|
|
49
|
+
return []
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
public visitOneHasMany({ entity, targetEntity, targetRelation, relation }: Model.OneHasManyContext) {
|
|
52
53
|
if (!targetRelation) {
|
|
53
|
-
return
|
|
54
|
+
return []
|
|
54
55
|
}
|
|
55
56
|
const uniqueConstraints = getFieldsForUniqueWhere(this.schema, targetEntity)
|
|
56
57
|
const composedUnique = uniqueConstraints
|
|
@@ -63,6 +64,8 @@ export class HasManyToHasOneRelationReducerFieldVisitor implements
|
|
|
63
64
|
.map(fields => fields[0])
|
|
64
65
|
.filter(it => it !== targetRelation.name)
|
|
65
66
|
|
|
67
|
+
|
|
68
|
+
const existing = new Set<string>()
|
|
66
69
|
return [...composedUnique, ...singleUnique]
|
|
67
70
|
.filter(field =>
|
|
68
71
|
acceptFieldVisitor(
|
|
@@ -72,7 +75,11 @@ export class HasManyToHasOneRelationReducerFieldVisitor implements
|
|
|
72
75
|
new FieldAccessVisitor(Acl.Operation.read, this.authorizator),
|
|
73
76
|
),
|
|
74
77
|
)
|
|
75
|
-
.
|
|
78
|
+
.map<Result | null>(fieldName => {
|
|
79
|
+
if (existing.has(fieldName)) {
|
|
80
|
+
return null
|
|
81
|
+
}
|
|
82
|
+
existing.add(fieldName)
|
|
76
83
|
const graphQlName = relation.name + GqlTypeName`By${fieldName}`
|
|
77
84
|
const uniqueWhere: GraphQLInputObjectType = new GraphQLInputObjectType({
|
|
78
85
|
//todo this can be simplified to ${targetEntity.name}By${fieldName}, but singleton must be used
|
|
@@ -84,12 +91,13 @@ export class HasManyToHasOneRelationReducerFieldVisitor implements
|
|
|
84
91
|
|
|
85
92
|
const entityType = this.entityTypeProvider.getEntity(targetEntity.name)
|
|
86
93
|
|
|
87
|
-
return
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
return [
|
|
95
|
+
graphQlName,
|
|
96
|
+
{
|
|
90
97
|
type: entityType,
|
|
91
98
|
extensions: {
|
|
92
99
|
relationName: relation.name,
|
|
100
|
+
extensionKey: HasManyToHasOneReducer.extensionName,
|
|
93
101
|
},
|
|
94
102
|
args: {
|
|
95
103
|
by: { type: new GraphQLNonNull(uniqueWhere) },
|
|
@@ -97,7 +105,8 @@ export class HasManyToHasOneRelationReducerFieldVisitor implements
|
|
|
97
105
|
},
|
|
98
106
|
resolve: aliasAwareResolver,
|
|
99
107
|
},
|
|
100
|
-
|
|
101
|
-
}
|
|
108
|
+
]
|
|
109
|
+
})
|
|
110
|
+
.filter((it): it is Result => it !== null)
|
|
102
111
|
}
|
|
103
112
|
}
|
|
@@ -8,11 +8,14 @@ export class PaginatedHasManyFieldProvider implements EntityFieldsProvider<Pagin
|
|
|
8
8
|
|
|
9
9
|
constructor(private readonly schema: Model.Schema, private readonly visitor: PaginatedHasManyFieldProviderVisitor) {}
|
|
10
10
|
|
|
11
|
-
getFields(entity: Model.Entity,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
{
|
|
15
|
-
|
|
11
|
+
getFields(entity: Model.Entity, accessibleFields: Model.AnyField[]): FieldMap<PaginatedHasManyFieldProviderExtension> {
|
|
12
|
+
const fields: FieldMap<PaginatedHasManyFieldProviderExtension> = {}
|
|
13
|
+
for (const field of accessibleFields) {
|
|
14
|
+
for (const [name, fieldConfig] of acceptFieldVisitor(this.schema, entity, field, this.visitor)) {
|
|
15
|
+
fields[name] = fieldConfig
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return fields
|
|
16
19
|
}
|
|
17
20
|
}
|
|
18
21
|
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { Model } from '@contember/schema'
|
|
2
|
-
import {
|
|
3
|
-
import { PaginatedHasManyFieldProviderExtension } from './PaginatedHasManyFieldProvider'
|
|
2
|
+
import { PaginatedHasManyFieldProvider, PaginatedHasManyFieldProviderExtension } from './PaginatedHasManyFieldProvider'
|
|
4
3
|
import { capitalizeFirstLetter } from '../../utils'
|
|
5
4
|
import { PaginatedFieldConfigFactory } from '../../schema/PaginatedFieldConfigFactory'
|
|
6
5
|
import { aliasAwareResolver } from '../../schema'
|
|
6
|
+
import { GraphQLFieldConfig } from 'graphql'
|
|
7
|
+
|
|
8
|
+
type Result = [
|
|
9
|
+
string,
|
|
10
|
+
GraphQLFieldConfig<any, any> & {
|
|
11
|
+
extensions: PaginatedHasManyFieldProviderExtension
|
|
12
|
+
}
|
|
13
|
+
]
|
|
7
14
|
|
|
8
15
|
export class PaginatedHasManyFieldProviderVisitor implements
|
|
9
|
-
Model.ColumnVisitor<
|
|
10
|
-
Model.RelationByTypeVisitor<
|
|
16
|
+
Model.ColumnVisitor<Result[]>,
|
|
17
|
+
Model.RelationByTypeVisitor<Result[]> {
|
|
11
18
|
|
|
12
19
|
constructor(private readonly paginatedFieldFactory: PaginatedFieldConfigFactory) {}
|
|
13
20
|
|
|
@@ -23,31 +30,35 @@ export class PaginatedHasManyFieldProviderVisitor implements
|
|
|
23
30
|
return this.createField(targetEntity, relation)
|
|
24
31
|
}
|
|
25
32
|
|
|
26
|
-
private createField(entity: Model.Entity, relation: Model.Relation):
|
|
27
|
-
return
|
|
28
|
-
[
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
private createField(entity: Model.Entity, relation: Model.Relation): Result[] {
|
|
34
|
+
return [
|
|
35
|
+
[
|
|
36
|
+
`paginate${capitalizeFirstLetter(relation.name)}`,
|
|
37
|
+
{
|
|
38
|
+
...this.paginatedFieldFactory.createFieldConfig(entity),
|
|
39
|
+
extensions: {
|
|
40
|
+
relationName: relation.name,
|
|
41
|
+
extensionKey: PaginatedHasManyFieldProvider.extensionName,
|
|
42
|
+
},
|
|
43
|
+
resolve: aliasAwareResolver,
|
|
32
44
|
},
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
45
|
+
],
|
|
46
|
+
]
|
|
36
47
|
}
|
|
37
48
|
|
|
38
49
|
visitColumn() {
|
|
39
|
-
return
|
|
50
|
+
return []
|
|
40
51
|
}
|
|
41
52
|
|
|
42
53
|
visitManyHasOne() {
|
|
43
|
-
return
|
|
54
|
+
return []
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
visitOneHasOneInverse() {
|
|
47
|
-
return
|
|
58
|
+
return []
|
|
48
59
|
}
|
|
49
60
|
|
|
50
61
|
visitOneHasOneOwning() {
|
|
51
|
-
return
|
|
62
|
+
return []
|
|
52
63
|
}
|
|
53
64
|
}
|
|
@@ -5,6 +5,7 @@ import { JSONType } from '@contember/graphql-utils'
|
|
|
5
5
|
import {
|
|
6
6
|
GraphQLBoolean,
|
|
7
7
|
GraphQLEnumType,
|
|
8
|
+
GraphQLFieldResolver,
|
|
8
9
|
GraphQLInt,
|
|
9
10
|
GraphQLInterfaceType,
|
|
10
11
|
GraphQLList,
|
|
@@ -176,6 +177,24 @@ const _Schema = new GraphQLObjectType({
|
|
|
176
177
|
})
|
|
177
178
|
|
|
178
179
|
|
|
180
|
+
const createSchemaConfig = (resolver?: GraphQLFieldResolver<any, any>): GraphQLSchemaConfig => {
|
|
181
|
+
return {
|
|
182
|
+
query: new GraphQLObjectType({
|
|
183
|
+
name: 'Query',
|
|
184
|
+
fields: {
|
|
185
|
+
schema: {
|
|
186
|
+
type: _Schema,
|
|
187
|
+
resolve: resolver,
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
}),
|
|
191
|
+
types: [_Column, _Relation],
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
export default new GraphQLSchema(createSchemaConfig())
|
|
197
|
+
|
|
179
198
|
export class IntrospectionSchemaDefinitionFactory {
|
|
180
199
|
constructor(private readonly introspectionSchemaFactory: IntrospectionSchemaFactory) {}
|
|
181
200
|
|
|
@@ -184,19 +203,8 @@ export class IntrospectionSchemaDefinitionFactory {
|
|
|
184
203
|
}
|
|
185
204
|
|
|
186
205
|
public createConfig(): GraphQLSchemaConfig {
|
|
187
|
-
return {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
fields: {
|
|
191
|
-
schema: {
|
|
192
|
-
type: _Schema,
|
|
193
|
-
resolve: (): ContentSchema._Schema => {
|
|
194
|
-
return this.introspectionSchemaFactory.create()
|
|
195
|
-
},
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
}),
|
|
199
|
-
types: [_Column, _Relation],
|
|
200
|
-
}
|
|
206
|
+
return createSchemaConfig((): ContentSchema._Schema => {
|
|
207
|
+
return this.introspectionSchemaFactory.create()
|
|
208
|
+
})
|
|
201
209
|
}
|
|
202
210
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { default as ContentSchema } from './content-schema.graphql'
|
|
2
1
|
export * as ContentSchemaTypes from './content-schema.types'
|
|
3
|
-
export
|
|
2
|
+
export { IntrospectionSchemaDefinitionFactory, default as ContentSchema } from './IntrospectionSchemaDefinitionFactory'
|
|
4
3
|
export * from './IntrospectionSchemaFactory'
|
package/src/mapper/ErrorUtils.ts
CHANGED
|
@@ -11,8 +11,9 @@ import {
|
|
|
11
11
|
import * as Database from '@contember/database'
|
|
12
12
|
import { UniqueWhereError } from '../inputProcessing'
|
|
13
13
|
import { Model } from '@contember/schema'
|
|
14
|
-
import { acceptFieldVisitor,
|
|
14
|
+
import { acceptFieldVisitor, tryGetColumnName } from '@contember/schema-utils'
|
|
15
15
|
import { logger } from '@contember/logger'
|
|
16
|
+
import { DatabaseMetadata } from '@contember/database'
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
type UniqueConstraintResult = {
|
|
@@ -22,8 +23,8 @@ type UniqueConstraintResult = {
|
|
|
22
23
|
|
|
23
24
|
const getEntityByTableName = (model: Model.Schema, tableName: string) => Object.values(model.entities).find(it => it.tableName === tableName)
|
|
24
25
|
|
|
25
|
-
const findUniqueConstraint = (model: Model.Schema, databaseMetadata:
|
|
26
|
-
const constraint = databaseMetadata.
|
|
26
|
+
const findUniqueConstraint = (model: Model.Schema, databaseMetadata: DatabaseMetadata, tableName: string, constraintName: string): UniqueConstraintResult | null => {
|
|
27
|
+
const constraint = databaseMetadata.uniqueConstraints.filter({ tableName, constraintName }).first()
|
|
27
28
|
if (!constraint) {
|
|
28
29
|
return null
|
|
29
30
|
}
|
|
@@ -50,8 +51,8 @@ type RelationInfo = {
|
|
|
50
51
|
targetEntity: Model.Entity
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
const findForeignConstraint = (model: Model.Schema, databaseMetadata:
|
|
54
|
-
const constraint = databaseMetadata.
|
|
54
|
+
const findForeignConstraint = (model: Model.Schema, databaseMetadata: DatabaseMetadata, tableName: string, constraintName: string): RelationInfo | null => {
|
|
55
|
+
const constraint = databaseMetadata.foreignKeys.filter({ fromTable: tableName, constraintName }).first()
|
|
55
56
|
if (!constraint) {
|
|
56
57
|
return null
|
|
57
58
|
}
|
|
@@ -88,7 +89,7 @@ const findForeignConstraint = (model: Model.Schema, databaseMetadata: SchemaData
|
|
|
88
89
|
|
|
89
90
|
export const convertError = (
|
|
90
91
|
schema: Model.Schema,
|
|
91
|
-
databaseMetadata:
|
|
92
|
+
databaseMetadata: DatabaseMetadata,
|
|
92
93
|
e: any,
|
|
93
94
|
): MutationResult => {
|
|
94
95
|
|
|
@@ -140,7 +141,7 @@ export const convertError = (
|
|
|
140
141
|
throw e
|
|
141
142
|
}
|
|
142
143
|
|
|
143
|
-
export const tryMutation = async (schema: Model.Schema, databaseMetadata:
|
|
144
|
+
export const tryMutation = async (schema: Model.Schema, databaseMetadata: DatabaseMetadata, cb: () => Promise<MutationResultList>): Promise<MutationResultList> => {
|
|
144
145
|
try {
|
|
145
146
|
return await cb()
|
|
146
147
|
} catch (e) {
|
package/src/mapper/Mapper.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Input, Model } from '@contember/schema'
|
|
2
|
-
import { acceptFieldVisitor, getColumnName
|
|
2
|
+
import { acceptFieldVisitor, getColumnName } from '@contember/schema-utils'
|
|
3
3
|
import {
|
|
4
4
|
OrderByHelper,
|
|
5
5
|
PathFactory,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
SelectResultObject,
|
|
11
11
|
WhereBuilder,
|
|
12
12
|
} from './select'
|
|
13
|
-
import { Client, Connection, ConstraintHelper, SelectBuilder } from '@contember/database'
|
|
13
|
+
import { Client, Connection, ConstraintHelper, DatabaseMetadata, SelectBuilder } from '@contember/database'
|
|
14
14
|
import { PredicatesInjector } from '../acl'
|
|
15
15
|
import { JunctionTableManager } from './JunctionTableManager'
|
|
16
16
|
import { DeletedEntitiesStorage, DeleteExecutor } from './delete'
|
|
@@ -38,7 +38,7 @@ export class Mapper<ConnectionType extends Connection.ConnectionLike = Connectio
|
|
|
38
38
|
public readonly identityId: string,
|
|
39
39
|
public readonly transactionId: string,
|
|
40
40
|
private readonly schema: Model.Schema,
|
|
41
|
-
private readonly schemaDatabaseMetadata:
|
|
41
|
+
private readonly schemaDatabaseMetadata: DatabaseMetadata,
|
|
42
42
|
private readonly predicatesInjector: PredicatesInjector,
|
|
43
43
|
private readonly selectBuilderFactory: SelectBuilderFactory,
|
|
44
44
|
private readonly uniqueWhereExpander: UniqueWhereExpander,
|
|
@@ -49,7 +49,7 @@ export class Mapper<ConnectionType extends Connection.ConnectionLike = Connectio
|
|
|
49
49
|
private readonly inserter: Inserter,
|
|
50
50
|
private readonly pathFactory: PathFactory,
|
|
51
51
|
) {
|
|
52
|
-
this.constraintHelper = new ConstraintHelper(db)
|
|
52
|
+
this.constraintHelper = new ConstraintHelper(db, this.schemaDatabaseMetadata)
|
|
53
53
|
this.eventManager = new EventManager(this)
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -6,9 +6,9 @@ import { DeleteExecutor } from './delete'
|
|
|
6
6
|
import { Updater } from './update'
|
|
7
7
|
import { Inserter } from './insert'
|
|
8
8
|
import { Model } from '@contember/schema'
|
|
9
|
-
import { Client, Connection } from '@contember/database'
|
|
9
|
+
import { Client, Connection, DatabaseMetadata } from '@contember/database'
|
|
10
10
|
import { Mapper } from './Mapper'
|
|
11
|
-
import { Providers
|
|
11
|
+
import { Providers } from '@contember/schema-utils'
|
|
12
12
|
|
|
13
13
|
export type MapperFactoryHook = (mapper: Mapper) => void
|
|
14
14
|
|
|
@@ -20,7 +20,7 @@ export class MapperFactory {
|
|
|
20
20
|
private readonly db: Client,
|
|
21
21
|
private readonly identityId: string,
|
|
22
22
|
private readonly schema: Model.Schema,
|
|
23
|
-
private readonly schemaDatabaseMetadata:
|
|
23
|
+
private readonly schemaDatabaseMetadata: DatabaseMetadata,
|
|
24
24
|
private readonly predicatesInjector: PredicatesInjector,
|
|
25
25
|
private readonly selectBuilderFactory: SelectBuilderFactory,
|
|
26
26
|
private readonly uniqueWhereExpander: UniqueWhereExpander,
|
package/src/mapper/Result.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Input, Model, Value } from '@contember/schema'
|
|
2
2
|
import { convertError } from './ErrorUtils'
|
|
3
3
|
import { getFulfilledValues, getRejections } from '../utils'
|
|
4
|
-
import { SerializationFailureError } from '@contember/database'
|
|
4
|
+
import { DatabaseMetadata, SerializationFailureError } from '@contember/database'
|
|
5
5
|
import { logger } from '@contember/logger'
|
|
6
|
-
import { SchemaDatabaseMetadata } from '@contember/schema-utils'
|
|
7
6
|
|
|
8
7
|
export enum MutationResultType {
|
|
9
8
|
ok = 'ok',
|
|
@@ -213,7 +212,7 @@ export type ResultListNotFlatten = MutationResultList | MutationResultList[]
|
|
|
213
212
|
|
|
214
213
|
export const collectResults = async (
|
|
215
214
|
schema: Model.Schema,
|
|
216
|
-
schemaDatabaseMetadata:
|
|
215
|
+
schemaDatabaseMetadata: DatabaseMetadata,
|
|
217
216
|
mainPromise: Promise<ResultListNotFlatten | undefined> | undefined,
|
|
218
217
|
otherPromises: (Promise<ResultListNotFlatten | undefined> | undefined)[],
|
|
219
218
|
): Promise<MutationResultList> => {
|
|
@@ -252,7 +252,7 @@ export class DeleteExecutor {
|
|
|
252
252
|
relation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,
|
|
253
253
|
values: Input.PrimaryValue[],
|
|
254
254
|
): Promise<void> {
|
|
255
|
-
if (mapper.constraintHelper.
|
|
255
|
+
if (mapper.constraintHelper.areConstraintsDeferred('foreignKey')) {
|
|
256
256
|
return
|
|
257
257
|
}
|
|
258
258
|
const qb = this.createFetchByIdQueryBuilder(entity, relation, values)
|
|
@@ -11,16 +11,17 @@ import { CreateInputVisitor } from '../../inputProcessing'
|
|
|
11
11
|
import { SqlCreateInputProcessor } from './SqlCreateInputProcessor'
|
|
12
12
|
import { Mapper } from '../Mapper'
|
|
13
13
|
import { Input, Model, Value } from '@contember/schema'
|
|
14
|
-
import { acceptEveryFieldVisitor, Providers
|
|
14
|
+
import { acceptEveryFieldVisitor, Providers } from '@contember/schema-utils'
|
|
15
15
|
import { InsertBuilderFactory } from './InsertBuilderFactory'
|
|
16
16
|
import { InsertBuilder } from './InsertBuilder'
|
|
17
17
|
import { tryMutation } from '../ErrorUtils'
|
|
18
18
|
import { rowDataToFieldValues } from '../ColumnValue'
|
|
19
|
+
import { DatabaseMetadata } from '@contember/database'
|
|
19
20
|
|
|
20
21
|
export class Inserter {
|
|
21
22
|
constructor(
|
|
22
23
|
private readonly schema: Model.Schema,
|
|
23
|
-
private readonly schemaDatabaseMetadata:
|
|
24
|
+
private readonly schemaDatabaseMetadata: DatabaseMetadata,
|
|
24
25
|
private readonly insertBuilderFactory: InsertBuilderFactory,
|
|
25
26
|
private readonly providers: Providers,
|
|
26
27
|
) {}
|
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import { Acl, Input, Model } from '@contember/schema'
|
|
1
|
+
import { Acl, Input, Model, Settings } from '@contember/schema'
|
|
2
2
|
import { Mapper } from '../../Mapper'
|
|
3
3
|
import { RelationFetcher } from '../RelationFetcher'
|
|
4
4
|
import { SelectExecutionHandlerContext } from '../SelectExecutionHandler'
|
|
5
5
|
import { PredicateFactory } from '../../../acl'
|
|
6
|
-
import {
|
|
6
|
+
import { Literal, wrapIdentifier } from '@contember/database'
|
|
7
7
|
|
|
8
8
|
export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.ColumnVisitor<void> {
|
|
9
9
|
constructor(
|
|
10
|
-
private readonly schema: Model.Schema,
|
|
11
10
|
private readonly relationFetcher: RelationFetcher,
|
|
12
11
|
private readonly predicateFactory: PredicateFactory,
|
|
13
|
-
private readonly whereBuilder: WhereBuilder,
|
|
14
12
|
private readonly mapper: Mapper,
|
|
15
13
|
private readonly executionContext: SelectExecutionHandlerContext,
|
|
16
14
|
private readonly relationPath: Model.AnyRelationContext[],
|
|
15
|
+
private readonly settings: Settings.ContentSettings,
|
|
17
16
|
) {}
|
|
18
17
|
|
|
19
18
|
visitColumn({ entity, column }: Model.ColumnContext): void {
|
|
@@ -21,8 +20,13 @@ export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.C
|
|
|
21
20
|
const tableAlias = columnPath.back().alias
|
|
22
21
|
const columnAlias = columnPath.alias
|
|
23
22
|
|
|
23
|
+
let selectFrom = wrapIdentifier(tableAlias) + '.' + wrapIdentifier(column.columnName)
|
|
24
|
+
if (column.type === Model.ColumnType.Date && this.settings.shortDateResponse) {
|
|
25
|
+
selectFrom += '::text'
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
this.executionContext.addColumn({
|
|
25
|
-
query: qb => qb.select(
|
|
29
|
+
query: qb => qb.select(new Literal(selectFrom), columnAlias),
|
|
26
30
|
predicate: this.getRequiredPredicate(entity, column),
|
|
27
31
|
})
|
|
28
32
|
}
|
|
@@ -1,28 +1,25 @@
|
|
|
1
1
|
import { FieldsVisitor } from './FieldsVisitor'
|
|
2
2
|
import { RelationFetcher } from '../RelationFetcher'
|
|
3
|
-
import { Model } from '@contember/schema'
|
|
4
3
|
import { Mapper } from '../../Mapper'
|
|
5
4
|
import { SelectExecutionHandlerContext } from '../SelectExecutionHandler'
|
|
6
5
|
import { PredicateFactory } from '../../../acl'
|
|
7
|
-
import {
|
|
6
|
+
import { Settings } from '@contember/schema'
|
|
8
7
|
|
|
9
8
|
export class FieldsVisitorFactory {
|
|
10
9
|
constructor(
|
|
11
|
-
private readonly schema: Model.Schema,
|
|
12
10
|
private readonly relationFetcher: RelationFetcher,
|
|
13
11
|
private readonly predicateFactory: PredicateFactory,
|
|
14
|
-
private readonly
|
|
12
|
+
private readonly settings: Settings.ContentSettings,
|
|
15
13
|
) {}
|
|
16
14
|
|
|
17
15
|
create(mapper: Mapper, context: SelectExecutionHandlerContext): FieldsVisitor {
|
|
18
16
|
return new FieldsVisitor(
|
|
19
|
-
this.schema,
|
|
20
17
|
this.relationFetcher,
|
|
21
18
|
this.predicateFactory,
|
|
22
|
-
this.whereBuilder,
|
|
23
19
|
mapper,
|
|
24
20
|
context,
|
|
25
21
|
context.relationPath,
|
|
22
|
+
this.settings,
|
|
26
23
|
)
|
|
27
24
|
}
|
|
28
25
|
}
|
|
@@ -4,7 +4,7 @@ import { Input, Model } from '@contember/schema'
|
|
|
4
4
|
import { PredicateFactory } from '../../acl'
|
|
5
5
|
import { UpdateBuilderFactory } from './UpdateBuilderFactory'
|
|
6
6
|
import { Mapper } from '../Mapper'
|
|
7
|
-
import { acceptEveryFieldVisitor
|
|
7
|
+
import { acceptEveryFieldVisitor } from '@contember/schema-utils'
|
|
8
8
|
import {
|
|
9
9
|
collectResults,
|
|
10
10
|
MutationNoResultError,
|
|
@@ -17,11 +17,12 @@ import {
|
|
|
17
17
|
} from '../Result'
|
|
18
18
|
import { UpdateBuilder } from './UpdateBuilder'
|
|
19
19
|
import { rowDataToFieldValues } from '../ColumnValue'
|
|
20
|
+
import { DatabaseMetadata } from '@contember/database'
|
|
20
21
|
|
|
21
22
|
export class Updater {
|
|
22
23
|
constructor(
|
|
23
24
|
private readonly schema: Model.Schema,
|
|
24
|
-
private readonly schemaDatabaseMetadata:
|
|
25
|
+
private readonly schemaDatabaseMetadata: DatabaseMetadata,
|
|
25
26
|
private readonly predicateFactory: PredicateFactory,
|
|
26
27
|
private readonly updateBuilderFactory: UpdateBuilderFactory,
|
|
27
28
|
) {}
|