appwrite-utils-cli 0.9.51 → 0.9.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -124,6 +124,7 @@ This updated CLI ensures that developers have robust tools at their fingertips t
124
124
 
125
125
  ## Changelog
126
126
 
127
+ - 0.9.52: Add delay after creating indexes, attributes, and others to prevent `fetch failed` errors during large-scale collection creation
127
128
  - 0.9.51: Fix transfer databases, remove "ensure duplicates" check
128
129
  - 0.9.5: Fixed not checking for storage bucket for each database (checking the creation status) when importing data
129
130
  - 0.9.4: Fixed migrations database ensuring it has the required collections
@@ -2,7 +2,7 @@ import { Query } from "node-appwrite";
2
2
  import { attributeSchema, parseAttribute, } from "appwrite-utils";
3
3
  import { nameToIdMapping, enqueueOperation } from "../migrations/queue.js";
4
4
  import _ from "lodash";
5
- import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
5
+ import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
6
6
  const attributesSame = (databaseAttribute, configAttribute) => {
7
7
  return (databaseAttribute.key == configAttribute.key &&
8
8
  databaseAttribute.type == configAttribute.type &&
@@ -207,18 +207,18 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
207
207
  };
208
208
  export const createUpdateCollectionAttributes = async (db, dbId, collection, attributes) => {
209
209
  console.log(`Creating/Updating attributes for collection: ${collection.name}`);
210
- const batchSize = 3; // Size of each batch
210
+ const batchSize = 3;
211
211
  for (let i = 0; i < attributes.length; i += batchSize) {
212
- // Slice the attributes array to get a batch of at most batchSize elements
213
212
  const batch = attributes.slice(i, i + batchSize);
214
213
  const attributePromises = batch.map((attribute) => createOrUpdateAttribute(db, dbId, collection, attribute));
215
- // Await the completion of all promises in the current batch
216
214
  const results = await Promise.allSettled(attributePromises);
217
215
  results.forEach((result) => {
218
216
  if (result.status === "rejected") {
219
217
  console.error("An attribute promise was rejected:", result.reason);
220
218
  }
221
219
  });
220
+ // Add delay after each batch
221
+ await delay(2000);
222
222
  }
223
223
  console.log(`Finished creating/updating attributes for collection: ${collection.name}`);
224
224
  };
@@ -1,6 +1,6 @@
1
1
  import { indexSchema } from "appwrite-utils";
2
2
  import { Databases, IndexType, Query } from "node-appwrite";
3
- import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
3
+ import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
4
4
  export const createOrUpdateIndex = async (dbId, db, collectionId, index) => {
5
5
  const existingIndex = await db.listIndexes(dbId, collectionId, [
6
6
  Query.equal("key", index.key),
@@ -23,5 +23,7 @@ export const createOrUpdateIndex = async (dbId, db, collectionId, index) => {
23
23
  export const createOrUpdateIndexes = async (dbId, db, collectionId, indexes) => {
24
24
  for (const index of indexes) {
25
25
  await tryAwaitWithRetry(async () => await createOrUpdateIndex(dbId, db, collectionId, index));
26
+ // Add delay after each index creation/update
27
+ await delay(1000);
26
28
  }
27
29
  };
@@ -4,7 +4,7 @@ import { createUpdateCollectionAttributes } from "./attributes.js";
4
4
  import { createOrUpdateIndexes } from "./indexes.js";
5
5
  import _ from "lodash";
6
6
  import { SchemaGenerator } from "../utils/schemaStrings.js";
7
- import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
7
+ import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
8
8
  export const documentExists = async (db, dbId, targetCollectionId, toCreateObject) => {
9
9
  // Had to do this because kept running into issues with type checking arrays so, sorry 40ms
10
10
  const collection = await db.getCollection(dbId, targetCollectionId);
@@ -109,7 +109,7 @@ export const createOrUpdateCollections = async (database, databaseId, config, de
109
109
  if (!configCollections) {
110
110
  return;
111
111
  }
112
- const usedIds = new Set(); // To track IDs used in this operation
112
+ const usedIds = new Set();
113
113
  for (const { attributes, indexes, ...collection } of configCollections) {
114
114
  // Prepare permissions for the collection
115
115
  const permissions = [];
@@ -149,15 +149,15 @@ export const createOrUpdateCollections = async (database, databaseId, config, de
149
149
  let foundColl = deletedCollections?.find((coll) => coll.collectionName.toLowerCase().trim().replace(" ", "") ===
150
150
  collection.name.toLowerCase().trim().replace(" ", ""));
151
151
  if (collection.$id) {
152
- collectionId = collection.$id; // Always use the provided $id if present
152
+ collectionId = collection.$id;
153
153
  }
154
154
  else if (foundColl && !usedIds.has(foundColl.collectionId)) {
155
- collectionId = foundColl.collectionId; // Use ID from deleted collection if not already used
155
+ collectionId = foundColl.collectionId;
156
156
  }
157
157
  else {
158
- collectionId = ID.unique(); // Generate a new unique ID
158
+ collectionId = ID.unique();
159
159
  }
160
- usedIds.add(collectionId); // Mark this ID as used
160
+ usedIds.add(collectionId);
161
161
  // Create the collection with the determined ID
162
162
  try {
163
163
  collectionToUse = await tryAwaitWithRetry(async () => await database.createCollection(databaseId, collectionId, collection.name, permissions, collection.documentSecurity ?? false, collection.enabled ?? true));
@@ -166,18 +166,24 @@ export const createOrUpdateCollections = async (database, databaseId, config, de
166
166
  }
167
167
  catch (error) {
168
168
  console.error(`Failed to create collection ${collection.name} with ID ${collectionId}: ${error}`);
169
- continue; // Skip to the next collection on failure
169
+ continue;
170
170
  }
171
171
  }
172
172
  else {
173
173
  console.log(`Collection ${collection.name} exists, updating it`);
174
174
  await tryAwaitWithRetry(async () => await database.updateCollection(databaseId, collectionToUse.$id, collection.name, permissions, collection.documentSecurity ?? false, collection.enabled ?? true));
175
175
  }
176
+ // Add delay after creating/updating collection
177
+ await delay(1000);
176
178
  // Update attributes and indexes for the collection
177
179
  console.log("Creating Attributes");
178
180
  await createUpdateCollectionAttributes(database, databaseId, collectionToUse, attributes);
181
+ // Add delay after creating attributes
182
+ await delay(1000);
179
183
  console.log("Creating Indexes");
180
184
  await createOrUpdateIndexes(databaseId, database, collectionToUse.$id, indexes ?? []);
185
+ // Add delay after creating indexes
186
+ await delay(1000);
181
187
  }
182
188
  // Process any remaining tasks in the queue
183
189
  await processQueue(database, databaseId);
@@ -45,3 +45,4 @@ export declare let numTimesFailedTotal: number;
45
45
  */
46
46
  export declare const tryAwaitWithRetry: <T>(createFunction: () => Promise<T>, attemptNum?: number, throwError?: boolean) => Promise<T>;
47
47
  export declare const getAppwriteClient: (endpoint: string, projectId: string, apiKey: string) => Client;
48
+ export declare const delay: (ms: number) => Promise<unknown>;
@@ -116,3 +116,4 @@ export const getAppwriteClient = (endpoint, projectId, apiKey) => {
116
116
  .setProject(projectId)
117
117
  .setKey(apiKey);
118
118
  };
119
+ export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
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.9.51",
4
+ "version": "0.9.52",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -6,7 +6,7 @@ import {
6
6
  } from "appwrite-utils";
7
7
  import { nameToIdMapping, enqueueOperation } from "../migrations/queue.js";
8
8
  import _ from "lodash";
9
- import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
9
+ import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
10
10
 
11
11
  const attributesSame = (
12
12
  databaseAttribute: Attribute,
@@ -461,21 +461,22 @@ export const createUpdateCollectionAttributes = async (
461
461
  `Creating/Updating attributes for collection: ${collection.name}`
462
462
  );
463
463
 
464
- const batchSize = 3; // Size of each batch
464
+ const batchSize = 3;
465
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
466
  const batch = attributes.slice(i, i + batchSize);
468
467
  const attributePromises = batch.map((attribute) =>
469
468
  createOrUpdateAttribute(db, dbId, collection, attribute)
470
469
  );
471
470
 
472
- // Await the completion of all promises in the current batch
473
471
  const results = await Promise.allSettled(attributePromises);
474
472
  results.forEach((result) => {
475
473
  if (result.status === "rejected") {
476
474
  console.error("An attribute promise was rejected:", result.reason);
477
475
  }
478
476
  });
477
+
478
+ // Add delay after each batch
479
+ await delay(2000);
479
480
  }
480
481
  console.log(
481
482
  `Finished creating/updating attributes for collection: ${collection.name}`
@@ -1,6 +1,6 @@
1
1
  import { indexSchema, type Index } from "appwrite-utils";
2
2
  import { Databases, IndexType, Query, type Models } from "node-appwrite";
3
- import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
3
+ import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
4
4
 
5
5
  export const createOrUpdateIndex = async (
6
6
  dbId: string,
@@ -49,5 +49,7 @@ export const createOrUpdateIndexes = async (
49
49
  await tryAwaitWithRetry(
50
50
  async () => await createOrUpdateIndex(dbId, db, collectionId, index)
51
51
  );
52
+ // Add delay after each index creation/update
53
+ await delay(1000);
52
54
  }
53
55
  };
@@ -12,7 +12,7 @@ import { createUpdateCollectionAttributes } from "./attributes.js";
12
12
  import { createOrUpdateIndexes } from "./indexes.js";
13
13
  import _ from "lodash";
14
14
  import { SchemaGenerator } from "../utils/schemaStrings.js";
15
- import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
15
+ import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
16
16
 
17
17
  export const documentExists = async (
18
18
  db: Databases,
@@ -163,7 +163,7 @@ export const createOrUpdateCollections = async (
163
163
  if (!configCollections) {
164
164
  return;
165
165
  }
166
- const usedIds = new Set(); // To track IDs used in this operation
166
+ const usedIds = new Set();
167
167
 
168
168
  for (const { attributes, indexes, ...collection } of configCollections) {
169
169
  // Prepare permissions for the collection
@@ -215,14 +215,14 @@ export const createOrUpdateCollections = async (
215
215
  );
216
216
 
217
217
  if (collection.$id) {
218
- collectionId = collection.$id; // Always use the provided $id if present
218
+ collectionId = collection.$id;
219
219
  } else if (foundColl && !usedIds.has(foundColl.collectionId)) {
220
- collectionId = foundColl.collectionId; // Use ID from deleted collection if not already used
220
+ collectionId = foundColl.collectionId;
221
221
  } else {
222
- collectionId = ID.unique(); // Generate a new unique ID
222
+ collectionId = ID.unique();
223
223
  }
224
224
 
225
- usedIds.add(collectionId); // Mark this ID as used
225
+ usedIds.add(collectionId);
226
226
 
227
227
  // Create the collection with the determined ID
228
228
  try {
@@ -243,7 +243,7 @@ export const createOrUpdateCollections = async (
243
243
  console.error(
244
244
  `Failed to create collection ${collection.name} with ID ${collectionId}: ${error}`
245
245
  );
246
- continue; // Skip to the next collection on failure
246
+ continue;
247
247
  }
248
248
  } else {
249
249
  console.log(`Collection ${collection.name} exists, updating it`);
@@ -260,6 +260,9 @@ export const createOrUpdateCollections = async (
260
260
  );
261
261
  }
262
262
 
263
+ // Add delay after creating/updating collection
264
+ await delay(1000);
265
+
263
266
  // Update attributes and indexes for the collection
264
267
  console.log("Creating Attributes");
265
268
  await createUpdateCollectionAttributes(
@@ -268,6 +271,10 @@ export const createOrUpdateCollections = async (
268
271
  collectionToUse!,
269
272
  attributes
270
273
  );
274
+
275
+ // Add delay after creating attributes
276
+ await delay(1000);
277
+
271
278
  console.log("Creating Indexes");
272
279
  await createOrUpdateIndexes(
273
280
  databaseId,
@@ -275,6 +282,9 @@ export const createOrUpdateCollections = async (
275
282
  collectionToUse!.$id,
276
283
  indexes ?? []
277
284
  );
285
+
286
+ // Add delay after creating indexes
287
+ await delay(1000);
278
288
  }
279
289
  // Process any remaining tasks in the queue
280
290
  await processQueue(database, databaseId);
@@ -179,3 +179,6 @@ export const getAppwriteClient = (
179
179
  .setProject(projectId)
180
180
  .setKey(apiKey);
181
181
  };
182
+
183
+ export const delay = (ms: number) =>
184
+ new Promise((resolve) => setTimeout(resolve, ms));