@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.
- package/dist/development/content/upload/S3FileUploader.js +1 -1
- package/dist/development/content/upload/S3FileUploader.js.map +1 -1
- package/dist/development/crudQueryBuilder/types.js +1 -1
- package/dist/development/crudQueryBuilder/types.js.map +1 -1
- package/dist/production/content/upload/S3FileUploader.js +1 -1
- package/dist/production/content/upload/S3FileUploader.js.map +1 -1
- package/dist/production/crudQueryBuilder/types.js +1 -1
- package/dist/production/crudQueryBuilder/types.js.map +1 -1
- package/dist/types/content/formatContentApiRelativeUrl.d.ts +2 -0
- package/dist/types/content/formatContentApiRelativeUrl.d.ts.map +1 -0
- package/dist/types/content/index.d.ts +4 -0
- package/dist/types/content/index.d.ts.map +1 -0
- package/dist/types/content/params/index.d.ts +2 -0
- package/dist/types/content/params/index.d.ts.map +1 -0
- package/dist/types/content/params/whereToFilter.d.ts +4 -0
- package/dist/types/content/params/whereToFilter.d.ts.map +1 -0
- package/dist/types/content/upload/FileUploadError.d.ts +9 -0
- package/dist/types/content/upload/FileUploadError.d.ts.map +1 -0
- package/dist/types/content/upload/FileUploadProgress.d.ts +4 -0
- package/dist/types/content/upload/FileUploadProgress.d.ts.map +1 -0
- package/dist/types/content/upload/FileUploader.d.ts +15 -0
- package/dist/types/content/upload/FileUploader.d.ts.map +1 -0
- package/dist/types/content/upload/GenerateUploadUrlMutationBuilder.d.ts +30 -0
- package/dist/types/content/upload/GenerateUploadUrlMutationBuilder.d.ts.map +1 -0
- package/dist/types/content/upload/S3FileUploader.d.ts +26 -0
- package/dist/types/content/upload/S3FileUploader.d.ts.map +1 -0
- package/dist/types/content/upload/SwitchFileUploader.d.ts +13 -0
- package/dist/types/content/upload/SwitchFileUploader.d.ts.map +1 -0
- package/dist/types/content/upload/UploadedFileMetadata.d.ts +4 -0
- package/dist/types/content/upload/UploadedFileMetadata.d.ts.map +1 -0
- package/dist/types/content/upload/index.d.ts +8 -0
- package/dist/types/content/upload/index.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/CrudQueryBuilder.d.ts +21 -0
- package/dist/types/crudQueryBuilder/CrudQueryBuilder.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/CrudQueryBuilderError.d.ts +3 -0
- package/dist/types/crudQueryBuilder/CrudQueryBuilderError.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/ErrorsRelationBuilder.d.ts +5 -0
- package/dist/types/crudQueryBuilder/ErrorsRelationBuilder.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/ReadBuilder.d.ts +31 -0
- package/dist/types/crudQueryBuilder/ReadBuilder.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/ValidationRelationBuilder.d.ts +5 -0
- package/dist/types/crudQueryBuilder/ValidationRelationBuilder.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/WriteBuilder.d.ts +24 -0
- package/dist/types/crudQueryBuilder/WriteBuilder.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/WriteDataBuilder.d.ts +24 -0
- package/dist/types/crudQueryBuilder/WriteDataBuilder.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/WriteManyRelationBuilder.d.ts +27 -0
- package/dist/types/crudQueryBuilder/WriteManyRelationBuilder.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/WriteOneRelationBuilder.d.ts +28 -0
- package/dist/types/crudQueryBuilder/WriteOneRelationBuilder.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/index.d.ts +8 -0
- package/dist/types/crudQueryBuilder/index.d.ts.map +1 -0
- package/dist/types/crudQueryBuilder/types.d.ts +45 -0
- package/dist/types/crudQueryBuilder/types.d.ts.map +1 -0
- package/dist/types/graphQlBuilder/GraphQlBuilderError.d.ts +3 -0
- package/dist/types/graphQlBuilder/GraphQlBuilderError.d.ts.map +1 -0
- package/dist/types/graphQlBuilder/GraphQlLiteral.d.ts +6 -0
- package/dist/types/graphQlBuilder/GraphQlLiteral.d.ts.map +1 -0
- package/dist/types/graphQlBuilder/ObjectBuilder.d.ts +28 -0
- package/dist/types/graphQlBuilder/ObjectBuilder.d.ts.map +1 -0
- package/dist/types/graphQlBuilder/QueryBuilder.d.ts +17 -0
- package/dist/types/graphQlBuilder/QueryBuilder.d.ts.map +1 -0
- package/dist/types/graphQlBuilder/QueryCompiler.d.ts +13 -0
- package/dist/types/graphQlBuilder/QueryCompiler.d.ts.map +1 -0
- package/dist/types/graphQlBuilder/RootObjectBuilder.d.ts +17 -0
- package/dist/types/graphQlBuilder/RootObjectBuilder.d.ts.map +1 -0
- package/dist/types/graphQlBuilder/index.d.ts +6 -0
- package/dist/types/graphQlBuilder/index.d.ts.map +1 -0
- package/dist/types/graphQlClient/GraphQlClient.d.ts +19 -0
- package/dist/types/graphQlClient/GraphQlClient.d.ts.map +1 -0
- package/dist/types/graphQlClient/index.d.ts +2 -0
- package/dist/types/graphQlClient/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/system/events/RelationFilter.d.ts +5 -0
- package/dist/types/system/events/RelationFilter.d.ts.map +1 -0
- package/dist/types/system/events/SystemEvent.d.ts +10 -0
- package/dist/types/system/events/SystemEvent.d.ts.map +1 -0
- package/dist/types/system/events/TreeFilter.d.ts +7 -0
- package/dist/types/system/events/TreeFilter.d.ts.map +1 -0
- package/dist/types/system/events/index.d.ts +4 -0
- package/dist/types/system/events/index.d.ts.map +1 -0
- package/dist/types/system/formatSystemApiRelativeUrl.d.ts +2 -0
- package/dist/types/system/formatSystemApiRelativeUrl.d.ts.map +1 -0
- package/dist/types/system/index.d.ts +3 -0
- package/dist/types/system/index.d.ts.map +1 -0
- package/dist/types/tenant/index.d.ts +4 -0
- package/dist/types/tenant/index.d.ts.map +1 -0
- package/dist/types/tenant/loginMutation.d.ts +32 -0
- package/dist/types/tenant/loginMutation.d.ts.map +1 -0
- package/dist/types/tenant/tenantApiRelativeUrl.d.ts +2 -0
- package/dist/types/tenant/tenantApiRelativeUrl.d.ts.map +1 -0
- package/dist/types/tenant/tenantErrorMessages.d.ts +5 -0
- package/dist/types/tenant/tenantErrorMessages.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/dist/types/utils/index.d.ts +3 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/dist/types/utils/isEmptyObject.d.ts +2 -0
- package/dist/types/utils/isEmptyObject.d.ts.map +1 -0
- package/dist/types/utils/readFileAsArrayBuffer.d.ts +2 -0
- package/dist/types/utils/readFileAsArrayBuffer.d.ts.map +1 -0
- package/package.json +4 -5
- package/src/content/formatContentApiRelativeUrl.ts +2 -0
- package/src/content/index.ts +4 -0
- package/src/content/params/index.ts +1 -0
- package/src/content/params/whereToFilter.ts +19 -0
- package/src/content/upload/FileUploadError.ts +10 -0
- package/src/content/upload/FileUploadProgress.ts +3 -0
- package/src/content/upload/FileUploader.ts +19 -0
- package/src/content/upload/GenerateUploadUrlMutationBuilder.ts +58 -0
- package/src/content/upload/S3FileUploader.ts +121 -0
- package/src/content/upload/SwitchFileUploader.ts +40 -0
- package/src/content/upload/UploadedFileMetadata.ts +3 -0
- package/src/content/upload/index.ts +7 -0
- package/src/crudQueryBuilder/CrudQueryBuilder.ts +160 -0
- package/src/crudQueryBuilder/CrudQueryBuilderError.ts +1 -0
- package/src/crudQueryBuilder/ErrorsRelationBuilder.ts +17 -0
- package/src/crudQueryBuilder/ReadBuilder.ts +106 -0
- package/src/crudQueryBuilder/ValidationRelationBuilder.ts +18 -0
- package/src/crudQueryBuilder/WriteBuilder.ts +79 -0
- package/src/crudQueryBuilder/WriteDataBuilder.ts +153 -0
- package/src/crudQueryBuilder/WriteManyRelationBuilder.ts +141 -0
- package/src/crudQueryBuilder/WriteOneRelationBuilder.ts +101 -0
- package/src/crudQueryBuilder/index.ts +7 -0
- package/src/crudQueryBuilder/types.ts +73 -0
- package/src/graphQlBuilder/GraphQlBuilderError.ts +1 -0
- package/src/graphQlBuilder/GraphQlLiteral.ts +7 -0
- package/src/graphQlBuilder/ObjectBuilder.ts +87 -0
- package/src/graphQlBuilder/QueryBuilder.ts +34 -0
- package/src/graphQlBuilder/QueryCompiler.ts +115 -0
- package/src/graphQlBuilder/RootObjectBuilder.ts +36 -0
- package/src/graphQlBuilder/index.ts +5 -0
- package/src/graphQlClient/GraphQlClient.ts +52 -0
- package/src/graphQlClient/index.ts +1 -0
- package/src/index.ts +11 -0
- package/src/system/events/RelationFilter.ts +4 -0
- package/src/system/events/SystemEvent.ts +9 -0
- package/src/system/events/TreeFilter.ts +7 -0
- package/src/system/events/index.ts +3 -0
- package/src/system/formatSystemApiRelativeUrl.ts +1 -0
- package/src/system/index.ts +2 -0
- package/src/tenant/index.ts +3 -0
- package/src/tenant/loginMutation.ts +61 -0
- package/src/tenant/tenantApiRelativeUrl.ts +1 -0
- package/src/tenant/tenantErrorMessages.ts +14 -0
- package/src/tsconfig.json +6 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/isEmptyObject.ts +9 -0
- package/src/utils/readFileAsArrayBuffer.ts +12 -0
- package/dist/client.d.ts +0 -716
|
@@ -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,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,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
|
+
}
|