@commitspark/graphql-api 0.9.4 → 0.10.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 (89) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/container.js +21 -13
  3. package/dist/container.js.map +1 -1
  4. package/dist/graphql/field-resolver/entry-reference-resolver.d.ts +9 -0
  5. package/dist/graphql/field-resolver/entry-reference-resolver.js +15 -0
  6. package/dist/graphql/field-resolver/entry-reference-resolver.js.map +1 -0
  7. package/dist/graphql/field-resolver/field-default-value-resolver.d.ts +14 -0
  8. package/dist/graphql/field-resolver/field-default-value-resolver.js +73 -0
  9. package/dist/graphql/field-resolver/field-default-value-resolver.js.map +1 -0
  10. package/dist/graphql/field-resolver/fieldResolver.d.ts +11 -0
  11. package/dist/graphql/field-resolver/fieldResolver.js +3 -0
  12. package/dist/graphql/field-resolver/fieldResolver.js.map +1 -0
  13. package/dist/graphql/field-resolver/union-value-resolver.d.ts +10 -0
  14. package/dist/graphql/field-resolver/union-value-resolver.js +17 -0
  15. package/dist/graphql/field-resolver/union-value-resolver.js.map +1 -0
  16. package/dist/graphql/input-type-generator.service.d.ts +3 -3
  17. package/dist/graphql/input-type-generator.service.js +18 -7
  18. package/dist/graphql/input-type-generator.service.js.map +1 -1
  19. package/dist/graphql/queries-mutations-generator.service.d.ts +1 -1
  20. package/dist/graphql/resolver-generators/mutation-create-resolver-generator.d.ts +3 -1
  21. package/dist/graphql/resolver-generators/mutation-create-resolver-generator.js +46 -4
  22. package/dist/graphql/resolver-generators/mutation-create-resolver-generator.js.map +1 -1
  23. package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.d.ts +3 -1
  24. package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.js +32 -9
  25. package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.js.map +1 -1
  26. package/dist/graphql/resolver-generators/{mutation-update.resolver-generator.d.ts → mutation-update-resolver-generator.d.ts} +4 -1
  27. package/dist/graphql/resolver-generators/mutation-update-resolver-generator.js +53 -0
  28. package/dist/graphql/resolver-generators/mutation-update-resolver-generator.js.map +1 -0
  29. package/dist/graphql/resolver-generators/object-type-field-default-value-resolver-generator.d.ts +13 -0
  30. package/dist/graphql/resolver-generators/object-type-field-default-value-resolver-generator.js +58 -0
  31. package/dist/graphql/resolver-generators/object-type-field-default-value-resolver-generator.js.map +1 -0
  32. package/dist/graphql/resolver-generators/query-all-resolver-generator.js +4 -1
  33. package/dist/graphql/resolver-generators/query-all-resolver-generator.js.map +1 -1
  34. package/dist/graphql/resolver-generators/query-by-id-resolver-generator.js +2 -1
  35. package/dist/graphql/resolver-generators/query-by-id-resolver-generator.js.map +1 -1
  36. package/dist/graphql/resolver-generators/union-type-resolver-generator.d.ts +4 -4
  37. package/dist/graphql/resolver-generators/union-type-resolver-generator.js +3 -3
  38. package/dist/graphql/resolver-generators/union-type-resolver-generator.js.map +1 -1
  39. package/dist/graphql/schema-analyzer.service.d.ts +1 -9
  40. package/dist/graphql/schema-analyzer.service.js +6 -17
  41. package/dist/graphql/schema-analyzer.service.js.map +1 -1
  42. package/dist/graphql/schema-generator.service.d.ts +3 -5
  43. package/dist/graphql/schema-generator.service.js +7 -12
  44. package/dist/graphql/schema-generator.service.js.map +1 -1
  45. package/dist/graphql/schema-utils/entry-reference-util.d.ts +12 -4
  46. package/dist/graphql/schema-utils/entry-reference-util.js +105 -21
  47. package/dist/graphql/schema-utils/entry-reference-util.js.map +1 -1
  48. package/dist/graphql/schema-utils/entry-type-util.d.ts +6 -0
  49. package/dist/graphql/schema-utils/entry-type-util.js +34 -0
  50. package/dist/graphql/schema-utils/entry-type-util.js.map +1 -0
  51. package/dist/graphql/schema-utils/union-type-util.d.ts +5 -0
  52. package/dist/graphql/schema-utils/union-type-util.js +21 -0
  53. package/dist/graphql/schema-utils/union-type-util.js.map +1 -0
  54. package/dist/persistence/persistence.service.d.ts +4 -7
  55. package/dist/persistence/persistence.service.js +18 -83
  56. package/dist/persistence/persistence.service.js.map +1 -1
  57. package/dist/tsconfig.build.tsbuildinfo +1 -1
  58. package/package.json +2 -2
  59. package/src/container.ts +29 -15
  60. package/src/graphql/field-resolver/entry-reference-resolver.ts +49 -0
  61. package/src/graphql/field-resolver/field-default-value-resolver.ts +154 -0
  62. package/src/graphql/field-resolver/fieldResolver.ts +19 -0
  63. package/src/graphql/field-resolver/union-value-resolver.ts +46 -0
  64. package/src/graphql/input-type-generator.service.ts +22 -8
  65. package/src/graphql/queries-mutations-generator.service.ts +1 -1
  66. package/src/graphql/resolver-generators/mutation-create-resolver-generator.ts +78 -13
  67. package/src/graphql/resolver-generators/mutation-delete-resolver-generator.ts +69 -21
  68. package/src/graphql/resolver-generators/mutation-update-resolver-generator.ts +131 -0
  69. package/src/graphql/resolver-generators/object-type-field-default-value-resolver-generator.ts +119 -0
  70. package/src/graphql/resolver-generators/query-all-resolver-generator.ts +5 -1
  71. package/src/graphql/resolver-generators/query-by-id-resolver-generator.ts +3 -1
  72. package/src/graphql/resolver-generators/union-type-resolver-generator.ts +5 -7
  73. package/src/graphql/schema-analyzer.service.ts +10 -24
  74. package/src/graphql/schema-generator.service.ts +11 -20
  75. package/src/graphql/schema-utils/entry-reference-util.ts +170 -30
  76. package/src/graphql/schema-utils/entry-type-util.ts +42 -0
  77. package/src/graphql/schema-utils/union-type-util.ts +23 -0
  78. package/src/persistence/persistence.service.ts +33 -132
  79. package/dist/graphql/resolver-generators/entry-reference-resolver.generator.d.ts +0 -12
  80. package/dist/graphql/resolver-generators/entry-reference-resolver.generator.js +0 -29
  81. package/dist/graphql/resolver-generators/entry-reference-resolver.generator.js.map +0 -1
  82. package/dist/graphql/resolver-generators/mutation-update.resolver-generator.js +0 -29
  83. package/dist/graphql/resolver-generators/mutation-update.resolver-generator.js.map +0 -1
  84. package/dist/graphql/resolver-generators/union-value-resolver-generator.d.ts +0 -13
  85. package/dist/graphql/resolver-generators/union-value-resolver-generator.js +0 -80
  86. package/dist/graphql/resolver-generators/union-value-resolver-generator.js.map +0 -1
  87. package/src/graphql/resolver-generators/entry-reference-resolver.generator.ts +0 -71
  88. package/src/graphql/resolver-generators/mutation-update.resolver-generator.ts +0 -59
  89. 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,49 @@
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 {
12
+ Entry,
13
+ PersistenceService,
14
+ } from '../../persistence/persistence.service'
15
+
16
+ export class EntryReferenceResolver implements FieldResolver<any> {
17
+ resolve: GraphQLFieldResolver<
18
+ any,
19
+ FieldResolverContext,
20
+ any,
21
+ Promise<ResolvedEntryData<Entry | Entry[] | null>>
22
+ >
23
+
24
+ constructor(private readonly persistence: PersistenceService) {
25
+ this.resolve = (
26
+ fieldValue,
27
+ args: any,
28
+ context: FieldResolverContext,
29
+ info,
30
+ ): Promise<ResolvedEntryData<Entry | Entry[] | null>> =>
31
+ this.resolveFieldValue(fieldValue, args, context, info, info.returnType)
32
+ }
33
+
34
+ private async resolveFieldValue(
35
+ fieldValue: any,
36
+ args: any,
37
+ context: FieldResolverContext,
38
+ info: GraphQLResolveInfo,
39
+ currentType: GraphQLOutputType,
40
+ ): Promise<ResolvedEntryData<Entry | Entry[] | null>> {
41
+ const entry = await this.persistence.findById(
42
+ context.gitAdapter,
43
+ context.getCurrentRef(),
44
+ fieldValue.id,
45
+ )
46
+
47
+ return { ...entry.data, id: entry.id }
48
+ }
49
+ }
@@ -0,0 +1,154 @@
1
+ import {
2
+ FieldResolver,
3
+ ResolvedEntryData,
4
+ FieldResolverContext,
5
+ } from './fieldResolver'
6
+ import { Entry } from '../../persistence/persistence.service'
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<Entry | Entry[] | 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<Entry | Entry[] | 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<Entry | Entry[] | 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 { Entry } from '../../persistence/persistence.service'
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<Entry | Entry[] | 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 { Entry } from '../../persistence/persistence.service'
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<Entry | Entry[] | null>>
16
+ >
17
+
18
+ constructor(private readonly unionTypeUtil: UnionTypeUtil) {
19
+ this.resolve = (
20
+ fieldValue,
21
+ args,
22
+ context,
23
+ info,
24
+ ): Promise<ResolvedEntryData<Entry | Entry[] | null>> =>
25
+ this.resolveFieldValue(fieldValue)
26
+ }
27
+
28
+ private resolveFieldValue(
29
+ fieldValue: any,
30
+ ): Promise<ResolvedEntryData<Entry | Entry[] | 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: Entry = {
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
 
@@ -5,7 +5,7 @@ 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'
@@ -5,9 +5,18 @@ import {
5
5
  PersistenceService,
6
6
  } from '../../persistence/persistence.service'
7
7
  import { GraphQLError } from 'graphql/error/GraphQLError'
8
+ import { EntryReferenceUtil } from '../schema-utils/entry-reference-util'
9
+ import { isObjectType } from 'graphql'
10
+ import {
11
+ ContentEntryDraft,
12
+ ENTRY_ID_INVALID_CHARACTERS,
13
+ } from '@commitspark/git-adapter'
8
14
 
9
15
  export class MutationCreateResolverGenerator {
10
- constructor(private readonly persistence: PersistenceService) {}
16
+ constructor(
17
+ private readonly persistence: PersistenceService,
18
+ private readonly entryReferenceUtil: EntryReferenceUtil,
19
+ ) {}
11
20
 
12
21
  public createResolver(
13
22
  typeName: string,
@@ -18,6 +27,23 @@ export class MutationCreateResolverGenerator {
18
27
  context: ApolloContext,
19
28
  info,
20
29
  ): Promise<Entry> => {
30
+ if (!isObjectType(info.returnType)) {
31
+ throw new Error('Expected to create an ObjectType')
32
+ }
33
+
34
+ const idValidationResult = args.id.match(ENTRY_ID_INVALID_CHARACTERS)
35
+ if (idValidationResult) {
36
+ throw new GraphQLError(
37
+ `"id" contains invalid characters "${idValidationResult.join(', ')}"`,
38
+ {
39
+ extensions: {
40
+ code: 'BAD_USER_INPUT',
41
+ argumentName: 'id',
42
+ },
43
+ },
44
+ )
45
+ }
46
+
21
47
  let existingEntry
22
48
  try {
23
49
  existingEntry = await this.persistence.findById(
@@ -35,23 +61,62 @@ export class MutationCreateResolverGenerator {
35
61
  })
36
62
  }
37
63
 
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(
64
+ const referencedEntryIds =
65
+ await this.entryReferenceUtil.getReferencedEntryIds(
66
+ info.returnType,
67
+ context,
68
+ null,
69
+ info.returnType,
70
+ args.data,
71
+ )
72
+
73
+ const referencedEntryUpdates: ContentEntryDraft[] = []
74
+ for (const referencedEntryId of referencedEntryIds) {
75
+ const referencedEntry = await this.persistence.findById(
76
+ context.gitAdapter,
77
+ context.getCurrentRef(),
78
+ referencedEntryId,
79
+ )
80
+ const newReferencedEntryIds: string[] = [
81
+ ...(referencedEntry.metadata.referencedBy ?? []),
82
+ args.id,
83
+ ].sort()
84
+ const newReferencedEntryDraft: ContentEntryDraft = {
85
+ ...referencedEntry,
86
+ metadata: {
87
+ ...referencedEntry.metadata,
88
+ referencedBy: newReferencedEntryIds,
89
+ },
90
+ deletion: false,
91
+ }
92
+ referencedEntryUpdates.push(newReferencedEntryDraft)
93
+ }
94
+
95
+ const newEntryDraft: ContentEntryDraft = {
96
+ id: args.id,
97
+ metadata: {
98
+ type: typeName,
99
+ referencedBy: [],
100
+ },
101
+ data: args.data,
102
+ deletion: false,
103
+ }
104
+
105
+ const commit = await context.gitAdapter.createCommit({
106
+ ref: context.branch,
107
+ parentSha: context.getCurrentRef(),
108
+ contentEntries: [newEntryDraft, ...referencedEntryUpdates],
109
+ message: args.message,
110
+ })
111
+ context.setCurrentRef(commit.ref)
112
+
113
+ const newEntry = await this.persistence.findByTypeId(
50
114
  context.gitAdapter,
51
115
  context.getCurrentRef(),
52
116
  typeName,
53
117
  args.id,
54
118
  )
119
+ return { ...newEntry.data, id: newEntry.id }
55
120
  }
56
121
  }
57
122
  }
@@ -5,9 +5,15 @@ import {
5
5
  import { GraphQLFieldResolver } from 'graphql/type/definition'
6
6
  import { ApolloContext } from '../../app/api.service'
7
7
  import { GraphQLError } from 'graphql/error/GraphQLError'
8
+ import { ContentEntry, ContentEntryDraft } from '@commitspark/git-adapter'
9
+ import { EntryReferenceUtil } from '../schema-utils/entry-reference-util'
10
+ import { isObjectType } from 'graphql'
8
11
 
9
12
  export class MutationDeleteResolverGenerator {
10
- constructor(private readonly persistence: PersistenceService) {}
13
+ constructor(
14
+ private readonly persistence: PersistenceService,
15
+ private readonly entryReferenceUtil: EntryReferenceUtil,
16
+ ) {}
11
17
 
12
18
  public createResolver(
13
19
  typeName: string,
@@ -18,35 +24,77 @@ export class MutationDeleteResolverGenerator {
18
24
  context: ApolloContext,
19
25
  info,
20
26
  ): Promise<Entry> => {
21
- try {
22
- await this.persistence.findByTypeId(
23
- context.gitAdapter,
24
- context.getCurrentRef(),
25
- typeName,
26
- args.id,
27
- )
28
- } catch (_) {
27
+ const entry: ContentEntry = await this.persistence.findByTypeId(
28
+ context.gitAdapter,
29
+ context.getCurrentRef(),
30
+ typeName,
31
+ args.id,
32
+ )
33
+
34
+ if (
35
+ entry.metadata.referencedBy &&
36
+ entry.metadata.referencedBy.length > 0
37
+ ) {
38
+ const otherIds = entry.metadata.referencedBy
39
+ .map((referenceId) => `"${referenceId}"`)
40
+ .join(', ')
29
41
  throw new GraphQLError(
30
- `No entry of type "${typeName}" with id "${args.id}" exists`,
42
+ `Entry with id "${args.id}" is referenced by other entries: [${otherIds}]`,
31
43
  {
32
44
  extensions: {
33
- code: 'BAD_USER_INPUT',
45
+ code: 'IN_USE',
34
46
  argumentName: 'id',
35
47
  },
36
48
  },
37
49
  )
38
50
  }
39
51
 
40
- // TODO validate ID to delete is not referenced anywhere
41
- const deleteResult = await this.persistence.deleteByTypeId(
42
- context.gitAdapter,
43
- context.branch,
44
- context.getCurrentRef(),
45
- typeName,
46
- args.id,
47
- args.message,
48
- )
49
- context.setCurrentRef(deleteResult.ref)
52
+ const entryType = info.schema.getType(typeName)
53
+ if (!isObjectType(entryType)) {
54
+ throw new Error('Expected to delete an ObjectType')
55
+ }
56
+
57
+ const referencedEntryIds =
58
+ await this.entryReferenceUtil.getReferencedEntryIds(
59
+ entryType,
60
+ context,
61
+ null,
62
+ entryType,
63
+ entry.data,
64
+ )
65
+ const referencedEntryUpdates: ContentEntryDraft[] = []
66
+ for (const referencedEntryId of referencedEntryIds) {
67
+ const noLongerReferencedEntry = await this.persistence.findById(
68
+ context.gitAdapter,
69
+ context.getCurrentRef(),
70
+ referencedEntryId,
71
+ )
72
+ referencedEntryUpdates.push({
73
+ ...noLongerReferencedEntry,
74
+ metadata: {
75
+ ...noLongerReferencedEntry.metadata,
76
+ referencedBy: noLongerReferencedEntry.metadata.referencedBy?.filter(
77
+ (entryId) => entryId !== args.id,
78
+ ),
79
+ },
80
+ deletion: false,
81
+ })
82
+ }
83
+
84
+ const commit = await context.gitAdapter.createCommit({
85
+ ref: context.branch,
86
+ parentSha: context.getCurrentRef(),
87
+ contentEntries: [
88
+ {
89
+ ...entry,
90
+ deletion: true,
91
+ },
92
+ ...referencedEntryUpdates,
93
+ ],
94
+ message: args.message,
95
+ })
96
+ context.setCurrentRef(commit.ref)
97
+
50
98
  return {
51
99
  id: args.id,
52
100
  }