@commitspark/graphql-api 0.9.4 → 0.11.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +96 -85
  3. package/dist/container.js +21 -13
  4. package/dist/container.js.map +1 -1
  5. package/dist/graphql/field-resolver/entry-reference-resolver.d.ts +10 -0
  6. package/dist/graphql/field-resolver/entry-reference-resolver.js +15 -0
  7. package/dist/graphql/field-resolver/entry-reference-resolver.js.map +1 -0
  8. package/dist/graphql/field-resolver/field-default-value-resolver.d.ts +14 -0
  9. package/dist/graphql/field-resolver/field-default-value-resolver.js +73 -0
  10. package/dist/graphql/field-resolver/field-default-value-resolver.js.map +1 -0
  11. package/dist/graphql/field-resolver/fieldResolver.d.ts +11 -0
  12. package/dist/graphql/field-resolver/fieldResolver.js +3 -0
  13. package/dist/graphql/field-resolver/fieldResolver.js.map +1 -0
  14. package/dist/graphql/field-resolver/union-value-resolver.d.ts +10 -0
  15. package/dist/graphql/field-resolver/union-value-resolver.js +17 -0
  16. package/dist/graphql/field-resolver/union-value-resolver.js.map +1 -0
  17. package/dist/graphql/input-type-generator.service.d.ts +3 -3
  18. package/dist/graphql/input-type-generator.service.js +18 -7
  19. package/dist/graphql/input-type-generator.service.js.map +1 -1
  20. package/dist/graphql/queries-mutations-generator.service.d.ts +7 -7
  21. package/dist/graphql/queries-mutations-generator.service.js +6 -6
  22. package/dist/graphql/queries-mutations-generator.service.js.map +1 -1
  23. package/dist/graphql/resolver-generators/mutation-create-resolver-generator.d.ts +6 -3
  24. package/dist/graphql/resolver-generators/mutation-create-resolver-generator.js +46 -4
  25. package/dist/graphql/resolver-generators/mutation-create-resolver-generator.js.map +1 -1
  26. package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.d.ts +6 -3
  27. package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.js +32 -9
  28. package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.js.map +1 -1
  29. package/dist/graphql/resolver-generators/mutation-update-resolver-generator.d.ts +12 -0
  30. package/dist/graphql/resolver-generators/mutation-update-resolver-generator.js +53 -0
  31. package/dist/graphql/resolver-generators/mutation-update-resolver-generator.js.map +1 -0
  32. package/dist/graphql/resolver-generators/object-type-field-default-value-resolver-generator.d.ts +13 -0
  33. package/dist/graphql/resolver-generators/object-type-field-default-value-resolver-generator.js +58 -0
  34. package/dist/graphql/resolver-generators/object-type-field-default-value-resolver-generator.js.map +1 -0
  35. package/dist/graphql/resolver-generators/query-all-resolver-generator.d.ts +3 -2
  36. package/dist/graphql/resolver-generators/query-all-resolver-generator.js +4 -1
  37. package/dist/graphql/resolver-generators/query-all-resolver-generator.js.map +1 -1
  38. package/dist/graphql/resolver-generators/query-by-id-resolver-generator.d.ts +3 -2
  39. package/dist/graphql/resolver-generators/query-by-id-resolver-generator.js +2 -1
  40. package/dist/graphql/resolver-generators/query-by-id-resolver-generator.js.map +1 -1
  41. package/dist/graphql/resolver-generators/union-type-resolver-generator.d.ts +4 -4
  42. package/dist/graphql/resolver-generators/union-type-resolver-generator.js +3 -3
  43. package/dist/graphql/resolver-generators/union-type-resolver-generator.js.map +1 -1
  44. package/dist/graphql/schema-analyzer.service.d.ts +1 -9
  45. package/dist/graphql/schema-analyzer.service.js +6 -17
  46. package/dist/graphql/schema-analyzer.service.js.map +1 -1
  47. package/dist/graphql/schema-generator.service.d.ts +3 -5
  48. package/dist/graphql/schema-generator.service.js +7 -12
  49. package/dist/graphql/schema-generator.service.js.map +1 -1
  50. package/dist/graphql/schema-utils/entry-reference-util.d.ts +12 -4
  51. package/dist/graphql/schema-utils/entry-reference-util.js +105 -21
  52. package/dist/graphql/schema-utils/entry-reference-util.js.map +1 -1
  53. package/dist/graphql/schema-utils/entry-type-util.d.ts +6 -0
  54. package/dist/graphql/schema-utils/entry-type-util.js +34 -0
  55. package/dist/graphql/schema-utils/entry-type-util.js.map +1 -0
  56. package/dist/graphql/schema-utils/union-type-util.d.ts +5 -0
  57. package/dist/graphql/schema-utils/union-type-util.js +21 -0
  58. package/dist/graphql/schema-utils/union-type-util.js.map +1 -0
  59. package/dist/persistence/persistence.service.d.ts +1 -8
  60. package/dist/persistence/persistence.service.js +22 -87
  61. package/dist/persistence/persistence.service.js.map +1 -1
  62. package/dist/tsconfig.build.tsbuildinfo +1 -1
  63. package/package.json +3 -3
  64. package/src/container.ts +29 -15
  65. package/src/graphql/field-resolver/entry-reference-resolver.ts +47 -0
  66. package/src/graphql/field-resolver/field-default-value-resolver.ts +154 -0
  67. package/src/graphql/field-resolver/fieldResolver.ts +19 -0
  68. package/src/graphql/field-resolver/union-value-resolver.ts +46 -0
  69. package/src/graphql/input-type-generator.service.ts +22 -8
  70. package/src/graphql/queries-mutations-generator.service.ts +18 -18
  71. package/src/graphql/resolver-generators/mutation-create-resolver-generator.ts +82 -19
  72. package/src/graphql/resolver-generators/mutation-delete-resolver-generator.ts +72 -27
  73. package/src/graphql/resolver-generators/mutation-update-resolver-generator.ts +128 -0
  74. package/src/graphql/resolver-generators/object-type-field-default-value-resolver-generator.ts +119 -0
  75. package/src/graphql/resolver-generators/query-all-resolver-generator.ts +9 -7
  76. package/src/graphql/resolver-generators/query-by-id-resolver-generator.ts +7 -7
  77. package/src/graphql/resolver-generators/union-type-resolver-generator.ts +5 -7
  78. package/src/graphql/schema-analyzer.service.ts +10 -24
  79. package/src/graphql/schema-generator.service.ts +13 -22
  80. package/src/graphql/schema-utils/entry-reference-util.ts +170 -30
  81. package/src/graphql/schema-utils/entry-type-util.ts +42 -0
  82. package/src/graphql/schema-utils/union-type-util.ts +23 -0
  83. package/src/persistence/persistence.service.ts +30 -142
  84. package/dist/graphql/resolver-generators/entry-reference-resolver.generator.d.ts +0 -12
  85. package/dist/graphql/resolver-generators/entry-reference-resolver.generator.js +0 -29
  86. package/dist/graphql/resolver-generators/entry-reference-resolver.generator.js.map +0 -1
  87. package/dist/graphql/resolver-generators/mutation-update.resolver-generator.d.ts +0 -8
  88. package/dist/graphql/resolver-generators/mutation-update.resolver-generator.js +0 -29
  89. package/dist/graphql/resolver-generators/mutation-update.resolver-generator.js.map +0 -1
  90. package/dist/graphql/resolver-generators/union-value-resolver-generator.d.ts +0 -13
  91. package/dist/graphql/resolver-generators/union-value-resolver-generator.js +0 -80
  92. package/dist/graphql/resolver-generators/union-value-resolver-generator.js.map +0 -1
  93. package/src/graphql/resolver-generators/entry-reference-resolver.generator.ts +0 -71
  94. package/src/graphql/resolver-generators/mutation-update.resolver-generator.ts +0 -59
  95. package/src/graphql/resolver-generators/union-value-resolver-generator.ts +0 -125
