appwrite-utils-cli 0.0.286 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +162 -96
  2. package/dist/collections/attributes.d.ts +4 -0
  3. package/dist/collections/attributes.js +224 -0
  4. package/dist/collections/indexes.d.ts +4 -0
  5. package/dist/collections/indexes.js +27 -0
  6. package/dist/collections/methods.d.ts +16 -0
  7. package/dist/collections/methods.js +216 -0
  8. package/dist/databases/methods.d.ts +6 -0
  9. package/dist/databases/methods.js +33 -0
  10. package/dist/interactiveCLI.d.ts +19 -0
  11. package/dist/interactiveCLI.js +555 -0
  12. package/dist/main.js +224 -62
  13. package/dist/migrations/afterImportActions.js +37 -40
  14. package/dist/migrations/appwriteToX.d.ts +26 -25
  15. package/dist/migrations/appwriteToX.js +42 -6
  16. package/dist/migrations/attributes.js +21 -20
  17. package/dist/migrations/backup.d.ts +93 -87
  18. package/dist/migrations/collections.d.ts +6 -0
  19. package/dist/migrations/collections.js +149 -20
  20. package/dist/migrations/converters.d.ts +2 -18
  21. package/dist/migrations/converters.js +13 -2
  22. package/dist/migrations/dataLoader.d.ts +276 -161
  23. package/dist/migrations/dataLoader.js +535 -292
  24. package/dist/migrations/databases.js +8 -2
  25. package/dist/migrations/helper.d.ts +3 -0
  26. package/dist/migrations/helper.js +21 -0
  27. package/dist/migrations/importController.d.ts +5 -2
  28. package/dist/migrations/importController.js +125 -88
  29. package/dist/migrations/importDataActions.d.ts +9 -1
  30. package/dist/migrations/importDataActions.js +15 -3
  31. package/dist/migrations/indexes.js +3 -2
  32. package/dist/migrations/logging.js +20 -8
  33. package/dist/migrations/migrationHelper.d.ts +9 -4
  34. package/dist/migrations/migrationHelper.js +6 -5
  35. package/dist/migrations/openapi.d.ts +1 -1
  36. package/dist/migrations/openapi.js +33 -18
  37. package/dist/migrations/queue.js +3 -2
  38. package/dist/migrations/relationships.d.ts +2 -2
  39. package/dist/migrations/schemaStrings.js +53 -41
  40. package/dist/migrations/setupDatabase.d.ts +2 -4
  41. package/dist/migrations/setupDatabase.js +24 -105
  42. package/dist/migrations/storage.d.ts +3 -1
  43. package/dist/migrations/storage.js +110 -16
  44. package/dist/migrations/transfer.d.ts +30 -0
  45. package/dist/migrations/transfer.js +337 -0
  46. package/dist/migrations/users.d.ts +2 -1
  47. package/dist/migrations/users.js +78 -43
  48. package/dist/schemas/authUser.d.ts +2 -2
  49. package/dist/storage/methods.d.ts +15 -0
  50. package/dist/storage/methods.js +207 -0
  51. package/dist/storage/schemas.d.ts +687 -0
  52. package/dist/storage/schemas.js +175 -0
  53. package/dist/utils/getClientFromConfig.d.ts +4 -0
  54. package/dist/utils/getClientFromConfig.js +16 -0
  55. package/dist/utils/helperFunctions.d.ts +11 -1
  56. package/dist/utils/helperFunctions.js +38 -0
  57. package/dist/utils/retryFailedPromises.d.ts +2 -0
  58. package/dist/utils/retryFailedPromises.js +21 -0
  59. package/dist/utils/schemaStrings.d.ts +13 -0
  60. package/dist/utils/schemaStrings.js +403 -0
  61. package/dist/utils/setupFiles.js +110 -61
  62. package/dist/utilsController.d.ts +40 -22
  63. package/dist/utilsController.js +164 -84
  64. package/package.json +13 -15
  65. package/src/collections/attributes.ts +483 -0
  66. package/src/collections/indexes.ts +53 -0
  67. package/src/collections/methods.ts +331 -0
  68. package/src/databases/methods.ts +47 -0
  69. package/src/init.ts +64 -64
  70. package/src/interactiveCLI.ts +767 -0
  71. package/src/main.ts +289 -83
  72. package/src/migrations/afterImportActions.ts +553 -490
  73. package/src/migrations/appwriteToX.ts +237 -174
  74. package/src/migrations/attributes.ts +483 -422
  75. package/src/migrations/backup.ts +205 -205
  76. package/src/migrations/collections.ts +545 -300
  77. package/src/migrations/converters.ts +161 -150
  78. package/src/migrations/dataLoader.ts +1615 -1304
  79. package/src/migrations/databases.ts +44 -25
  80. package/src/migrations/dbHelpers.ts +92 -92
  81. package/src/migrations/helper.ts +40 -0
  82. package/src/migrations/importController.ts +448 -384
  83. package/src/migrations/importDataActions.ts +315 -307
  84. package/src/migrations/indexes.ts +40 -37
  85. package/src/migrations/logging.ts +29 -16
  86. package/src/migrations/migrationHelper.ts +207 -201
  87. package/src/migrations/openapi.ts +83 -70
  88. package/src/migrations/queue.ts +118 -119
  89. package/src/migrations/relationships.ts +324 -324
  90. package/src/migrations/schemaStrings.ts +472 -460
  91. package/src/migrations/setupDatabase.ts +118 -219
  92. package/src/migrations/storage.ts +538 -358
  93. package/src/migrations/transfer.ts +608 -0
  94. package/src/migrations/users.ts +362 -285
  95. package/src/migrations/validationRules.ts +63 -63
  96. package/src/schemas/authUser.ts +23 -23
  97. package/src/setup.ts +8 -8
  98. package/src/storage/methods.ts +371 -0
  99. package/src/storage/schemas.ts +205 -0
  100. package/src/types.ts +9 -9
  101. package/src/utils/getClientFromConfig.ts +17 -0
  102. package/src/utils/helperFunctions.ts +181 -127
  103. package/src/utils/index.ts +2 -2
  104. package/src/utils/loadConfigs.ts +59 -59
  105. package/src/utils/retryFailedPromises.ts +27 -0
  106. package/src/utils/schemaStrings.ts +473 -0
  107. package/src/utils/setupFiles.ts +228 -182
  108. package/src/utilsController.ts +325 -194
  109. package/tsconfig.json +37 -37
