appwrite-utils-cli 0.0.20 → 0.0.21

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.
@@ -148,7 +148,7 @@ export class ImportController {
148
148
  async processBatch(db, collection, importDef, dataToImport, updateDefs = [], isMembersCollection = false) {
149
149
  for (let i = 0; i < dataToImport.length; i += this.batchLimit) {
150
150
  const batch = dataToImport.slice(i, i + this.batchLimit);
151
- const results = await Promise.allSettled(batch.map(async (item) => {
151
+ for (const item of batch) {
152
152
  let context = this.createContext(db, collection, item);
153
153
  let finalItem = await this.transformData(item, importDef.attributeMappings);
154
154
  let createIdToUse = undefined;
@@ -222,13 +222,17 @@ export class ImportController {
222
222
  // attributeMappings: attributeMappingsWithActions,
223
223
  // });
224
224
  }
225
- }));
226
- results.forEach((result) => {
227
- if (result.status === "rejected") {
228
- console.error("A process batch promise was rejected:", result.reason);
229
- logger.error("An error occurred during creation: ", result.reason);
230
- }
231
- });
225
+ }
226
+ // const results = await Promise.allSettled(
227
+ // batch.map(async (item: any) => {
228
+ // })
229
+ // );
230
+ // results.forEach((result) => {
231
+ // if (result.status === "rejected") {
232
+ // console.error("A process batch promise was rejected:", result.reason);
233
+ // logger.error("An error occurred during creation: ", result.reason);
234
+ // }
235
+ // });
232
236
  }
233
237
  }
234
238
  async handleCreate(context, finalItem, updateDefs, id) {
@@ -49,7 +49,6 @@ export const getAfterImportOperations = async (database, collectionId) => {
49
49
  const query = [
50
50
  Query.equal("collectionId", collectionId),
51
51
  Query.equal("operationType", "afterImportAction"),
52
- Query.equal("status", "ready"),
53
52
  Query.limit(100),
54
53
  ];
55
54
  if (lastDocumentId) {
@@ -58,7 +57,7 @@ export const getAfterImportOperations = async (database, collectionId) => {
58
57
  const operations = await database.listDocuments("migrations", "currentOperations", query);
59
58
  total = operations.total; // Update total with the latest fetch
60
59
  allOperations.push(...operations.documents);
61
- if (operations.documents.length > 0) {
60
+ if (operations.documents.length > 0 && operations.documents.length >= 100) {
62
61
  lastDocumentId =
63
62
  operations.documents[operations.documents.length - 1].$id;
64
63
  }
@@ -79,7 +78,7 @@ export const setAllPendingAfterImportActionsToReady = async (database, dbId, col
79
78
  await database.updateDocument("migrations", "currentOperations", operation.$id, { status: "ready" });
80
79
  }
81
80
  // Prepare for the next iteration in case there are more than 100 documents
82
- if (operations.documents.length > 0) {
81
+ if (operations.documents.length > 0 && operations.documents.length >= 100) {
83
82
  lastDocumentId =
84
83
  operations.documents[operations.documents.length - 1].$id;
85
84
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "appwrite-utils-cli",
3
3
  "description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
4
- "version": "0.0.20",
4
+ "version": "0.0.21",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -257,133 +257,135 @@ export class ImportController {
257
257
  ) {
258
258
  for (let i = 0; i < dataToImport.length; i += this.batchLimit) {
259
259
  const batch = dataToImport.slice(i, i + this.batchLimit);
260
- const results = await Promise.allSettled(
261
- batch.map(async (item: any) => {
262
- let context = this.createContext(db, collection, item);
263
- let finalItem = await this.transformData(
264
- item,
265
- importDef.attributeMappings
260
+ for (const item of batch) {
261
+ let context = this.createContext(db, collection, item);
262
+ let finalItem = await this.transformData(
263
+ item,
264
+ importDef.attributeMappings
265
+ );
266
+ let createIdToUse: string | undefined = undefined;
267
+ let associatedDoc: Models.Document | undefined;
268
+ if (
269
+ isMembersCollection &&
270
+ (finalItem.hasOwnProperty("email") || item.hasOwnProperty("phone"))
271
+ ) {
272
+ const usersController = new UsersController(
273
+ this.config,
274
+ this.database
266
275
  );
267
- let createIdToUse: string | undefined = undefined;
268
- let associatedDoc: Models.Document | undefined;
269
- if (
270
- isMembersCollection &&
271
- (finalItem.hasOwnProperty("email") || item.hasOwnProperty("phone"))
272
- ) {
273
- const usersController = new UsersController(
274
- this.config,
275
- this.database
276
- );
277
- const userToCreate = AuthUserCreateSchema.safeParse({
278
- ...finalItem,
279
- });
280
- if (!userToCreate.success) {
281
- console.error(userToCreate.error);
282
- logger.error(userToCreate.error);
283
- return;
284
- }
285
- const user = await usersController.createUserAndReturn(
286
- userToCreate.data
287
- );
288
- if (!user) {
289
- logger.error(
290
- `Skipping user & contact creation for ${item} because of an error...`
291
- );
292
- return;
293
- }
294
- createIdToUse = user.$id;
295
- context.docId = createIdToUse;
296
- context = { ...context, ...user };
297
- const associatedDocFound = await this.database.listDocuments(
298
- db.$id,
299
- context.collId,
300
- [Query.equal("$id", createIdToUse)]
301
- );
302
- if (associatedDocFound.documents.length > 0) {
303
- associatedDoc = associatedDocFound.documents[0];
304
- }
305
- // Delete keys in finalItem that also exist in user
306
- let deletedKeys: string[] = [];
307
- Object.keys(finalItem).forEach((key) => {
308
- if (user.hasOwnProperty(key)) {
309
- delete finalItem[key];
310
- deletedKeys.push(key);
311
- }
312
- });
313
- } else if (isMembersCollection) {
276
+ const userToCreate = AuthUserCreateSchema.safeParse({
277
+ ...finalItem,
278
+ });
279
+ if (!userToCreate.success) {
280
+ console.error(userToCreate.error);
281
+ logger.error(userToCreate.error);
282
+ return;
283
+ }
284
+ const user = await usersController.createUserAndReturn(
285
+ userToCreate.data
286
+ );
287
+ if (!user) {
314
288
  logger.error(
315
- `Skipping user & contact creation for ${item} due to lack of email...`
289
+ `Skipping user & contact creation for ${item} because of an error...`
316
290
  );
291
+ return;
292
+ }
293
+ createIdToUse = user.$id;
294
+ context.docId = createIdToUse;
295
+ context = { ...context, ...user };
296
+ const associatedDocFound = await this.database.listDocuments(
297
+ db.$id,
298
+ context.collId,
299
+ [Query.equal("$id", createIdToUse)]
300
+ );
301
+ if (associatedDocFound.documents.length > 0) {
302
+ associatedDoc = associatedDocFound.documents[0];
317
303
  }
304
+ // Delete keys in finalItem that also exist in user
305
+ let deletedKeys: string[] = [];
306
+ Object.keys(finalItem).forEach((key) => {
307
+ if (user.hasOwnProperty(key)) {
308
+ delete finalItem[key];
309
+ deletedKeys.push(key);
310
+ }
311
+ });
312
+ } else if (isMembersCollection) {
313
+ logger.error(
314
+ `Skipping user & contact creation for ${item} due to lack of email...`
315
+ );
316
+ }
317
+
318
+ context = { ...context, ...finalItem };
319
+ const validated = await this.importDataActions.validateItem(
320
+ finalItem,
321
+ importDef.attributeMappings,
322
+ context
323
+ );
324
+ if (!validated) {
325
+ console.error("Validation failed for item:", finalItem);
326
+ logger.error("Validation failed for item:", finalItem);
327
+ return;
328
+ }
318
329
 
319
- context = { ...context, ...finalItem };
320
- const validated = await this.importDataActions.validateItem(
330
+ if (
331
+ (importDef.type === "create" || !importDef.type) &&
332
+ !associatedDoc
333
+ ) {
334
+ const createdContext = await this.handleCreate(
335
+ context,
336
+ finalItem,
337
+ updateDefs,
338
+ createIdToUse
339
+ );
340
+ context = { ...context, ...createdContext };
341
+ } else {
342
+ const updatedContext = await this.handleUpdate(
343
+ context,
321
344
  finalItem,
345
+ importDef
346
+ );
347
+ context = { ...context, ...updatedContext };
348
+ }
349
+ const afterImportActionContext = structuredClone(context);
350
+ const attributeMappingsWithActions =
351
+ this.getAttributeMappingsWithActions(
322
352
  importDef.attributeMappings,
323
- context
353
+ afterImportActionContext,
354
+ finalItem
324
355
  );
325
- if (!validated) {
326
- console.error("Validation failed for item:", finalItem);
327
- logger.error("Validation failed for item:", finalItem);
328
- return;
329
- }
330
-
331
- if (
332
- (importDef.type === "create" || !importDef.type) &&
333
- !associatedDoc
334
- ) {
335
- const createdContext = await this.handleCreate(
336
- context,
337
- finalItem,
338
- updateDefs,
339
- createIdToUse
340
- );
341
- context = { ...context, ...createdContext };
342
- } else {
343
- const updatedContext = await this.handleUpdate(
344
- context,
345
- finalItem,
346
- importDef
347
- );
348
- context = { ...context, ...updatedContext };
349
- }
350
- const afterImportActionContext = structuredClone(context);
351
- const attributeMappingsWithActions =
352
- this.getAttributeMappingsWithActions(
353
- importDef.attributeMappings,
354
- afterImportActionContext,
355
- finalItem
356
- );
357
- if (attributeMappingsWithActions.some((m) => m.postImportActions)) {
358
- logger.info(
359
- `Pushing to post-import actions queue for ${context.docId}`
360
- );
361
- const afterImportOperationContext = ContextObject.parse({
362
- dbId: db.$id,
363
- collectionId: collection.$id,
364
- finalItem: finalItem,
365
- attributeMappings: attributeMappingsWithActions,
366
- context: afterImportActionContext,
367
- });
368
- await createOrFindAfterImportOperation(
369
- this.database,
370
- context.collId,
371
- afterImportOperationContext
372
- );
373
- // this.postImportActionsQueue.push({
374
- // context: afterImportActionContext,
375
- // finalItem: finalItem,
376
- // attributeMappings: attributeMappingsWithActions,
377
- // });
378
- }
379
- })
380
- );
381
- results.forEach((result) => {
382
- if (result.status === "rejected") {
383
- console.error("A process batch promise was rejected:", result.reason);
384
- logger.error("An error occurred during creation: ", result.reason);
356
+ if (attributeMappingsWithActions.some((m) => m.postImportActions)) {
357
+ logger.info(
358
+ `Pushing to post-import actions queue for ${context.docId}`
359
+ );
360
+ const afterImportOperationContext = ContextObject.parse({
361
+ dbId: db.$id,
362
+ collectionId: collection.$id,
363
+ finalItem: finalItem,
364
+ attributeMappings: attributeMappingsWithActions,
365
+ context: afterImportActionContext,
366
+ });
367
+ await createOrFindAfterImportOperation(
368
+ this.database,
369
+ context.collId,
370
+ afterImportOperationContext
371
+ );
372
+ // this.postImportActionsQueue.push({
373
+ // context: afterImportActionContext,
374
+ // finalItem: finalItem,
375
+ // attributeMappings: attributeMappingsWithActions,
376
+ // });
385
377
  }
386
- });
378
+ }
379
+ // const results = await Promise.allSettled(
380
+ // batch.map(async (item: any) => {
381
+ // })
382
+ // );
383
+ // results.forEach((result) => {
384
+ // if (result.status === "rejected") {
385
+ // console.error("A process batch promise was rejected:", result.reason);
386
+ // logger.error("An error occurred during creation: ", result.reason);
387
+ // }
388
+ // });
387
389
  }
388
390
  }
389
391
 
@@ -78,7 +78,6 @@ export const getAfterImportOperations = async (
78
78
  const query = [
79
79
  Query.equal("collectionId", collectionId),
80
80
  Query.equal("operationType", "afterImportAction"),
81
- Query.equal("status", "ready"),
82
81
  Query.limit(100),
83
82
  ];
84
83
 
@@ -94,7 +93,7 @@ export const getAfterImportOperations = async (
94
93
  total = operations.total; // Update total with the latest fetch
95
94
  allOperations.push(...operations.documents);
96
95
 
97
- if (operations.documents.length > 0) {
96
+ if (operations.documents.length > 0 && operations.documents.length >= 100) {
98
97
  lastDocumentId =
99
98
  operations.documents[operations.documents.length - 1].$id;
100
99
  }
@@ -134,7 +133,7 @@ export const setAllPendingAfterImportActionsToReady = async (
134
133
  }
135
134
 
136
135
  // Prepare for the next iteration in case there are more than 100 documents
137
- if (operations.documents.length > 0) {
136
+ if (operations.documents.length > 0 && operations.documents.length >= 100) {
138
137
  lastDocumentId =
139
138
  operations.documents[operations.documents.length - 1].$id;
140
139
  } else {