@contember/client-content 2.0.0-alpha.4 → 2.0.0-alpha.40

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 (158) hide show
  1. package/api-extractor.json +3 -0
  2. package/dist/development/index.cjs +5 -5
  3. package/dist/development/index.js +5 -5
  4. package/dist/development/src/ContentClient.cjs.map +1 -0
  5. package/dist/development/src/ContentClient.js.map +1 -0
  6. package/dist/development/src/ContentQueryBuilder.cjs.map +1 -0
  7. package/dist/development/src/ContentQueryBuilder.js.map +1 -0
  8. package/dist/development/src/nodes/ContentEntitySelection.cjs.map +1 -0
  9. package/dist/development/src/nodes/ContentEntitySelection.js.map +1 -0
  10. package/dist/development/src/nodes/ContentOperation.cjs.map +1 -0
  11. package/dist/development/src/nodes/ContentOperation.js.map +1 -0
  12. package/dist/development/src/utils/ContentOperationSet.cjs.map +1 -0
  13. package/dist/development/src/utils/ContentOperationSet.js.map +1 -0
  14. package/dist/development/src/utils/createListArgs.cjs.map +1 -0
  15. package/dist/development/src/utils/createListArgs.js.map +1 -0
  16. package/dist/development/src/utils/createMutationOperationSet.cjs.map +1 -0
  17. package/dist/development/src/utils/createMutationOperationSet.js.map +1 -0
  18. package/dist/development/src/utils/createQueryOperationSet.cjs.map +1 -0
  19. package/dist/development/src/utils/createQueryOperationSet.js.map +1 -0
  20. package/dist/development/src/utils/createTypedArgs.cjs.map +1 -0
  21. package/dist/development/src/utils/createTypedArgs.js.map +1 -0
  22. package/dist/development/src/utils/mutationFragments.cjs.map +1 -0
  23. package/dist/development/src/utils/mutationFragments.js.map +1 -0
  24. package/dist/production/index.cjs +5 -5
  25. package/dist/production/index.js +5 -5
  26. package/dist/production/src/ContentClient.cjs.map +1 -0
  27. package/dist/production/src/ContentClient.js.map +1 -0
  28. package/dist/production/src/ContentQueryBuilder.cjs.map +1 -0
  29. package/dist/production/src/ContentQueryBuilder.js.map +1 -0
  30. package/dist/production/src/nodes/ContentEntitySelection.cjs.map +1 -0
  31. package/dist/production/src/nodes/ContentEntitySelection.js.map +1 -0
  32. package/dist/production/src/nodes/ContentOperation.cjs.map +1 -0
  33. package/dist/production/src/nodes/ContentOperation.js.map +1 -0
  34. package/dist/production/src/utils/ContentOperationSet.cjs.map +1 -0
  35. package/dist/production/src/utils/ContentOperationSet.js.map +1 -0
  36. package/dist/production/src/utils/createListArgs.cjs.map +1 -0
  37. package/dist/production/src/utils/createListArgs.js.map +1 -0
  38. package/dist/production/src/utils/createMutationOperationSet.cjs.map +1 -0
  39. package/dist/production/src/utils/createMutationOperationSet.js.map +1 -0
  40. package/dist/production/src/utils/createQueryOperationSet.cjs.map +1 -0
  41. package/dist/production/src/utils/createQueryOperationSet.js.map +1 -0
  42. package/dist/production/src/utils/createTypedArgs.cjs.map +1 -0
  43. package/dist/production/src/utils/createTypedArgs.js.map +1 -0
  44. package/dist/production/src/utils/mutationFragments.cjs.map +1 -0
  45. package/dist/production/src/utils/mutationFragments.js.map +1 -0
  46. package/dist/types/nodes/ContentEntitySelection.d.ts.map +1 -1
  47. package/dist/types/nodes/ContentOperation.d.ts.map +1 -1
  48. package/dist/types/nodes/TypedEntitySelection.d.ts.map +1 -1
  49. package/dist/types/tsconfig.tsbuildinfo +1 -1
  50. package/dist/types/types/Schema.d.ts +6 -3
  51. package/dist/types/types/Schema.d.ts.map +1 -1
  52. package/dist/types/utils/createListArgs.d.ts +1 -1
  53. package/dist/types/utils/createListArgs.d.ts.map +1 -1
  54. package/dist/types/utils/createMutationOperationSet.d.ts.map +1 -1
  55. package/dist/types/utils/createQueryOperationSet.d.ts.map +1 -1
  56. package/dist/types/utils/createTypedArgs.d.ts.map +1 -1
  57. package/package.json +10 -17
  58. package/src/ContentQueryBuilder.ts +1 -1
  59. package/src/nodes/TypedEntitySelection.ts +1 -1
  60. package/src/tsconfig.json +3 -0
  61. package/src/types/Schema.ts +6 -3
  62. package/src/utils/createListArgs.ts +1 -1
  63. package/tests/cases/unit/__snapshots__/mutation.test.ts.snap +1198 -0
  64. package/tests/cases/unit/__snapshots__/query.test.ts.snap +102 -0
  65. package/tests/cases/unit/mutation.test.ts +521 -0
  66. package/tests/cases/unit/query.test.ts +450 -0
  67. package/tests/cases/unit/types.test.ts +145 -0
  68. package/tests/client/entities.ts +108 -0
  69. package/tests/client/enums.ts +3 -0
  70. package/tests/client/index.ts +17 -0
  71. package/tests/client/names.ts +117 -0
  72. package/tests/generate.ts +13 -0
  73. package/tests/lib.ts +16 -0
  74. package/tests/schema.ts +37 -0
  75. package/tests/tsconfig.json +13 -0
  76. package/tsconfig.json +8 -0
  77. package/tsdoc.json +6 -0
  78. package/vitest.config.ts +3 -0
  79. package/dist/development/ContentClient.cjs.map +0 -1
  80. package/dist/development/ContentClient.js.map +0 -1
  81. package/dist/development/ContentQueryBuilder.cjs.map +0 -1
  82. package/dist/development/ContentQueryBuilder.js.map +0 -1
  83. package/dist/development/nodes/ContentEntitySelection.cjs.map +0 -1
  84. package/dist/development/nodes/ContentEntitySelection.js.map +0 -1
  85. package/dist/development/nodes/ContentOperation.cjs.map +0 -1
  86. package/dist/development/nodes/ContentOperation.js.map +0 -1
  87. package/dist/development/utils/ContentOperationSet.cjs.map +0 -1
  88. package/dist/development/utils/ContentOperationSet.js.map +0 -1
  89. package/dist/development/utils/createListArgs.cjs.map +0 -1
  90. package/dist/development/utils/createListArgs.js.map +0 -1
  91. package/dist/development/utils/createMutationOperationSet.cjs.map +0 -1
  92. package/dist/development/utils/createMutationOperationSet.js.map +0 -1
  93. package/dist/development/utils/createQueryOperationSet.cjs.map +0 -1
  94. package/dist/development/utils/createQueryOperationSet.js.map +0 -1
  95. package/dist/development/utils/createTypedArgs.cjs.map +0 -1
  96. package/dist/development/utils/createTypedArgs.js.map +0 -1
  97. package/dist/development/utils/mutationFragments.cjs.map +0 -1
  98. package/dist/development/utils/mutationFragments.js.map +0 -1
  99. package/dist/production/ContentClient.cjs.map +0 -1
  100. package/dist/production/ContentClient.js.map +0 -1
  101. package/dist/production/ContentQueryBuilder.cjs.map +0 -1
  102. package/dist/production/ContentQueryBuilder.js.map +0 -1
  103. package/dist/production/nodes/ContentEntitySelection.cjs.map +0 -1
  104. package/dist/production/nodes/ContentEntitySelection.js.map +0 -1
  105. package/dist/production/nodes/ContentOperation.cjs.map +0 -1
  106. package/dist/production/nodes/ContentOperation.js.map +0 -1
  107. package/dist/production/utils/ContentOperationSet.cjs.map +0 -1
  108. package/dist/production/utils/ContentOperationSet.js.map +0 -1
  109. package/dist/production/utils/createListArgs.cjs.map +0 -1
  110. package/dist/production/utils/createListArgs.js.map +0 -1
  111. package/dist/production/utils/createMutationOperationSet.cjs.map +0 -1
  112. package/dist/production/utils/createMutationOperationSet.js.map +0 -1
  113. package/dist/production/utils/createQueryOperationSet.cjs.map +0 -1
  114. package/dist/production/utils/createQueryOperationSet.js.map +0 -1
  115. package/dist/production/utils/createTypedArgs.cjs.map +0 -1
  116. package/dist/production/utils/createTypedArgs.js.map +0 -1
  117. package/dist/production/utils/mutationFragments.cjs.map +0 -1
  118. package/dist/production/utils/mutationFragments.js.map +0 -1
  119. /package/dist/development/{ContentClient.cjs → src/ContentClient.cjs} +0 -0
  120. /package/dist/development/{ContentClient.js → src/ContentClient.js} +0 -0
  121. /package/dist/development/{ContentQueryBuilder.cjs → src/ContentQueryBuilder.cjs} +0 -0
  122. /package/dist/development/{ContentQueryBuilder.js → src/ContentQueryBuilder.js} +0 -0
  123. /package/dist/development/{nodes → src/nodes}/ContentEntitySelection.cjs +0 -0
  124. /package/dist/development/{nodes → src/nodes}/ContentEntitySelection.js +0 -0
  125. /package/dist/development/{nodes → src/nodes}/ContentOperation.cjs +0 -0
  126. /package/dist/development/{nodes → src/nodes}/ContentOperation.js +0 -0
  127. /package/dist/development/{utils → src/utils}/ContentOperationSet.cjs +0 -0
  128. /package/dist/development/{utils → src/utils}/ContentOperationSet.js +0 -0
  129. /package/dist/development/{utils → src/utils}/createListArgs.cjs +0 -0
  130. /package/dist/development/{utils → src/utils}/createListArgs.js +0 -0
  131. /package/dist/development/{utils → src/utils}/createMutationOperationSet.cjs +0 -0
  132. /package/dist/development/{utils → src/utils}/createMutationOperationSet.js +0 -0
  133. /package/dist/development/{utils → src/utils}/createQueryOperationSet.cjs +0 -0
  134. /package/dist/development/{utils → src/utils}/createQueryOperationSet.js +0 -0
  135. /package/dist/development/{utils → src/utils}/createTypedArgs.cjs +0 -0
  136. /package/dist/development/{utils → src/utils}/createTypedArgs.js +0 -0
  137. /package/dist/development/{utils → src/utils}/mutationFragments.cjs +0 -0
  138. /package/dist/development/{utils → src/utils}/mutationFragments.js +0 -0
  139. /package/dist/production/{ContentClient.cjs → src/ContentClient.cjs} +0 -0
  140. /package/dist/production/{ContentClient.js → src/ContentClient.js} +0 -0
  141. /package/dist/production/{ContentQueryBuilder.cjs → src/ContentQueryBuilder.cjs} +0 -0
  142. /package/dist/production/{ContentQueryBuilder.js → src/ContentQueryBuilder.js} +0 -0
  143. /package/dist/production/{nodes → src/nodes}/ContentEntitySelection.cjs +0 -0
  144. /package/dist/production/{nodes → src/nodes}/ContentEntitySelection.js +0 -0
  145. /package/dist/production/{nodes → src/nodes}/ContentOperation.cjs +0 -0
  146. /package/dist/production/{nodes → src/nodes}/ContentOperation.js +0 -0
  147. /package/dist/production/{utils → src/utils}/ContentOperationSet.cjs +0 -0
  148. /package/dist/production/{utils → src/utils}/ContentOperationSet.js +0 -0
  149. /package/dist/production/{utils → src/utils}/createListArgs.cjs +0 -0
  150. /package/dist/production/{utils → src/utils}/createListArgs.js +0 -0
  151. /package/dist/production/{utils → src/utils}/createMutationOperationSet.cjs +0 -0
  152. /package/dist/production/{utils → src/utils}/createMutationOperationSet.js +0 -0
  153. /package/dist/production/{utils → src/utils}/createQueryOperationSet.cjs +0 -0
  154. /package/dist/production/{utils → src/utils}/createQueryOperationSet.js +0 -0
  155. /package/dist/production/{utils → src/utils}/createTypedArgs.cjs +0 -0
  156. /package/dist/production/{utils → src/utils}/createTypedArgs.js +0 -0
  157. /package/dist/production/{utils → src/utils}/mutationFragments.cjs +0 -0
  158. /package/dist/production/{utils → src/utils}/mutationFragments.js +0 -0