@@ -1,422 +1,483 @@
1
- import { Query, type Databases, type Models } from "node-appwrite";
2
- import {
3
- attributeSchema,
4
- parseAttribute,
5
- type Attribute,
6
- } from "appwrite-utils";
7
- import { nameToIdMapping, enqueueOperation } from "./queue.js";
8
- import _ from "lodash";
9
-
10
- const attributesSame = (
11
- databaseAttribute: Attribute,
12
- configAttribute: Attribute
13
- ): boolean => {
14
- return (
15
- databaseAttribute.key == configAttribute.key &&
16
- databaseAttribute.type == configAttribute.type &&
17
- databaseAttribute.array == configAttribute.array
18
- );
19
- };
20
-
21
- export const createOrUpdateAttribute = async (
22
- db: Databases,
23
- dbId: string,
24
- collection: Models.Collection,
25
- attribute: Attribute
26
- ): Promise<void> => {
27
- let action = "create";
28
- let foundAttribute: Attribute | undefined;
29
- const updateEnabled = false;
30
- let finalAttribute: any = attribute;
31
- try {
32
- const collectionAttr = collection.attributes.find(
33
- // @ts-expect-error
34
- (attr) => attr.key === attribute.key
35
- ) as unknown as any;
36
- foundAttribute = parseAttribute(collectionAttr);
37
- } catch (error) {
38
- foundAttribute = undefined;
39
- }
40
-
41
- if (
42
- foundAttribute &&
43
- attributesSame(foundAttribute, attribute) &&
44
- updateEnabled
45
- ) {
46
- // Check if mutable properties have changed and set action to "update" if necessary
47
- const requiredChanged =
48
- "required" in foundAttribute && "required" in attribute
49
- ? foundAttribute.required !== attribute.required
50
- : false;
51
-
52
- // const xdefaultChanged =
53
- // "xdefault" in foundAttribute && "xdefault" in attribute
54
- // ? foundAttribute.xdefault !== attribute.xdefault
55
- // : false;
56
-
57
- const onDeleteChanged =
58
- foundAttribute.type === "relationship" &&
59
- attribute.type === "relationship" &&
60
- "onDelete" in foundAttribute &&
61
- "onDelete" in attribute
62
- ? foundAttribute.onDelete !== attribute.onDelete
63
- : false;
64
-
65
- if (requiredChanged || onDeleteChanged) {
66
- console.log(
67
- `Required changed: ${requiredChanged}\nOnDelete changed: ${onDeleteChanged}`
68
- );
69
- console.log(
70
- `Found attribute: ${JSON.stringify(foundAttribute, null, 2)}`
71
- );
72
- console.log(`Attribute: ${JSON.stringify(attribute, null, 2)}`);
73
- finalAttribute = {
74
- ...attribute,
75
- ...foundAttribute,
76
- };
77
- action = "update";
78
- } else {
79
- // If no properties that can be updated have changed, return early
80
- return;
81
- }
82
- } else if (
83
- foundAttribute &&
84
- !attributesSame(foundAttribute, attribute) &&
85
- updateEnabled
86
- ) {
87
- console.log(
88
- `Deleting attribute with same key ${
89
- attribute.key
90
- } -- but different values -- ${JSON.stringify(
91
- attribute,
92
- null,
93
- 2
94
- )} -- ${JSON.stringify(foundAttribute, null, 2)}`
95
- );
96
- await db.deleteAttribute(dbId, collection.$id, attribute.key);
97
- // After deletion, you might want to create the attribute anew
98
- finalAttribute = attribute;
99
- action = "create";
100
- } else if (!updateEnabled && foundAttribute) {
101
- return;
102
- }
103
-
104
- // Relationship attribute logic with adjustments
105
- let collectionFoundViaRelatedCollection: Models.Collection | undefined;
106
- let relatedCollectionId: string | undefined;
107
- if (finalAttribute.type === "relationship") {
108
- if (nameToIdMapping.has(finalAttribute.relatedCollection)) {
109
- relatedCollectionId = nameToIdMapping.get(
110
- finalAttribute.relatedCollection
111
- );
112
- try {
113
- collectionFoundViaRelatedCollection = await db.getCollection(
114
- dbId,
115
- relatedCollectionId!
116
- );
117
- } catch (e) {
118
- console.log(
119
- `Collection not found: ${finalAttribute.relatedCollection} when nameToIdMapping was set`
120
- );
121
- collectionFoundViaRelatedCollection = undefined;
122
- }
123
- } else {
124
- const collectionsPulled = await db.listCollections(dbId, [
125
- Query.equal("name", finalAttribute.relatedCollection),
126
- ]);
127
- if (collectionsPulled.total > 0) {
128
- collectionFoundViaRelatedCollection = collectionsPulled.collections[0];
129
- relatedCollectionId = collectionFoundViaRelatedCollection.$id;
130
- nameToIdMapping.set(
131
- finalAttribute.relatedCollection,
132
- relatedCollectionId
133
- );
134
- }
135
- }
136
- if (!(relatedCollectionId && collectionFoundViaRelatedCollection)) {
137
- console.log(`Enqueueing operation for attribute: ${finalAttribute.key}`);
138
- enqueueOperation({
139
- type: "attribute",
140
- collectionId: collection.$id,
141
- collection: collection,
142
- attribute,
143
- dependencies: [finalAttribute.relatedCollection],
144
- });
145
- return;
146
- }
147
- }
148
- finalAttribute = attributeSchema.parse(finalAttribute);
149
- switch (finalAttribute.type) {
150
- case "string":
151
- if (action === "create") {
152
- await db.createStringAttribute(
153
- dbId,
154
- collection.$id,
155
- finalAttribute.key,
156
- finalAttribute.size,
157
- finalAttribute.required || false,
158
- (finalAttribute.xdefault as string) || undefined,
159
- finalAttribute.array || false,
160
- finalAttribute.encrypted
161
- );
162
- } else {
163
- await db.updateStringAttribute(
164
- dbId,
165
- collection.$id,
166
- finalAttribute.key,
167
- finalAttribute.required || false,
168
- (finalAttribute.xdefault as string) || undefined
169
- );
170
- }
171
- break;
172
- case "integer":
173
- if (action === "create") {
174
- if (
175
- finalAttribute.min &&
176
- BigInt(finalAttribute.min) === BigInt(-9223372036854776000)
177
- ) {
178
- delete finalAttribute.min;
179
- }
180
- if (
181
- finalAttribute.max &&
182
- BigInt(finalAttribute.max) === BigInt(9223372036854776000)
183
- ) {
184
- delete finalAttribute.max;
185
- }
186
- await db.createIntegerAttribute(
187
- dbId,
188
- collection.$id,
189
- finalAttribute.key,
190
- finalAttribute.required || false,
191
- finalAttribute.min,
192
- finalAttribute.max,
193
- finalAttribute.xdefault || undefined,
194
- finalAttribute.array
195
- );
196
- } else {
197
- if (
198
- finalAttribute.min &&
199
- BigInt(finalAttribute.min) === BigInt(-9223372036854776000)
200
- ) {
201
- delete finalAttribute.min;
202
- }
203
- if (
204
- finalAttribute.max &&
205
- BigInt(finalAttribute.max) === BigInt(9223372036854776000)
206
- ) {
207
- delete finalAttribute.max;
208
- }
209
- await db.updateIntegerAttribute(
210
- dbId,
211
- collection.$id,
212
- finalAttribute.key,
213
- finalAttribute.required || false,
214
- finalAttribute.min || 0,
215
- finalAttribute.max || 2147483647,
216
- finalAttribute.xdefault || undefined
217
- );
218
- }
219
- break;
220
- case "float":
221
- if (action === "create") {
222
- await db.createFloatAttribute(
223
- dbId,
224
- collection.$id,
225
- finalAttribute.key,
226
- finalAttribute.required || false,
227
- finalAttribute.min,
228
- finalAttribute.max,
229
- finalAttribute.xdefault || undefined,
230
- finalAttribute.array
231
- );
232
- } else {
233
- await db.updateFloatAttribute(
234
- dbId,
235
- collection.$id,
236
- finalAttribute.key,
237
- finalAttribute.required || false,
238
- finalAttribute.min || 0,
239
- finalAttribute.max || 2147483647,
240
- finalAttribute.xdefault || undefined
241
- );
242
- }
243
- break;
244
- case "boolean":
245
- if (action === "create") {
246
- await db.createBooleanAttribute(
247
- dbId,
248
- collection.$id,
249
- finalAttribute.key,
250
- finalAttribute.required || false,
251
- finalAttribute.xdefault || undefined,
252
- finalAttribute.array
253
- );
254
- } else {
255
- await db.updateBooleanAttribute(
256
- dbId,
257
- collection.$id,
258
- finalAttribute.key,
259
- finalAttribute.required || false,
260
- finalAttribute.xdefault || null
261
- );
262
- }
263
- break;
264
- case "datetime":
265
- if (action === "create") {
266
- await db.createDatetimeAttribute(
267
- dbId,
268
- collection.$id,
269
- finalAttribute.key,
270
- finalAttribute.required || false,
271
- finalAttribute.xdefault || undefined,
272
- finalAttribute.array
273
- );
274
- } else {
275
- await db.updateDatetimeAttribute(
276
- dbId,
277
- collection.$id,
278
- finalAttribute.key,
279
- finalAttribute.required || false,
280
- finalAttribute.xdefault || undefined
281
- );
282
- }
283
- break;
284
- case "email":
285
- if (action === "create") {
286
- await db.createEmailAttribute(
287
- dbId,
288
- collection.$id,
289
- finalAttribute.key,
290
- finalAttribute.required || false,
291
- finalAttribute.xdefault || undefined,
292
- finalAttribute.array
293
- );
294
- } else {
295
- await db.updateEmailAttribute(
296
- dbId,
297
- collection.$id,
298
- finalAttribute.key,
299
- finalAttribute.required || false,
300
- finalAttribute.xdefault || undefined
301
- );
302
- }
303
- break;
304
- case "ip":
305
- if (action === "create") {
306
- await db.createIpAttribute(
307
- dbId,
308
- collection.$id,
309
- finalAttribute.key,
310
- finalAttribute.required || false,
311
- finalAttribute.xdefault || undefined,
312
- finalAttribute.array
313
- );
314
- } else {
315
- await db.updateIpAttribute(
316
- dbId,
317
- collection.$id,
318
- finalAttribute.key,
319
- finalAttribute.required || false,
320
- finalAttribute.xdefault || undefined
321
- );
322
- }
323
- break;
324
- case "url":
325
- if (action === "create") {
326
- await db.createUrlAttribute(
327
- dbId,
328
- collection.$id,
329
- finalAttribute.key,
330
- finalAttribute.required || false,
331
- finalAttribute.xdefault || undefined,
332
- finalAttribute.array
333
- );
334
- } else {
335
- await db.updateUrlAttribute(
336
- dbId,
337
- collection.$id,
338
- finalAttribute.key,
339
- finalAttribute.required || false,
340
- finalAttribute.xdefault || undefined
341
- );
342
- }
343
- break;
344
- case "enum":
345
- if (action === "create") {
346
- await db.createEnumAttribute(
347
- dbId,
348
- collection.$id,
349
- finalAttribute.key,
350
- finalAttribute.elements,
351
- finalAttribute.required || false,
352
- finalAttribute.xdefault || undefined,
353
- finalAttribute.array
354
- );
355
- } else {
356
- await db.updateEnumAttribute(
357
- dbId,
358
- collection.$id,
359
- finalAttribute.key,
360
- finalAttribute.elements,
361
- finalAttribute.required || false,
362
- finalAttribute.xdefault || undefined
363
- );
364
- }
365
- break;
366
- case "relationship":
367
- if (action === "create") {
368
- await db.createRelationshipAttribute(
369
- dbId,
370
- collection.$id,
371
- relatedCollectionId!,
372
- finalAttribute.relationType,
373
- finalAttribute.twoWay,
374
- finalAttribute.key,
375
- finalAttribute.twoWayKey,
376
- finalAttribute.onDelete
377
- );
378
- } else {
379
- await db.updateRelationshipAttribute(
380
- dbId,
381
- collection.$id,
382
- finalAttribute.key,
383
- finalAttribute.onDelete
384
- );
385
- }
386
- break;
387
- default:
388
- console.error("Invalid attribute type");
389
- break;
390
- }
391
- };
392
-
393
- export const createUpdateCollectionAttributes = async (
394
- db: Databases,
395
- dbId: string,
396
- collection: Models.Collection,
397
- attributes: Attribute[]
398
- ): Promise<void> => {
399
- console.log(
400
- `Creating/Updating attributes for collection: ${collection.name}`
401
- );
402
-
403
- const batchSize = 3; // Size of each batch
404
- for (let i = 0; i < attributes.length; i += batchSize) {
405
- // Slice the attributes array to get a batch of at most batchSize elements
406
- const batch = attributes.slice(i, i + batchSize);
407
- const attributePromises = batch.map((attribute) =>
408
- createOrUpdateAttribute(db, dbId, collection, attribute)
409
- );
410
-
411
- // Await the completion of all promises in the current batch
412
- const results = await Promise.allSettled(attributePromises);
413
- results.forEach((result) => {
414
- if (result.status === "rejected") {
415
- console.error("An attribute promise was rejected:", result.reason);
416
- }
417
- });
418
- }
419
- console.log(
420
- `Finished creating/updating attributes for collection: ${collection.name}`
421
- );
422
- };
1
+ import { Query, type Databases, type Models } from "node-appwrite";
2
+ import {
3
+ attributeSchema,
4
+ parseAttribute,
5
+ type Attribute,
6
+ } from "appwrite-utils";
7
+ import { nameToIdMapping, enqueueOperation } from "./queue.js";
8
+ import _ from "lodash";
9
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
10
+
11
+ const attributesSame = (
12
+ databaseAttribute: Attribute,
13
+ configAttribute: Attribute
14
+ ): boolean => {
15
+ return (
16
+ databaseAttribute.key == configAttribute.key &&
17
+ databaseAttribute.type == configAttribute.type &&
18
+ databaseAttribute.array == configAttribute.array
19
+ );
20
+ };
21
+
22
+ export const createOrUpdateAttribute = async (
23
+ db: Databases,
24
+ dbId: string,
25
+ collection: Models.Collection,
26
+ attribute: Attribute
27
+ ): Promise<void> => {
28
+ let action = "create";
29
+ let foundAttribute: Attribute | undefined;
30
+ const updateEnabled = false;
31
+ let finalAttribute: any = attribute;
32
+ try {
33
+ const collectionAttr = collection.attributes.find(
34
+ // @ts-expect-error
35
+ (attr) => attr.key === attribute.key
36
+ ) as unknown as any;
37
+ foundAttribute = parseAttribute(collectionAttr);
38
+ } catch (error) {
39
+ foundAttribute = undefined;
40
+ }
41
+
42
+ if (
43
+ foundAttribute &&
44
+ attributesSame(foundAttribute, attribute) &&
45
+ updateEnabled
46
+ ) {
47
+ // Check if mutable properties have changed and set action to "update" if necessary
48
+ const requiredChanged =
49
+ "required" in foundAttribute && "required" in attribute
50
+ ? foundAttribute.required !== attribute.required
51
+ : false;
52
+
53
+ // const xdefaultChanged =
54
+ // "xdefault" in foundAttribute && "xdefault" in attribute
55
+ // ? foundAttribute.xdefault !== attribute.xdefault
56
+ // : false;
57
+
58
+ const onDeleteChanged =
59
+ foundAttribute.type === "relationship" &&
60
+ attribute.type === "relationship" &&
61
+ "onDelete" in foundAttribute &&
62
+ "onDelete" in attribute
63
+ ? foundAttribute.onDelete !== attribute.onDelete
64
+ : false;
65
+
66
+ if (requiredChanged || onDeleteChanged) {
67
+ console.log(
68
+ `Required changed: ${requiredChanged}\nOnDelete changed: ${onDeleteChanged}`
69
+ );
70
+ console.log(
71
+ `Found attribute: ${JSON.stringify(foundAttribute, null, 2)}`
72
+ );
73
+ console.log(`Attribute: ${JSON.stringify(attribute, null, 2)}`);
74
+ finalAttribute = {
75
+ ...attribute,
76
+ ...foundAttribute,
77
+ };
78
+ action = "update";
79
+ } else {
80
+ // If no properties that can be updated have changed, return early
81
+ return;
82
+ }
83
+ } else if (
84
+ foundAttribute &&
85
+ !attributesSame(foundAttribute, attribute) &&
86
+ updateEnabled
87
+ ) {
88
+ console.log(
89
+ `Deleting attribute with same key ${
90
+ attribute.key
91
+ } -- but different values -- ${JSON.stringify(
92
+ attribute,
93
+ null,
94
+ 2
95
+ )} -- ${JSON.stringify(foundAttribute, null, 2)}`
96
+ );
97
+ await db.deleteAttribute(dbId, collection.$id, attribute.key);
98
+ // After deletion, you might want to create the attribute anew
99
+ finalAttribute = attribute;
100
+ action = "create";
101
+ } else if (!updateEnabled && foundAttribute) {
102
+ return;
103
+ }
104
+
105
+ // Relationship attribute logic with adjustments
106
+ let collectionFoundViaRelatedCollection: Models.Collection | undefined;
107
+ let relatedCollectionId: string | undefined;
108
+ if (finalAttribute.type === "relationship") {
109
+ if (nameToIdMapping.has(finalAttribute.relatedCollection)) {
110
+ relatedCollectionId = nameToIdMapping.get(
111
+ finalAttribute.relatedCollection
112
+ );
113
+ try {
114
+ collectionFoundViaRelatedCollection = await db.getCollection(
115
+ dbId,
116
+ relatedCollectionId!
117
+ );
118
+ } catch (e) {
119
+ console.log(
120
+ `Collection not found: ${finalAttribute.relatedCollection} when nameToIdMapping was set`
121
+ );
122
+ collectionFoundViaRelatedCollection = undefined;
123
+ }
124
+ } else {
125
+ const collectionsPulled = await db.listCollections(dbId, [
126
+ Query.equal("name", finalAttribute.relatedCollection),
127
+ ]);
128
+ if (collectionsPulled.total > 0) {
129
+ collectionFoundViaRelatedCollection = collectionsPulled.collections[0];
130
+ relatedCollectionId = collectionFoundViaRelatedCollection.$id;
131
+ nameToIdMapping.set(
132
+ finalAttribute.relatedCollection,
133
+ relatedCollectionId
134
+ );
135
+ }
136
+ }
137
+ if (!(relatedCollectionId && collectionFoundViaRelatedCollection)) {
138
+ console.log(`Enqueueing operation for attribute: ${finalAttribute.key}`);
139
+ enqueueOperation({
140
+ type: "attribute",
141
+ collectionId: collection.$id,
142
+ collection: collection,
143
+ attribute,
144
+ dependencies: [finalAttribute.relatedCollection],
145
+ });
146
+ return;
147
+ }
148
+ }
149
+ finalAttribute = attributeSchema.parse(finalAttribute);
150
+ switch (finalAttribute.type) {
151
+ case "string":
152
+ if (action === "create") {
153
+ await tryAwaitWithRetry(
154
+ async () =>
155
+ await db.createStringAttribute(
156
+ dbId,
157
+ collection.$id,
158
+ finalAttribute.key,
159
+ finalAttribute.size,
160
+ finalAttribute.required || false,
161
+ (finalAttribute.xdefault as string) || undefined,
162
+ finalAttribute.array || false,
163
+ finalAttribute.encrypted
164
+ )
165
+ );
166
+ } else {
167
+ await tryAwaitWithRetry(
168
+ async () =>
169
+ await db.updateStringAttribute(
170
+ dbId,
171
+ collection.$id,
172
+ finalAttribute.key,
173
+ finalAttribute.required || false,
174
+ (finalAttribute.xdefault as string) || undefined
175
+ )
176
+ );
177
+ }
178
+ break;
179
+ case "integer":
180
+ if (action === "create") {
181
+ if (
182
+ finalAttribute.min &&
183
+ BigInt(finalAttribute.min) === BigInt(-9223372036854776000)
184
+ ) {
185
+ delete finalAttribute.min;
186
+ }
187
+ if (
188
+ finalAttribute.max &&
189
+ BigInt(finalAttribute.max) === BigInt(9223372036854776000)
190
+ ) {
191
+ delete finalAttribute.max;
192
+ }
193
+ await tryAwaitWithRetry(
194
+ async () =>
195
+ await db.createIntegerAttribute(
196
+ dbId,
197
+ collection.$id,
198
+ finalAttribute.key,
199
+ finalAttribute.required || false,
200
+ finalAttribute.min,
201
+ finalAttribute.max,
202
+ finalAttribute.xdefault || undefined,
203
+ finalAttribute.array
204
+ )
205
+ );
206
+ } else {
207
+ if (
208
+ finalAttribute.min &&
209
+ BigInt(finalAttribute.min) === BigInt(-9223372036854776000)
210
+ ) {
211
+ delete finalAttribute.min;
212
+ }
213
+ if (
214
+ finalAttribute.max &&
215
+ BigInt(finalAttribute.max) === BigInt(9223372036854776000)
216
+ ) {
217
+ delete finalAttribute.max;
218
+ }
219
+ await tryAwaitWithRetry(
220
+ async () =>
221
+ await db.updateIntegerAttribute(
222
+ dbId,
223
+ collection.$id,
224
+ finalAttribute.key,
225
+ finalAttribute.required || false,
226
+ finalAttribute.min || 0,
227
+ finalAttribute.max || 2147483647,
228
+ finalAttribute.xdefault || undefined
229
+ )
230
+ );
231
+ }
232
+ break;
233
+ case "float":
234
+ if (action === "create") {
235
+ await tryAwaitWithRetry(
236
+ async () =>
237
+ await db.createFloatAttribute(
238
+ dbId,
239
+ collection.$id,
240
+ finalAttribute.key,
241
+ finalAttribute.required || false,
242
+ finalAttribute.min,
243
+ finalAttribute.max,
244
+ finalAttribute.xdefault || undefined,
245
+ finalAttribute.array
246
+ )
247
+ );
248
+ } else {
249
+ await tryAwaitWithRetry(
250
+ async () =>
251
+ await db.updateFloatAttribute(
252
+ dbId,
253
+ collection.$id,
254
+ finalAttribute.key,
255
+ finalAttribute.required || false,
256
+ finalAttribute.min || 0,
257
+ finalAttribute.max || 2147483647,
258
+ finalAttribute.xdefault || undefined
259
+ )
260
+ );
261
+ }
262
+ break;
263
+ case "boolean":
264
+ if (action === "create") {
265
+ await tryAwaitWithRetry(
266
+ async () =>
267
+ await db.createBooleanAttribute(
268
+ dbId,
269
+ collection.$id,
270
+ finalAttribute.key,
271
+ finalAttribute.required || false,
272
+ finalAttribute.xdefault || undefined,
273
+ finalAttribute.array
274
+ )
275
+ );
276
+ } else {
277
+ await tryAwaitWithRetry(
278
+ async () =>
279
+ await db.updateBooleanAttribute(
280
+ dbId,
281
+ collection.$id,
282
+ finalAttribute.key,
283
+ finalAttribute.required || false,
284
+ finalAttribute.xdefault || null
285
+ )
286
+ );
287
+ }
288
+ break;
289
+ case "datetime":
290
+ if (action === "create") {
291
+ await tryAwaitWithRetry(
292
+ async () =>
293
+ await db.createDatetimeAttribute(
294
+ dbId,
295
+ collection.$id,
296
+ finalAttribute.key,
297
+ finalAttribute.required || false,
298
+ finalAttribute.xdefault || undefined,
299
+ finalAttribute.array
300
+ )
301
+ );
302
+ } else {
303
+ await tryAwaitWithRetry(
304
+ async () =>
305
+ await db.updateDatetimeAttribute(
306
+ dbId,
307
+ collection.$id,
308
+ finalAttribute.key,
309
+ finalAttribute.required || false,
310
+ finalAttribute.xdefault || undefined
311
+ )
312
+ );
313
+ }
314
+ break;
315
+ case "email":
316
+ if (action === "create") {
317
+ await tryAwaitWithRetry(
318
+ async () =>
319
+ await db.createEmailAttribute(
320
+ dbId,
321
+ collection.$id,
322
+ finalAttribute.key,
323
+ finalAttribute.required || false,
324
+ finalAttribute.xdefault || undefined,
325
+ finalAttribute.array
326
+ )
327
+ );
328
+ } else {
329
+ await tryAwaitWithRetry(
330
+ async () =>
331
+ await db.updateEmailAttribute(
332
+ dbId,
333
+ collection.$id,
334
+ finalAttribute.key,
335
+ finalAttribute.required || false,
336
+ finalAttribute.xdefault || undefined
337
+ )
338
+ );
339
+ }
340
+ break;
341
+ case "ip":
342
+ if (action === "create") {
343
+ await tryAwaitWithRetry(
344
+ async () =>
345
+ await db.createIpAttribute(
346
+ dbId,
347
+ collection.$id,
348
+ finalAttribute.key,
349
+ finalAttribute.required || false,
350
+ finalAttribute.xdefault || undefined,
351
+ finalAttribute.array
352
+ )
353
+ );
354
+ } else {
355
+ await tryAwaitWithRetry(
356
+ async () =>
357
+ await db.updateIpAttribute(
358
+ dbId,
359
+ collection.$id,
360
+ finalAttribute.key,
361
+ finalAttribute.required || false,
362
+ finalAttribute.xdefault || undefined
363
+ )
364
+ );
365
+ }
366
+ break;
367
+ case "url":
368
+ if (action === "create") {
369
+ await tryAwaitWithRetry(
370
+ async () =>
371
+ await db.createUrlAttribute(
372
+ dbId,
373
+ collection.$id,
374
+ finalAttribute.key,
375
+ finalAttribute.required || false,
376
+ finalAttribute.xdefault || undefined,
377
+ finalAttribute.array
378
+ )
379
+ );
380
+ } else {
381
+ await tryAwaitWithRetry(
382
+ async () =>
383
+ await db.updateUrlAttribute(
384
+ dbId,
385
+ collection.$id,
386
+ finalAttribute.key,
387
+ finalAttribute.required || false,
388
+ finalAttribute.xdefault || undefined
389
+ )
390
+ );
391
+ }
392
+ break;
393
+ case "enum":
394
+ if (action === "create") {
395
+ await tryAwaitWithRetry(
396
+ async () =>
397
+ await db.createEnumAttribute(
398
+ dbId,
399
+ collection.$id,
400
+ finalAttribute.key,
401
+ finalAttribute.elements,
402
+ finalAttribute.required || false,
403
+ finalAttribute.xdefault || undefined,
404
+ finalAttribute.array
405
+ )
406
+ );
407
+ } else {
408
+ await tryAwaitWithRetry(
409
+ async () =>
410
+ await db.updateEnumAttribute(
411
+ dbId,
412
+ collection.$id,
413
+ finalAttribute.key,
414
+ finalAttribute.elements,
415
+ finalAttribute.required || false,
416
+ finalAttribute.xdefault || undefined
417
+ )
418
+ );
419
+ }
420
+ break;
421
+ case "relationship":
422
+ if (action === "create") {
423
+ await tryAwaitWithRetry(
424
+ async () =>
425
+ await db.createRelationshipAttribute(
426
+ dbId,
427
+ collection.$id,
428
+ relatedCollectionId!,
429
+ finalAttribute.relationType,
430
+ finalAttribute.twoWay,
431
+ finalAttribute.key,
432
+ finalAttribute.twoWayKey,
433
+ finalAttribute.onDelete
434
+ )
435
+ );
436
+ } else {
437
+ await tryAwaitWithRetry(
438
+ async () =>
439
+ await db.updateRelationshipAttribute(
440
+ dbId,
441
+ collection.$id,
442
+ finalAttribute.key,
443
+ finalAttribute.onDelete
444
+ )
445
+ );
446
+ }
447
+ break;
448
+ default:
449
+ console.error("Invalid attribute type");
450
+ break;
451
+ }
452
+ };
453
+
454
+ export const createUpdateCollectionAttributes = async (
455
+ db: Databases,
456
+ dbId: string,
457
+ collection: Models.Collection,
458
+ attributes: Attribute[]
459
+ ): Promise<void> => {
460
+ console.log(
461
+ `Creating/Updating attributes for collection: ${collection.name}`
462
+ );
463
+
464
+ const batchSize = 3; // Size of each batch
465
+ for (let i = 0; i < attributes.length; i += batchSize) {
466
+ // Slice the attributes array to get a batch of at most batchSize elements
467
+ const batch = attributes.slice(i, i + batchSize);
468
+ const attributePromises = batch.map((attribute) =>
469
+ createOrUpdateAttribute(db, dbId, collection, attribute)
470
+ );
471
+
472
+ // Await the completion of all promises in the current batch
473
+ const results = await Promise.allSettled(attributePromises);
474
+ results.forEach((result) => {
475
+ if (result.status === "rejected") {
476
+ console.error("An attribute promise was rejected:", result.reason);
477
+ }
478
+ });
479
+ }
480
+ console.log(
481
+ `Finished creating/updating attributes for collection: ${collection.name}`
482
+ );
483
+ };