package/src/container.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { ApiService } from './app/api.service'
2
2
  import { ApolloConfigFactoryService } from './graphql/apollo-config-factory.service'
3
- import { EntryReferenceResolverGenerator } from './graphql/resolver-generators/entry-reference-resolver.generator'
4
3
  import { InputTypeGeneratorService } from './graphql/input-type-generator.service'
5
4
  import { QueriesMutationsGeneratorService } from './graphql/queries-mutations-generator.service'
6
5
  import { SchemaAnalyzerService } from './graphql/schema-analyzer.service'
@@ -10,36 +9,46 @@ import { PersistenceService } from './persistence/persistence.service'
10
9
  import { SchemaGeneratorService } from './graphql/schema-generator.service'
11
10
  import { MutationCreateResolverGenerator } from './graphql/resolver-generators/mutation-create-resolver-generator'
12
11
  import { MutationDeleteResolverGenerator } from './graphql/resolver-generators/mutation-delete-resolver-generator'
13
- import { MutationUpdateResolverGenerator } from './graphql/resolver-generators/mutation-update.resolver-generator'
12
+ import { MutationUpdateResolverGenerator } from './graphql/resolver-generators/mutation-update-resolver-generator'
14
13
  import { QueryAllResolverGenerator } from './graphql/resolver-generators/query-all-resolver-generator'
15
14
  import { QueryByIdResolverGenerator } from './graphql/resolver-generators/query-by-id-resolver-generator'