@@ -0,0 +1,450 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import { createClient } from '../../lib'
3
+ import { Input } from '@contember/schema'
4
+ import OrderDirection = Input.OrderDirection
5
+ import { queryBuilder } from '../../client'
6
+
7
+ describe('queries', () => {
8
+
9
+ const qb = queryBuilder
10
+ test('list', async () => {
11
+ const [client, calls] = createClient({
12
+ authors: [
13
+ {
14
+ id: '1',
15
+ name: 'John',
16
+ email: 'foo@localhost',
17
+ },
18
+ {
19
+ id: '2',
20
+ name: 'John',
21
+ email: 'bar@localhost',
22
+ },
23
+ ],
24
+ })
25
+ const result = await client.query({
26
+ authors: qb.list('Author', {}, it => it.$$()),
27
+ })
28
+ expect(result).toStrictEqual({
29
+ authors: [
30
+ {
31
+ id: '1',
32
+ name: 'John',
33
+ email: 'foo@localhost',
34
+ },
35
+ {
36
+ id: '2',
37
+ name: 'John',
38
+ email: 'bar@localhost',
39
+ },
40
+ ],
41
+ })
42
+ expect(calls).toHaveLength(1)
43
+ expect(calls[0].query).toMatchSnapshot()
44
+ expect(calls[0].variables).toStrictEqual({})
45
+ })
46
+
47
+ test('multiple queries', async () => {
48
+ const [client, calls] = createClient({
49
+ authors: [
50
+ {
51
+ name: 'John',
52
+ email: 'foo@localhost',
53
+ },
54
+ {
55
+ name: 'John',
56
+ email: 'bar@localhost',
57
+ },
58
+ ],
59
+ posts: [
60
+ {
61
+ title: 'Post 1',
62
+ content: 'Content 1',
63
+ },
64
+ {
65
+ title: 'Post 2',
66
+ content: 'Content 2',
67
+ },
68
+ ],
69
+ })
70
+ const result = await client.query({
71
+ authors: qb.list('Author', {}, it => it.$$()),
72
+ posts: qb.list('Post', {}, it => it.$$()),
73
+ })
74
+ expect(result as any).toStrictEqual({
75
+ authors: [
76
+ {
77
+ name: 'John',
78
+ email: 'foo@localhost',
79
+ },
80
+ {
81
+ name: 'John',
82
+ email: 'bar@localhost',
83
+ },
84
+ ],
85
+ posts: [
86
+ {
87
+ title: 'Post 1',
88
+ content: 'Content 1',
89
+ },
90
+ {
91
+ title: 'Post 2',
92
+ content: 'Content 2',
93
+ },
94
+ ],
95
+ })
96
+ expect(calls).toHaveLength(1)
97
+ expect(calls[0].query).toMatchSnapshot()
98
+ expect(calls[0].variables).toEqual({})
99
+ })
100
+
101
+
102
+ test('single query', async () => {
103
+ const [client, calls] = createClient({
104
+ value: [
105
+ {
106
+ title: 'Post 1',
107
+ content: 'Content 1',
108
+ },
109
+ {
110
+ title: 'Post 2',
111
+ content: 'Content 2',
112
+ },
113
+ ],
114
+ })
115
+
116
+ const result = await client.query(qb.list('Post', {}, it => it.$$()))
117
+ expect(result as any).toStrictEqual([
118
+ {
119
+ title: 'Post 1',
120
+ content: 'Content 1',
121
+ },
122
+ {
123
+ title: 'Post 2',
124
+ content: 'Content 2',
125
+ },
126
+ ])
127
+ expect(calls).toHaveLength(1)
128
+ expect(calls[0].query).toMatchSnapshot()
129
+ expect(calls[0].variables).toEqual({})
130
+ })
131
+
132
+
133
+ test('nested object', async () => {
134
+ const [client, calls] = createClient()
135
+ await client.query({
136
+ authors: qb.list('Author', {}, it => it.$$().$('posts', {}, it => it.$$().$('tags', {}, it => it.$$()))),
137
+ })
138
+ expect(calls).toHaveLength(1)
139
+ expect(calls[0].query).toMatchSnapshot()
140
+ expect(calls[0].variables).toEqual({})
141
+ })
142
+ test('nested object args', async () => {
143
+ const [client, calls] = createClient()
144
+ await client.query({
145
+ authors: qb.list('Author', {}, it => it.$$().$('posts', {
146
+ limit: 10,
147
+ filter: { tags: { name: { eq: 'foo' } } },
148
+ }, it => it.$$())),
149
+ })
150
+ expect(calls).toHaveLength(1)
151
+ expect(calls[0].query).toMatchSnapshot()
152
+ expect(calls[0].variables).toStrictEqual({
153
+ 'Int_1': 10,
154
+ 'PostWhere_0': {
155
+ 'tags': {
156
+ 'name': {
157
+ 'eq': 'foo',
158
+ },
159
+ },
160
+ },
161
+ })
162
+ })
163
+
164
+
165
+ test('list with args', async () => {
166
+ const [client, calls] = createClient()
167
+ await client.query({
168
+ authors: qb.list('Author', {
169
+ filter: { name: { eq: 'John' } },
170
+ orderBy: [{ name: OrderDirection.asc }],
171
+ limit: 10,
172
+ offset: 20,
173
+ }, it => it.$$()),
174
+ })
175
+ expect(calls).toHaveLength(1)
176
+ expect(calls[0].query).toMatchSnapshot(`
177
+ "query($AuthorWhere_0: AuthorWhere, $AuthorOrderBy_1: [AuthorOrderBy!], $Int_2: Int, $Int_3: Int) {
178
+ authors: listAuthor(filter: $AuthorWhere_0, orderBy: $AuthorOrderBy_1, limit: $Int_2, offset: $Int_3) {
179
+ id
180
+ name
181
+ email
182
+ }
183
+ }
184
+ "
185
+ `)
186
+ expect(calls[0].variables).toStrictEqual(
187
+ {
188
+ 'AuthorOrderBy_1': [
189
+ {
190
+ 'name': 'asc',
191
+ },
192
+ ],
193
+ 'AuthorWhere_0': {
194
+ 'name': {
195
+ 'eq': 'John',
196
+ },
197
+ },
198
+ 'Int_2': 10,
199
+ 'Int_3': 20,
200
+ },
201
+ )
202
+ })
203
+
204
+
205
+ test('get by id', async () => {
206
+ const [client, calls] = createClient()
207
+ const result = await client.query({
208
+ authors: qb.get('Author', {
209
+ by: { id: 'ca7a9b84-efbb-435d-a063-da11f205335a' },
210
+ }, it => it.$$()),
211
+ })
212
+ expect(calls).toHaveLength(1)
213
+ expect(calls[0].query).toMatchSnapshot()
214
+ expect(calls[0].variables).toEqual({
215
+ 'AuthorUniqueWhere_0': {
216
+ 'id': 'ca7a9b84-efbb-435d-a063-da11f205335a',
217
+ },
218
+ })
219
+ })
220
+
221
+ test('top level list transform', async () => {
222
+ const [client, calls] = createClient({
223
+ authors: [
224
+ {
225
+ name: 'John',
226
+ email: 'foo@localhost',
227
+ },
228
+ {
229
+ name: 'Jane',
230
+ email: 'bar@localhost',
231
+ },
232
+ ],
233
+ })
234
+ const result = await client.query({
235
+ authors: qb.list('Author', {}, it => it
236
+ .$$()
237
+ .transform(it => ({
238
+ ...it,
239
+ label: `${it.name} (${it.email})`,
240
+ })),
241
+ ),
242
+ })
243
+ expect(result as any).toStrictEqual({
244
+ authors: [
245
+ {
246
+ name: 'John',
247
+ email: 'foo@localhost',
248
+ label: 'John (foo@localhost)',
249
+ },
250
+ {
251
+ name: 'Jane',
252
+ email: 'bar@localhost',
253
+ label: 'Jane (bar@localhost)',
254
+ },
255
+ ],
256
+ })
257
+ expect(calls).toHaveLength(1)
258
+ })
259
+
260
+ test('top level get transform', async () => {
261
+ const [client, calls] = createClient({
262
+ author: {
263
+ name: 'John',
264
+ email: 'foo@localhost',
265
+ },
266
+ })
267
+ const result = await client.query({
268
+ author: qb.get('Author', { by: { id: '123' } }, it => it
269
+ .$$()
270
+ .transform(it => ({
271
+ ...it,
272
+ label: `${it.name} (${it.email})`,
273
+ })),
274
+ ),
275
+ })
276
+ expect(result as any).toStrictEqual({
277
+ author: {
278
+ name: 'John',
279
+ email: 'foo@localhost',
280
+ label: 'John (foo@localhost)',
281
+ },
282
+ })
283
+ expect(calls).toHaveLength(1)
284
+ })
285
+
286
+
287
+ test('nested has-many transform', async () => {
288
+ const [client, calls] = createClient({
289
+ author: {
290
+ name: 'John',
291
+ email: 'foo@localhost',
292
+ posts: [
293
+ {
294
+ publishedAt: '2021-01-01T00:00:00Z',
295
+ },
296
+ {
297
+ publishedAt: '2021-01-02T00:00:00Z',
298
+ },
299
+ ],
300
+ },
301
+ })
302
+ const result = await client.query({
303
+ author: qb.get('Author', { by: { id: '123' } }, it => it
304
+ .$$()
305
+ .$('posts', {}, it => it.$$().transform(it => ({
306
+ ...it,
307
+ publishYear: it.publishedAt ? new Date(it.publishedAt).getFullYear() : null,
308
+ }))),
309
+ ),
310
+ })
311
+ expect(result as any).toStrictEqual({
312
+ author: {
313
+ name: 'John',
314
+ email: 'foo@localhost',
315
+ posts: [
316
+ {
317
+ publishedAt: '2021-01-01T00:00:00Z',
318
+ publishYear: 2021,
319
+ },
320
+ {
321
+ publishedAt: '2021-01-02T00:00:00Z',
322
+ publishYear: 2021,
323
+ },
324
+ ],
325
+ },
326
+ })
327
+ expect(calls).toHaveLength(1)
328
+ })
329
+
330
+
331
+ test('nested has-one transform', async () => {
332
+ const [client, calls] = createClient({
333
+ post: {
334
+ publishedAt: '2021-01-01T00:00:00Z',
335
+ author: {
336
+ name: 'John',
337
+ email: 'foo@localhost',
338
+ },
339
+ },
340
+ })
341
+ const author = qb.fragment('Author', it => it
342
+ .$$()
343
+ .transform(it => ({
344
+ ...it,
345
+ label: `${it.name} (${it.email})`,
346
+ })),
347
+ )
348
+
349
+ const result = await client.query({
350
+ post: qb.get('Post', { by: { id: '123' } }, it => it
351
+ .$$()
352
+ .$('author', author),
353
+ ),
354
+ })
355
+ expect(result as any).toStrictEqual({
356
+ post: {
357
+ publishedAt: '2021-01-01T00:00:00Z',
358
+ author: {
359
+ name: 'John',
360
+ email: 'foo@localhost',
361
+ label: 'John (foo@localhost)',
362
+ },
363
+ },
364
+ })
365
+ })
366
+
367
+
368
+ test('nested has-many-by transform', async () => {
369
+ const [client, calls] = createClient({
370
+ post: {
371
+ publishedAt: '2021-01-01T00:00:00Z',
372
+ localesByLocale: {
373
+ title: 'Hello',
374
+ },
375
+ },
376
+ })
377
+ const result = await client.query({
378
+ post: qb.get('Post', { by: { id: '123' } }, it => it
379
+ .$$()
380
+ .$('localesByLocale', { by: { locale: { code: 'en' } } }, it => it.$$().transform(it => ({
381
+ ...it,
382
+ label: it.title?.toUpperCase(),
383
+ }))),
384
+ ),
385
+ })
386
+ expect(result as any).toStrictEqual({
387
+ post: {
388
+ publishedAt: '2021-01-01T00:00:00Z',
389
+ localesByLocale: {
390
+ title: 'Hello',
391
+ label: 'HELLO',
392
+ },
393
+ },
394
+ })
395
+ })
396
+
397
+ test('multiple transforms', async () => {
398
+ const [client, calls] = createClient({
399
+ author: {
400
+ name: 'John',
401
+ email: 'foo@localhost',
402
+ posts: [
403
+ {
404
+ publishedAt: '2021-01-01T00:00:00Z',
405
+ },
406
+ {
407
+ publishedAt: '2021-01-02T00:00:00Z',
408
+ },
409
+ ],
410
+ },
411
+ })
412
+ const result = await client.query({
413
+ author: qb.get('Author', { by: { id: '123' } }, it => it
414
+ .$$()
415
+ .transform(it => ({
416
+ ...it,
417
+ value1: 'foo',
418
+ }))
419
+ .$('posts', {}, it => it.$$().transform(it => ({
420
+ ...it,
421
+ postLabel: 'foo bar',
422
+ })))
423
+ .transform(it => ({
424
+ ...it,
425
+ value2: 'bar',
426
+ })),
427
+ ),
428
+ })
429
+ expect(result as any).toStrictEqual({
430
+ author: {
431
+ name: 'John',
432
+ email: 'foo@localhost',
433
+ value1: 'foo',
434
+ value2: 'bar',
435
+ posts: [
436
+ {
437
+ publishedAt: '2021-01-01T00:00:00Z',
438
+ postLabel: 'foo bar',
439
+ },
440
+ {
441
+ publishedAt: '2021-01-02T00:00:00Z',
442
+ postLabel: 'foo bar',
443
+ },
444
+ ],
445
+ },
446
+ })
447
+ expect(calls).toHaveLength(1)
448
+ })
449
+
450
+ })
@@ -0,0 +1,145 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
2
+ import { describe, expect, test } from 'bun:test'
3
+ import { ContentClientInput } from '../../../src'
4
+ import { ContemberClientEntities, FragmentOf, FragmentType, queryBuilder } from '../../client'
5
+ import { expectTypeOf } from 'expect-type'
6
+
7
+ const qb = queryBuilder
8
+ describe('ts types', () => {
9
+ test('fragment - valid', async () => {
10
+ expectTypeOf(
11
+ qb.fragment('Post')
12
+ .$('author', qb.fragment('Author')),
13
+ ).toMatchTypeOf<FragmentOf<'Post'>>()
14
+ })
15
+
16
+ test('fragment - invalid', async () => {
17
+ const postFragment = qb.fragment('Post')
18
+
19
+ // @ts-expect-error
20
+ postFragment.$('author', qb.fragment('Post'))
21
+ })
22
+
23
+ test('where - valid', async () => {
24
+ qb.list('Post', {
25
+ filter: {
26
+ publishedAt: { eq: 'foo' },
27
+ },
28
+ }, it => it.$$())
29
+ })
30
+
31
+ test('where - invalid with literal', async () => {
32
+ qb.list('Post', {
33
+ filter: {
34
+ // @ts-expect-error
35
+ caption: { eq: 'foo' },
36
+ },
37
+ }, it => it.$$())
38
+ })
39
+
40
+ test('where - invalid assignment to type', async () => {
41
+ const where: ContentClientInput.Where<ContemberClientEntities['Post']> = {
42
+ // @ts-expect-error
43
+ caption: { eq: 'foo' },
44
+ }
45
+ })
46
+
47
+ test('where - valid extracted without a type', async () => {
48
+ const where = {
49
+ publishedAt: { eq: 'foo' },
50
+ }
51
+ qb.list('Post', {
52
+ filter: where,
53
+ }, it => it.$$())
54
+ })
55
+
56
+ test('where - valid extracted with a type', async () => {
57
+ const where: ContentClientInput.Where<ContemberClientEntities['Post']> = {
58
+ publishedAt: { eq: 'foo' },
59
+ }
60
+ qb.list('Post', {
61
+ filter: where,
62
+ }, it => it.$$())
63
+ })
64
+
65
+ test('where - incompatible types', async () => {
66
+ const where: ContentClientInput.Where<ContemberClientEntities['Post']> = {
67
+ publishedAt: { eq: 'foo' },
68
+ }
69
+ qb.list('Author', {
70
+ // @ts-expect-error
71
+ filter: where,
72
+ }, it => it.$$())
73
+ })
74
+
75
+ test('has one field on fragment type', async () => {
76
+ const fragment = qb.fragment('Post', it => it.$('author', it => it.$$().$('posts', it => it.$('id'))))
77
+ type fragmentType = FragmentType<typeof fragment>
78
+ expectTypeOf<fragmentType>().toEqualTypeOf<{ author: ({ id: string; name: string | null; email: string | null } & { posts: { id: string }[] }) | null }>()
79
+ })
80
+
81
+
82
+ test('has one without arg', async () => {
83
+ qb.list('Post', {}, it => it.$('author', it => it.$$()))
84
+ })
85
+
86
+ test('has one with arg', async () => {
87
+ qb.list('Post', {}, it => it.$('author', { filter: { name: { eq: 'John' } } }, it => it.$$()))
88
+ })
89
+
90
+ test('has one with invalid arg', async () => {
91
+ qb.list('Post', {}, it => it
92
+ .$('author',
93
+ // @ts-expect-error
94
+ { filter: { foo: { eq: 'xx' } } },
95
+ it => it.$$(),
96
+ ),
97
+ )
98
+ })
99
+
100
+ test('has many without arg', async () => {
101
+ qb.list('Post', {}, it => it.$('locales', it => it.$$()))
102
+ })
103
+
104
+ test('has many with arg', async () => {
105
+ qb.list('Post', {}, it => it.$('locales', { filter: { locale: { code: { eq: 'cs' } } } }, it => it.$$()))
106
+ })
107
+
108
+ test('has many with invalid arg', async () => {
109
+ qb.list('Post', {}, it => it
110
+ .$('locales',
111
+ // @ts-expect-error
112
+ { filter: { locale: { eq: 'cs' } } },
113
+ it => it.$$(),
114
+ ),
115
+ )
116
+ })
117
+
118
+ test('reduced has may', async () => {
119
+ qb.list('Post', {}, it => it.$('localesByLocale', { by: { locale: { code: 'cs' } } }, it => it.$$()))
120
+ })
121
+
122
+ test('reduced has may - invalid "by"', async () => {
123
+ qb.list('Post',
124
+ {},
125
+ it => it
126
+ .$('localesByLocale',
127
+ // @ts-expect-error
128
+ { by: { locale: {} } },
129
+ qb.fragment('PostLocale'),
130
+ ),
131
+ )
132
+ })
133
+
134
+
135
+ test('invalid field', async () => {
136
+ expect(() => {
137
+ qb.list(
138
+ 'Post',
139
+ {},
140
+ // @ts-expect-error
141
+ it => it.$('lorem', it => it.$$()),
142
+ )
143
+ }).toThrow('Field Post.lorem does not exist.')
144
+ })
145
+ })
@@ -0,0 +1,108 @@
1
+
2
+ export type JSONPrimitive = string | number | boolean | null
3
+ export type JSONValue = JSONPrimitive | JSONObject | JSONArray
4
+ export type JSONObject = { readonly [K in string]?: JSONValue }
5
+ export type JSONArray = readonly JSONValue[]
6
+
7
+ export type Locale <OverRelation extends string | never = never> = {
8
+ name: 'Locale'
9
+ unique:
10
+ | Omit<{ id: string}, OverRelation>
11
+ | Omit<{ code: string}, OverRelation>
12
+ columns: {
13
+ id: string
14
+ code: string
15
+ }
16
+ hasOne: {
17
+ }
18
+ hasMany: {
19
+ }
20
+ hasManyBy: {
21
+ }
22
+ }
23
+ export type Author <OverRelation extends string | never = never> = {
24
+ name: 'Author'
25
+ unique:
26
+ | Omit<{ id: string}, OverRelation>
27
+ | Omit<{ posts: Post['unique']}, OverRelation>
28
+ columns: {
29
+ id: string
30
+ name: string | null
31
+ email: string | null
32
+ }
33
+ hasOne: {
34
+ }
35
+ hasMany: {
36
+ posts: Post<'author'>
37
+ }
38
+ hasManyBy: {
39
+ postsByLocales: { entity: Post; by: {locales: PostLocale['unique']} }
40
+ }
41
+ }
42
+ export type Post <OverRelation extends string | never = never> = {
43
+ name: 'Post'
44
+ unique:
45
+ | Omit<{ id: string}, OverRelation>
46
+ | Omit<{ locales: PostLocale['unique']}, OverRelation>
47
+ columns: {
48
+ id: string
49
+ publishedAt: string | null
50
+ }
51
+ hasOne: {
52
+ author: Author
53
+ }
54
+ hasMany: {
55
+ tags: Tag
56
+ locales: PostLocale<'post'>
57
+ }
58
+ hasManyBy: {
59
+ localesByLocale: { entity: PostLocale; by: {locale: Locale['unique']} }
60
+ }
61
+ }
62
+ export type PostLocale <OverRelation extends string | never = never> = {
63
+ name: 'PostLocale'
64
+ unique:
65
+ | Omit<{ id: string}, OverRelation>
66
+ | Omit<{ locale: Locale['unique'], post: Post['unique']}, OverRelation>
67
+ columns: {
68
+ id: string
69
+ title: string | null
70
+ content: string | null
71
+ }
72
+ hasOne: {
73
+ locale: Locale
74
+ post: Post
75
+ }
76
+ hasMany: {
77
+ }
78
+ hasManyBy: {
79
+ }
80
+ }
81
+ export type Tag <OverRelation extends string | never = never> = {
82
+ name: 'Tag'
83
+ unique:
84
+ | Omit<{ id: string}, OverRelation>
85
+ columns: {
86
+ id: string
87
+ name: string | null
88
+ }
89
+ hasOne: {
90
+ }
91
+ hasMany: {
92
+ posts: Post
93
+ }
94
+ hasManyBy: {
95
+ }
96
+ }
97
+
98
+ export type ContemberClientEntities = {
99
+ Locale: Locale
100
+ Author: Author
101
+ Post: Post
102
+ PostLocale: PostLocale
103
+ Tag: Tag
104
+ }
105
+
106
+ export type ContemberClientSchema = {
107
+ entities: ContemberClientEntities
108
+ }
@@ -0,0 +1,3 @@
1
+ export type ContemberClientEnums = {
2
+ }
3
+
@@ -0,0 +1,17 @@
1
+
2
+ import { ContemberClientNames } from './names'
3
+ import type { ContemberClientSchema } from './entities'
4
+ import { ContentQueryBuilder, TypedContentQueryBuilder, TypedEntitySelection } from '@contember/client-content'
5
+ export * from './names'
6
+ export * from './enums'
7
+ export * from './entities'
8
+
9
+ export const queryBuilder = new ContentQueryBuilder(ContemberClientNames) as unknown as TypedContentQueryBuilder<ContemberClientSchema>
10
+
11
+ export type FragmentOf<EntityName extends keyof ContemberClientSchema['entities'] & string, Data = unknown> =
12
+ TypedEntitySelection<ContemberClientSchema, EntityName, ContemberClientSchema['entities'][EntityName], Data>
13
+
14
+ export type FragmentType<T extends TypedEntitySelection<any, any, any, any> = any> =
15
+ T extends TypedEntitySelection<any, any, any, infer TFields>
16
+ ? TFields
17
+ : never