appwrite-utils-cli 0.0.37 → 0.0.39

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 (35) hide show
  1. package/README.md +1 -0
  2. package/dist/migrations/attributes.js +21 -20
  3. package/dist/migrations/collections.js +10 -13
  4. package/dist/migrations/converters.js +15 -1
  5. package/dist/migrations/dataLoader.d.ts +12 -21
  6. package/dist/migrations/dataLoader.js +168 -58
  7. package/dist/migrations/databases.js +2 -1
  8. package/dist/migrations/importController.js +6 -24
  9. package/dist/migrations/importDataActions.d.ts +9 -1
  10. package/dist/migrations/importDataActions.js +14 -2
  11. package/dist/migrations/indexes.js +2 -1
  12. package/dist/migrations/migrationHelper.js +2 -1
  13. package/dist/migrations/queue.js +3 -2
  14. package/dist/migrations/setupDatabase.js +10 -12
  15. package/dist/migrations/storage.js +14 -13
  16. package/dist/migrations/users.js +14 -36
  17. package/dist/utils/helperFunctions.d.ts +10 -1
  18. package/dist/utils/helperFunctions.js +27 -0
  19. package/dist/utilsController.js +2 -1
  20. package/package.json +2 -2
  21. package/src/migrations/attributes.ts +204 -143
  22. package/src/migrations/collections.ts +49 -33
  23. package/src/migrations/converters.ts +17 -1
  24. package/src/migrations/dataLoader.ts +232 -63
  25. package/src/migrations/databases.ts +4 -1
  26. package/src/migrations/importController.ts +13 -27
  27. package/src/migrations/importDataActions.ts +17 -3
  28. package/src/migrations/indexes.ts +4 -1
  29. package/src/migrations/migrationHelper.ts +9 -5
  30. package/src/migrations/queue.ts +5 -6
  31. package/src/migrations/setupDatabase.ts +35 -18
  32. package/src/migrations/storage.ts +50 -36
  33. package/src/migrations/users.ts +28 -38
  34. package/src/utils/helperFunctions.ts +33 -1
  35. package/src/utilsController.ts +3 -1
@@ -6,6 +6,7 @@ import {
6
6
  } from "appwrite-utils";
7
7
  import { nameToIdMapping, enqueueOperation } from "./queue.js";
8
8
  import _ from "lodash";
9
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
9
10
 
10
11
  const attributesSame = (
11
12
  databaseAttribute: Attribute,
@@ -149,23 +150,29 @@ export const createOrUpdateAttribute = async (
149
150
  switch (finalAttribute.type) {
150
151
  case "string":
151
152
  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
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
+ )
161
165
  );
162
166
  } else {
163
- await db.updateStringAttribute(
164
- dbId,
165
- collection.$id,
166
- finalAttribute.key,
167
- finalAttribute.required || false,
168
- (finalAttribute.xdefault as string) || undefined
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
+ )
169
176
  );
170
177
  }
171
178
  break;
@@ -183,15 +190,18 @@ export const createOrUpdateAttribute = async (
183
190
  ) {
184
191
  delete finalAttribute.max;
185
192
  }
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
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
+ )
195
205
  );
196
206
  } else {
197
207
  if (
@@ -206,181 +216,232 @@ export const createOrUpdateAttribute = async (
206
216
  ) {
207
217
  delete finalAttribute.max;
208
218
  }
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
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
+ )
217
230
  );
218
231
  }
219
232
  break;
220
233
  case "float":
221
234
  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
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
+ )
231
247
  );
232
248
  } 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
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
+ )
241
260
  );
242
261
  }
243
262
  break;
244
263
  case "boolean":
245
264
  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
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
+ )
253
275
  );
254
276
  } else {
255
- await db.updateBooleanAttribute(
256
- dbId,
257
- collection.$id,
258
- finalAttribute.key,
259
- finalAttribute.required || false,
260
- finalAttribute.xdefault || null
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
+ )
261
286
  );
262
287
  }
263
288
  break;
264
289
  case "datetime":
265
290
  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
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
+ )
273
301
  );
274
302
  } else {
275
- await db.updateDatetimeAttribute(
276
- dbId,
277
- collection.$id,
278
- finalAttribute.key,
279
- finalAttribute.required || false,
280
- finalAttribute.xdefault || undefined
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
+ )
281
312
  );
282
313
  }
283
314
  break;
284
315
  case "email":
285
316
  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
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
+ )
293
327
  );
294
328
  } else {
295
- await db.updateEmailAttribute(
296
- dbId,
297
- collection.$id,
298
- finalAttribute.key,
299
- finalAttribute.required || false,
300
- finalAttribute.xdefault || undefined
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
+ )
301
338
  );
302
339
  }
303
340
  break;
304
341
  case "ip":
305
342
  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
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
+ )
313
353
  );
314
354
  } else {
315
- await db.updateIpAttribute(
316
- dbId,
317
- collection.$id,
318
- finalAttribute.key,
319
- finalAttribute.required || false,
320
- finalAttribute.xdefault || undefined
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
+ )
321
364
  );