16
15
  import { QueryCountAllResolverGenerator } from './graphql/resolver-generators/query-count-all-resolver-generator'
17
16
  import { QueryTypeByIdResolverGenerator } from './graphql/resolver-generators/query-type-by-id-resolver-generator'
18
17
  import { SchemaValidator } from './graphql/schema-validator'
19
- import { UnionValueResolverGenerator } from './graphql/resolver-generators/union-value-resolver-generator'
18
+ import { UnionValueResolver } from './graphql/field-resolver/union-value-resolver'
20
19
  import { EntryReferenceUtil } from './graphql/schema-utils/entry-reference-util'
20
+ import { ObjectTypeFieldDefaultValueResolverGenerator } from './graphql/resolver-generators/object-type-field-default-value-resolver-generator'
21
+ import { FieldDefaultValueResolver } from './graphql/field-resolver/field-default-value-resolver'
22
+ import { EntryReferenceResolver } from './graphql/field-resolver/entry-reference-resolver'
23
+ import { UnionTypeUtil } from './graphql/schema-utils/union-type-util'
24
+ import { EntryTypeUtil } from './graphql/schema-utils/entry-type-util'
21
25
 
22
26
  // we used to have a DI container here, however that doesn't work well with webpack & co, so doing it by hand for now
23
27
 
24
- const entryReferenceUtil = new EntryReferenceUtil()
25
28
  const schemaValidator = new SchemaValidator()
26
29
  const persistenceService = new PersistenceService()
30
+ const entryTypeUtil = new EntryTypeUtil()
31
+ const unionTypeUtil = new UnionTypeUtil()
32
+ const entryReferenceUtil = new EntryReferenceUtil(
33
+ persistenceService,
34
+ entryTypeUtil,
35
+ unionTypeUtil,
36
+ )
27
37
  const schemaRootTypeGeneratorService = new SchemaRootTypeGeneratorService()
28
38
 
29
- const inputTypeGeneratorService = new InputTypeGeneratorService(
30
- entryReferenceUtil,
31
- )
32
- const schemaAnalyzerService = new SchemaAnalyzerService(entryReferenceUtil)
33
- const entryReferenceResolverGeneratorService =
34
- new EntryReferenceResolverGenerator(persistenceService)
39
+ const inputTypeGeneratorService = new InputTypeGeneratorService(entryTypeUtil)
40
+ const schemaAnalyzerService = new SchemaAnalyzerService()
35
41
  const mutationCreateResolverGenerator = new MutationCreateResolverGenerator(
36
42
  persistenceService,
43
+ entryReferenceUtil,
37
44
  )
38
45
  const mutationDeleteResolverGenerator = new MutationDeleteResolverGenerator(
39
46
  persistenceService,
47
+ entryReferenceUtil,
40
48
  )
41
49
  const mutationUpdateResolverGenerator = new MutationUpdateResolverGenerator(
42
50
  persistenceService,
51
+ entryReferenceUtil,
43
52
  )
