@commitspark/graphql-api 0.8.0 → 0.9.1
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/CHANGELOG.md +14 -0
- package/dist/app/api.service.js +1 -0
- package/dist/app/api.service.js.map +1 -1
- package/dist/graphql/input-type-generator.service.js +1 -1
- package/dist/graphql/input-type-generator.service.js.map +1 -1
- package/dist/graphql/queries-mutations-generator.service.js +1 -1
- package/dist/graphql/queries-mutations-generator.service.js.map +1 -1
- package/dist/graphql/resolver-generators/mutation-create-resolver-generator.js +17 -3
- package/dist/graphql/resolver-generators/mutation-create-resolver-generator.js.map +1 -1
- package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.js +12 -0
- package/dist/graphql/resolver-generators/mutation-delete-resolver-generator.js.map +1 -1
- package/dist/graphql/resolver-generators/mutation-update.resolver-generator.js +12 -0
- package/dist/graphql/resolver-generators/mutation-update.resolver-generator.js.map +1 -1
- package/dist/graphql/schema-generator.service.js +10 -9
- package/dist/graphql/schema-generator.service.js.map +1 -1
- package/dist/graphql/schema-root-type-generator.service.js +3 -1
- package/dist/graphql/schema-root-type-generator.service.js.map +1 -1
- package/dist/persistence/persistence.service.d.ts +6 -9
- package/dist/persistence/persistence.service.js +15 -11
- package/dist/persistence/persistence.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +16 -5
- package/src/app/api.service.ts +2 -0
- package/src/graphql/input-type-generator.service.ts +1 -1
- package/src/graphql/queries-mutations-generator.service.ts +1 -1
- package/src/graphql/resolver-generators/mutation-create-resolver-generator.ts +23 -4
- package/src/graphql/resolver-generators/mutation-delete-resolver-generator.ts +20 -0
- package/src/graphql/resolver-generators/mutation-update.resolver-generator.ts +20 -0
- package/src/graphql/schema-generator.service.ts +12 -9
- package/src/graphql/schema-root-type-generator.service.ts +3 -1
- package/src/persistence/persistence.service.ts +28 -25
- package/.eslintrc.js +0 -24
- package/.prettierrc +0 -6
- package/tsconfig.build.json +0 -10
- package/tsconfig.json +0 -18
- package/webpack.config.js +0 -25
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
Entry,
|
|
5
5
|
PersistenceService,
|
|
6
6
|
} from '../../persistence/persistence.service'
|
|
7
|
+
import { GraphQLError } from 'graphql/error/GraphQLError'
|
|
7
8
|
|
|
8
9
|
export class MutationCreateResolverGenerator {
|
|
9
10
|
constructor(private readonly persistence: PersistenceService) {}
|
|
@@ -17,21 +18,39 @@ export class MutationCreateResolverGenerator {
|
|
|
17
18
|
context: ApolloContext,
|
|
18
19
|
info,
|
|
19
20
|
): Promise<Entry> => {
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
let existingEntry
|
|
22
|
+
try {
|
|
23
|
+
existingEntry = await this.persistence.findById(
|
|
24
|
+
context.gitAdapter,
|
|
25
|
+
context.getCurrentRef(),
|
|
26
|
+
args.id,
|
|
27
|
+
)
|
|
28
|
+
} catch (_) {}
|
|
29
|
+
if (existingEntry) {
|
|
30
|
+
throw new GraphQLError(`An entry with id "${args.id}" already exists`, {
|
|
31
|
+
extensions: {
|
|
32
|
+
code: 'BAD_USER_INPUT',
|
|
33
|
+
argumentName: 'id',
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
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(
|
|
22
40
|
context.gitAdapter,
|
|
23
41
|
context.branch,
|
|
24
42
|
context.getCurrentRef(),
|
|
25
43
|
typeName,
|
|
44
|
+
args.id,
|
|
26
45
|
args.data,
|
|
27
46
|
args.message,
|
|
28
47
|
)
|
|
29
|
-
context.setCurrentRef(
|
|
48
|
+
context.setCurrentRef(commitResult.ref)
|
|
30
49
|
return this.persistence.findByTypeId(
|
|
31
50
|
context.gitAdapter,
|
|
32
51
|
context.getCurrentRef(),
|
|
33
52
|
typeName,
|
|
34
|
-
|
|
53
|
+
args.id,
|
|
35
54
|
)
|
|
36
55
|
}
|
|
37
56
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
} from '../../persistence/persistence.service'
|
|
5
5
|
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
6
6
|
import { ApolloContext } from '../../app/api.service'
|
|
7
|
+
import { GraphQLError } from 'graphql/error/GraphQLError'
|
|
7
8
|
|
|
8
9
|
export class MutationDeleteResolverGenerator {
|
|
9
10
|
constructor(private readonly persistence: PersistenceService) {}
|
|
@@ -17,6 +18,25 @@ export class MutationDeleteResolverGenerator {
|
|
|
17
18
|
context: ApolloContext,
|
|
18
19
|
info,
|
|
19
20
|
): Promise<Entry> => {
|
|
21
|
+
try {
|
|
22
|
+
await this.persistence.findByTypeId(
|
|
23
|
+
context.gitAdapter,
|
|
24
|
+
context.getCurrentRef(),
|
|
25
|
+
typeName,
|
|
26
|
+
args.id,
|
|
27
|
+
)
|
|
28
|
+
} catch (_) {
|
|
29
|
+
throw new GraphQLError(
|
|
30
|
+
`No entry of type "${typeName}" with id "${args.id}" exists`,
|
|
31
|
+
{
|
|
32
|
+
extensions: {
|
|
33
|
+
code: 'BAD_USER_INPUT',
|
|
34
|
+
argumentName: 'id',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
20
40
|
// TODO validate ID to delete is not referenced anywhere
|
|
21
41
|
const deleteResult = await this.persistence.deleteByTypeId(
|
|
22
42
|
context.gitAdapter,
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
} from '../../persistence/persistence.service'
|
|
5
5
|
import { GraphQLFieldResolver } from 'graphql/type/definition'
|
|
6
6
|
import { ApolloContext } from '../../app/api.service'
|
|
7
|
+
import { GraphQLError } from 'graphql/error/GraphQLError'
|
|
7
8
|
|
|
8
9
|
export class MutationUpdateResolverGenerator {
|
|
9
10
|
constructor(private readonly persistence: PersistenceService) {}
|
|
@@ -17,6 +18,25 @@ export class MutationUpdateResolverGenerator {
|
|
|
17
18
|
context: ApolloContext,
|
|
18
19
|
info,
|
|
19
20
|
): Promise<Entry> => {
|
|
21
|
+
try {
|
|
22
|
+
await this.persistence.findByTypeId(
|
|
23
|
+
context.gitAdapter,
|
|
24
|
+
context.getCurrentRef(),
|
|
25
|
+
typeName,
|
|
26
|
+
args.id,
|
|
27
|
+
)
|
|
28
|
+
} catch (_) {
|
|
29
|
+
throw new GraphQLError(
|
|
30
|
+
`No entry of type "${typeName}" with id "${args.id}" exists`,
|
|
31
|
+
{
|
|
32
|
+
extensions: {
|
|
33
|
+
code: 'BAD_USER_INPUT',
|
|
34
|
+
argumentName: 'id',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
20
40
|
// TODO validate ID references in payload to assert referenced ID exists and points to correct entry type
|
|
21
41
|
const updateResult = await this.persistence.updateByTypeId(
|
|
22
42
|
context.gitAdapter,
|
|
@@ -49,7 +49,8 @@ export class SchemaGeneratorService {
|
|
|
49
49
|
}
|
|
50
50
|
const schemaAnalyzerResult = this.schemaAnalyzer.analyzeSchema(schema)
|
|
51
51
|
|
|
52
|
-
const filteredOriginalSchemaString =
|
|
52
|
+
const filteredOriginalSchemaString =
|
|
53
|
+
printSchemaWithDirectives(schema) + '\n'
|
|
53
54
|
|
|
54
55
|
const generatedIdInputTypeStrings =
|
|
55
56
|
this.inputTypeGenerator.generateIdInputTypeStrings(schemaAnalyzerResult)
|
|
@@ -61,7 +62,7 @@ export class SchemaGeneratorService {
|
|
|
61
62
|
const generatedTypeNameQuery =
|
|
62
63
|
this.queriesMutationsGenerator.generateTypeNameQuery()
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
const generatedEntryReferenceResolvers: Record<
|
|
65
66
|
string,
|
|
66
67
|
Record<
|
|
67
68
|
string,
|
|
@@ -172,14 +173,16 @@ export class SchemaGeneratorService {
|
|
|
172
173
|
}
|
|
173
174
|
}
|
|
174
175
|
|
|
176
|
+
const typeDefs = [
|
|
177
|
+
filteredOriginalSchemaString,
|
|
178
|
+
generatedSchemaString,
|
|
179
|
+
generatedIdInputTypeStrings.join('\n'),
|
|
180
|
+
generatedObjectInputTypeStrings.join('\n'),
|
|
181
|
+
generatedUnionInputTypeStrings.join('\n'),
|
|
182
|
+
].filter((typeDef) => typeDef.length > 0)
|
|
183
|
+
|
|
175
184
|
return {
|
|
176
|
-
typeDefs:
|
|
177
|
-
filteredOriginalSchemaString,
|
|
178
|
-
generatedSchemaString,
|
|
179
|
-
generatedIdInputTypeStrings.join('\n'),
|
|
180
|
-
generatedObjectInputTypeStrings.join('\n'),
|
|
181
|
-
generatedUnionInputTypeStrings.join('\n'),
|
|
182
|
-
],
|
|
185
|
+
typeDefs: typeDefs,
|
|
183
186
|
resolvers: allGeneratedResolvers,
|
|
184
187
|
}
|
|
185
188
|
}
|
|
@@ -13,16 +13,18 @@ export class SchemaRootTypeGeneratorService {
|
|
|
13
13
|
generatedSchemas
|
|
14
14
|
.map((generated) => ' ' + generated.queryAll.schemaString)
|
|
15
15
|
.join('\n') +
|
|
16
|
+
'\n' +
|
|
16
17
|
generatedSchemas
|
|
17
18
|
.map((generated) => ' ' + generated.queryAllMeta.schemaString)
|
|
18
19
|
.join('\n') +
|
|
20
|
+
'\n' +
|
|
19
21
|
generatedSchemas
|
|
20
22
|
.map((generated) => ' ' + generated.queryById.schemaString)
|
|
21
23
|
.join('\n') +
|
|
22
24
|
'\n' +
|
|
23
25
|
` ${typeQuery.schemaString}` +
|
|
24
26
|
'\n' +
|
|
25
|
-
'}\n' +
|
|
27
|
+
'}\n\n' +
|
|
26
28
|
'type Mutation {\n' +
|
|
27
29
|
generatedSchemas
|
|
28
30
|
.map((generated) => ' ' + generated.createMutation.schemaString)
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import { v4 as uuidv4 } from 'uuid'
|
|
2
1
|
import { ContentEntry, GitAdapter } from '@commitspark/git-adapter'
|
|
2
|
+
import { GraphQLError } from 'graphql/error/GraphQLError'
|
|
3
3
|
|
|
4
4
|
export class PersistenceService {
|
|
5
|
-
constructor() {}
|
|
6
|
-
|
|
7
5
|
public async getTypeById(
|
|
8
6
|
gitAdapter: GitAdapter,
|
|
9
7
|
commitHash: string,
|
|
10
|
-
id:
|
|
8
|
+
id: string,
|
|
11
9
|
): Promise<string> {
|
|
12
10
|
const allEntries = await gitAdapter.getContentEntries(commitHash)
|
|
13
11
|
const requestedEntry = allEntries.filter(
|
|
14
|
-
(contentEntry: ContentEntry) => contentEntry.id ===
|
|
12
|
+
(contentEntry: ContentEntry) => contentEntry.id === id,
|
|
15
13
|
)[0]
|
|
16
14
|
if (requestedEntry === undefined) {
|
|
17
15
|
throw new Error(`Not found: ${id}`)
|
|
@@ -23,11 +21,11 @@ export class PersistenceService {
|
|
|
23
21
|
public async findById(
|
|
24
22
|
gitAdapter: GitAdapter,
|
|
25
23
|
commitHash: string,
|
|
26
|
-
id:
|
|
24
|
+
id: string,
|
|
27
25
|
): Promise<Entry> {
|
|
28
26
|
const allEntries = await gitAdapter.getContentEntries(commitHash)
|
|
29
27
|
const requestedEntry = allEntries.filter(
|
|
30
|
-
(contentEntry: ContentEntry) => contentEntry.id ===
|
|
28
|
+
(contentEntry: ContentEntry) => contentEntry.id === id,
|
|
31
29
|
)[0]
|
|
32
30
|
if (requestedEntry === undefined) {
|
|
33
31
|
throw new Error(`Not found: ${id}`)
|
|
@@ -53,11 +51,11 @@ export class PersistenceService {
|
|
|
53
51
|
gitAdapter: GitAdapter,
|
|
54
52
|
commitHash: string,
|
|
55
53
|
type: string,
|
|
56
|
-
id:
|
|
54
|
+
id: string,
|
|
57
55
|
): Promise<Entry> {
|
|
58
56
|
const allEntries = await gitAdapter.getContentEntries(commitHash)
|
|
59
57
|
const requestedEntry = allEntries.filter(
|
|
60
|
-
(contentEntry: ContentEntry) => contentEntry.id ===
|
|
58
|
+
(contentEntry: ContentEntry) => contentEntry.id === id,
|
|
61
59
|
)[0]
|
|
62
60
|
if (requestedEntry === undefined || requestedEntry.metadata.type !== type) {
|
|
63
61
|
throw new Error(`Not found: ${type}, ${id}`)
|
|
@@ -70,21 +68,32 @@ export class PersistenceService {
|
|
|
70
68
|
gitAdapter: GitAdapter,
|
|
71
69
|
branch: string,
|
|
72
70
|
commitHash: string,
|
|
73
|
-
|
|
71
|
+
typeName: string,
|
|
72
|
+
id: string,
|
|
74
73
|
data: Entry,
|
|
75
74
|
message: string,
|
|
76
75
|
): Promise<CommitResult> {
|
|
77
|
-
|
|
76
|
+
// TODO expose regex publicly to allow reuse
|
|
77
|
+
const regex = /^[a-zA-Z\-_]{1,250}$/
|
|
78
|
+
if (!id.match(regex)) {
|
|
79
|
+
throw new GraphQLError(`"id" does not match regex "${regex}"`, {
|
|
80
|
+
extensions: {
|
|
81
|
+
code: 'BAD_USER_INPUT',
|
|
82
|
+
argumentName: 'id',
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
78
87
|
const commit = await gitAdapter.createCommit({
|
|
79
88
|
ref: branch,
|
|
80
89
|
parentSha: commitHash,
|
|
81
90
|
contentEntries: [
|
|
82
91
|
{
|
|
83
92
|
id: id,
|
|
84
|
-
data: data,
|
|
85
93
|
metadata: {
|
|
86
|
-
type:
|
|
94
|
+
type: typeName,
|
|
87
95
|
},
|
|
96
|
+
data: data,
|
|
88
97
|
deletion: false,
|
|
89
98
|
},
|
|
90
99
|
],
|
|
@@ -92,7 +101,6 @@ export class PersistenceService {
|
|
|
92
101
|
})
|
|
93
102
|
|
|
94
103
|
return {
|
|
95
|
-
id,
|
|
96
104
|
ref: commit.ref,
|
|
97
105
|
}
|
|
98
106
|
}
|
|
@@ -102,13 +110,13 @@ export class PersistenceService {
|
|
|
102
110
|
branch: string,
|
|
103
111
|
commitHash: string,
|
|
104
112
|
type: string,
|
|
105
|
-
id:
|
|
113
|
+
id: string,
|
|
106
114
|
data: Entry,
|
|
107
115
|
message: string,
|
|
108
116
|
): Promise<CommitResult> {
|
|
109
117
|
const allEntries = await gitAdapter.getContentEntries(commitHash)
|
|
110
118
|
const requestedEntry = allEntries.filter(
|
|
111
|
-
(contentEntry: ContentEntry) => contentEntry.id ===
|
|
119
|
+
(contentEntry: ContentEntry) => contentEntry.id === id,
|
|
112
120
|
)[0]
|
|
113
121
|
if (requestedEntry === undefined || requestedEntry.metadata.type !== type) {
|
|
114
122
|
throw new Error(`Not found: ${type}, ${id}`)
|
|
@@ -122,8 +130,8 @@ export class PersistenceService {
|
|
|
122
130
|
contentEntries: [
|
|
123
131
|
{
|
|
124
132
|
id: id,
|
|
125
|
-
data: newData,
|
|
126
133
|
metadata: requestedEntry.metadata,
|
|
134
|
+
data: newData,
|
|
127
135
|
deletion: false,
|
|
128
136
|
},
|
|
129
137
|
],
|
|
@@ -131,7 +139,6 @@ export class PersistenceService {
|
|
|
131
139
|
})
|
|
132
140
|
|
|
133
141
|
return {
|
|
134
|
-
id,
|
|
135
142
|
ref: commit.ref,
|
|
136
143
|
}
|
|
137
144
|
}
|
|
@@ -141,12 +148,12 @@ export class PersistenceService {
|
|
|
141
148
|
branch: string,
|
|
142
149
|
commitHash: string,
|
|
143
150
|
type: string,
|
|
144
|
-
id:
|
|
151
|
+
id: string,
|
|
145
152
|
message: string,
|
|
146
153
|
): Promise<CommitResult> {
|
|
147
154
|
const allEntries = await gitAdapter.getContentEntries(commitHash)
|
|
148
155
|
const requestedEntry = allEntries.filter(
|
|
149
|
-
(contentEntry: ContentEntry) => contentEntry.id ===
|
|
156
|
+
(contentEntry: ContentEntry) => contentEntry.id === id,
|
|
150
157
|
)[0]
|
|
151
158
|
if (requestedEntry === undefined || requestedEntry.metadata.type !== type) {
|
|
152
159
|
throw new Error(`Not found: ${type}, ${id}`)
|
|
@@ -158,8 +165,8 @@ export class PersistenceService {
|
|
|
158
165
|
contentEntries: [
|
|
159
166
|
{
|
|
160
167
|
id: id,
|
|
161
|
-
data: {},
|
|
162
168
|
metadata: requestedEntry.metadata,
|
|
169
|
+
data: {},
|
|
163
170
|
deletion: true,
|
|
164
171
|
},
|
|
165
172
|
],
|
|
@@ -167,17 +174,13 @@ export class PersistenceService {
|
|
|
167
174
|
})
|
|
168
175
|
|
|
169
176
|
return {
|
|
170
|
-
id,
|
|
171
177
|
ref: commit.ref,
|
|
172
178
|
}
|
|
173
179
|
}
|
|
174
180
|
}
|
|
175
181
|
|
|
176
182
|
export interface CommitResult {
|
|
177
|
-
id: ID
|
|
178
183
|
ref: string // commit sha
|
|
179
184
|
}
|
|
180
185
|
|
|
181
|
-
export type ID = string
|
|
182
|
-
|
|
183
186
|
export type Entry = Record<string, unknown>
|
package/.eslintrc.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
parser: '@typescript-eslint/parser',
|
|
3
|
-
parserOptions: {
|
|
4
|
-
project: 'tsconfig.json',
|
|
5
|
-
sourceType: 'module',
|
|
6
|
-
},
|
|
7
|
-
plugins: ['@typescript-eslint/eslint-plugin'],
|
|
8
|
-
extends: [
|
|
9
|
-
'plugin:@typescript-eslint/recommended',
|
|
10
|
-
'plugin:prettier/recommended',
|
|
11
|
-
],
|
|
12
|
-
root: true,
|
|
13
|
-
env: {
|
|
14
|
-
node: true,
|
|
15
|
-
jest: true,
|
|
16
|
-
},
|
|
17
|
-
ignorePatterns: ['.eslintrc.js'],
|
|
18
|
-
rules: {
|
|
19
|
-
'@typescript-eslint/interface-name-prefix': 'off',
|
|
20
|
-
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
21
|
-
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
22
|
-
'@typescript-eslint/no-explicit-any': 'off',
|
|
23
|
-
},
|
|
24
|
-
};
|
package/.prettierrc
DELETED
package/tsconfig.build.json
DELETED
package/tsconfig.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"module": "commonjs",
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"removeComments": true,
|
|
6
|
-
"emitDecoratorMetadata": true,
|
|
7
|
-
"experimentalDecorators": true,
|
|
8
|
-
"allowSyntheticDefaultImports": true,
|
|
9
|
-
"target": "es2017",
|
|
10
|
-
"sourceMap": true,
|
|
11
|
-
"outDir": "./dist",
|
|
12
|
-
"baseUrl": "./",
|
|
13
|
-
"incremental": true,
|
|
14
|
-
"skipLibCheck": true,
|
|
15
|
-
"esModuleInterop": true,
|
|
16
|
-
"strict": true
|
|
17
|
-
}
|
|
18
|
-
}
|
package/webpack.config.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
const path = require('node:path')
|
|
2
|
-
module.exports = (options, webpack) => {
|
|
3
|
-
return {
|
|
4
|
-
...options,
|
|
5
|
-
devtool: 'source-map', // create source map for debugging
|
|
6
|
-
externals: [],
|
|
7
|
-
entry: {
|
|
8
|
-
main: './src/index.ts',
|
|
9
|
-
},
|
|
10
|
-
output: {
|
|
11
|
-
...options.output,
|
|
12
|
-
libraryTarget: 'commonjs2',
|
|
13
|
-
},
|
|
14
|
-
plugins: [
|
|
15
|
-
...options.plugins,
|
|
16
|
-
],
|
|
17
|
-
resolve: {
|
|
18
|
-
// @see https://github.com/apollographql/apollo-server/issues/4983
|
|
19
|
-
extensions: ['.ts', '.js'],
|
|
20
|
-
alias: {
|
|
21
|
-
graphql$: path.resolve(__dirname, 'node_modules/graphql/index.js'),
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
}
|
|
25
|
-
}
|