322
365
  }
323
366
  break;
324
367
  case "url":
325
368
  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
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
+ )
333
379
  );
334
380
  } else {
335
- await db.updateUrlAttribute(
336
- dbId,
337
- collection.$id,
338
- finalAttribute.key,
339
- finalAttribute.required || false,
340
- finalAttribute.xdefault || undefined
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
+ )
341
390
  );
342
391
  }
343
392
  break;
344
393
  case "enum":
345
394
  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
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
+ )
354
406
  );
355
407
  } else {
356
- await db.updateEnumAttribute(
357
- dbId,
358
- collection.$id,
359
- finalAttribute.key,
360
- finalAttribute.elements,
361
- finalAttribute.required || false,
362
- finalAttribute.xdefault || undefined
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
+ )
363
418
  );
364
419
  }
365
420
  break;
366
421
  case "relationship":
367
422
  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
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
+ )
377
435
  );
378
436
  } else {
379
- await db.updateRelationshipAttribute(
380
- dbId,
381
- collection.$id,
382
- finalAttribute.key,
383
- finalAttribute.onDelete
437
+ await tryAwaitWithRetry(
438
+ async () =>
439
+ await db.updateRelationshipAttribute(
440
+ dbId,
441
+ collection.$id,
442
+ finalAttribute.key,
443
+ finalAttribute.onDelete
444
+ )
384
445
  );
385
446
  }
386
447
  break;
@@ -5,6 +5,7 @@ import { createUpdateCollectionAttributes } from "./attributes.js";
5
5
  import { createOrUpdateIndexes } from "./indexes.js";
6
6
  import _ from "lodash";
7
7
  import { SchemaGenerator } from "./schemaStrings.js";
8
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
8
9
 
9
10
  export const documentExists = async (
10
11
  db: Databases,
@@ -69,9 +70,10 @@ export const checkForCollection = async (
69
70
  ): Promise<Models.Collection | null> => {
70
71
  try {
71
72
  console.log(`Checking for collection with name: ${collection.name}`);
72
- const response = await db.listCollections(dbId, [
73
- Query.equal("name", collection.name!),
74
- ]);
73
+ const response = await tryAwaitWithRetry(
74
+ async () =>
75
+ await db.listCollections(dbId, [Query.equal("name", collection.name!)])
76
+ );
75
77
  if (response.collections.length > 0) {
76
78
  console.log(`Collection found: ${response.collections[0].$id}`);
77
79
  return { ...collection, ...response.collections[0] };
@@ -94,12 +96,15 @@ export const fetchAndCacheCollectionByName = async (
94
96
  if (nameToIdMapping.has(collectionName)) {
95
97
  const collectionId = nameToIdMapping.get(collectionName);
96
98
  console.log(`\tCollection found in cache: ${collectionId}`);
97
- return await db.getCollection(dbId, collectionId!);
99
+ return await tryAwaitWithRetry(
100
+ async () => await db.getCollection(dbId, collectionId!)
101
+ );
98
102
  } else {
99
103
  console.log(`\tFetching collection by name: ${collectionName}`);
100
- const collectionsPulled = await db.listCollections(dbId, [
101
- Query.equal("name", collectionName),
102
- ]);
104
+ const collectionsPulled = await tryAwaitWithRetry(
105
+ async () =>
106
+ await db.listCollections(dbId, [Query.equal("name", collectionName)])
107
+ );
103
108
  if (collectionsPulled.total > 0) {
104
109
  const collection = collectionsPulled.collections[0];
105
110
  console.log(`\tCollection found: ${collection.$id}`);
@@ -117,8 +122,8 @@ export const wipeDatabase = async (
117
122
  databaseId: string
118
123
  ): Promise<{ collectionId: string; collectionName: string }[]> => {
119
124
  console.log(`Wiping database: ${databaseId}`);
120
- const { collections: existingCollections } = await database.listCollections(
121
- databaseId
125
+ const { collections: existingCollections } = await tryAwaitWithRetry(
126
+ async () => await database.listCollections(databaseId)
122
127
  );
123
128
  let collectionsDeleted: { collectionId: string; collectionName: string }[] =
124
129
  [];
@@ -155,7 +160,7 @@ export const createOrUpdateCollections = async (
155
160
 
156
161
  for (const { attributes, indexes, ...collection } of configCollections) {
157
162
  // Prepare permissions for the collection
158
- const permissions = [];
163
+ const permissions: string[] = [];
159
164
  if (collection.$permissions && collection.$permissions.length > 0) {
160
165
  for (const permission of collection.$permissions) {
161
166
  switch (permission.permission) {
@@ -182,15 +187,18 @@ export const createOrUpdateCollections = async (
182
187
  }
183
188
 
184
189
  // Check if the collection already exists by name
185
- let collectionsFound = await database.listCollections(databaseId, [
186
- Query.equal("name", collection.name),
187
- ]);
190
+ let collectionsFound = await tryAwaitWithRetry(
191
+ async () =>
192
+ await database.listCollections(databaseId, [
193
+ Query.equal("name", collection.name),
194
+ ])
195
+ );
188
196
 
189
197
  let collectionToUse =
190
198
  collectionsFound.total > 0 ? collectionsFound.collections[0] : null;
191
199
 
192
200
  // Determine the correct ID for the collection
193
- let collectionId;
201
+ let collectionId: string;
194
202
  if (!collectionToUse) {
195
203
  console.log(`Creating collection: ${collection.name}`);
196
204
  const foundColl = deletedCollections?.find(
@@ -211,16 +219,19 @@ export const createOrUpdateCollections = async (
211
219
 
212
220
  // Create the collection with the determined ID
213
221
  try {
214
- collectionToUse = await database.createCollection(
215
- databaseId,
216
- collectionId,
217
- collection.name,
218
- permissions,
219
- collection.documentSecurity ?? false,
220
- collection.enabled ?? true
222
+ collectionToUse = await tryAwaitWithRetry(
223
+ async () =>
224
+ await database.createCollection(
225
+ databaseId,
226
+ collectionId,
227
+ collection.name,
228
+ permissions,
229
+ collection.documentSecurity ?? false,
230
+ collection.enabled ?? true
231
+ )
221
232
  );
222
- collection.$id = collectionToUse.$id;
223
- nameToIdMapping.set(collection.name, collectionToUse.$id);
233
+ collection.$id = collectionToUse!.$id;
234
+ nameToIdMapping.set(collection.name, collectionToUse!.$id);
224
235
  } catch (error) {
225
236
  console.error(
226
237
  `Failed to create collection ${collection.name} with ID ${collectionId}: ${error}`
@@ -229,13 +240,16 @@ export const createOrUpdateCollections = async (
229
240
  }
230
241
  } else {
231
242
  console.log(`Collection ${collection.name} exists, updating it`);
232
- await database.updateCollection(
233
- databaseId,
234
- collectionToUse.$id,
235
- collection.name,
236
- permissions,
237
- collection.documentSecurity ?? false,
238
- collection.enabled ?? true
243
+ await tryAwaitWithRetry(
244
+ async () =>
245
+ await database.updateCollection(
246
+ databaseId,
247
+ collectionToUse!.$id,
248
+ collection.name,
249
+ permissions,
250
+ collection.documentSecurity ?? false,
251
+ collection.enabled ?? true
252
+ )
239
253
  );
240
254
  }
241
255
 
@@ -244,14 +258,14 @@ export const createOrUpdateCollections = async (
244
258
  await createUpdateCollectionAttributes(
245
259
  database,
246
260
  databaseId,
247
- collectionToUse,
261
+ collectionToUse!,
248
262
  attributes
249
263
  );
250
264
  console.log("Creating Indexes");
251
265
  await createOrUpdateIndexes(
252
266
  databaseId,
253
267
  database,
254
- collectionToUse.$id,
268
+ collectionToUse!.$id,
255
269
  indexes ?? []
256
270
  );
257
271
  }
@@ -294,7 +308,9 @@ export const fetchAllCollections = async (
294
308
  if (lastCollectionId) {
295
309
  queries.push(Query.cursorAfter(lastCollectionId));
296
310
  }
297
- const response = await database.listCollections(dbId, queries);
311
+ const response = await tryAwaitWithRetry(
312
+ async () => await database.listCollections(dbId, queries)
313
+ );
298
314
  collections = collections.concat(response.collections);
299
315
  moreCollections = response.collections.length === 500;
300
316
  if (moreCollections) {
@@ -108,7 +108,13 @@ export const convertObjectByAttributeMappings = (
108
108
  const values = mapping.oldKeys
109
109
  .map((oldKey) => resolveValue(obj, oldKey))
110
110
  .flat(Infinity);
111
- result[mapping.targetKey] = values.filter((value) => value !== undefined);
111
+ if (values.length > 0) {
112
+ result[mapping.targetKey] = values.filter(
113
+ (value) => value !== undefined
114
+ );
115
+ } else {
116
+ result[mapping.targetKey] = null;
117
+ }
112
118
  } else if (mapping.oldKey) {
113
119
  // Resolve single oldKey
114
120
  const value = resolveValue(obj, mapping.oldKey);
@@ -116,9 +122,19 @@ export const convertObjectByAttributeMappings = (
116
122
  result[mapping.targetKey] = Array.isArray(value)
117
123
  ? value.flat(Infinity)
118
124
  : value;
125
+ } else {
126
+ result[mapping.targetKey] = null;
119
127
  }
120
128
  }
121
129
  }
130
+
131
+ // Ensure any keys in the original object that are not mapped are copied over
132
+ for (const key of Object.keys(obj)) {
133
+ if (!Object.keys(result).includes(key)) {
134
+ result[key] = obj[key];
135
+ }
136
+ }
137
+
122
138
  return result;
123
139
  };
124
140