44
53
  const queryAllResolverGenerator = new QueryAllResolverGenerator(
45
54
  persistenceService,
@@ -55,11 +64,17 @@ const queryTypeByIdResolverGenerator = new QueryTypeByIdResolverGenerator(
55
64
  )
56
65
  const unionTypeResolverGenerator = new UnionTypeResolverGenerator(
57
66
  persistenceService,
58
- entryReferenceUtil,
67
+ entryTypeUtil,
59
68
  )
60
- const unionValueResolverGenerator = new UnionValueResolverGenerator(
61
- entryReferenceUtil,
69
+ const unionValueResolver = new UnionValueResolver(unionTypeUtil)
70
+ const entryReferenceResolver = new EntryReferenceResolver(persistenceService)
71
+ const fieldDefaultValueResolver = new FieldDefaultValueResolver(
72
+ entryTypeUtil,
73
+ unionValueResolver,
74
+ entryReferenceResolver,
62
75
  )
76
+ const objectTypeFieldDefaultValueResolverGenerator =
77
+ new ObjectTypeFieldDefaultValueResolverGenerator(fieldDefaultValueResolver)
63
78
 
64
79
  const queriesMutationsGeneratorService = new QueriesMutationsGeneratorService(
65
80
  queryAllResolverGenerator,
@@ -76,9 +91,8 @@ const schemaGeneratorService = new SchemaGeneratorService(
76
91
  schemaAnalyzerService,
77
92
  inputTypeGeneratorService,
78
93
  schemaRootTypeGeneratorService,
79
- entryReferenceResolverGeneratorService,
80
94
  unionTypeResolverGenerator,
81
- unionValueResolverGenerator,
95
+ objectTypeFieldDefaultValueResolverGenerator,
82
96
  schemaValidator,
83
97
  )
84
98
 
@@ -0,0 +1,47 @@
1
+ import {
2
+ FieldResolver,
3
+ ResolvedEntryData,
4
+ FieldResolverContext,
5
+ } from './fieldResolver'
6
+ import {
7
+ GraphQLFieldResolver,
8
+ GraphQLOutputType,
9
+ GraphQLResolveInfo,
10
+ } from 'graphql/type/definition'
11
+ import { PersistenceService } from '../../persistence/persistence.service'
12
+ import { EntryData } from '@commitspark/git-adapter'
13
+
14
+ export class EntryReferenceResolver implements FieldResolver<any> {
15
+ resolve: GraphQLFieldResolver<
16
+ any,
17
+ FieldResolverContext,
18
+ any,
19
+ Promise<ResolvedEntryData<EntryData | EntryData[] | null>>
20
+ >
21
+
22
+ constructor(private readonly persistence: PersistenceService) {
23
+ this.resolve = (
24
+ fieldValue,
25
+ args: any,
26
+ context: FieldResolverContext,
27
+ info,
28
+ ): Promise<ResolvedEntryData<EntryData | EntryData[] | null>> =>
29
+ this.resolveFieldValue(fieldValue, args, context, info, info.returnType)
30
+ }
31
+
32
+ private async resolveFieldValue(
33
+ fieldValue: any,
34
+ args: any,
35
+ context: FieldResolverContext,
36
+ info: GraphQLResolveInfo,
37
+ currentType: GraphQLOutputType,
38
+ ): Promise<ResolvedEntryData<EntryData | EntryData[] | null>> {
39
+ const entry = await this.persistence.findById(
40
+ context.gitAdapter,
41
+ context.getCurrentRef(),
42
+ fieldValue.id,
43
+ )
44
+
45
+ return { ...entry.data, id: entry.id }
46
+ }
47
+ }
@@ -0,0 +1,154 @@
1
+ import {
2
+ FieldResolver,
3
+ ResolvedEntryData,
4
+ FieldResolverContext,
5
+ } from './fieldResolver'
6
+ import { EntryData } from '@commitspark/git-adapter'
7
+ import {
8
+ GraphQLFieldResolver,
9
+ GraphQLOutputType,
10
+ GraphQLResolveInfo,
11
+ } from 'graphql/type/definition'
12
+ import {
13
+ GraphQLNonNull,
14
+ GraphQLUnionType,
15
+ isListType,
16
+ isNonNullType,
17
+ isObjectType,
18
+ isUnionType,
19
+ } from 'graphql'
20
+ import { EntryTypeUtil } from '../schema-utils/entry-type-util'
21
+ import { UnionValueResolver } from './union-value-resolver'
22
+ import { EntryReferenceResolver } from './entry-reference-resolver'
23
+
24
+ export class FieldDefaultValueResolver implements FieldResolver<any> {
25
+ resolve: GraphQLFieldResolver<
26
+ any,
27
+ FieldResolverContext,
28
+ any,
29
+ Promise<ResolvedEntryData<EntryData | EntryData[] | null>>
30
+ >
31
+
32
+ constructor(
33
+ private readonly entryTypeUtil: EntryTypeUtil,
34
+ private readonly unionValueResolver: UnionValueResolver,
35
+ private readonly entryReferenceResolver: EntryReferenceResolver,
36
+ ) {
37
+ this.resolve = (
38
+ fieldValue,
39
+ args,
40
+ context,
41
+ info,
42
+ ): Promise<ResolvedEntryData<EntryData | EntryData[] | null>> =>
43
+ this.resolveFieldValue(
44
+ fieldValue,
45
+ args,
46
+ context,
47
+ info,
48
+ info.returnType,
49
+ false,
50
+ )
51
+ }
52
+
53
+ private resolveFieldValue(
54
+ fieldValue: any,
55
+ args: any,
56
+ context: FieldResolverContext,
57
+ info: GraphQLResolveInfo,
58
+ currentType: GraphQLOutputType,
59
+ hasNonNullParent: boolean,
60
+ ): Promise<ResolvedEntryData<EntryData | EntryData[] | null>> {
61
+ if (isNonNullType(currentType)) {
62
+ return this.resolveFieldValue(
63
+ fieldValue,
64
+ args,
65
+ {
66
+ gitAdapter: context.gitAdapter,
67
+ getCurrentRef: context.getCurrentRef,
68
+ },
69
+ info,
70
+ currentType.ofType,
71
+ true,
72
+ )
73
+ } else if (isListType(currentType)) {
74
+ if (fieldValue === undefined || fieldValue === null) {
75
+ if (hasNonNullParent) {
76
+ return new Promise((resolve) => resolve([]))
77
+ } else {
78
+ return new Promise((resolve) => resolve(null))
79
+ }
80
+ }
81
+
82
+ if (!Array.isArray(fieldValue)) {
83
+ throw new Error(
84
+ `Expected array while resolving value for field "${info.fieldName}".`,
85
+ )
86
+ }
87
+
88
+ const resultPromises = []
89
+ for (const item of fieldValue) {
90
+ const resultPromise = this.resolveFieldValue(
91
+ item,
92
+ args,
93
+ {
94
+ gitAdapter: context.gitAdapter,
95
+ getCurrentRef: context.getCurrentRef,
96
+ },
97
+ info,
98
+ currentType.ofType,
99
+ hasNonNullParent,
100
+ )
101
+ resultPromises.push(resultPromise)
102
+ }
103
+ return Promise.all(resultPromises)
104
+ } else if (isUnionType(currentType)) {
105
+ if (fieldValue === undefined || fieldValue === null) {
106
+ if (hasNonNullParent) {
107
+ throw new Error(
108
+ `Cannot generate a default value for NonNull field "${
109
+ info.parentType.name
110
+ }.${info.fieldName}" because it is a union field of type "${
111
+ (info.returnType as GraphQLNonNull<GraphQLUnionType>).ofType.name
112
+ }".`,
113
+ )
114
+ } else {
115
+ return new Promise((resolve) => resolve(null))
116
+ }
117
+ }
118
+
119
+ if (this.entryTypeUtil.buildsOnTypeWithEntryDirective(currentType)) {
120
+ return this.entryReferenceResolver.resolve(
121
+ fieldValue,
122
+ args,
123
+ context,
124
+ info,
125
+ )
126
+ }
127
+
128
+ return this.unionValueResolver.resolve(fieldValue, args, context, info)
129
+ } else if (isObjectType(currentType)) {
130
+ if (fieldValue === undefined || fieldValue === null) {
131
+ if (hasNonNullParent) {
132
+ throw new Error(
133
+ `Cannot generate a default value for NonNull field "${info.fieldName}" of type "${info.parentType.name}".`,
134
+ )
135
+ } else {
136
+ return new Promise((resolve) => resolve(null))
137
+ }
138
+ }
139
+
140
+ if (this.entryTypeUtil.hasEntryDirective(currentType)) {
141
+ return this.entryReferenceResolver.resolve(
142
+ fieldValue,
143
+ args,
144
+ context,
145
+ info,
146
+ )
147
+ }
148
+
149
+ return fieldValue
150
+ }
151
+
152
+ return fieldValue
153
+ }
154
+ }
@@ -0,0 +1,19 @@
1
+ import { GraphQLFieldResolver } from 'graphql/type/definition'
2
+ import { EntryData } from '@commitspark/git-adapter'
3
+ import { GitAdapter } from '@commitspark/git-adapter'
4
+
5
+ export interface FieldResolverContext {
6
+ gitAdapter: GitAdapter
7
+ getCurrentRef(): string
8
+ }
9
+
10
+ export interface FieldResolver<
11
+ TSource,
12
+ TContext = FieldResolverContext,
13
+ TArgs = any,
14
+ TResult = Promise<ResolvedEntryData<EntryData | EntryData[] | null>>,
15
+ > {
16
+ resolve: GraphQLFieldResolver<TSource, TContext, TArgs, TResult>
17
+ }
18
+
19
+ export type ResolvedEntryData<T> = T | Array<ResolvedEntryData<T>>
@@ -0,0 +1,46 @@
1
+ import { GraphQLFieldResolver } from 'graphql/type/definition'
2
+ import { EntryData } from '@commitspark/git-adapter'
3
+ import {
4
+ FieldResolver,
5
+ ResolvedEntryData,
6
+ FieldResolverContext,
7
+ } from './fieldResolver'
8
+ import { UnionTypeUtil } from '../schema-utils/union-type-util'
9
+
10
+ export class UnionValueResolver implements FieldResolver<any> {
11
+ resolve: GraphQLFieldResolver<
12
+ any,
13
+ FieldResolverContext,
14
+ any,
15
+ Promise<ResolvedEntryData<EntryData | EntryData[] | null>>
16
+ >
17
+
18
+ constructor(private readonly unionTypeUtil: UnionTypeUtil) {
19
+ this.resolve = (
20
+ fieldValue,
21
+ args,
22
+ context,
23
+ info,
24
+ ): Promise<ResolvedEntryData<EntryData | EntryData[] | null>> =>
25
+ this.resolveFieldValue(fieldValue)
26
+ }
27
+
28
+ private resolveFieldValue(
29
+ fieldValue: any,
30
+ ): Promise<ResolvedEntryData<EntryData | EntryData[] | null>> {
31
+ const typeName =
32
+ this.unionTypeUtil.getUnionTypeNameFromFieldValue(fieldValue)
33
+ const unionValue = this.unionTypeUtil.getUnionValue(fieldValue)
34
+
35
+ // We replace the helper type name field that holds our field's actual data
36
+ // with this actual data and add a `__typename` field, so that our output data
37
+ // corresponds to the output schema provided by the user (i.e. there is
38
+ // no additional nesting level there).
39
+ const res: EntryData = {
40
+ ...unionValue,
41
+ __typename: typeName,
42
+ }
43
+
44
+ return new Promise((resolve) => resolve(res))
45
+ }
46
+ }
@@ -13,10 +13,11 @@ import {
13
13
  isUnionType,
14
14
  } from 'graphql'
15
15
  import { ISchemaAnalyzerResult } from './schema-analyzer.service'
16
- import { EntryReferenceUtil } from './schema-utils/entry-reference-util'
16
+ import { EntryTypeUtil } from './schema-utils/entry-type-util'
17
+ import { isScalarType } from 'graphql/type/definition'
17
18
 
18
19
  export class InputTypeGeneratorService {
19
- constructor(private readonly entryReferenceUtil: EntryReferenceUtil) {}
20
+ constructor(private readonly entryTypeUtil: EntryTypeUtil) {}
20
21
 
21
22
  public generateFieldInputTypeString(type: GraphQLNullableType): string {
22
23
  if (isListType(type)) {
@@ -24,7 +25,7 @@ export class InputTypeGeneratorService {
24
25
  } else if (isNonNullType(type)) {
25
26
  return `${this.generateFieldInputTypeString(type.ofType)}!`
26
27
  } else if (isObjectType(type)) {
27
- if (this.entryReferenceUtil.hasEntryDirective(type)) {
28
+ if (this.entryTypeUtil.hasEntryDirective(type)) {
28
29
  return `${type.name}IdInput`
29
30
  } else {
30
31
  return `${type.name}Input`
@@ -33,7 +34,7 @@ export class InputTypeGeneratorService {
33
34
  // TODO
34
35
  return ''
35
36
  } else if (isUnionType(type)) {
36
- if (this.entryReferenceUtil.buildsOnTypeWithEntryDirective(type)) {
37
+ if (this.entryTypeUtil.buildsOnTypeWithEntryDirective(type)) {
37
38
  return `${type.name}IdInput`
38
39
  } else {
39
40
  return `${type.name}Input`
@@ -73,16 +74,29 @@ export class InputTypeGeneratorService {
73
74
  const name = objectType.name
74
75
  const inputTypeName = `${name}Input`
75
76
  let inputType = `input ${inputTypeName} {\n`
77
+ let inputTypeFieldStrings = ''
76
78
  for (const fieldsKey in objectType.getFields()) {
77
79
  const field = objectType.getFields()[fieldsKey]
78
- if (field.name === 'id') {
79
- // TODO check by type name `ID` (incl. non-null) instead of field name
80
+ if (
81
+ (isNonNullType(field.type) &&
82
+ isScalarType(field.type.ofType) &&
83
+ field.type.ofType.name === 'ID') ||
84
+ (isScalarType(field.type) && field.type.name === 'ID')
85
+ ) {
80
86
  continue
81
87
  }
82
88
  const inputTypeString = this.generateFieldInputTypeString(field.type)
83
- inputType += ` ${field.name}: ${inputTypeString}\n`
89
+ inputTypeFieldStrings += ` ${field.name}: ${inputTypeString}\n`
90
+ }
91
+
92
+ if (inputTypeFieldStrings.length > 0) {
93
+ inputType += `${inputTypeFieldStrings}`
94
+ } else {
95
+ // generate a dummy field as empty input types are not permitted
96
+ inputType += ' _: Boolean\n'
84
97
  }
85
98
  inputType += '}\n'
99
+
86
100
  return inputType
87
101
  })
88
102
  }
@@ -91,7 +105,7 @@ export class InputTypeGeneratorService {
91
105
  unionTypes: GraphQLUnionType[],
92
106
  ): string[] {
93
107
  const typeStrings = unionTypes.map((unionType): string => {
94
- if (this.entryReferenceUtil.buildsOnTypeWithEntryDirective(unionType)) {
108
+ if (this.entryTypeUtil.buildsOnTypeWithEntryDirective(unionType)) {
95
109
  return ''
96
110
  }
97
111
 
@@ -1,11 +1,11 @@
1
- import { Entry } from '../persistence/persistence.service'
1
+ import { EntryData } from '@commitspark/git-adapter'
2
2
  import { ApolloContext } from '../app/api.service'
3
3
  import { GraphQLFieldResolver } from 'graphql/type/definition'
4
4
  import { GraphQLObjectType } from 'graphql/type'
5
5
  import { QueryAllResolverGenerator } from './resolver-generators/query-all-resolver-generator'
6
6
  import { QueryByIdResolverGenerator } from './resolver-generators/query-by-id-resolver-generator'
7
7
  import { MutationCreateResolverGenerator } from './resolver-generators/mutation-create-resolver-generator'
8
- import { MutationUpdateResolverGenerator } from './resolver-generators/mutation-update.resolver-generator'
8
+ import { MutationUpdateResolverGenerator } from './resolver-generators/mutation-update-resolver-generator'
9
9
  import { MutationDeleteResolverGenerator } from './resolver-generators/mutation-delete-resolver-generator'
10
10
  import { QueryCountAllResolverGenerator } from './resolver-generators/query-count-all-resolver-generator'
11
11
  import { QueryTypeByIdResolverGenerator } from './resolver-generators/query-type-by-id-resolver-generator'
@@ -33,7 +33,7 @@ export class QueriesMutationsGeneratorService {
33
33
  any,
34
34
  ApolloContext,
35
35
  any,
36
- Promise<Entry[]>
36
+ Promise<EntryData[]>
37
37
  > = this.queryAllResolverGenerator.createResolver(typeName)
38
38
 
39
39
  const queryAllMetaName = `_${queryAllName}Meta`
@@ -51,7 +51,7 @@ export class QueriesMutationsGeneratorService {
51
51
  any,
52
52
  ApolloContext,
53
53
  any,
54
- Promise<Entry>
54
+ Promise<EntryData>
55
55
  > = this.queryByIdResolverGenerator.createResolver(typeName)
56
56
 
57
57
  const inputTypeName = `${typeName}Input`
@@ -61,7 +61,7 @@ export class QueriesMutationsGeneratorService {
61
61
  any,
62
62
  ApolloContext,
63
63
  any,
64
- Promise<Entry>
64
+ Promise<EntryData>
65
65
  > = this.mutationCreateResolverGenerator.createResolver(typeName)
66
66
 
67
67
  const updateMutationName = `update${typeName}`
@@ -70,7 +70,7 @@ export class QueriesMutationsGeneratorService {
70
70
  any,
71
71
  ApolloContext,
72
72
  any,
73
- Promise<Entry>
73
+ Promise<EntryData>
74
74
  > = this.mutationUpdateResolverGenerator.createResolver(typeName)
75
75
 
76
76
  const deleteMutationName = `delete${typeName}`
@@ -79,7 +79,7 @@ export class QueriesMutationsGeneratorService {
79
79
  any,
80
80
  ApolloContext,
81
81
  any,
82
- Promise<Entry>
82
+ Promise<EntryData>
83
83
  > = this.mutationDeleteResolverGenerator.createResolver(typeName)
84
84
 
85
85
  return {
@@ -118,9 +118,9 @@ export class QueriesMutationsGeneratorService {
118
118
  }
119
119
 
120
120
  public generateTypeNameQuery(): IGeneratedQuery<Promise<string>> {
121
- const contentTypeQueryName = '_typeName'
122
- const contentTypeQueryString = `${contentTypeQueryName}(id: ID!): String`
123
- const contentTypeQueryResolver: GraphQLFieldResolver<
121
+ const entryTypeQueryName = '_typeName'
122
+ const entryTypeQueryString = `${entryTypeQueryName}(id: ID!): String`
123
+ const entryTypeQueryResolver: GraphQLFieldResolver<
124
124
  any,
125
125
  ApolloContext,
126
126
  any,
@@ -128,20 +128,20 @@ export class QueriesMutationsGeneratorService {
128
128
  > = this.queryTypeByIdResolverGenerator.createResolver()
129
129
 
130
130
  return {
131
- name: contentTypeQueryName,
132
- schemaString: contentTypeQueryString,
133
- resolver: contentTypeQueryResolver,
131
+ name: entryTypeQueryName,
132
+ schemaString: entryTypeQueryString,
133
+ resolver: entryTypeQueryResolver,
134
134
  }
135
135
  }
136
136
  }
137
137
 
138
138
  export interface IGeneratedSchema {
139
- queryAll: IGeneratedQuery<Promise<Entry[]>>
139
+ queryAll: IGeneratedQuery<Promise<EntryData[]>>
140
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>>
141
+ queryById: IGeneratedQuery<Promise<EntryData>>
142
+ createMutation: IGeneratedQuery<Promise<EntryData>>
143
+ updateMutation: IGeneratedQuery<Promise<EntryData>>
144
+ deleteMutation: IGeneratedQuery<Promise<EntryData>>
145
145
  }
146
146
 
147
147
  export interface IGeneratedQuery<T> {
@@ -1,23 +1,47 @@
1
1
  import { GraphQLFieldResolver } from 'graphql/type/definition'
2
2
  import { ApolloContext } from '../../app/api.service'
3
- import {
4
- Entry,
5
- PersistenceService,
6
- } from '../../persistence/persistence.service'
3
+ import { PersistenceService } from '../../persistence/persistence.service'
7
4
  import { GraphQLError } from 'graphql/error/GraphQLError'
5
+ import { EntryReferenceUtil } from '../schema-utils/entry-reference-util'
6
+ import { isObjectType } from 'graphql'
7
+ import {
8
+ EntryDraft,
9
+ EntryData,
10
+ ENTRY_ID_INVALID_CHARACTERS,
11
+ } from '@commitspark/git-adapter'
8
12
 
9
13
  export class MutationCreateResolverGenerator {
10
- constructor(private readonly persistence: PersistenceService) {}
14
+ constructor(
15
+ private readonly persistence: PersistenceService,
16
+ private readonly entryReferenceUtil: EntryReferenceUtil,
17
+ ) {}
11
18
 
12
19
  public createResolver(
13
20
  typeName: string,
14
- ): GraphQLFieldResolver<any, ApolloContext, any, Promise<Entry>> {
21
+ ): GraphQLFieldResolver<any, ApolloContext, any, Promise<EntryData>> {
15
22
  return async (
16
23
  source,
17
24
  args,
18
25
  context: ApolloContext,
19
26
  info,
20
- ): Promise<Entry> => {
27
+ ): Promise<EntryData> => {
28
+ if (!isObjectType(info.returnType)) {
29
+ throw new Error('Expected to create an ObjectType')
30
+ }
31
+
32
+ const idValidationResult = args.id.match(ENTRY_ID_INVALID_CHARACTERS)
33
+ if (idValidationResult) {
34
+ throw new GraphQLError(
35
+ `"id" contains invalid characters "${idValidationResult.join(', ')}"`,
36
+ {
37
+ extensions: {
38
+ code: 'BAD_USER_INPUT',
39
+ argumentName: 'id',
40
+ },
41
+ },
42
+ )
43
+ }
44
+
21
45
  let existingEntry
22
46
  try {
23
47
  existingEntry = await this.persistence.findById(
@@ -35,23 +59,62 @@ export class MutationCreateResolverGenerator {
35
59
  })
36
60
  }
37
61
 
38
- // TODO validate ID references within args.data to assert referenced IDs exist and point to correct entry type
39
- const commitResult = await this.persistence.createType(
40
- context.gitAdapter,
41
- context.branch,
42
- context.getCurrentRef(),
43
- typeName,
44
- args.id,
45
- args.data,
46
- args.message,
47
- )
48
- context.setCurrentRef(commitResult.ref)
49
- return this.persistence.findByTypeId(
62
+ const referencedEntryIds =
63
+ await this.entryReferenceUtil.getReferencedEntryIds(
64
+ info.returnType,
65
+ context,
66
+ null,
67
+ info.returnType,
68
+ args.data,
69
+ )
70
+
71
+ const referencedEntryUpdates: EntryDraft[] = []
72
+ for (const referencedEntryId of referencedEntryIds) {
73
+ const referencedEntry = await this.persistence.findById(
74
+ context.gitAdapter,
75
+ context.getCurrentRef(),
76
+ referencedEntryId,
77
+ )
78
+ const newReferencedEntryIds: string[] = [
79
+ ...(referencedEntry.metadata.referencedBy ?? []),
80
+ args.id,
81
+ ].sort()
82
+ const newReferencedEntryDraft: EntryDraft = {
83
+ ...referencedEntry,
84
+ metadata: {
85
+ ...referencedEntry.metadata,
86
+ referencedBy: newReferencedEntryIds,
87
+ },
88
+ deletion: false,
89
+ }
90
+ referencedEntryUpdates.push(newReferencedEntryDraft)
91
+ }
92
+
93
+ const newEntryDraft: EntryDraft = {
94
+ id: args.id,
95
+ metadata: {
96
+ type: typeName,
97
+ referencedBy: [],
98
+ },
99
+ data: args.data,
100
+ deletion: false,
101
+ }
102
+
103
+ const commit = await context.gitAdapter.createCommit({
104
+ ref: context.branch,
105
+ parentSha: context.getCurrentRef(),
106
+ entries: [newEntryDraft, ...referencedEntryUpdates],
107
+ message: args.message,
108
+ })
109
+ context.setCurrentRef(commit.ref)
110
+
111
+ const newEntry = await this.persistence.findByTypeId(
50
112
  context.gitAdapter,
51
113
  context.getCurrentRef(),
52
114
  typeName,
53
115
  args.id,
54
116
  )
117
+ return { ...newEntry.data, id: newEntry.id }
55
118
  }
56
119
  }
57
120
  }