@contember/client 1.0.0-rc.0 → 1.0.0-rc.11

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 (150) hide show
  1. package/dist/development/content/upload/S3FileUploader.js +1 -1
  2. package/dist/development/content/upload/S3FileUploader.js.map +1 -1
  3. package/dist/development/crudQueryBuilder/types.js +1 -1
  4. package/dist/development/crudQueryBuilder/types.js.map +1 -1
  5. package/dist/production/content/upload/S3FileUploader.js +1 -1
  6. package/dist/production/content/upload/S3FileUploader.js.map +1 -1
  7. package/dist/production/crudQueryBuilder/types.js +1 -1
  8. package/dist/production/crudQueryBuilder/types.js.map +1 -1
  9. package/dist/types/content/formatContentApiRelativeUrl.d.ts +2 -0
  10. package/dist/types/content/formatContentApiRelativeUrl.d.ts.map +1 -0
  11. package/dist/types/content/index.d.ts +4 -0
  12. package/dist/types/content/index.d.ts.map +1 -0
  13. package/dist/types/content/params/index.d.ts +2 -0
  14. package/dist/types/content/params/index.d.ts.map +1 -0
  15. package/dist/types/content/params/whereToFilter.d.ts +4 -0
  16. package/dist/types/content/params/whereToFilter.d.ts.map +1 -0
  17. package/dist/types/content/upload/FileUploadError.d.ts +9 -0
  18. package/dist/types/content/upload/FileUploadError.d.ts.map +1 -0
  19. package/dist/types/content/upload/FileUploadProgress.d.ts +4 -0
  20. package/dist/types/content/upload/FileUploadProgress.d.ts.map +1 -0
  21. package/dist/types/content/upload/FileUploader.d.ts +15 -0
  22. package/dist/types/content/upload/FileUploader.d.ts.map +1 -0
  23. package/dist/types/content/upload/GenerateUploadUrlMutationBuilder.d.ts +30 -0
  24. package/dist/types/content/upload/GenerateUploadUrlMutationBuilder.d.ts.map +1 -0
  25. package/dist/types/content/upload/S3FileUploader.d.ts +26 -0
  26. package/dist/types/content/upload/S3FileUploader.d.ts.map +1 -0
  27. package/dist/types/content/upload/SwitchFileUploader.d.ts +13 -0
  28. package/dist/types/content/upload/SwitchFileUploader.d.ts.map +1 -0
  29. package/dist/types/content/upload/UploadedFileMetadata.d.ts +4 -0
  30. package/dist/types/content/upload/UploadedFileMetadata.d.ts.map +1 -0
  31. package/dist/types/content/upload/index.d.ts +8 -0
  32. package/dist/types/content/upload/index.d.ts.map +1 -0
  33. package/dist/types/crudQueryBuilder/CrudQueryBuilder.d.ts +21 -0
  34. package/dist/types/crudQueryBuilder/CrudQueryBuilder.d.ts.map +1 -0
  35. package/dist/types/crudQueryBuilder/CrudQueryBuilderError.d.ts +3 -0
  36. package/dist/types/crudQueryBuilder/CrudQueryBuilderError.d.ts.map +1 -0
  37. package/dist/types/crudQueryBuilder/ErrorsRelationBuilder.d.ts +5 -0
  38. package/dist/types/crudQueryBuilder/ErrorsRelationBuilder.d.ts.map +1 -0
  39. package/dist/types/crudQueryBuilder/ReadBuilder.d.ts +31 -0
  40. package/dist/types/crudQueryBuilder/ReadBuilder.d.ts.map +1 -0
  41. package/dist/types/crudQueryBuilder/ValidationRelationBuilder.d.ts +5 -0
  42. package/dist/types/crudQueryBuilder/ValidationRelationBuilder.d.ts.map +1 -0
  43. package/dist/types/crudQueryBuilder/WriteBuilder.d.ts +24 -0
  44. package/dist/types/crudQueryBuilder/WriteBuilder.d.ts.map +1 -0
  45. package/dist/types/crudQueryBuilder/WriteDataBuilder.d.ts +24 -0
  46. package/dist/types/crudQueryBuilder/WriteDataBuilder.d.ts.map +1 -0
  47. package/dist/types/crudQueryBuilder/WriteManyRelationBuilder.d.ts +27 -0
  48. package/dist/types/crudQueryBuilder/WriteManyRelationBuilder.d.ts.map +1 -0
  49. package/dist/types/crudQueryBuilder/WriteOneRelationBuilder.d.ts +28 -0
  50. package/dist/types/crudQueryBuilder/WriteOneRelationBuilder.d.ts.map +1 -0
  51. package/dist/types/crudQueryBuilder/index.d.ts +8 -0
  52. package/dist/types/crudQueryBuilder/index.d.ts.map +1 -0
  53. package/dist/types/crudQueryBuilder/types.d.ts +45 -0
  54. package/dist/types/crudQueryBuilder/types.d.ts.map +1 -0
  55. package/dist/types/graphQlBuilder/GraphQlBuilderError.d.ts +3 -0
  56. package/dist/types/graphQlBuilder/GraphQlBuilderError.d.ts.map +1 -0
  57. package/dist/types/graphQlBuilder/GraphQlLiteral.d.ts +6 -0
  58. package/dist/types/graphQlBuilder/GraphQlLiteral.d.ts.map +1 -0
  59. package/dist/types/graphQlBuilder/ObjectBuilder.d.ts +28 -0
  60. package/dist/types/graphQlBuilder/ObjectBuilder.d.ts.map +1 -0
  61. package/dist/types/graphQlBuilder/QueryBuilder.d.ts +17 -0
  62. package/dist/types/graphQlBuilder/QueryBuilder.d.ts.map +1 -0
  63. package/dist/types/graphQlBuilder/QueryCompiler.d.ts +13 -0
  64. package/dist/types/graphQlBuilder/QueryCompiler.d.ts.map +1 -0
  65. package/dist/types/graphQlBuilder/RootObjectBuilder.d.ts +17 -0
  66. package/dist/types/graphQlBuilder/RootObjectBuilder.d.ts.map +1 -0
  67. package/dist/types/graphQlBuilder/index.d.ts +6 -0
  68. package/dist/types/graphQlBuilder/index.d.ts.map +1 -0
  69. package/dist/types/graphQlClient/GraphQlClient.d.ts +19 -0
  70. package/dist/types/graphQlClient/GraphQlClient.d.ts.map +1 -0
  71. package/dist/types/graphQlClient/index.d.ts +2 -0
  72. package/dist/types/graphQlClient/index.d.ts.map +1 -0
  73. package/dist/types/index.d.ts +10 -0
  74. package/dist/types/index.d.ts.map +1 -0
  75. package/dist/types/system/events/RelationFilter.d.ts +5 -0
  76. package/dist/types/system/events/RelationFilter.d.ts.map +1 -0
  77. package/dist/types/system/events/SystemEvent.d.ts +10 -0
  78. package/dist/types/system/events/SystemEvent.d.ts.map +1 -0
  79. package/dist/types/system/events/TreeFilter.d.ts +7 -0
  80. package/dist/types/system/events/TreeFilter.d.ts.map +1 -0
  81. package/dist/types/system/events/index.d.ts +4 -0
  82. package/dist/types/system/events/index.d.ts.map +1 -0
  83. package/dist/types/system/formatSystemApiRelativeUrl.d.ts +2 -0
  84. package/dist/types/system/formatSystemApiRelativeUrl.d.ts.map +1 -0
  85. package/dist/types/system/index.d.ts +3 -0
  86. package/dist/types/system/index.d.ts.map +1 -0
  87. package/dist/types/tenant/index.d.ts +4 -0
  88. package/dist/types/tenant/index.d.ts.map +1 -0
  89. package/dist/types/tenant/loginMutation.d.ts +32 -0
  90. package/dist/types/tenant/loginMutation.d.ts.map +1 -0
  91. package/dist/types/tenant/tenantApiRelativeUrl.d.ts +2 -0
  92. package/dist/types/tenant/tenantApiRelativeUrl.d.ts.map +1 -0
  93. package/dist/types/tenant/tenantErrorMessages.d.ts +5 -0
  94. package/dist/types/tenant/tenantErrorMessages.d.ts.map +1 -0
  95. package/dist/types/tsconfig.tsbuildinfo +1 -0
  96. package/dist/types/utils/index.d.ts +3 -0
  97. package/dist/types/utils/index.d.ts.map +1 -0
  98. package/dist/types/utils/isEmptyObject.d.ts +2 -0
  99. package/dist/types/utils/isEmptyObject.d.ts.map +1 -0
  100. package/dist/types/utils/readFileAsArrayBuffer.d.ts +2 -0
  101. package/dist/types/utils/readFileAsArrayBuffer.d.ts.map +1 -0
  102. package/package.json +4 -5
  103. package/src/content/formatContentApiRelativeUrl.ts +2 -0
  104. package/src/content/index.ts +4 -0
  105. package/src/content/params/index.ts +1 -0
  106. package/src/content/params/whereToFilter.ts +19 -0
  107. package/src/content/upload/FileUploadError.ts +10 -0
  108. package/src/content/upload/FileUploadProgress.ts +3 -0
  109. package/src/content/upload/FileUploader.ts +19 -0
  110. package/src/content/upload/GenerateUploadUrlMutationBuilder.ts +58 -0
  111. package/src/content/upload/S3FileUploader.ts +121 -0
  112. package/src/content/upload/SwitchFileUploader.ts +40 -0
  113. package/src/content/upload/UploadedFileMetadata.ts +3 -0
  114. package/src/content/upload/index.ts +7 -0
  115. package/src/crudQueryBuilder/CrudQueryBuilder.ts +160 -0
  116. package/src/crudQueryBuilder/CrudQueryBuilderError.ts +1 -0
  117. package/src/crudQueryBuilder/ErrorsRelationBuilder.ts +17 -0
  118. package/src/crudQueryBuilder/ReadBuilder.ts +106 -0
  119. package/src/crudQueryBuilder/ValidationRelationBuilder.ts +18 -0
  120. package/src/crudQueryBuilder/WriteBuilder.ts +79 -0
  121. package/src/crudQueryBuilder/WriteDataBuilder.ts +153 -0
  122. package/src/crudQueryBuilder/WriteManyRelationBuilder.ts +141 -0
  123. package/src/crudQueryBuilder/WriteOneRelationBuilder.ts +101 -0
  124. package/src/crudQueryBuilder/index.ts +7 -0
  125. package/src/crudQueryBuilder/types.ts +73 -0
  126. package/src/graphQlBuilder/GraphQlBuilderError.ts +1 -0
  127. package/src/graphQlBuilder/GraphQlLiteral.ts +7 -0
  128. package/src/graphQlBuilder/ObjectBuilder.ts +87 -0
  129. package/src/graphQlBuilder/QueryBuilder.ts +34 -0
  130. package/src/graphQlBuilder/QueryCompiler.ts +115 -0
  131. package/src/graphQlBuilder/RootObjectBuilder.ts +36 -0
  132. package/src/graphQlBuilder/index.ts +5 -0
  133. package/src/graphQlClient/GraphQlClient.ts +52 -0
  134. package/src/graphQlClient/index.ts +1 -0
  135. package/src/index.ts +11 -0
  136. package/src/system/events/RelationFilter.ts +4 -0
  137. package/src/system/events/SystemEvent.ts +9 -0
  138. package/src/system/events/TreeFilter.ts +7 -0
  139. package/src/system/events/index.ts +3 -0
  140. package/src/system/formatSystemApiRelativeUrl.ts +1 -0
  141. package/src/system/index.ts +2 -0
  142. package/src/tenant/index.ts +3 -0
  143. package/src/tenant/loginMutation.ts +61 -0
  144. package/src/tenant/tenantApiRelativeUrl.ts +1 -0
  145. package/src/tenant/tenantErrorMessages.ts +14 -0
  146. package/src/tsconfig.json +6 -0
  147. package/src/utils/index.ts +2 -0
  148. package/src/utils/isEmptyObject.ts +9 -0
  149. package/src/utils/readFileAsArrayBuffer.ts +12 -0
  150. package/dist/client.d.ts +0 -716
