@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.
Files changed (57) hide show
  1. package/dist/types/ContentClient.d.ts +18 -0
  2. package/dist/types/ContentClient.d.ts.map +1 -0
  3. package/dist/types/ContentQueryBuilder.d.ts +25 -0
  4. package/dist/types/ContentQueryBuilder.d.ts.map +1 -0
  5. package/dist/types/TypedContentQueryBuilder.d.ts +21 -0
  6. package/dist/types/TypedContentQueryBuilder.d.ts.map +1 -0
  7. package/dist/types/index.d.ts +6 -0
  8. package/dist/types/index.d.ts.map +1 -0
  9. package/dist/types/nodes/ContentEntitySelection.d.ts +51 -0
  10. package/dist/types/nodes/ContentEntitySelection.d.ts.map +1 -0
  11. package/dist/types/nodes/ContentOperation.d.ts +30 -0
  12. package/dist/types/nodes/ContentOperation.d.ts.map +1 -0
  13. package/dist/types/nodes/TypedEntitySelection.d.ts +42 -0
  14. package/dist/types/nodes/TypedEntitySelection.d.ts.map +1 -0
  15. package/dist/types/nodes/index.d.ts +4 -0
  16. package/dist/types/nodes/index.d.ts.map +1 -0
  17. package/dist/types/tsconfig.tsbuildinfo +1 -0
  18. package/dist/types/types/Input.d.ts +141 -0
  19. package/dist/types/types/Input.d.ts.map +1 -0
  20. package/dist/types/types/Result.d.ts +39 -0
  21. package/dist/types/types/Result.d.ts.map +1 -0
  22. package/dist/types/types/Schema.d.ts +43 -0
  23. package/dist/types/types/Schema.d.ts.map +1 -0
  24. package/dist/types/types/index.d.ts +4 -0
  25. package/dist/types/types/index.d.ts.map +1 -0
  26. package/dist/types/utils/ContentOperationSet.d.ts +13 -0
  27. package/dist/types/utils/ContentOperationSet.d.ts.map +1 -0
  28. package/dist/types/utils/createListArgs.d.ts +9 -0
  29. package/dist/types/utils/createListArgs.d.ts.map +1 -0
  30. package/dist/types/utils/createMutationOperationSet.d.ts +4 -0
  31. package/dist/types/utils/createMutationOperationSet.d.ts.map +1 -0
  32. package/dist/types/utils/createQueryOperationSet.d.ts +4 -0
  33. package/dist/types/utils/createQueryOperationSet.d.ts.map +1 -0
  34. package/dist/types/utils/createTypedArgs.d.ts +3 -0
  35. package/dist/types/utils/createTypedArgs.d.ts.map +1 -0
  36. package/dist/types/utils/mutationFragments.d.ts +3 -0
  37. package/dist/types/utils/mutationFragments.d.ts.map +1 -0
  38. package/package.json +48 -0
  39. package/src/ContentClient.ts +42 -0
  40. package/src/ContentQueryBuilder.ts +200 -0
  41. package/src/TypedContentQueryBuilder.ts +76 -0
  42. package/src/index.ts +5 -0
  43. package/src/nodes/ContentEntitySelection.ts +240 -0
  44. package/src/nodes/ContentOperation.ts +23 -0
  45. package/src/nodes/TypedEntitySelection.ts +107 -0
  46. package/src/nodes/index.ts +3 -0
  47. package/src/tsconfig.json +14 -0
  48. package/src/types/Input.ts +213 -0
  49. package/src/types/Result.ts +43 -0
  50. package/src/types/Schema.ts +49 -0
  51. package/src/types/index.ts +3 -0
  52. package/src/utils/ContentOperationSet.ts +11 -0
  53. package/src/utils/createListArgs.ts +23 -0
  54. package/src/utils/createMutationOperationSet.ts +42 -0
  55. package/src/utils/createQueryOperationSet.ts +20 -0
  56. package/src/utils/createTypedArgs.ts +15 -0
  57. 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,3 @@
1
+ import { GraphQlFieldTypedArgs } from '@contember/graphql-builder';
2
+ export declare const createTypedArgs: <TArgs extends Record<string, any>>(args: TArgs, types: { [key in keyof TArgs]: string; }) => GraphQlFieldTypedArgs;
3
+ //# sourceMappingURL=createTypedArgs.d.ts.map
@@ -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,3 @@
1
+ import { GraphQlFragment } from '@contember/graphql-builder';
2
+ export declare const mutationFragments: Record<string, GraphQlFragment>;
3
+ //# sourceMappingURL=mutationFragments.d.ts.map
@@ -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,5 @@
1
+ export * from './ContentClient'
2
+ export * from './TypedContentQueryBuilder'
3
+ export * from './ContentQueryBuilder'
4
+ export * from './nodes'
5
+ export * from './types'
@@ -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
+ }