@contember/client-content 1.3.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/types/ContentClient.d.ts +18 -0
- package/dist/types/ContentClient.d.ts.map +1 -0
- package/dist/types/ContentQueryBuilder.d.ts +25 -0
- package/dist/types/ContentQueryBuilder.d.ts.map +1 -0
- package/dist/types/TypedContentQueryBuilder.d.ts +21 -0
- package/dist/types/TypedContentQueryBuilder.d.ts.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/nodes/ContentEntitySelection.d.ts +51 -0
- package/dist/types/nodes/ContentEntitySelection.d.ts.map +1 -0
- package/dist/types/nodes/ContentOperation.d.ts +30 -0
- package/dist/types/nodes/ContentOperation.d.ts.map +1 -0
- package/dist/types/nodes/TypedEntitySelection.d.ts +42 -0
- package/dist/types/nodes/TypedEntitySelection.d.ts.map +1 -0
- package/dist/types/nodes/index.d.ts +4 -0
- package/dist/types/nodes/index.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/dist/types/types/Input.d.ts +141 -0
- package/dist/types/types/Input.d.ts.map +1 -0
- package/dist/types/types/Result.d.ts +39 -0
- package/dist/types/types/Result.d.ts.map +1 -0
- package/dist/types/types/Schema.d.ts +43 -0
- package/dist/types/types/Schema.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +4 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/utils/ContentOperationSet.d.ts +13 -0
- package/dist/types/utils/ContentOperationSet.d.ts.map +1 -0
- package/dist/types/utils/createListArgs.d.ts +9 -0
- package/dist/types/utils/createListArgs.d.ts.map +1 -0
- package/dist/types/utils/createMutationOperationSet.d.ts +4 -0
- package/dist/types/utils/createMutationOperationSet.d.ts.map +1 -0
- package/dist/types/utils/createQueryOperationSet.d.ts +4 -0
- package/dist/types/utils/createQueryOperationSet.d.ts.map +1 -0
- package/dist/types/utils/createTypedArgs.d.ts +3 -0
- package/dist/types/utils/createTypedArgs.d.ts.map +1 -0
- package/dist/types/utils/mutationFragments.d.ts +3 -0
- package/dist/types/utils/mutationFragments.d.ts.map +1 -0
- package/package.json +48 -0
- package/src/ContentClient.ts +42 -0
- package/src/ContentQueryBuilder.ts +200 -0
- package/src/TypedContentQueryBuilder.ts +76 -0
- package/src/index.ts +5 -0
- package/src/nodes/ContentEntitySelection.ts +240 -0
- package/src/nodes/ContentOperation.ts +23 -0
- package/src/nodes/TypedEntitySelection.ts +107 -0
- package/src/nodes/index.ts +3 -0
- package/src/tsconfig.json +14 -0
- package/src/types/Input.ts +213 -0
- package/src/types/Result.ts +43 -0
- package/src/types/Schema.ts +49 -0
- package/src/types/index.ts +3 -0
- package/src/utils/ContentOperationSet.ts +11 -0
- package/src/utils/createListArgs.ts +23 -0
- package/src/utils/createMutationOperationSet.ts +42 -0
- package/src/utils/createQueryOperationSet.ts +20 -0
- package/src/utils/createTypedArgs.ts +15 -0
- package/src/utils/mutationFragments.ts +52 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SchemaEntityNames } from '../types';
|
|
2
|
+
import { GraphQlFieldTypedArgs } from '@contember/graphql-builder';
|
|
3
|
+
export declare const createListArgs: (entity: SchemaEntityNames<string>, args: {
|
|
4
|
+
filter?: any;
|
|
5
|
+
orderBy?: any;
|
|
6
|
+
limit?: number;
|
|
7
|
+
offset?: number;
|
|
8
|
+
}, type?: 'list' | 'paginate') => GraphQlFieldTypedArgs;
|
|
9
|
+
//# sourceMappingURL=createListArgs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createListArgs.d.ts","sourceRoot":"","sources":["../../../src/utils/createListArgs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAElE,eAAO,MAAM,cAAc,WAAY,kBAAkB,MAAM,CAAC,QAAQ;IAAE,MAAM,CAAC,EAAE,GAAG,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,SAAQ,MAAM,GAAG,UAAU,KAAY,qBAmB9K,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ContentMutation, ContentQuery } from '../nodes';
|
|
2
|
+
import { ContentOperationSet } from './ContentOperationSet';
|
|
3
|
+
export declare const createMutationOperationSet: (input: Record<string, ContentMutation<any> | ContentQuery<any>> | ContentMutation<any> | ContentMutation<any>[]) => ContentOperationSet<any>;
|
|
4
|
+
//# sourceMappingURL=createMutationOperationSet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createMutationOperationSet.d.ts","sourceRoot":"","sources":["../../../src/utils/createMutationOperationSet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAoB,YAAY,EAAE,MAAM,UAAU,CAAA;AAE1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAE3D,eAAO,MAAM,0BAA0B,UAEnC,OAAO,MAAM,EAAE,gBAAgB,GAAG,CAAC,GAAG,aAAa,GAAG,CAAC,CAAC,GACxD,gBAAgB,GAAG,CAAC,GACpB,gBAAgB,GAAG,CAAC,EAAE,KACvB,oBAAoB,GAAG,CAgCzB,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ContentQuery } from '../nodes';
|
|
2
|
+
import { ContentOperationSet } from './ContentOperationSet';
|
|
3
|
+
export declare const createQueryOperationSet: (input: Record<string, ContentQuery<any>> | ContentQuery<any>) => ContentOperationSet<any>;
|
|
4
|
+
//# sourceMappingURL=createQueryOperationSet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createQueryOperationSet.d.ts","sourceRoot":"","sources":["../../../src/utils/createQueryOperationSet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,YAAY,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAG3D,eAAO,MAAM,uBAAuB,UAC5B,OAAO,MAAM,EAAE,aAAa,GAAG,CAAC,CAAC,GAAG,aAAa,GAAG,CAAC,KAC1D,oBAAoB,GAAG,CAazB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createTypedArgs.d.ts","sourceRoot":"","sources":["../../../src/utils/createTypedArgs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAElE,eAAO,MAAM,eAAe,gGAGzB,qBASF,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutationFragments.d.ts","sourceRoot":"","sources":["../../../src/utils/mutationFragments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,eAAe,EAAgD,MAAM,4BAA4B,CAAA;AAExH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAiD7D,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@contember/client-content",
|
|
3
|
+
"license": "Apache-2.0",
|
|
4
|
+
"version": "1.3.0-alpha.2",
|
|
5
|
+
"main": "./dist/production/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": {
|
|
9
|
+
"types": "./dist/types/index.d.ts",
|
|
10
|
+
"development": "./dist/development/index.js",
|
|
11
|
+
"production": "./dist/production/index.js",
|
|
12
|
+
"default": "./dist/production/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/types/index.d.ts",
|
|
16
|
+
"development": "./dist/development/index.cjs",
|
|
17
|
+
"production": "./dist/production/index.cjs",
|
|
18
|
+
"default": "./dist/production/index.cjs"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist/",
|
|
24
|
+
"src/"
|
|
25
|
+
],
|
|
26
|
+
"typings": "./dist/types/index.d.ts",
|
|
27
|
+
"type": "module",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "yarn build:js:dev && yarn build:js:prod",
|
|
31
|
+
"build:js:dev": "NODE_ENV=development vite build --mode development",
|
|
32
|
+
"build:js:prod": "vite build --mode production",
|
|
33
|
+
"ae:build": "api-extractor run --local",
|
|
34
|
+
"ae:test": "api-extractor run",
|
|
35
|
+
"test": "vitest"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@contember/graphql-builder": "1.3.0-alpha.2",
|
|
39
|
+
"@contember/graphql-client": "1.3.0-alpha.2",
|
|
40
|
+
"@contember/schema": "^1.3.6"
|
|
41
|
+
},
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/contember/interface.git",
|
|
45
|
+
"directory": "packages/client-content"
|
|
46
|
+
},
|
|
47
|
+
"stableVersion": "0.0.0"
|
|
48
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { mutationFragments } from './utils/mutationFragments'
|
|
2
|
+
import { GraphQlClientRequestOptions } from '@contember/graphql-client'
|
|
3
|
+
import { GraphQlQueryPrinter } from '@contember/graphql-builder'
|
|
4
|
+
import { ContentMutation, ContentQuery } from './nodes'
|
|
5
|
+
import { createMutationOperationSet } from './utils/createMutationOperationSet'
|
|
6
|
+
import { createQueryOperationSet } from './utils/createQueryOperationSet'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export type QueryExecutorOptions = GraphQlClientRequestOptions
|
|
10
|
+
|
|
11
|
+
export type QueryExecutor = <T = unknown>(query: string, options: GraphQlClientRequestOptions) => Promise<T>
|
|
12
|
+
|
|
13
|
+
export class ContentClient {
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly executor: QueryExecutor,
|
|
16
|
+
) {
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
public async query<Value>(query: ContentQuery<Value>, options?: QueryExecutorOptions): Promise<Value>
|
|
21
|
+
public async query<Values extends Record<string, any>>(queries: {[K in keyof Values]: ContentQuery<Values[K]>}, options?: QueryExecutorOptions): Promise<Values>
|
|
22
|
+
public async query(queries: Record<string, ContentQuery<any>> | ContentQuery<any>, options?: QueryExecutorOptions): Promise<any> {
|
|
23
|
+
const printer = new GraphQlQueryPrinter()
|
|
24
|
+
const operationSet = createQueryOperationSet(queries)
|
|
25
|
+
const { query, variables } = printer.printDocument('query', operationSet.selection, {})
|
|
26
|
+
const result = await this.executor(query, { variables, ...options })
|
|
27
|
+
return operationSet.parse(result)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public async mutate<Value>(mutation: ContentMutation<Value>, options?: QueryExecutorOptions,): Promise<Value>
|
|
31
|
+
public async mutate<Value>(mutations: ContentMutation<Value>[], options?: QueryExecutorOptions,): Promise<Value[]>
|
|
32
|
+
public async mutate<Values extends Record<string, any>>(mutations: { [K in keyof Values]: ContentMutation<Values[K]> | ContentQuery<Values[K]> }, options?: QueryExecutorOptions): Promise<Values>
|
|
33
|
+
public async mutate(input: Record<string, ContentMutation<any> | ContentQuery<any>> | ContentMutation<any> | ContentMutation<any>[], options?: QueryExecutorOptions): Promise<any> {
|
|
34
|
+
const operationSet = createMutationOperationSet(input)
|
|
35
|
+
|
|
36
|
+
const printer = new GraphQlQueryPrinter()
|
|
37
|
+
const { query, variables } = printer.printDocument('mutation', operationSet.selection, mutationFragments)
|
|
38
|
+
const result = await this.executor(query, { variables, ...options })
|
|
39
|
+
|
|
40
|
+
return operationSet.parse(result)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { ContentClientInput, MutationResult, SchemaNames, TransactionResult } from './types'
|
|
2
|
+
import {
|
|
3
|
+
ContentEntitySelection,
|
|
4
|
+
ContentEntitySelectionCallback,
|
|
5
|
+
ContentEntitySelectionContext,
|
|
6
|
+
ContentMutation,
|
|
7
|
+
ContentOperation,
|
|
8
|
+
ContentQuery,
|
|
9
|
+
} from './nodes'
|
|
10
|
+
import { createListArgs } from './utils/createListArgs'
|
|
11
|
+
import { createTypedArgs } from './utils/createTypedArgs'
|
|
12
|
+
import { Input } from '@contember/schema'
|
|
13
|
+
import { GraphQlField, GraphQlFragmentSpread, GraphQlSelectionSet } from '@contember/graphql-builder'
|
|
14
|
+
import { createMutationOperationSet } from './utils/createMutationOperationSet'
|
|
15
|
+
|
|
16
|
+
export type EntitySelectionOrCallback =
|
|
17
|
+
| ContentEntitySelection
|
|
18
|
+
| ContentEntitySelectionCallback
|
|
19
|
+
|
|
20
|
+
export type MutationTransactionOptions = {
|
|
21
|
+
deferForeignKeyConstraints?: boolean
|
|
22
|
+
deferUniqueConstraints?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class ContentQueryBuilder {
|
|
26
|
+
constructor(private readonly schema: SchemaNames) {
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
public fragment(name: string, fieldsCallback?: ContentEntitySelectionCallback): ContentEntitySelection {
|
|
31
|
+
const context = this.createContext(name)
|
|
32
|
+
|
|
33
|
+
const entitySelection = new ContentEntitySelection(context, [])
|
|
34
|
+
if (!fieldsCallback) {
|
|
35
|
+
return entitySelection
|
|
36
|
+
}
|
|
37
|
+
return fieldsCallback(entitySelection)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
public count(name: string, args: Pick<ContentClientInput.AnyListQueryInput, 'filter'>): ContentQuery<number> {
|
|
43
|
+
const context = this.createContext(name)
|
|
44
|
+
const fieldName = `paginate${name}`
|
|
45
|
+
const typedArgs = createTypedArgs(args, {
|
|
46
|
+
filter: `${context.entity.name}Where`,
|
|
47
|
+
})
|
|
48
|
+
const selectionSet: GraphQlSelectionSet = [
|
|
49
|
+
new GraphQlField(null, 'pageInfo', {}, [
|
|
50
|
+
new GraphQlField(null, 'totalCount'),
|
|
51
|
+
]),
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
return new ContentOperation('query', fieldName, typedArgs, selectionSet, it => {
|
|
55
|
+
return it.pageInfo.totalCount
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
public list(name: string, args: ContentClientInput.AnyListQueryInput, fields: EntitySelectionOrCallback): ContentQuery<any[]> {
|
|
61
|
+
const context = this.createContext(name)
|
|
62
|
+
const fieldName = `list${name}`
|
|
63
|
+
const typedArgs = createListArgs(context.entity, args)
|
|
64
|
+
const selectionSet = this.resolveSelectionSet(fields, context)
|
|
65
|
+
|
|
66
|
+
return new ContentOperation('query', fieldName, typedArgs, selectionSet)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
public get(name: string, args: Input.UniqueQueryInput, fields: EntitySelectionOrCallback): ContentQuery<Record<string, unknown> | null> {
|
|
71
|
+
const context = this.createContext(name)
|
|
72
|
+
const fieldName = `get${name}`
|
|
73
|
+
const typedArgs = createTypedArgs(args, {
|
|
74
|
+
by: `${context.entity.name}UniqueWhere!`,
|
|
75
|
+
filter: `${context.entity.name}Where`,
|
|
76
|
+
})
|
|
77
|
+
const selectionSet = this.resolveSelectionSet(fields, context)
|
|
78
|
+
|
|
79
|
+
return new ContentOperation('query', fieldName, typedArgs, selectionSet)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
public create(name: string, args: Input.CreateInput, fields?: EntitySelectionOrCallback): ContentMutation<MutationResult> {
|
|
84
|
+
|
|
85
|
+
const context = this.createContext(name)
|
|
86
|
+
const fieldName = `create${name}`
|
|
87
|
+
const typedArgs = createTypedArgs(args, {
|
|
88
|
+
data: `${context.entity.name}CreateInput!`,
|
|
89
|
+
})
|
|
90
|
+
const selectionSet = this.createMutationSelection('create', fields ? this.resolveSelectionSet(fields, context) : undefined)
|
|
91
|
+
|
|
92
|
+
return new ContentOperation('mutation', fieldName, typedArgs, selectionSet)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
public update(name: string, args: Input.UpdateInput, fields?: EntitySelectionOrCallback): ContentMutation<MutationResult> {
|
|
97
|
+
|
|
98
|
+
const context = this.createContext(name)
|
|
99
|
+
const fieldName = `update${name}`
|
|
100
|
+
const typedArgs = createTypedArgs(args, {
|
|
101
|
+
data: `${context.entity.name}UpdateInput!`,
|
|
102
|
+
by: `${context.entity.name}UniqueWhere!`,
|
|
103
|
+
filter: `${context.entity.name}Where`,
|
|
104
|
+
})
|
|
105
|
+
const selectionSet = this.createMutationSelection('update', fields ? this.resolveSelectionSet(fields, context) : undefined)
|
|
106
|
+
|
|
107
|
+
return new ContentOperation('mutation', fieldName, typedArgs, selectionSet)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
public upsert(name: string, args: Input.UpsertInput, fields?: EntitySelectionOrCallback): ContentMutation<MutationResult> {
|
|
112
|
+
|
|
113
|
+
const context = this.createContext(name)
|
|
114
|
+
const fieldName = `upsert${name}`
|
|
115
|
+
const typedArgs = createTypedArgs(args, {
|
|
116
|
+
update: `${context.entity.name}UpdateInput!`,
|
|
117
|
+
create: `${context.entity.name}CreateInput!`,
|
|
118
|
+
by: `${context.entity.name}UniqueWhere!`,
|
|
119
|
+
filter: `${context.entity.name}Where`,
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
const selectionSet = this.createMutationSelection('upsert', fields ? this.resolveSelectionSet(fields, context) : undefined)
|
|
123
|
+
|
|
124
|
+
return new ContentOperation('mutation', fieldName, typedArgs, selectionSet)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
public delete(name: string, args: Input.UniqueQueryInput, fields?: EntitySelectionOrCallback): ContentMutation<MutationResult> {
|
|
129
|
+
|
|
130
|
+
const context = this.createContext(name)
|
|
131
|
+
const typedArgs = createTypedArgs(args, {
|
|
132
|
+
by: `${context.entity.name}UniqueWhere!`,
|
|
133
|
+
filter: `${context.entity.name}Where`,
|
|
134
|
+
})
|
|
135
|
+
const fieldName = `delete${name}`
|
|
136
|
+
const selectionSet = this.createMutationSelection('delete', fields ? this.resolveSelectionSet(fields, context) : undefined)
|
|
137
|
+
|
|
138
|
+
return new ContentOperation('mutation', fieldName, typedArgs, selectionSet)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public transaction(
|
|
142
|
+
input: Record<string, ContentMutation<any> | ContentQuery<any>> | ContentMutation<any> | ContentMutation<any>[],
|
|
143
|
+
options: MutationTransactionOptions = {},
|
|
144
|
+
): ContentMutation<TransactionResult<any>> {
|
|
145
|
+
const combined = createMutationOperationSet(input)
|
|
146
|
+
|
|
147
|
+
const transactionArgs = createTypedArgs({ options }, {
|
|
148
|
+
options: 'MutationTransactionOptions',
|
|
149
|
+
})
|
|
150
|
+
return new ContentOperation<TransactionResult<any>, 'mutation'>('mutation', 'transaction', transactionArgs, combined.selection, ({ ok, errorMessage, errors, validation, ...data }) => {
|
|
151
|
+
return {
|
|
152
|
+
ok,
|
|
153
|
+
errorMessage,
|
|
154
|
+
errors,
|
|
155
|
+
validation,
|
|
156
|
+
data: combined.parse(data),
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private createMutationSelection(operation: 'create' | 'update' | 'delete' | 'upsert', selection?: GraphQlSelectionSet): GraphQlSelectionSet {
|
|
162
|
+
const items: GraphQlSelectionSet = [
|
|
163
|
+
new GraphQlField(null, 'ok'),
|
|
164
|
+
new GraphQlField(null, 'errorMessage'),
|
|
165
|
+
new GraphQlField(null, 'errors', {}, [
|
|
166
|
+
new GraphQlFragmentSpread('MutationError'),
|
|
167
|
+
]),
|
|
168
|
+
]
|
|
169
|
+
if (operation !== 'delete') {
|
|
170
|
+
items.push(new GraphQlField(null, 'validation', {}, [
|
|
171
|
+
new GraphQlFragmentSpread('ValidationResult'),
|
|
172
|
+
]))
|
|
173
|
+
}
|
|
174
|
+
if (selection) {
|
|
175
|
+
items.push(new GraphQlField(null, 'node', {}, selection))
|
|
176
|
+
}
|
|
177
|
+
return items
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
private resolveSelectionSet(
|
|
182
|
+
fields: EntitySelectionOrCallback,
|
|
183
|
+
context: ContentEntitySelectionContext<string>,
|
|
184
|
+
) {
|
|
185
|
+
return (typeof fields === 'function' ? fields(new ContentEntitySelection(context, [])) : fields).selectionSet
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private createContext(
|
|
189
|
+
name: string,
|
|
190
|
+
): ContentEntitySelectionContext<string> {
|
|
191
|
+
const entity = this.schema.entities[name]
|
|
192
|
+
if (!entity) {
|
|
193
|
+
throw new Error(`Entity ${name} not found`)
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
entity: entity,
|
|
197
|
+
schema: this.schema,
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ContentClientInput, MutationResult, SchemaTypeLike, TransactionResult } from './types'
|
|
2
|
+
import { ContentMutation, ContentQuery, TypedEntitySelection, TypedEntitySelectionCallback } from './nodes'
|
|
3
|
+
import { MutationTransactionOptions } from './ContentQueryBuilder'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export type TypedContentEntitySelectionOrCallback<TSchema extends SchemaTypeLike, TEntityName extends keyof TSchema['entities'] & string, TValue> =
|
|
7
|
+
| TypedEntitySelection<TSchema, TEntityName, TSchema['entities'][TEntityName], TValue>
|
|
8
|
+
| TypedEntitySelectionCallback<TSchema, TEntityName, TSchema['entities'][TEntityName], TValue>
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
export interface TypedContentQueryBuilder<TSchema extends SchemaTypeLike> {
|
|
12
|
+
|
|
13
|
+
fragment<EntityName extends keyof TSchema['entities'] & string>(
|
|
14
|
+
name: EntityName,
|
|
15
|
+
): TypedEntitySelection<TSchema, EntityName, TSchema['entities'][EntityName], {}>
|
|
16
|
+
fragment<EntityName extends keyof TSchema['entities'] & string, TFields>(
|
|
17
|
+
name: EntityName,
|
|
18
|
+
fieldsCallback: TypedEntitySelectionCallback<TSchema, EntityName, TSchema['entities'][EntityName], TFields>,
|
|
19
|
+
): TypedEntitySelection<TSchema, EntityName, TSchema['entities'][EntityName], TFields>
|
|
20
|
+
|
|
21
|
+
count<EntityName extends keyof TSchema['entities'] & string>(
|
|
22
|
+
name: EntityName,
|
|
23
|
+
args: Pick<ContentClientInput.ListQueryInput<TSchema['entities'][EntityName]>, 'filter'>,
|
|
24
|
+
): ContentQuery<number>
|
|
25
|
+
|
|
26
|
+
list<EntityName extends keyof TSchema['entities'] & string, TValue>(
|
|
27
|
+
name: EntityName,
|
|
28
|
+
args: ContentClientInput.ListQueryInput<TSchema['entities'][EntityName]>,
|
|
29
|
+
fields: TypedContentEntitySelectionOrCallback<TSchema, EntityName, TValue>,
|
|
30
|
+
): ContentQuery<TValue[]>
|
|
31
|
+
|
|
32
|
+
get<EntityName extends keyof TSchema['entities'] & string, TValue>(
|
|
33
|
+
name: EntityName,
|
|
34
|
+
args: ContentClientInput.UniqueQueryInput<TSchema['entities'][EntityName]>,
|
|
35
|
+
fields: TypedContentEntitySelectionOrCallback<TSchema, EntityName, TValue>,
|
|
36
|
+
): ContentQuery<TValue | null>
|
|
37
|
+
|
|
38
|
+
create<EntityName extends keyof TSchema['entities'] & string, TValue>(
|
|
39
|
+
name: EntityName,
|
|
40
|
+
args: ContentClientInput.CreateInput<TSchema['entities'][EntityName]>,
|
|
41
|
+
fields?: TypedContentEntitySelectionOrCallback<TSchema, EntityName, TValue>,
|
|
42
|
+
): ContentMutation<MutationResult<TValue>>
|
|
43
|
+
|
|
44
|
+
update<EntityName extends keyof TSchema['entities'] & string, TValue>(
|
|
45
|
+
name: EntityName,
|
|
46
|
+
args: ContentClientInput.UpdateInput<TSchema['entities'][EntityName]>,
|
|
47
|
+
fields?: TypedContentEntitySelectionOrCallback<TSchema, EntityName, TValue>,
|
|
48
|
+
): ContentMutation<MutationResult<TValue>>
|
|
49
|
+
|
|
50
|
+
upsert<EntityName extends keyof TSchema['entities'] & string, TValue>(
|
|
51
|
+
name: EntityName,
|
|
52
|
+
args: ContentClientInput.UpsertInput<TSchema['entities'][EntityName]>,
|
|
53
|
+
fields?: TypedContentEntitySelectionOrCallback<TSchema, EntityName, TValue>,
|
|
54
|
+
): ContentMutation<MutationResult<TValue>>
|
|
55
|
+
|
|
56
|
+
delete<EntityName extends keyof TSchema['entities'] & string, TValue>(
|
|
57
|
+
name: EntityName,
|
|
58
|
+
args: ContentClientInput.UniqueQueryInput<TSchema['entities'][EntityName]>,
|
|
59
|
+
fields?: TypedContentEntitySelectionOrCallback<TSchema, EntityName, TValue>,
|
|
60
|
+
): ContentMutation<MutationResult<TValue>>
|
|
61
|
+
|
|
62
|
+
transaction<Value>(
|
|
63
|
+
mutation: ContentMutation<Value>,
|
|
64
|
+
options?: MutationTransactionOptions,
|
|
65
|
+
): ContentMutation<TransactionResult<Value>>
|
|
66
|
+
transaction<Value>(
|
|
67
|
+
mutations: ContentMutation<Value>[],
|
|
68
|
+
options?: MutationTransactionOptions,
|
|
69
|
+
): ContentMutation<TransactionResult<Value[]>>
|
|
70
|
+
|
|
71
|
+
transaction<Values extends Record<string, any>>(
|
|
72
|
+
mutations: { [K in keyof Values]: ContentMutation<Values[K]> | ContentQuery<Values[K]> },
|
|
73
|
+
options?: MutationTransactionOptions,
|
|
74
|
+
): ContentMutation<TransactionResult<Values>>
|
|
75
|
+
}
|
|
76
|
+
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { createListArgs } from '../utils/createListArgs'
|
|
2
|
+
import { ContentClientInput, SchemaEntityNames, SchemaNames } from '../types'
|
|
3
|
+
import { Input } from '@contember/schema'
|
|
4
|
+
import { GraphQlField, GraphQlFieldTypedArgs, GraphQlSelectionSet } from '@contember/graphql-builder'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export type ContentEntitySelectionContext<Name extends string> = {
|
|
10
|
+
entity: SchemaEntityNames<Name>
|
|
11
|
+
schema: SchemaNames
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type ContentEntitySelectionCallback = (select: ContentEntitySelection) => ContentEntitySelection
|
|
15
|
+
|
|
16
|
+
export type EntitySelectionCommonInput<Alias extends string | null = string | null> = { as?: Alias }
|
|
17
|
+
export type EntitySelectionManyArgs<Alias extends string | null = string | null> = ContentClientInput.AnyListQueryInput & EntitySelectionCommonInput<Alias>
|
|
18
|
+
export type EntitySelectionManyByArgs<Alias extends string | null = string | null> = { by: Input.UniqueWhere; filter?: Input.Where } & EntitySelectionCommonInput<Alias>
|
|
19
|
+
export type EntitySelectionOneArgs<Alias extends string | null = string | null> = { filter?: Input.Where } & EntitySelectionCommonInput<Alias>
|
|
20
|
+
export type EntitySelectionColumnArgs<Alias extends string | null = string | null> = EntitySelectionCommonInput<Alias>
|
|
21
|
+
|
|
22
|
+
export type EntitySelectionAnyArgs =
|
|
23
|
+
| EntitySelectionColumnArgs
|
|
24
|
+
| EntitySelectionManyArgs
|
|
25
|
+
| EntitySelectionManyByArgs
|
|
26
|
+
| EntitySelectionOneArgs
|
|
27
|
+
|
|
28
|
+
export type ContentEntitySelectionOrCallback = ContentEntitySelectionCallback | ContentEntitySelection
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
export class ContentEntitySelection {
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
constructor(
|
|
37
|
+
/** @internal */
|
|
38
|
+
public readonly context: ContentEntitySelectionContext<string>,
|
|
39
|
+
/** @internal */
|
|
40
|
+
public readonly selectionSet: GraphQlSelectionSet,
|
|
41
|
+
) {
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
$(field: string, args?: EntitySelectionColumnArgs): ContentEntitySelection
|
|
46
|
+
$(field: string, args: EntitySelectionManyArgs, selection: ContentEntitySelectionOrCallback): ContentEntitySelection
|
|
47
|
+
$(field: string, args: EntitySelectionManyByArgs, selection: ContentEntitySelectionOrCallback): ContentEntitySelection
|
|
48
|
+
$(field: string, args: EntitySelectionOneArgs, selection: ContentEntitySelectionOrCallback): ContentEntitySelection
|
|
49
|
+
$(field: string, selection: ContentEntitySelectionOrCallback): ContentEntitySelection
|
|
50
|
+
|
|
51
|
+
$(field: string, argsOrSelection?: EntitySelectionAnyArgs | ContentEntitySelectionOrCallback, selectionIn?: ContentEntitySelectionOrCallback): ContentEntitySelection {
|
|
52
|
+
const [args, selection] = typeof argsOrSelection === 'function' || argsOrSelection instanceof ContentEntitySelection
|
|
53
|
+
? [{}, argsOrSelection]
|
|
54
|
+
: [argsOrSelection ?? {}, selectionIn]
|
|
55
|
+
if (field === '__typename') {
|
|
56
|
+
return this.withField(new GraphQlField(args.as ?? null, '__typename'))
|
|
57
|
+
}
|
|
58
|
+
const fieldInfo = this.context.entity.fields[field]
|
|
59
|
+
if (!fieldInfo) {
|
|
60
|
+
if ('by' in args && field.includes('By')) {
|
|
61
|
+
if (!selection) {
|
|
62
|
+
throw new Error(`Selection is required for ${this.context.entity.name}.${field}.`)
|
|
63
|
+
}
|
|
64
|
+
return this._manyBy(field, args as EntitySelectionManyByArgs, selection)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
throw new Error(`Field ${this.context.entity.name}.${field} does not exist.`)
|
|
68
|
+
}
|
|
69
|
+
if (fieldInfo.type === 'column') {
|
|
70
|
+
return this._column(field, args as EntitySelectionColumnArgs)
|
|
71
|
+
}
|
|
72
|
+
if (fieldInfo.type === 'many') {
|
|
73
|
+
if (!selection) {
|
|
74
|
+
throw new Error(`Selection is required for ${this.context.entity.name}.${field}.`)
|
|
75
|
+
}
|
|
76
|
+
return this._many(field, args as EntitySelectionManyArgs, selection)
|
|
77
|
+
}
|
|
78
|
+
if (fieldInfo.type === 'one') {
|
|
79
|
+
if (!selection) {
|
|
80
|
+
throw new Error(`Selection is required for ${this.context.entity.name}.${field}.`)
|
|
81
|
+
}
|
|
82
|
+
return this._one(field, args as EntitySelectionOneArgs, selection)
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`Unknown field type ${fieldInfo.type}.`)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
$$(): ContentEntitySelection {
|
|
88
|
+
const columns = this.context.entity.scalars
|
|
89
|
+
const nodes = [
|
|
90
|
+
...this.selectionSet,
|
|
91
|
+
...columns.map(col => new GraphQlField(null, col)),
|
|
92
|
+
]
|
|
93
|
+
return new ContentEntitySelection(this.context, nodes)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private _column(
|
|
97
|
+
name: string,
|
|
98
|
+
args: EntitySelectionCommonInput = {},
|
|
99
|
+
): ContentEntitySelection {
|
|
100
|
+
let fieldInfo = this.context.entity.fields[name]
|
|
101
|
+
if (!fieldInfo) {
|
|
102
|
+
throw new Error(`Field ${this.context.entity.name}.${name} does not exist.`)
|
|
103
|
+
}
|
|
104
|
+
if (fieldInfo?.type !== 'column') {
|
|
105
|
+
throw new Error(`Field ${this.context.entity.name}.${name} is not a column.`)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const alias = args.as ?? name
|
|
109
|
+
|
|
110
|
+
const field = new GraphQlField(alias, name, {})
|
|
111
|
+
return this.withField(field)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
private _many(
|
|
116
|
+
name: string,
|
|
117
|
+
args: EntitySelectionManyArgs,
|
|
118
|
+
fields:
|
|
119
|
+
| ContentEntitySelectionCallback
|
|
120
|
+
| ContentEntitySelection,
|
|
121
|
+
): ContentEntitySelection{
|
|
122
|
+
const alias = args.as ?? name
|
|
123
|
+
const fieldInfo = this.context.entity.fields[name]
|
|
124
|
+
if (!fieldInfo) {
|
|
125
|
+
throw new Error(`Field ${this.context.entity.name}.${name} does not exist.`)
|
|
126
|
+
}
|
|
127
|
+
if (fieldInfo?.type !== 'many') {
|
|
128
|
+
throw new Error(`Field ${this.context.entity.name}.${name} is not a has-many relation.`)
|
|
129
|
+
}
|
|
130
|
+
const entity = this.context.schema.entities[fieldInfo.entity]
|
|
131
|
+
|
|
132
|
+
const newContext = {
|
|
133
|
+
entity: entity,
|
|
134
|
+
schema: this.context.schema,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const entitySelection = typeof fields === 'function' ? fields(new ContentEntitySelection(newContext, [])) : fields
|
|
138
|
+
const newObjectField = new GraphQlField(
|
|
139
|
+
alias,
|
|
140
|
+
name,
|
|
141
|
+
createListArgs(entity, args),
|
|
142
|
+
entitySelection.selectionSet,
|
|
143
|
+
)
|
|
144
|
+
return this.withField(newObjectField)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
private _manyBy(
|
|
149
|
+
name: string,
|
|
150
|
+
args: EntitySelectionManyByArgs,
|
|
151
|
+
fields:
|
|
152
|
+
| ContentEntitySelectionCallback
|
|
153
|
+
| ContentEntitySelection,
|
|
154
|
+
): ContentEntitySelection {
|
|
155
|
+
const alias = args.as ?? name
|
|
156
|
+
const byField = Object.keys(args.by)[0]
|
|
157
|
+
const relationField = name.substring(0, name.length - byField.length - 2)
|
|
158
|
+
|
|
159
|
+
const field = this.context.entity.fields[relationField]
|
|
160
|
+
if (!field) {
|
|
161
|
+
throw new Error(`Field ${this.context.entity.name}.${relationField} does not exist.`)
|
|
162
|
+
}
|
|
163
|
+
if (field?.type !== 'many') {
|
|
164
|
+
throw new Error(`Field ${this.context.entity.name}.${relationField} is not a has-many relation.`)
|
|
165
|
+
}
|
|
166
|
+
const entity = this.context.schema.entities[field.entity]
|
|
167
|
+
const newContext = {
|
|
168
|
+
entity: entity,
|
|
169
|
+
schema: this.context.schema,
|
|
170
|
+
}
|
|
171
|
+
const fieldUpperFirst = name.charAt(0).toUpperCase() + name.slice(1)
|
|
172
|
+
|
|
173
|
+
const argsWithType: GraphQlFieldTypedArgs = {
|
|
174
|
+
filter: {
|
|
175
|
+
graphQlType: `${entity.name}Where`,
|
|
176
|
+
value: args.filter,
|
|
177
|
+
},
|
|
178
|
+
by: {
|
|
179
|
+
graphQlType: `${this.context.entity.name}${fieldUpperFirst}UniqueWhere!`,
|
|
180
|
+
value: args.by,
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const entitySelection = typeof fields === 'function' ? fields(new ContentEntitySelection(newContext, []) as any) : fields
|
|
185
|
+
const newObjectField = new GraphQlField(
|
|
186
|
+
alias,
|
|
187
|
+
name,
|
|
188
|
+
argsWithType,
|
|
189
|
+
entitySelection.selectionSet,
|
|
190
|
+
)
|
|
191
|
+
return this.withField(newObjectField)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private _one(
|
|
195
|
+
name: string,
|
|
196
|
+
args: EntitySelectionOneArgs,
|
|
197
|
+
fields:
|
|
198
|
+
| ContentEntitySelectionCallback
|
|
199
|
+
| ContentEntitySelection,
|
|
200
|
+
): ContentEntitySelection {
|
|
201
|
+
const alias = args.as ?? name
|
|
202
|
+
const fieldInfo = this.context.entity.fields[name]
|
|
203
|
+
if (!fieldInfo) {
|
|
204
|
+
throw new Error(`Field ${this.context.entity.name}.${name} does not exist.`)
|
|
205
|
+
}
|
|
206
|
+
if (fieldInfo?.type !== 'one') {
|
|
207
|
+
throw new Error(`Field ${this.context.entity.name}.${name} is not a has-one relation.`)
|
|
208
|
+
}
|
|
209
|
+
const entity = this.context.schema.entities[fieldInfo.entity]
|
|
210
|
+
|
|
211
|
+
const newContext: ContentEntitySelectionContext<(typeof entity)['name']> = {
|
|
212
|
+
entity: entity,
|
|
213
|
+
schema: this.context.schema,
|
|
214
|
+
}
|
|
215
|
+
const argsWithType: GraphQlFieldTypedArgs = {
|
|
216
|
+
filter: {
|
|
217
|
+
graphQlType: `${entity.name}Where`,
|
|
218
|
+
value: args.filter,
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
const entitySelection = typeof fields === 'function'
|
|
222
|
+
? fields(new ContentEntitySelection(newContext, []) as any)
|
|
223
|
+
: fields
|
|
224
|
+
const newObjectField = new GraphQlField(
|
|
225
|
+
alias,
|
|
226
|
+
name,
|
|
227
|
+
argsWithType,
|
|
228
|
+
entitySelection.selectionSet,
|
|
229
|
+
)
|
|
230
|
+
return this.withField(newObjectField)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
private withField(field: GraphQlField) {
|
|
235
|
+
return new ContentEntitySelection(this.context, [
|
|
236
|
+
...this.selectionSet,
|
|
237
|
+
field,
|
|
238
|
+
])
|
|
239
|
+
}
|
|
240
|
+
}
|