@commitspark/graphql-api 0.7.0
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/.eslintrc.js +24 -0
- package/.prettierrc +6 -0
- package/CHANGELOG.md +83 -0
- package/LICENSE +15 -0
- package/README.md +223 -0
- package/dist/app/api.service.d.ts +31 -0
- package/dist/app/api.service.js +60 -0
- package/dist/app/api.service.js.map +1 -0
- package/dist/container.d.ts +2 -0
- package/dist/container.js +44 -0
- package/dist/container.js.map +1 -0
- package/dist/graphql/apollo-config-factory.service.d.ts +8 -0
- package/dist/graphql/apollo-config-factory.service.js +20 -0
- package/dist/graphql/apollo-config-factory.service.js.map +1 -0
- package/dist/graphql/input-type-generator.service.d.ts +12 -0
- package/dist/graphql/input-type-generator.service.js +86 -0
- package/dist/graphql/input-type-generator.service.js.map +1 -0
- package/dist/graphql/queries-mutations-generator.service.d.ts +39 -0
- package/dist/graphql/queries-mutations-generator.service.js +82 -0
- package/dist/graphql/queries-mutations-generator.service.js.map +1 -0
- package/dist/graphql/resolver-generators/entry-reference-resolver.generator.d.ts +12 -0
- package/dist/graphql/resolver-generators/entry-reference-resolver.generator.js +29 -0
- package/dist/graphql/resolver-generators/entry-reference-resolver.generator.js.map +1 -0
- package/dist/graphql/resolver-generators/mutation-create-resolver-generator.d.ts +8 -0
- package/dist/graphql/resolver-generators/mutation-create-resolver-generator.js +17 -0
- package/dist/graphql/resolver-generators/mutation-create-resolver-generator.js.map +1 -0
- package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.d.ts +8 -0
- package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.js +19 -0
- package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.js.map +1 -0
- package/dist/graphql/resolver-generators/mutation-update.resolver-generator.d.ts +8 -0
- package/dist/graphql/resolver-generators/mutation-update.resolver-generator.js +17 -0
- package/dist/graphql/resolver-generators/mutation-update.resolver-generator.js.map +1 -0
- package/dist/graphql/resolver-generators/query-all-resolver-generator.d.ts +8 -0
- package/dist/graphql/resolver-generators/query-all-resolver-generator.js +15 -0
- package/dist/graphql/resolver-generators/query-all-resolver-generator.js.map +1 -0
- package/dist/graphql/resolver-generators/query-by-id-resolver-generator.d.ts +8 -0
- package/dist/graphql/resolver-generators/query-by-id-resolver-generator.js +15 -0
- package/dist/graphql/resolver-generators/query-by-id-resolver-generator.js.map +1 -0
- package/dist/graphql/resolver-generators/query-count-all-resolver-generator.d.ts +9 -0
- package/dist/graphql/resolver-generators/query-count-all-resolver-generator.js +17 -0
- package/dist/graphql/resolver-generators/query-count-all-resolver-generator.js.map +1 -0
- package/dist/graphql/resolver-generators/query-type-by-id-resolver-generator.d.ts +8 -0
- package/dist/graphql/resolver-generators/query-type-by-id-resolver-generator.js +15 -0
- package/dist/graphql/resolver-generators/query-type-by-id-resolver-generator.js.map +1 -0
- package/dist/graphql/resolver-generators/union-type-resolver-generator.d.ts +10 -0
- package/dist/graphql/resolver-generators/union-type-resolver-generator.js +21 -0
- package/dist/graphql/resolver-generators/union-type-resolver-generator.js.map +1 -0
- package/dist/graphql/resolver-generators/union-value-resolver-generator.d.ts +13 -0
- package/dist/graphql/resolver-generators/union-value-resolver-generator.js +80 -0
- package/dist/graphql/resolver-generators/union-value-resolver-generator.js.map +1 -0
- package/dist/graphql/schema-analyzer.service.d.ts +19 -0
- package/dist/graphql/schema-analyzer.service.js +52 -0
- package/dist/graphql/schema-analyzer.service.js.map +1 -0
- package/dist/graphql/schema-generator.service.d.ts +22 -0
- package/dist/graphql/schema-generator.service.js +99 -0
- package/dist/graphql/schema-generator.service.js.map +1 -0
- package/dist/graphql/schema-root-type-generator.service.d.ts +4 -0
- package/dist/graphql/schema-root-type-generator.service.js +37 -0
- package/dist/graphql/schema-root-type-generator.service.js.map +1 -0
- package/dist/graphql/schema-utils/entry-reference-util.d.ts +7 -0
- package/dist/graphql/schema-utils/entry-reference-util.js +42 -0
- package/dist/graphql/schema-utils/entry-reference-util.js.map +1 -0
- package/dist/graphql/schema-validator.d.ts +5 -0
- package/dist/graphql/schema-validator.js +33 -0
- package/dist/graphql/schema-validator.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/persistence/persistence.service.d.ts +17 -0
- package/dist/persistence/persistence.service.js +110 -0
- package/dist/persistence/persistence.service.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +34 -0
- package/src/app/api.service.ts +113 -0
- package/src/container.ts +92 -0
- package/src/graphql/apollo-config-factory.service.ts +21 -0
- package/src/graphql/input-type-generator.service.ts +114 -0
- package/src/graphql/queries-mutations-generator.service.ts +155 -0
- package/src/graphql/resolver-generators/entry-reference-resolver.generator.ts +71 -0
- package/src/graphql/resolver-generators/mutation-create-resolver-generator.ts +38 -0
- package/src/graphql/resolver-generators/mutation-delete-resolver-generator.ts +35 -0
- package/src/graphql/resolver-generators/mutation-update.resolver-generator.ts +39 -0
- package/src/graphql/resolver-generators/query-all-resolver-generator.ts +27 -0
- package/src/graphql/resolver-generators/query-by-id-resolver-generator.ts +23 -0
- package/src/graphql/resolver-generators/query-count-all-resolver-generator.ts +29 -0
- package/src/graphql/resolver-generators/query-type-by-id-resolver-generator.ts +27 -0
- package/src/graphql/resolver-generators/union-type-resolver-generator.ts +40 -0
- package/src/graphql/resolver-generators/union-value-resolver-generator.ts +116 -0
- package/src/graphql/schema-analyzer.service.ts +70 -0
- package/src/graphql/schema-generator.service.ts +190 -0
- package/src/graphql/schema-root-type-generator.service.ts +42 -0
- package/src/graphql/schema-utils/entry-reference-util.ts +49 -0
- package/src/graphql/schema-validator.ts +41 -0
- package/src/index.ts +8 -0
- package/src/persistence/persistence.service.ts +183 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.json +18 -0
- package/webpack.config.js +25 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Entry } from '../persistence/persistence.service'
|
|
2
|
+
import { ApolloContext } from '../app/api.service'
|
|
3
|
+
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
4
|
+
import { GraphQLObjectType } from 'graphql/type'
|
|
5
|
+
import { QueryAllResolverGenerator } from './resolver-generators/query-all-resolver-generator'
|
|
6
|
+
import { QueryByIdResolverGenerator } from './resolver-generators/query-by-id-resolver-generator'
|
|
7
|
+
import { MutationCreateResolverGenerator } from './resolver-generators/mutation-create-resolver-generator'
|
|
8
|
+
import { MutationUpdateResolverGenerator } from './resolver-generators/mutation-update.resolver-generator'
|
|
9
|
+
import { MutationDeleteResolverGenerator } from './resolver-generators/mutation-delete-resolver-generator'
|
|
10
|
+
import { QueryCountAllResolverGenerator } from './resolver-generators/query-count-all-resolver-generator'
|
|
11
|
+
import { QueryTypeByIdResolverGenerator } from './resolver-generators/query-type-by-id-resolver-generator'
|
|
12
|
+
|
|
13
|
+
export class QueriesMutationsGeneratorService {
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly queryAllResolverGenerator: QueryAllResolverGenerator,
|
|
16
|
+
private readonly queryByIdResolverGenerator: QueryByIdResolverGenerator,
|
|
17
|
+
private readonly queryCountAllResolverGenerator: QueryCountAllResolverGenerator,
|
|
18
|
+
private readonly queryTypeByIdResolverGenerator: QueryTypeByIdResolverGenerator,
|
|
19
|
+
private readonly mutationCreateResolverGenerator: MutationCreateResolverGenerator,
|
|
20
|
+
private readonly mutationUpdateResolverGenerator: MutationUpdateResolverGenerator,
|
|
21
|
+
private readonly mutationDeleteResolverGenerator: MutationDeleteResolverGenerator,
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
public generateFromAnalyzedSchema(
|
|
25
|
+
entryDirectiveTypes: GraphQLObjectType[],
|
|
26
|
+
): IGeneratedSchema[] {
|
|
27
|
+
return entryDirectiveTypes.map((objectType): IGeneratedSchema => {
|
|
28
|
+
const typeName = objectType.name
|
|
29
|
+
|
|
30
|
+
const queryAllName = `all${typeName}s`
|
|
31
|
+
const queryAllString = `${queryAllName}: [${objectType.name}]`
|
|
32
|
+
const queryAllResolver: GraphQLFieldResolver<
|
|
33
|
+
any,
|
|
34
|
+
ApolloContext,
|
|
35
|
+
any,
|
|
36
|
+
Promise<Entry[]>
|
|
37
|
+
> = this.queryAllResolverGenerator.createResolver(typeName)
|
|
38
|
+
|
|
39
|
+
const queryAllMetaName = `_${queryAllName}Meta`
|
|
40
|
+
const queryAllMetaString = `${queryAllMetaName}: ListMetadata`
|
|
41
|
+
const queryAllMetaResolver: GraphQLFieldResolver<
|
|
42
|
+
any,
|
|
43
|
+
ApolloContext,
|
|
44
|
+
any,
|
|
45
|
+
Promise<TypeCount>
|
|
46
|
+
> = this.queryCountAllResolverGenerator.createResolver(typeName)
|
|
47
|
+
|
|
48
|
+
const queryByIdName = typeName
|
|
49
|
+
const queryByIdString = `${queryByIdName}(id: ID!): ${objectType.name}`
|
|
50
|
+
const queryByIdResolver: GraphQLFieldResolver<
|
|
51
|
+
any,
|
|
52
|
+
ApolloContext,
|
|
53
|
+
any,
|
|
54
|
+
Promise<Entry>
|
|
55
|
+
> = this.queryByIdResolverGenerator.createResolver(typeName)
|
|
56
|
+
|
|
57
|
+
const inputTypeName = `${typeName}Input`
|
|
58
|
+
const createMutationName = `create${typeName}`
|
|
59
|
+
const createMutationString = `${createMutationName}(data:${inputTypeName}, message:String): ${typeName}`
|
|
60
|
+
const createMutationResolver: GraphQLFieldResolver<
|
|
61
|
+
any,
|
|
62
|
+
ApolloContext,
|
|
63
|
+
any,
|
|
64
|
+
Promise<Entry>
|
|
65
|
+
> = this.mutationCreateResolverGenerator.createResolver(typeName)
|
|
66
|
+
|
|
67
|
+
const updateMutationName = `update${typeName}`
|
|
68
|
+
const updateMutationString = `${updateMutationName}(id: ID!, data:${inputTypeName}, message:String): ${typeName}`
|
|
69
|
+
const updateMutationResolver: GraphQLFieldResolver<
|
|
70
|
+
any,
|
|
71
|
+
ApolloContext,
|
|
72
|
+
any,
|
|
73
|
+
Promise<Entry>
|
|
74
|
+
> = this.mutationUpdateResolverGenerator.createResolver(typeName)
|
|
75
|
+
|
|
76
|
+
const deleteMutationName = `delete${typeName}`
|
|
77
|
+
const deleteMutationString = `${deleteMutationName}(id: ID!, message:String): DeletionResult`
|
|
78
|
+
const deleteMutationResolver: GraphQLFieldResolver<
|
|
79
|
+
any,
|
|
80
|
+
ApolloContext,
|
|
81
|
+
any,
|
|
82
|
+
Promise<Entry>
|
|
83
|
+
> = this.mutationDeleteResolverGenerator.createResolver(typeName)
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
queryAll: {
|
|
87
|
+
name: queryAllName,
|
|
88
|
+
schemaString: queryAllString,
|
|
89
|
+
resolver: queryAllResolver,
|
|
90
|
+
},
|
|
91
|
+
queryAllMeta: {
|
|
92
|
+
name: queryAllMetaName,
|
|
93
|
+
schemaString: queryAllMetaString,
|
|
94
|
+
resolver: queryAllMetaResolver,
|
|
95
|
+
},
|
|
96
|
+
queryById: {
|
|
97
|
+
name: queryByIdName,
|
|
98
|
+
schemaString: queryByIdString,
|
|
99
|
+
resolver: queryByIdResolver,
|
|
100
|
+
},
|
|
101
|
+
createMutation: {
|
|
102
|
+
name: createMutationName,
|
|
103
|
+
schemaString: createMutationString,
|
|
104
|
+
resolver: createMutationResolver,
|
|
105
|
+
},
|
|
106
|
+
updateMutation: {
|
|
107
|
+
name: updateMutationName,
|
|
108
|
+
schemaString: updateMutationString,
|
|
109
|
+
resolver: updateMutationResolver,
|
|
110
|
+
},
|
|
111
|
+
deleteMutation: {
|
|
112
|
+
name: deleteMutationName,
|
|
113
|
+
schemaString: deleteMutationString,
|
|
114
|
+
resolver: deleteMutationResolver,
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public generateTypeNameQuery(): IGeneratedQuery<Promise<string>> {
|
|
121
|
+
const contentTypeQueryName = '_typeName'
|
|
122
|
+
const contentTypeQueryString = `${contentTypeQueryName}(id: ID!): String`
|
|
123
|
+
const contentTypeQueryResolver: GraphQLFieldResolver<
|
|
124
|
+
any,
|
|
125
|
+
ApolloContext,
|
|
126
|
+
any,
|
|
127
|
+
Promise<string>
|
|
128
|
+
> = this.queryTypeByIdResolverGenerator.createResolver()
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
name: contentTypeQueryName,
|
|
132
|
+
schemaString: contentTypeQueryString,
|
|
133
|
+
resolver: contentTypeQueryResolver,
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface IGeneratedSchema {
|
|
139
|
+
queryAll: IGeneratedQuery<Promise<Entry[]>>
|
|
140
|
+
queryAllMeta: IGeneratedQuery<Promise<TypeCount>>
|
|
141
|
+
queryById: IGeneratedQuery<Promise<Entry>>
|
|
142
|
+
createMutation: IGeneratedQuery<Promise<Entry>>
|
|
143
|
+
updateMutation: IGeneratedQuery<Promise<Entry>>
|
|
144
|
+
deleteMutation: IGeneratedQuery<Promise<Entry>>
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface IGeneratedQuery<T> {
|
|
148
|
+
name: string
|
|
149
|
+
schemaString: string
|
|
150
|
+
resolver: GraphQLFieldResolver<any, ApolloContext, any, T>
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export type TypeCount = {
|
|
154
|
+
count: number
|
|
155
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { GraphQLField, GraphQLObjectType } from 'graphql'
|
|
2
|
+
import {
|
|
3
|
+
Entry,
|
|
4
|
+
PersistenceService,
|
|
5
|
+
} from '../../persistence/persistence.service'
|
|
6
|
+
import { ApolloContext } from '../../app/api.service'
|
|
7
|
+
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
8
|
+
|
|
9
|
+
export class EntryReferenceResolverGenerator {
|
|
10
|
+
constructor(private readonly persistence: PersistenceService) {}
|
|
11
|
+
|
|
12
|
+
public createResolver(
|
|
13
|
+
context: ApolloContext,
|
|
14
|
+
obj: {
|
|
15
|
+
type: GraphQLObjectType
|
|
16
|
+
fields: GraphQLField<any, any>[]
|
|
17
|
+
},
|
|
18
|
+
): Record<
|
|
19
|
+
string,
|
|
20
|
+
GraphQLFieldResolver<
|
|
21
|
+
Record<string, any>,
|
|
22
|
+
ApolloContext,
|
|
23
|
+
any,
|
|
24
|
+
Promise<Entry | Entry[] | undefined>
|
|
25
|
+
>
|
|
26
|
+
> {
|
|
27
|
+
const persistence = this.persistence
|
|
28
|
+
|
|
29
|
+
const fieldResolvers: Record<
|
|
30
|
+
string,
|
|
31
|
+
GraphQLFieldResolver<
|
|
32
|
+
Record<string, any>,
|
|
33
|
+
ApolloContext,
|
|
34
|
+
any,
|
|
35
|
+
Promise<Entry | Entry[] | undefined>
|
|
36
|
+
>
|
|
37
|
+
> = {}
|
|
38
|
+
|
|
39
|
+
for (const field of obj.fields) {
|
|
40
|
+
const fieldName = field.name
|
|
41
|
+
fieldResolvers[fieldName] = async (
|
|
42
|
+
source,
|
|
43
|
+
args,
|
|
44
|
+
context,
|
|
45
|
+
info,
|
|
46
|
+
): Promise<Entry | Entry[] | undefined> => {
|
|
47
|
+
if (source[fieldName] === undefined) {
|
|
48
|
+
return undefined
|
|
49
|
+
}
|
|
50
|
+
// TODO decide this based on type definition, not data
|
|
51
|
+
if (Array.isArray(source[fieldName])) {
|
|
52
|
+
return source[fieldName].map((el: any) =>
|
|
53
|
+
persistence.findById(
|
|
54
|
+
context.gitAdapter,
|
|
55
|
+
context.getCurrentRef(),
|
|
56
|
+
el.id,
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
} else {
|
|
60
|
+
return persistence.findById(
|
|
61
|
+
context.gitAdapter,
|
|
62
|
+
context.getCurrentRef(),
|
|
63
|
+
source[fieldName].id,
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return fieldResolvers
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
2
|
+
import { ApolloContext } from '../../app/api.service'
|
|
3
|
+
import {
|
|
4
|
+
Entry,
|
|
5
|
+
PersistenceService,
|
|
6
|
+
} from '../../persistence/persistence.service'
|
|
7
|
+
|
|
8
|
+
export class MutationCreateResolverGenerator {
|
|
9
|
+
constructor(private readonly persistence: PersistenceService) {}
|
|
10
|
+
|
|
11
|
+
public createResolver(
|
|
12
|
+
typeName: string,
|
|
13
|
+
): GraphQLFieldResolver<any, ApolloContext, any, Promise<Entry>> {
|
|
14
|
+
return async (
|
|
15
|
+
source,
|
|
16
|
+
args,
|
|
17
|
+
context: ApolloContext,
|
|
18
|
+
info,
|
|
19
|
+
): Promise<Entry> => {
|
|
20
|
+
// TODO validate ID references in payload to assert referenced ID exists and points to correct entry type
|
|
21
|
+
const createResult = await this.persistence.createType(
|
|
22
|
+
context.gitAdapter,
|
|
23
|
+
context.branch,
|
|
24
|
+
context.getCurrentRef(),
|
|
25
|
+
typeName,
|
|
26
|
+
args.data,
|
|
27
|
+
args.message,
|
|
28
|
+
)
|
|
29
|
+
context.setCurrentRef(createResult.ref)
|
|
30
|
+
return this.persistence.findByTypeId(
|
|
31
|
+
context.gitAdapter,
|
|
32
|
+
context.getCurrentRef(),
|
|
33
|
+
typeName,
|
|
34
|
+
createResult.id,
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Entry,
|
|
3
|
+
PersistenceService,
|
|
4
|
+
} from '../../persistence/persistence.service'
|
|
5
|
+
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
6
|
+
import { ApolloContext } from '../../app/api.service'
|
|
7
|
+
|
|
8
|
+
export class MutationDeleteResolverGenerator {
|
|
9
|
+
constructor(private readonly persistence: PersistenceService) {}
|
|
10
|
+
|
|
11
|
+
public createResolver(
|
|
12
|
+
typeName: string,
|
|
13
|
+
): GraphQLFieldResolver<any, ApolloContext, any, Promise<Entry>> {
|
|
14
|
+
return async (
|
|
15
|
+
source,
|
|
16
|
+
args,
|
|
17
|
+
context: ApolloContext,
|
|
18
|
+
info,
|
|
19
|
+
): Promise<Entry> => {
|
|
20
|
+
// TODO validate ID to delete is not referenced anywhere
|
|
21
|
+
const deleteResult = await this.persistence.deleteByTypeId(
|
|
22
|
+
context.gitAdapter,
|
|
23
|
+
context.branch,
|
|
24
|
+
context.getCurrentRef(),
|
|
25
|
+
typeName,
|
|
26
|
+
args.id,
|
|
27
|
+
args.message,
|
|
28
|
+
)
|
|
29
|
+
context.setCurrentRef(deleteResult.ref)
|
|
30
|
+
return {
|
|
31
|
+
id: args.id,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Entry,
|
|
3
|
+
PersistenceService,
|
|
4
|
+
} from '../../persistence/persistence.service'
|
|
5
|
+
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
6
|
+
import { ApolloContext } from '../../app/api.service'
|
|
7
|
+
|
|
8
|
+
export class MutationUpdateResolverGenerator {
|
|
9
|
+
constructor(private readonly persistence: PersistenceService) {}
|
|
10
|
+
|
|
11
|
+
public createResolver(
|
|
12
|
+
typeName: string,
|
|
13
|
+
): GraphQLFieldResolver<any, ApolloContext, any, Promise<Entry>> {
|
|
14
|
+
return async (
|
|
15
|
+
source,
|
|
16
|
+
args,
|
|
17
|
+
context: ApolloContext,
|
|
18
|
+
info,
|
|
19
|
+
): Promise<Entry> => {
|
|
20
|
+
// TODO validate ID references in payload to assert referenced ID exists and points to correct entry type
|
|
21
|
+
const updateResult = await this.persistence.updateByTypeId(
|
|
22
|
+
context.gitAdapter,
|
|
23
|
+
context.branch,
|
|
24
|
+
context.getCurrentRef(),
|
|
25
|
+
typeName,
|
|
26
|
+
args.id,
|
|
27
|
+
args.data,
|
|
28
|
+
args.message,
|
|
29
|
+
)
|
|
30
|
+
context.setCurrentRef(updateResult.ref)
|
|
31
|
+
return this.persistence.findByTypeId(
|
|
32
|
+
context.gitAdapter,
|
|
33
|
+
context.getCurrentRef(),
|
|
34
|
+
typeName,
|
|
35
|
+
args.id,
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ApolloContext } from '../../app/api.service'
|
|
2
|
+
import {
|
|
3
|
+
Entry,
|
|
4
|
+
PersistenceService,
|
|
5
|
+
} from '../../persistence/persistence.service'
|
|
6
|
+
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
7
|
+
|
|
8
|
+
export class QueryAllResolverGenerator {
|
|
9
|
+
constructor(private readonly persistence: PersistenceService) {}
|
|
10
|
+
|
|
11
|
+
public createResolver(
|
|
12
|
+
typeName: string,
|
|
13
|
+
): GraphQLFieldResolver<any, ApolloContext, any, Promise<Entry[]>> {
|
|
14
|
+
return async (
|
|
15
|
+
obj,
|
|
16
|
+
args,
|
|
17
|
+
context: ApolloContext,
|
|
18
|
+
info,
|
|
19
|
+
): Promise<Entry[]> => {
|
|
20
|
+
return this.persistence.findByType(
|
|
21
|
+
context.gitAdapter,
|
|
22
|
+
context.getCurrentRef(),
|
|
23
|
+
typeName,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Entry,
|
|
3
|
+
PersistenceService,
|
|
4
|
+
} from '../../persistence/persistence.service'
|
|
5
|
+
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
6
|
+
import { ApolloContext } from '../../app/api.service'
|
|
7
|
+
|
|
8
|
+
export class QueryByIdResolverGenerator {
|
|
9
|
+
constructor(private readonly persistence: PersistenceService) {}
|
|
10
|
+
|
|
11
|
+
public createResolver(
|
|
12
|
+
typeName: string,
|
|
13
|
+
): GraphQLFieldResolver<any, ApolloContext, any, Promise<Entry>> {
|
|
14
|
+
return async (obj, args, context, info): Promise<Entry> => {
|
|
15
|
+
return this.persistence.findByTypeId(
|
|
16
|
+
context.gitAdapter,
|
|
17
|
+
context.getCurrentRef(),
|
|
18
|
+
typeName,
|
|
19
|
+
args.id,
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { PersistenceService } from '../../persistence/persistence.service'
|
|
2
|
+
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
3
|
+
import { ApolloContext } from '../../app/api.service'
|
|
4
|
+
import { TypeCount } from '../queries-mutations-generator.service'
|
|
5
|
+
|
|
6
|
+
export class QueryCountAllResolverGenerator {
|
|
7
|
+
constructor(private readonly persistence: PersistenceService) {}
|
|
8
|
+
|
|
9
|
+
public createResolver(
|
|
10
|
+
typeName: string,
|
|
11
|
+
): GraphQLFieldResolver<any, ApolloContext, any, Promise<TypeCount>> {
|
|
12
|
+
return async (
|
|
13
|
+
obj,
|
|
14
|
+
args,
|
|
15
|
+
context: ApolloContext,
|
|
16
|
+
info,
|
|
17
|
+
): Promise<TypeCount> => {
|
|
18
|
+
return {
|
|
19
|
+
count: (
|
|
20
|
+
await this.persistence.findByType(
|
|
21
|
+
context.gitAdapter,
|
|
22
|
+
context.getCurrentRef(),
|
|
23
|
+
typeName,
|
|
24
|
+
)
|
|
25
|
+
).length,
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PersistenceService } from '../../persistence/persistence.service'
|
|
2
|
+
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
3
|
+
import { ApolloContext } from '../../app/api.service'
|
|
4
|
+
|
|
5
|
+
export class QueryTypeByIdResolverGenerator {
|
|
6
|
+
constructor(private readonly persistence: PersistenceService) {}
|
|
7
|
+
|
|
8
|
+
public createResolver(): GraphQLFieldResolver<
|
|
9
|
+
any,
|
|
10
|
+
ApolloContext,
|
|
11
|
+
any,
|
|
12
|
+
Promise<string>
|
|
13
|
+
> {
|
|
14
|
+
return async (
|
|
15
|
+
source,
|
|
16
|
+
args,
|
|
17
|
+
context: ApolloContext,
|
|
18
|
+
info,
|
|
19
|
+
): Promise<string> => {
|
|
20
|
+
return this.persistence.getTypeById(
|
|
21
|
+
context.gitAdapter,
|
|
22
|
+
context.getCurrentRef(),
|
|
23
|
+
args.id,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ApolloContext } from '../../app/api.service'
|
|
2
|
+
import { PersistenceService } from '../../persistence/persistence.service'
|
|
3
|
+
import {
|
|
4
|
+
GraphQLAbstractType,
|
|
5
|
+
GraphQLResolveInfo,
|
|
6
|
+
GraphQLTypeResolver,
|
|
7
|
+
} from 'graphql/type/definition'
|
|
8
|
+
import { EntryReferenceUtil } from '../schema-utils/entry-reference-util'
|
|
9
|
+
|
|
10
|
+
export class UnionTypeResolverGenerator {
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly persistence: PersistenceService,
|
|
13
|
+
private readonly entryReferenceUtil: EntryReferenceUtil,
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
public createResolver(): GraphQLTypeResolver<any, ApolloContext> {
|
|
17
|
+
return async (
|
|
18
|
+
obj: any,
|
|
19
|
+
context: ApolloContext,
|
|
20
|
+
info: GraphQLResolveInfo,
|
|
21
|
+
abstractType: GraphQLAbstractType,
|
|
22
|
+
): Promise<string> => {
|
|
23
|
+
if (
|
|
24
|
+
this.entryReferenceUtil.buildsOnTypeWithEntryDirective(abstractType)
|
|
25
|
+
) {
|
|
26
|
+
return this.persistence.getTypeById(
|
|
27
|
+
context.gitAdapter,
|
|
28
|
+
context.getCurrentRef(),
|
|
29
|
+
obj.id,
|
|
30
|
+
)
|
|
31
|
+
} else {
|
|
32
|
+
// We have injected an internal `__typename` field into the data of fields pointing to a non-entry union
|
|
33
|
+
// in UnionValueResolverGenerator. This artificial field holds the type information we need here.
|
|
34
|
+
return obj.__typename
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// TODO same for interface type: https://www.apollographql.com/docs/apollo-server/data/resolvers/#resolving-unions-and-interfaces
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GraphQLFieldResolver,
|
|
3
|
+
GraphQLNullableType,
|
|
4
|
+
GraphQLUnionType,
|
|
5
|
+
} from 'graphql/type/definition'
|
|
6
|
+
import { ApolloContext } from '../../app/api.service'
|
|
7
|
+
import { Entry } from '../../persistence/persistence.service'
|
|
8
|
+
import { GraphQLSchema, Kind } from 'graphql'
|
|
9
|
+
import {
|
|
10
|
+
GraphQLField,
|
|
11
|
+
GraphQLList,
|
|
12
|
+
GraphQLNonNull,
|
|
13
|
+
GraphQLObjectType,
|
|
14
|
+
} from 'graphql/type'
|
|
15
|
+
import { EntryReferenceUtil } from '../schema-utils/entry-reference-util'
|
|
16
|
+
|
|
17
|
+
export class UnionValueResolverGenerator {
|
|
18
|
+
constructor(private readonly entryReferenceUtil: EntryReferenceUtil) {}
|
|
19
|
+
|
|
20
|
+
public createResolver(
|
|
21
|
+
schema: GraphQLSchema,
|
|
22
|
+
): Record<
|
|
23
|
+
string,
|
|
24
|
+
Record<string, GraphQLFieldResolver<any, ApolloContext, any, Entry>>
|
|
25
|
+
> {
|
|
26
|
+
const resolvers: Record<
|
|
27
|
+
string,
|
|
28
|
+
Record<string, GraphQLFieldResolver<any, ApolloContext, any, Entry>>
|
|
29
|
+
> = {}
|
|
30
|
+
for (const typeName of Object.keys(schema.getTypeMap())) {
|
|
31
|
+
const type = schema.getType(typeName)
|
|
32
|
+
if (!type || type.astNode?.kind !== Kind.OBJECT_TYPE_DEFINITION) {
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
const objectType = type as GraphQLObjectType
|
|
36
|
+
const unionFieldsNotUsingEntry =
|
|
37
|
+
this.getFieldsWithUnionTypeNotUsingEntryTypes(objectType)
|
|
38
|
+
|
|
39
|
+
const fieldResolvers: Record<
|
|
40
|
+
string,
|
|
41
|
+
GraphQLFieldResolver<any, ApolloContext, any, Entry>
|
|
42
|
+
> = {}
|
|
43
|
+
for (const field of unionFieldsNotUsingEntry) {
|
|
44
|
+
fieldResolvers[field.name] = (obj, args, context, info): Entry => {
|
|
45
|
+
const fieldValue = obj[info.fieldName]
|
|
46
|
+
return this.collapseTypeField(field.type, fieldValue)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (Object.keys(fieldResolvers).length > 0) {
|
|
51
|
+
resolvers[typeName] = fieldResolvers
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return resolvers
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private getFieldsWithUnionTypeNotUsingEntryTypes(
|
|
59
|
+
objectType: GraphQLObjectType,
|
|
60
|
+
): GraphQLField<any, any>[] {
|
|
61
|
+
const fields = []
|
|
62
|
+
for (const fieldsKey in objectType.getFields()) {
|
|
63
|
+
const field: GraphQLField<any, any> = objectType.getFields()[fieldsKey]
|
|
64
|
+
if (
|
|
65
|
+
this.buildsOnUnionType(field.type) &&
|
|
66
|
+
!this.entryReferenceUtil.buildsOnTypeWithEntryDirective(field.type)
|
|
67
|
+
) {
|
|
68
|
+
fields.push(field)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return fields
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private buildsOnUnionType(type: GraphQLNullableType): boolean {
|
|
75
|
+
if (type instanceof GraphQLNonNull) {
|
|
76
|
+
return this.buildsOnUnionType(type.ofType)
|
|
77
|
+
} else if (type instanceof GraphQLList) {
|
|
78
|
+
return this.buildsOnUnionType(type.ofType)
|
|
79
|
+
} else if (type instanceof GraphQLUnionType) {
|
|
80
|
+
return true
|
|
81
|
+
} else if (type instanceof GraphQLObjectType) {
|
|
82
|
+
return false
|
|
83
|
+
}
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private collapseTypeField(
|
|
88
|
+
type: GraphQLNullableType,
|
|
89
|
+
fieldValue: Record<string, any> | Record<string, any>[],
|
|
90
|
+
): Record<string, any> {
|
|
91
|
+
if (type instanceof GraphQLNonNull) {
|
|
92
|
+
return this.collapseTypeField(type.ofType, fieldValue)
|
|
93
|
+
} else if (type instanceof GraphQLList) {
|
|
94
|
+
if (!Array.isArray(fieldValue)) {
|
|
95
|
+
throw new Error('Expected array value')
|
|
96
|
+
}
|
|
97
|
+
return fieldValue.map((item) => this.collapseTypeField(type.ofType, item))
|
|
98
|
+
} else {
|
|
99
|
+
// Based on our @oneOf directive, we expect only one field whose name
|
|
100
|
+
// corresponds to the concrete type's name.
|
|
101
|
+
const firstKey = Object.keys(fieldValue)[0]
|
|
102
|
+
if (Array.isArray(fieldValue)) {
|
|
103
|
+
throw new Error('Did not expect array value')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// We replace the above name field that nests our concrete data directly
|
|
107
|
+
// with the data and a `__typename` field, so that our output data
|
|
108
|
+
// corresponds to the output schema provided by the user (i.e. there is
|
|
109
|
+
// no additional nesting level there).
|
|
110
|
+
return {
|
|
111
|
+
...fieldValue[firstKey],
|
|
112
|
+
__typename: firstKey.slice(0, 1).toUpperCase() + firstKey.slice(1),
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { GraphQLField, GraphQLObjectType, GraphQLSchema } from 'graphql'
|
|
2
|
+
import { getDirective } from '@graphql-tools/utils'
|
|
3
|
+
import { GraphQLInterfaceType, GraphQLUnionType } from 'graphql/type/definition'
|
|
4
|
+
import { Kind } from 'graphql/language/kinds'
|
|
5
|
+
import { ApolloContext } from '../app/api.service'
|
|
6
|
+
import { EntryReferenceUtil } from './schema-utils/entry-reference-util'
|
|
7
|
+
|
|
8
|
+
export class SchemaAnalyzerService {
|
|
9
|
+
constructor(private readonly entryReferenceUtil: EntryReferenceUtil) {}
|
|
10
|
+
|
|
11
|
+
public analyzeSchema(schema: GraphQLSchema): ISchemaAnalyzerResult {
|
|
12
|
+
const result: ISchemaAnalyzerResult = {
|
|
13
|
+
entryDirectiveTypes: [],
|
|
14
|
+
objectTypes: [],
|
|
15
|
+
interfaceTypes: [],
|
|
16
|
+
unionTypes: [],
|
|
17
|
+
typesWithEntryReferences: [],
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const typeMap = schema.getTypeMap()
|
|
21
|
+
|
|
22
|
+
for (const [key, type] of Object.entries(typeMap)) {
|
|
23
|
+
if (key.startsWith('__')) {
|
|
24
|
+
continue
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (type.astNode?.kind === Kind.OBJECT_TYPE_DEFINITION) {
|
|
28
|
+
const objectType = type as GraphQLObjectType
|
|
29
|
+
result.objectTypes.push(objectType)
|
|
30
|
+
const entityDirective = getDirective(schema, objectType, 'Entry')?.[0]
|
|
31
|
+
if (entityDirective) {
|
|
32
|
+
result.entryDirectiveTypes.push(objectType)
|
|
33
|
+
}
|
|
34
|
+
const fieldsWithEntryReference =
|
|
35
|
+
this.entryReferenceUtil.getFieldsWithReferenceToTypeWithEntryDirective(
|
|
36
|
+
objectType,
|
|
37
|
+
)
|
|
38
|
+
if (fieldsWithEntryReference.length > 0) {
|
|
39
|
+
result.typesWithEntryReferences.push({
|
|
40
|
+
type: objectType,
|
|
41
|
+
fields: fieldsWithEntryReference,
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (type.astNode?.kind === Kind.INTERFACE_TYPE_DEFINITION) {
|
|
47
|
+
const interfaceType = type as GraphQLInterfaceType
|
|
48
|
+
result.interfaceTypes.push(interfaceType)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (type.astNode?.kind === Kind.UNION_TYPE_DEFINITION) {
|
|
52
|
+
const unionType = type as GraphQLUnionType
|
|
53
|
+
result.unionTypes.push(unionType)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return result
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface ISchemaAnalyzerResult {
|
|
62
|
+
entryDirectiveTypes: GraphQLObjectType[]
|
|
63
|
+
objectTypes: GraphQLObjectType[]
|
|
64
|
+
interfaceTypes: GraphQLInterfaceType[]
|
|
65
|
+
unionTypes: GraphQLUnionType[]
|
|
66
|
+
typesWithEntryReferences: {
|
|
67
|
+
type: GraphQLObjectType<any, ApolloContext>
|
|
68
|
+
fields: GraphQLField<any, ApolloContext>[]
|
|
69
|
+
}[]
|
|
70
|
+
}
|