@@ -0,0 +1,4 @@
1
+ export * from './upload'
2
+ export * from './params'
3
+
4
+ export * from './formatContentApiRelativeUrl'
@@ -0,0 +1 @@
1
+ export * from './whereToFilter'
@@ -0,0 +1,19 @@
1
+ import type { Input } from '@contember/schema'
2
+ import { GraphQlLiteral } from '../../graphQlBuilder'
3
+
4
+ export const whereToFilter = (
5
+ by: Input.UniqueWhere<GraphQlLiteral>,
6
+ ): Input.Where<Input.Condition<Input.ColumnValue<GraphQlLiteral>>> => {
7
+ const where: Input.Where<Input.Condition<Input.ColumnValue<GraphQlLiteral>>> = {}
8
+ for (const key in by) {
9
+ const value = by[key]
10
+
11
+ if (value instanceof GraphQlLiteral || typeof value === 'string' || typeof value === 'number') {
12
+ where[key] = { eq: value }
13
+ } else {
14
+ where[key] = whereToFilter(value)
15
+ }
16
+ }
17
+
18
+ return where
19
+ }
@@ -0,0 +1,10 @@
1
+ export interface FileUploadErrorOptions {
2
+ developerMessage?: string
3
+ endUserMessage?: string
4
+ }
5
+
6
+ export class FileUploadError extends Error {
7
+ public constructor(public readonly options: FileUploadErrorOptions = {}) {
8
+ super(options.developerMessage)
9
+ }
10
+ }
@@ -0,0 +1,3 @@
1
+ export interface FileUploadProgress {
2
+ progress?: number
3
+ }
@@ -0,0 +1,19 @@
1
+ import type { GraphQlClient } from '../../graphQlClient'
2
+ import type { FileUploadError } from './FileUploadError'
3
+ import type { FileUploadProgress } from './FileUploadProgress'
4
+ import type { UploadedFileMetadata } from './UploadedFileMetadata'
5
+
6
+ export interface FileUploader<Result = any, Error extends FileUploadError = FileUploadError> {
7
+ upload: (
8
+ files: Map<File, UploadedFileMetadata>,
9
+ options: FileUploaderInitializeOptions<Result, Error>,
10
+ ) => Promise<void>
11
+ destroy?: (files: Result[]) => Promise<void> // TODO Note that admin uploaders don'T actually invoke this yet.
12
+ }
13
+
14
+ export interface FileUploaderInitializeOptions<Result = any, Error extends FileUploadError = FileUploadError> {
15
+ contentApiClient: GraphQlClient
16
+ onSuccess: (result: Iterable<[File, Result]>) => void
17
+ onError: (error: Iterable<File | [File, Error]>) => void
18
+ onProgress: (progress: Iterable<[File, FileUploadProgress]>) => void
19
+ }
@@ -0,0 +1,58 @@
1
+ import { GraphQlLiteral, ObjectBuilder, QueryBuilder } from '../../graphQlBuilder'
2
+
3
+ class GenerateUploadUrlMutationBuilder {
4
+ private static generateUploadUrlFields = new ObjectBuilder()
5
+ .name('generateUploadUrl')
6
+ .field('url')
7
+ .field('publicUrl')
8
+ .field('method')
9
+ .object('headers', builder => builder.field('key').field('value'))
10
+
11
+ public static buildQuery(parameters: GenerateUploadUrlMutationBuilder.MutationParameters): string {
12
+ return new QueryBuilder().mutation(builder => {
13
+ for (const alias in parameters) {
14
+ const fileParameters = parameters[alias]
15
+
16
+ builder = builder.object(
17
+ alias,
18
+ GenerateUploadUrlMutationBuilder.generateUploadUrlFields
19
+ .argument('contentType', fileParameters.contentType)
20
+ .argument('expiration', fileParameters.expiration)
21
+ .argument('prefix', fileParameters.prefix)
22
+ .argument('acl', fileParameters.acl),
23
+ )
24
+ }
25
+
26
+ return builder
27
+ })
28
+ }
29
+ }
30
+
31
+ namespace GenerateUploadUrlMutationBuilder {
32
+ export interface FileParameters {
33
+ contentType: string
34
+ expiration?: number
35
+ prefix?: string
36
+ acl?: GraphQlLiteral<'PUBLIC_READ' | 'PRIVATE' | 'NONE'>
37
+ }
38
+
39
+ export interface MutationParameters {
40
+ [alias: string]: FileParameters
41
+ }
42
+
43
+ export interface ResponseBody {
44
+ url: string
45
+ publicUrl: string
46
+ method: string
47
+ headers: Array<{
48
+ key: string
49
+ value: string
50
+ }>
51
+ }
52
+
53
+ export interface MutationResponse {
54
+ [alias: string]: ResponseBody
55
+ }
56
+ }
57
+
58
+ export { GenerateUploadUrlMutationBuilder }
@@ -0,0 +1,121 @@
1
+ import { readFileAsArrayBuffer } from '../../utils'
2
+ import type { FileUploader, FileUploaderInitializeOptions } from './FileUploader'
3
+ import { GenerateUploadUrlMutationBuilder } from './GenerateUploadUrlMutationBuilder'
4
+ import type { UploadedFileMetadata } from './UploadedFileMetadata'
5
+
6
+ interface S3UploadState {
7
+ request?: XMLHttpRequest
8
+ alias: number
9
+ }
10
+
11
+ class S3FileUploader implements FileUploader<S3FileUploader.SuccessMetadata> {
12
+ private readonly uploadState: WeakMap<File, S3UploadState>
13
+
14
+ public constructor(public readonly options: S3FileUploader.Options = {}) {
15
+ this.uploadState = new WeakMap()
16
+ }
17
+
18
+ private generateNewAlias = (() => {
19
+ let alias = 1
20
+ return () => alias++
21
+ })()
22
+
23
+ private static formatFullAlias(alias: number) {
24
+ return `file${alias}`
25
+ }
26
+
27
+ public async upload(
28
+ files: Map<File, UploadedFileMetadata>,
29
+ { contentApiClient, onSuccess, onError, onProgress }: FileUploaderInitializeOptions,
30
+ ) {
31
+ const parameters: GenerateUploadUrlMutationBuilder.MutationParameters = {}
32
+
33
+ for (const [file, metadata] of files) {
34
+ if (this.uploadState.has(file)) {
35
+ const uploadState = this.uploadState.get(file)!
36
+ uploadState.request?.abort()
37
+ }
38
+
39
+ const alias = this.generateNewAlias()
40
+ this.uploadState.set(file, {
41
+ alias,
42
+ })
43
+
44
+ const uploadOptions = this.options.getUploadOptions?.(file)
45
+
46
+ parameters[S3FileUploader.formatFullAlias(alias)] = {
47
+ contentType: file.type,
48
+ prefix: uploadOptions?.filePrefix,
49
+ expiration: uploadOptions?.fileExpiration,
50
+ acl: uploadOptions?.fileAcl,
51
+ }
52
+
53
+ metadata.abortSignal.addEventListener('abort', () => {
54
+ this.uploadState.get(file)?.request?.abort()
55
+ })
56
+ }
57
+
58
+ const mutation = GenerateUploadUrlMutationBuilder.buildQuery(parameters)
59
+ try {
60
+ const response = await contentApiClient.sendRequest(mutation)
61
+ const responseData: GenerateUploadUrlMutationBuilder.MutationResponse = response.data
62
+
63
+ for (const [file] of files) {
64
+ const fileState = this.uploadState.get(file)!
65
+ const datumBody = responseData[S3FileUploader.formatFullAlias(fileState.alias)]
66
+ const uploadRequestBody = await readFileAsArrayBuffer(file)
67
+ const xhr = new XMLHttpRequest()
68
+
69
+ fileState.request = xhr
70
+
71
+ xhr.open(datumBody.method, datumBody.url)
72
+
73
+ for (const header of datumBody.headers) {
74
+ xhr.setRequestHeader(header.key, header.value)
75
+ }
76
+ xhr.addEventListener('load', () => {
77
+ const successMetadata: S3FileUploader.SuccessMetadata = {
78
+ fileUrl: datumBody.publicUrl,
79
+ }
80
+ onSuccess([[file, successMetadata]])
81
+ })
82
+ onError &&
83
+ xhr.addEventListener('error', e => {
84
+ onError([file])
85
+ })
86
+ onProgress &&
87
+ xhr.upload?.addEventListener('progress', e => {
88
+ onProgress([
89
+ [
90
+ file,
91
+ {
92
+ progress: e.loaded / e.total,
93
+ },
94
+ ],
95
+ ])
96
+ })
97
+ xhr.send(uploadRequestBody)
98
+ }
99
+ } catch (error) {
100
+ onError(Array.from(files).map(([file]) => [file, error]))
101
+ }
102
+ }
103
+ }
104
+
105
+ namespace S3FileUploader {
106
+ export interface SuccessMetadata {
107
+ fileUrl: string
108
+ }
109
+
110
+ export interface Options {
111
+ getUploadOptions?: (file: File) => S3UploadOptions
112
+ }
113
+
114
+ export interface S3UploadOptions {
115
+ fileExpiration?: GenerateUploadUrlMutationBuilder.FileParameters['expiration']
116
+ filePrefix?: GenerateUploadUrlMutationBuilder.FileParameters['prefix']
117
+ fileAcl?: GenerateUploadUrlMutationBuilder.FileParameters['acl']
118
+ }
119
+ }
120
+
121
+ export { S3FileUploader }
@@ -0,0 +1,40 @@
1
+ import type { FileUploader, FileUploaderInitializeOptions } from './FileUploader'
2
+ import type { UploadedFileMetadata } from './UploadedFileMetadata'
3
+
4
+ class SwitchFileUploader implements FileUploader {
5
+ public constructor(private readonly subUploaders: SwitchFileUploader.SubUploaders) {}
6
+
7
+ public async upload(files: Map<File, UploadedFileMetadata>, options: FileUploaderInitializeOptions) {
8
+ const fileKinds: Map<FileUploader, Map<File, UploadedFileMetadata>> = new Map()
9
+ const unhandledFiles: Array<[File, any]> = []
10
+
11
+ fileLoop: for (const [file, metadata] of files) {
12
+ for (const [predicate, uploader] of this.subUploaders) {
13
+ if (predicate(file)) {
14
+ let nestedMap = fileKinds.get(uploader)
15
+ if (nestedMap === undefined) {
16
+ fileKinds.set(uploader, (nestedMap = new Map()))
17
+ }
18
+ nestedMap.set(file, metadata)
19
+ continue fileLoop
20
+ }
21
+ }
22
+ unhandledFiles.push([file, undefined])
23
+ }
24
+
25
+ if (unhandledFiles.length && options.onError) {
26
+ options.onError(unhandledFiles)
27
+ }
28
+
29
+ for (const [uploader, files] of fileKinds) {
30
+ uploader.upload(files, options) // Deliberately no await
31
+ }
32
+ }
33
+ }
34
+
35
+ namespace SwitchFileUploader {
36
+ export type FilePredicate = (file: File) => boolean
37
+ export type SubUploaders = Iterable<[FilePredicate, FileUploader]>
38
+ }
39
+
40
+ export { SwitchFileUploader }
@@ -0,0 +1,3 @@
1
+ export interface UploadedFileMetadata {
2
+ abortSignal: AbortSignal
3
+ }
@@ -0,0 +1,7 @@
1
+ export * from './FileUploader'
2
+ export * from './FileUploadError'
3
+ export * from './FileUploadProgress'
4
+ export * from './GenerateUploadUrlMutationBuilder'
5
+ export * from './UploadedFileMetadata'
6
+ export * from './S3FileUploader'
7
+ export * from './UploadedFileMetadata'
@@ -0,0 +1,160 @@
1
+ import { ObjectBuilder, QueryBuilder, RootObjectBuilder } from '../graphQlBuilder'
2
+ import { isEmptyObject } from '../utils'
3
+ import { CrudQueryBuilderError } from './CrudQueryBuilderError'
4
+ import { ReadBuilder } from './ReadBuilder'
5
+ import type {
6
+ CreateMutationArguments,
7
+ CreateMutationFields,
8
+ DeleteMutationArguments,
9
+ DeleteMutationFields,
10
+ GetQueryArguments,
11
+ ListQueryArguments,
12
+ Mutations,
13
+ PaginateQueryArguments,
14
+ Queries,
15
+ UpdateMutationArguments,
16
+ UpdateMutationFields,
17
+ WriteOperation,
18
+ } from './types'
19
+ import { WriteBuilder } from './WriteBuilder'
20
+
21
+ export class CrudQueryBuilder {
22
+ constructor(
23
+ private type: undefined | 'query' | 'mutation' = undefined,
24
+ private rootObjectBuilder: RootObjectBuilder = new RootObjectBuilder(),
25
+ ) {}
26
+
27
+ public fragment(name: string, typeName: string, query: ReadBuilder.BuilderFactory<never>): CrudQueryBuilder {
28
+ const readBuilder = ReadBuilder.instantiateFromFactory(query)
29
+ const objectBuilder = readBuilder.objectBuilder.name(typeName)
30
+
31
+ return new CrudQueryBuilder(this.type, this.rootObjectBuilder.fragment(name, objectBuilder))
32
+ }
33
+
34
+ public list(
35
+ name: string,
36
+ query: ReadBuilder.BuilderFactory<ListQueryArguments>,
37
+ alias?: string,
38
+ ): Omit<CrudQueryBuilder, Mutations> {
39
+ if (this.type === 'mutation') {
40
+ throw new CrudQueryBuilderError('Cannot combine queries and mutations')
41
+ }
42
+ name = `list${name}`
43
+ query = ReadBuilder.instantiateFromFactory(query)
44
+
45
+ const [objectName, objectBuilder] =
46
+ typeof alias === 'string' ? [alias, query.objectBuilder.name(name)] : [name, query.objectBuilder]
47
+
48
+ return new CrudQueryBuilder('query', this.rootObjectBuilder.object(objectName, objectBuilder))
49
+ }
50
+
51
+ public paginate(
52
+ name: string,
53
+ query: ReadBuilder.BuilderFactory<PaginateQueryArguments>,
54
+ alias?: string,
55
+ ): Omit<CrudQueryBuilder, Mutations> {
56
+ if (this.type === 'mutation') {
57
+ throw new CrudQueryBuilderError('Cannot combine queries and mutations')
58
+ }
59
+ name = `paginate${name}`
60
+ query = ReadBuilder.instantiateFromFactory(query)
61
+
62
+ const [objectName, objectBuilder] =
63
+ typeof alias === 'string' ? [alias, query.objectBuilder.name(name)] : [name, query.objectBuilder]
64
+
65
+ return new CrudQueryBuilder('query', this.rootObjectBuilder.object(objectName, objectBuilder))
66
+ }
67
+
68
+ public get(
69
+ name: string,
70
+ query: ReadBuilder.BuilderFactory<GetQueryArguments>,
71
+ alias?: string,
72
+ ): Omit<CrudQueryBuilder, Mutations> {
73
+ if (this.type === 'mutation') {
74
+ throw new CrudQueryBuilderError('Cannot combine queries and mutations')
75
+ }
76
+ name = `get${name}`
77
+ query = ReadBuilder.instantiateFromFactory(query)
78
+
79
+ const [objectName, objectBuilder] =
80
+ typeof alias === 'string' ? [alias, query.objectBuilder.name(name)] : [name, query.objectBuilder]
81
+
82
+ return new CrudQueryBuilder('query', this.rootObjectBuilder.object(objectName, objectBuilder))
83
+ }
84
+
85
+ public update(
86
+ name: string,
87
+ query: WriteBuilder.BuilderFactory<UpdateMutationArguments, UpdateMutationFields, WriteOperation.Update>,
88
+ alias?: string,
89
+ ): Omit<CrudQueryBuilder, Queries> {
90
+ if (this.type === 'query') {
91
+ throw new CrudQueryBuilderError('Cannot combine queries and mutations')
92
+ }
93
+ name = `update${name}`
94
+ query = WriteBuilder.instantiateFromFactory(query)
95
+
96
+ if (isEmptyObject(query.objectBuilder.args.data)) {
97
+ return this
98
+ }
99
+
100
+ const [objectName, objectBuilder] =
101
+ typeof alias === 'string' ? [alias, query.objectBuilder.name(name)] : [name, query.objectBuilder]
102
+
103
+ return new CrudQueryBuilder('mutation', this.rootObjectBuilder.object(objectName, objectBuilder))
104
+ }
105
+
106
+ public create(
107
+ name: string,
108
+ query: WriteBuilder.BuilderFactory<CreateMutationArguments, CreateMutationFields, WriteOperation.Create>,
109
+ alias?: string,
110
+ ): Omit<CrudQueryBuilder, Queries> {
111
+ if (this.type === 'query') {
112
+ throw new CrudQueryBuilderError('Cannot combine queries and mutations')
113
+ }
114
+ name = `create${name}`
115
+ query = WriteBuilder.instantiateFromFactory(query)
116
+
117
+ if (isEmptyObject(query.objectBuilder.args.data)) {
118
+ return this
119
+ }
120
+
121
+ const [objectName, objectBuilder] =
122
+ typeof alias === 'string' ? [alias, query.objectBuilder.name(name)] : [name, query.objectBuilder]
123
+
124
+ return new CrudQueryBuilder('mutation', this.rootObjectBuilder.object(objectName, objectBuilder))
125
+ }
126
+
127
+ public delete(
128
+ name: string,
129
+ query: WriteBuilder.BuilderFactory<DeleteMutationArguments, DeleteMutationFields, WriteOperation.Delete>,
130
+ alias?: string,
131
+ ): Omit<CrudQueryBuilder, Queries> {
132
+ if (this.type === 'query') {
133
+ throw new CrudQueryBuilderError('Cannot combine queries and mutations')
134
+ }
135
+ name = `delete${name}`
136
+ query = WriteBuilder.instantiateFromFactory(query)
137
+
138
+ const [objectName, objectBuilder] =
139
+ typeof alias === 'string' ? [alias, query.objectBuilder.name(name)] : [name, query.objectBuilder]
140
+
141
+ return new CrudQueryBuilder('mutation', this.rootObjectBuilder.object(objectName, objectBuilder))
142
+ }
143
+
144
+ public inTransaction(alias: string = 'transaction', options: { deferForeignKeyConstraints?: boolean } = {}): CrudQueryBuilder {
145
+ const objectBuilder = new ObjectBuilder(undefined, { ...this.rootObjectBuilder.objects }, { options }, undefined, undefined, 'transaction')
146
+ return new CrudQueryBuilder(this.type, new RootObjectBuilder({ [alias]: objectBuilder }, this.rootObjectBuilder.fragmentDefinitions))
147
+ }
148
+
149
+ getGql(): string {
150
+ const builder = new QueryBuilder()
151
+ switch (this.type) {
152
+ case 'mutation':
153
+ return builder.mutation(this.rootObjectBuilder)
154
+ case 'query':
155
+ return builder.query(this.rootObjectBuilder)
156
+ default:
157
+ throw new CrudQueryBuilderError(`Invalid type ${this.type}`)
158
+ }
159
+ }
160
+ }
@@ -0,0 +1 @@
1
+ export class CrudQueryBuilderError extends Error {}
@@ -0,0 +1,17 @@
1
+ import type { ObjectBuilder } from '../graphQlBuilder'
2
+
3
+ export class ErrorsRelationBuilder {
4
+ public static errorsRelation(objectBuilder: ObjectBuilder): ObjectBuilder {
5
+ return objectBuilder.object('errors', builder =>
6
+ builder
7
+ .field('type')
8
+ .field('message')
9
+ .object('path', builder =>
10
+ builder
11
+ .field('__typename')
12
+ .inlineFragment('_FieldPathFragment', builder => builder.field('field'))
13
+ .inlineFragment('_IndexPathFragment', builder => builder.field('index').field('alias')),
14
+ ),
15
+ )
16
+ }
17
+ }
@@ -0,0 +1,106 @@
1
+ import type { Input } from '@contember/schema'
2
+ import { GraphQlLiteral, ObjectBuilder } from '../graphQlBuilder'
3
+ import type { HasManyArguments, HasOneArguments, OrderDirection, ReadArguments, ReductionArguments } from './types'
4
+
5
+ class ReadBuilder<AllowedArgs extends ReadArguments = ReadArguments> {
6
+ protected constructor(public readonly objectBuilder: ObjectBuilder = new ObjectBuilder()) {}
7
+
8
+ public static instantiate<AllowedArgs extends ReadArguments = ReadArguments>(
9
+ objectBuilder: ObjectBuilder = new ObjectBuilder(),
10
+ ): ReadBuilder.Builder<AllowedArgs> {
11
+ return new ReadBuilder<AllowedArgs>(objectBuilder)
12
+ }
13
+
14
+ public static instantiateFromFactory<AllowedArgs extends ReadArguments>(
15
+ builder: ReadBuilder.BuilderFactory<AllowedArgs>,
16
+ ): ReadBuilder.Builder<never> {
17
+ if (typeof builder === 'function') {
18
+ return builder(ReadBuilder.instantiate())
19
+ }
20
+ return builder
21
+ }
22
+
23
+ protected instantiate<AA extends ReadArguments = ReadArguments>(
24
+ objectBuilder: ObjectBuilder = new ObjectBuilder(),
25
+ ): ReadBuilder.Builder<AA> {
26
+ return ReadBuilder.instantiate<AA>(objectBuilder)
27
+ }
28
+
29
+ public by(by: Input.UniqueWhere<GraphQlLiteral>) {
30
+ return this.instantiate<Exclude<AllowedArgs, 'by'>>(this.objectBuilder.argument('by', by))
31
+ }
32
+
33
+ public filter(where: Input.Where<Input.Condition<Input.ColumnValue<GraphQlLiteral>>>) {
34
+ return this.instantiate<Exclude<AllowedArgs, 'filter'>>(this.objectBuilder.argument('filter', where))
35
+ }
36
+
37
+ public orderBy(orderBy: Input.OrderBy<OrderDirection>[]) {
38
+ return this.instantiate<Exclude<AllowedArgs, 'orderBy'>>(this.objectBuilder.argument('orderBy', orderBy))
39
+ }
40
+
41
+ public offset(offset: number) {
42
+ return this.instantiate<Exclude<AllowedArgs, 'offset'>>(this.objectBuilder.argument('offset', offset))
43
+ }
44
+
45
+ public limit(limit: number) {
46
+ return this.instantiate<Exclude<AllowedArgs, 'limit'>>(this.objectBuilder.argument('limit', limit))
47
+ }
48
+
49
+ public skip(offset: number) {
50
+ return this.instantiate<Exclude<AllowedArgs, 'skip'>>(this.objectBuilder.argument('skip', offset))
51
+ }
52
+
53
+ public first(limit: number) {
54
+ return this.instantiate<Exclude<AllowedArgs, 'first'>>(this.objectBuilder.argument('first', limit))
55
+ }
56
+
57
+ public column(name: string) {
58
+ return this.instantiate<AllowedArgs>(this.objectBuilder.field(name))
59
+ }
60
+
61
+ public inlineFragment(typeName: string, builder: ReadBuilder.BuilderFactory<never>) {
62
+ builder = ReadBuilder.instantiateFromFactory(builder)
63
+ return this.instantiate<AllowedArgs>(this.objectBuilder.inlineFragment(typeName, builder.objectBuilder))
64
+ }
65
+
66
+ public applyFragment(fragmentName: string) {
67
+ return this.instantiate<AllowedArgs>(this.objectBuilder.applyFragment(fragmentName))
68
+ }
69
+
70
+ public reductionRelation(name: string, builder: ReadBuilder.BuilderFactory<ReductionArguments>, alias?: string) {
71
+ return this.relation(name, builder, alias)
72
+ }
73
+
74
+ public hasOneRelation(name: string, builder: ReadBuilder.BuilderFactory<HasOneArguments>, alias?: string) {
75
+ return this.relation(name, builder, alias)
76
+ }
77
+
78
+ public hasManyRelation(name: string, builder: ReadBuilder.BuilderFactory<HasManyArguments>, alias?: string) {
79
+ return this.relation(name, builder, alias)
80
+ }
81
+
82
+ public anyRelation(name: string, builder: ReadBuilder.BuilderFactory<never>, alias?: string) {
83
+ return this.relation(name, builder, alias)
84
+ }
85
+
86
+ protected relation<A extends ReadArguments>(name: string, builder: ReadBuilder.BuilderFactory<A>, alias?: string) {
87
+ builder = ReadBuilder.instantiateFromFactory(builder)
88
+
89
+ const [objectName, objectBuilder] =
90
+ typeof alias === 'string' ? [alias, builder.objectBuilder.name(name)] : [name, builder.objectBuilder]
91
+
92
+ return this.instantiate<AllowedArgs>(this.objectBuilder.object(objectName, objectBuilder))
93
+ }
94
+ }
95
+
96
+ namespace ReadBuilder {
97
+ export type Builder<AllowedArgs extends ReadArguments> = Omit<
98
+ ReadBuilder<AllowedArgs>,
99
+ Exclude<ReadArguments, AllowedArgs>
100
+ >
101
+ export type BuilderFactory<AllowedArgs extends ReadArguments> =
102
+ | Builder<never>
103
+ | ((builder: Builder<AllowedArgs>) => Builder<never>)
104
+ }
105
+
106
+ export { ReadBuilder }
@@ -0,0 +1,18 @@
1
+ import type { ObjectBuilder } from '../graphQlBuilder'
2
+
3
+ export class ValidationRelationBuilder {
4
+ public static validationRelation(objectBuilder: ObjectBuilder): ObjectBuilder {
5
+ return objectBuilder.object('validation', builder =>
6
+ builder.field('valid').object('errors', builder =>
7
+ builder
8
+ .object('path', builder =>
9
+ builder
10
+ .field('__typename')
11
+ .inlineFragment('_FieldPathFragment', builder => builder.field('field'))
12
+ .inlineFragment('_IndexPathFragment', builder => builder.field('index').field('alias')),
13
+ )
14
+ .object('message', builder => builder.field('text')),
15
+ ),
16
+ )
17
+ }
18
+ }