appwrite-utils-cli 0.9.77 → 0.9.79
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 +3 -0
- package/dist/collections/attributes.js +12 -5
- package/dist/collections/methods.d.ts +2 -1
- package/dist/collections/methods.js +68 -36
- package/dist/interactiveCLI.d.ts +4 -0
- package/dist/interactiveCLI.js +141 -53
- package/dist/main.js +53 -39
- package/dist/migrations/importController.d.ts +3 -3
- package/dist/migrations/importController.js +126 -149
- package/dist/migrations/setupDatabase.d.ts +2 -1
- package/dist/migrations/setupDatabase.js +27 -5
- package/dist/storage/methods.js +4 -1
- package/dist/utils/setupFiles.js +4 -1
- package/dist/utilsController.d.ts +8 -4
- package/dist/utilsController.js +45 -15
- package/package.json +4 -3
- package/src/collections/attributes.ts +12 -7
- package/src/collections/methods.ts +78 -40
- package/src/interactiveCLI.ts +179 -75
- package/src/main.ts +60 -45
- package/src/migrations/importController.ts +167 -279
- package/src/migrations/setupDatabase.ts +48 -7
- package/src/storage/methods.ts +4 -4
- package/src/utils/setupFiles.ts +4 -1
- package/src/utilsController.ts +50 -13
@@ -67,7 +67,7 @@ export class ImportController {
|
|
67
67
|
this.databasesToRun = databasesToRun || [];
|
68
68
|
}
|
69
69
|
|
70
|
-
async run() {
|
70
|
+
async run(specificCollections?: string[]) {
|
71
71
|
let databasesToProcess: Models.Database[];
|
72
72
|
|
73
73
|
if (this.databasesToRun.length > 0) {
|
@@ -101,9 +101,9 @@ export class ImportController {
|
|
101
101
|
this.setupOptions.shouldWriteFile
|
102
102
|
);
|
103
103
|
await dataLoader.start(db.$id);
|
104
|
-
await this.importCollections(db, dataLoader);
|
104
|
+
await this.importCollections(db, dataLoader, specificCollections);
|
105
105
|
await resolveAndUpdateRelationships(db.$id, this.database, this.config);
|
106
|
-
await this.executePostImportActions(db.$id, dataLoader);
|
106
|
+
await this.executePostImportActions(db.$id, dataLoader, specificCollections);
|
107
107
|
} else if (databaseRan.$id !== db.$id) {
|
108
108
|
await this.updateOthersToFinalData(databaseRan, db);
|
109
109
|
}
|
@@ -142,307 +142,195 @@ export class ImportController {
|
|
142
142
|
}
|
143
143
|
}
|
144
144
|
|
145
|
-
async importCollections(db: ConfigDatabase, dataLoader: DataLoader) {
|
146
|
-
|
147
|
-
return;
|
148
|
-
}
|
149
|
-
for (const collection of this.config.collections) {
|
150
|
-
let isUsersCollection =
|
151
|
-
dataLoader.getCollectionKey(this.config.usersCollectionName) ===
|
152
|
-
dataLoader.getCollectionKey(collection.name);
|
153
|
-
const importOperationId = dataLoader.collectionImportOperations.get(
|
154
|
-
dataLoader.getCollectionKey(collection.name)
|
155
|
-
);
|
156
|
-
const createBatches = (finalData: CollectionImportData["data"]) => {
|
157
|
-
let maxBatchLength = 100;
|
158
|
-
const finalBatches: CollectionImportData["data"][] = [];
|
159
|
-
for (let i = 0; i < finalData.length; i++) {
|
160
|
-
if (i % maxBatchLength === 0) {
|
161
|
-
finalBatches.push([]);
|
162
|
-
}
|
163
|
-
finalBatches[finalBatches.length - 1].push(finalData[i]);
|
164
|
-
}
|
165
|
-
return finalBatches;
|
166
|
-
};
|
145
|
+
async importCollections(db: ConfigDatabase, dataLoader: DataLoader, specificCollections?: string[]) {
|
146
|
+
const collectionsToImport = specificCollections || (this.config.collections ? this.config.collections.map(c => c.name) : []);
|
167
147
|
|
168
|
-
|
169
|
-
|
170
|
-
|
148
|
+
for (const collection of this.config.collections || []) {
|
149
|
+
if (collectionsToImport.includes(collection.name)) {
|
150
|
+
let isUsersCollection =
|
151
|
+
dataLoader.getCollectionKey(this.config.usersCollectionName) ===
|
152
|
+
dataLoader.getCollectionKey(collection.name);
|
153
|
+
const importOperationId = dataLoader.collectionImportOperations.get(
|
154
|
+
dataLoader.getCollectionKey(collection.name)
|
171
155
|
);
|
172
|
-
const
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
156
|
+
const createBatches = (finalData: CollectionImportData["data"]) => {
|
157
|
+
let maxBatchLength = 100;
|
158
|
+
const finalBatches: CollectionImportData["data"][] = [];
|
159
|
+
for (let i = 0; i < finalData.length; i++) {
|
160
|
+
if (i % maxBatchLength === 0) {
|
161
|
+
finalBatches.push([]);
|
162
|
+
}
|
163
|
+
finalBatches[finalBatches.length - 1].push(finalData[i]);
|
164
|
+
}
|
165
|
+
return finalBatches;
|
166
|
+
};
|
167
|
+
|
168
|
+
if (isUsersCollection && !this.hasImportedUsers) {
|
169
|
+
const usersDataMap = dataLoader.importMap.get(
|
170
|
+
dataLoader.getCollectionKey("users")
|
171
|
+
);
|
172
|
+
const usersData = usersDataMap?.data;
|
173
|
+
const usersController = new UsersController(this.config, this.database);
|
174
|
+
if (usersData) {
|
175
|
+
console.log("Found users data", usersData.length);
|
176
|
+
const userDataBatches = createBatches(usersData);
|
177
|
+
for (const batch of userDataBatches) {
|
178
|
+
console.log("Importing users batch", batch.length);
|
179
|
+
const userBatchPromises = batch
|
180
|
+
.filter((item) => {
|
181
|
+
let itemId: string | undefined;
|
182
|
+
if (item.finalData.userId) {
|
183
|
+
itemId = item.finalData.userId;
|
184
|
+
} else if (item.finalData.docId) {
|
185
|
+
itemId = item.finalData.docId;
|
186
|
+
}
|
187
|
+
if (!itemId) {
|
188
|
+
return false;
|
189
|
+
}
|
190
|
+
return (
|
191
|
+
item &&
|
192
|
+
item.finalData &&
|
193
|
+
!dataLoader.userExistsMap.has(itemId)
|
194
|
+
);
|
195
|
+
})
|
196
|
+
.map((item) => {
|
197
|
+
dataLoader.userExistsMap.set(
|
198
|
+
item.finalData.userId ||
|
199
|
+
item.finalData.docId ||
|
200
|
+
item.context.userId ||
|
201
|
+
item.context.docId,
|
202
|
+
true
|
203
|
+
);
|
204
|
+
return usersController.createUserAndReturn(item.finalData);
|
205
|
+
});
|
206
|
+
const promiseResults = await Promise.allSettled(userBatchPromises);
|
207
|
+
for (const item of batch) {
|
208
|
+
if (item && item.finalData) {
|
209
|
+
dataLoader.userExistsMap.set(
|
210
|
+
item.finalData.userId ||
|
211
|
+
item.finalData.docId ||
|
212
|
+
item.context.userId ||
|
213
|
+
item.context.docId,
|
214
|
+
true
|
215
|
+
);
|
189
216
|
}
|
190
|
-
return (
|
191
|
-
item &&
|
192
|
-
item.finalData &&
|
193
|
-
!dataLoader.userExistsMap.has(itemId)
|
194
|
-
);
|
195
|
-
})
|
196
|
-
.map((item) => {
|
197
|
-
dataLoader.userExistsMap.set(
|
198
|
-
item.finalData.userId ||
|
199
|
-
item.finalData.docId ||
|
200
|
-
item.context.userId ||
|
201
|
-
item.context.docId,
|
202
|
-
true
|
203
|
-
);
|
204
|
-
return usersController.createUserAndReturn(item.finalData);
|
205
|
-
});
|
206
|
-
const promiseResults = await Promise.allSettled(userBatchPromises);
|
207
|
-
for (const item of batch) {
|
208
|
-
if (item && item.finalData) {
|
209
|
-
dataLoader.userExistsMap.set(
|
210
|
-
item.finalData.userId ||
|
211
|
-
item.finalData.docId ||
|
212
|
-
item.context.userId ||
|
213
|
-
item.context.docId,
|
214
|
-
true
|
215
|
-
);
|
216
217
|
}
|
218
|
+
console.log("Finished importing users batch");
|
217
219
|
}
|
218
|
-
|
220
|
+
this.hasImportedUsers = true;
|
221
|
+
console.log("Finished importing users");
|
219
222
|
}
|
220
|
-
this.hasImportedUsers = true;
|
221
|
-
console.log("Finished importing users");
|
222
223
|
}
|
223
|
-
}
|
224
|
-
|
225
|
-
if (!importOperationId) {
|
226
|
-
// Skip further processing if no import operation is found
|
227
|
-
continue;
|
228
|
-
}
|
229
|
-
|
230
|
-
const importOperation = await this.database.getDocument(
|
231
|
-
"migrations",
|
232
|
-
"currentOperations",
|
233
|
-
importOperationId
|
234
|
-
);
|
235
|
-
await updateOperation(this.database, importOperation.$id, {
|
236
|
-
status: "in_progress",
|
237
|
-
});
|
238
|
-
const collectionData = dataLoader.importMap.get(
|
239
|
-
dataLoader.getCollectionKey(collection.name)
|
240
|
-
);
|
241
|
-
console.log(`Processing collection: ${collection.name}...`);
|
242
|
-
if (!collectionData) {
|
243
|
-
console.log("No collection data for ", collection.name);
|
244
|
-
continue;
|
245
|
-
}
|
246
|
-
|
247
|
-
const dataSplit = createBatches(collectionData.data);
|
248
|
-
let processedItems = 0;
|
249
|
-
for (let i = 0; i < dataSplit.length; i++) {
|
250
|
-
const batches = dataSplit[i];
|
251
|
-
console.log(`Processing batch ${i + 1} of ${dataSplit.length}`);
|
252
224
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
// item.finalData.userId ||
|
258
|
-
// item.context.docId ||
|
259
|
-
// item.context.userId;
|
225
|
+
if (!importOperationId) {
|
226
|
+
// Skip further processing if no import operation is found
|
227
|
+
continue;
|
228
|
+
}
|
260
229
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
// });
|
230
|
+
const importOperation = await this.database.getDocument(
|
231
|
+
"migrations",
|
232
|
+
"currentOperations",
|
233
|
+
importOperationId
|
234
|
+
);
|
235
|
+
await updateOperation(this.database, importOperation.$id, {
|
236
|
+
status: "in_progress",
|
237
|
+
});
|
238
|
+
const collectionData = dataLoader.importMap.get(
|
239
|
+
dataLoader.getCollectionKey(collection.name)
|
240
|
+
);
|
241
|
+
console.log(`Processing collection: ${collection.name}...`);
|
242
|
+
if (!collectionData) {
|
243
|
+
console.log("No collection data for ", collection.name);
|
244
|
+
continue;
|
245
|
+
}
|
278
246
|
|
279
|
-
|
247
|
+
const dataSplit = createBatches(collectionData.data);
|
248
|
+
let processedItems = 0;
|
249
|
+
for (let i = 0; i < dataSplit.length; i++) {
|
250
|
+
const batches = dataSplit[i];
|
251
|
+
console.log(`Processing batch ${i + 1} of ${dataSplit.length}`);
|
280
252
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
253
|
+
const batchPromises = batches.map((item, index) => {
|
254
|
+
try {
|
255
|
+
const id =
|
256
|
+
item.finalData.docId ||
|
257
|
+
item.finalData.userId ||
|
258
|
+
item.context.docId ||
|
259
|
+
item.context.userId;
|
288
260
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
261
|
+
if (item.finalData.hasOwnProperty("userId")) {
|
262
|
+
delete item.finalData.userId;
|
263
|
+
}
|
264
|
+
if (item.finalData.hasOwnProperty("docId")) {
|
265
|
+
delete item.finalData.docId;
|
266
|
+
}
|
267
|
+
if (!item.finalData) {
|
268
|
+
return Promise.resolve();
|
269
|
+
}
|
270
|
+
return tryAwaitWithRetry(
|
271
|
+
async () =>
|
272
|
+
await this.database.createDocument(
|
273
|
+
db.$id,
|
274
|
+
collection.$id,
|
275
|
+
id,
|
276
|
+
item.finalData
|
277
|
+
)
|
278
|
+
);
|
279
|
+
} catch (error) {
|
280
|
+
console.error(error);
|
296
281
|
return Promise.resolve();
|
297
282
|
}
|
298
|
-
|
299
|
-
async () =>
|
300
|
-
await this.database.createDocument(
|
301
|
-
db.$id,
|
302
|
-
collection.$id,
|
303
|
-
id,
|
304
|
-
item.finalData
|
305
|
-
)
|
306
|
-
);
|
307
|
-
} catch (error) {
|
308
|
-
console.error(error);
|
309
|
-
return Promise.resolve();
|
310
|
-
}
|
311
|
-
});
|
283
|
+
});
|
312
284
|
|
313
|
-
|
314
|
-
|
315
|
-
|
285
|
+
// Wait for all promises in the current batch to resolve
|
286
|
+
await Promise.all(batchPromises);
|
287
|
+
console.log(`Completed batch ${i + 1} of ${dataSplit.length}`);
|
288
|
+
await updateOperation(this.database, importOperation.$id, {
|
289
|
+
progress: processedItems,
|
290
|
+
});
|
291
|
+
}
|
292
|
+
// After all batches are processed, update the operation status to completed
|
316
293
|
await updateOperation(this.database, importOperation.$id, {
|
317
|
-
|
294
|
+
status: "completed",
|
318
295
|
});
|
319
296
|
}
|
320
|
-
// After all batches are processed, update the operation status to completed
|
321
|
-
await updateOperation(this.database, importOperation.$id, {
|
322
|
-
status: "completed",
|
323
|
-
});
|
324
297
|
}
|
325
298
|
}
|
326
299
|
|
327
|
-
async executePostImportActions(dbId: string, dataLoader: DataLoader) {
|
300
|
+
async executePostImportActions(dbId: string, dataLoader: DataLoader, specificCollections?: string[]) {
|
301
|
+
const collectionsToProcess = specificCollections || Array.from(dataLoader.importMap.keys());
|
302
|
+
|
328
303
|
// Iterate over each collection in the importMap
|
329
|
-
for (const [
|
330
|
-
collectionKey
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
`Processing post-import actions for collection: ${collectionKey}`
|
335
|
-
);
|
304
|
+
for (const [collectionKey, collectionData] of dataLoader.importMap.entries()) {
|
305
|
+
if (collectionsToProcess.includes(collectionKey)) {
|
306
|
+
console.log(
|
307
|
+
`Processing post-import actions for collection: ${collectionKey}`
|
308
|
+
);
|
336
309
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
310
|
+
// Iterate over each item in the collectionData.data
|
311
|
+
for (const item of collectionData.data) {
|
312
|
+
// Assuming each item has attributeMappings that contain actions to be executed
|
313
|
+
if (item.importDef && item.importDef.attributeMappings) {
|
314
|
+
// Use item.context as the context for action execution
|
315
|
+
const context = item.context; // Directly use item.context as the context for action execution
|
316
|
+
// Iterate through attributeMappings to execute actions
|
317
|
+
try {
|
318
|
+
// Execute post-import actions for the current attributeMapping
|
319
|
+
// Pass item.finalData as the data to be processed along with the context
|
320
|
+
await this.importDataActions.executeAfterImportActions(
|
321
|
+
item.finalData,
|
322
|
+
item.importDef.attributeMappings,
|
323
|
+
context
|
324
|
+
);
|
325
|
+
} catch (error) {
|
326
|
+
console.error(
|
327
|
+
`Failed to execute post-import actions for item in collection ${collectionKey}:`,
|
328
|
+
error
|
329
|
+
);
|
330
|
+
}
|
358
331
|
}
|
359
332
|
}
|
360
333
|
}
|
361
334
|
}
|
362
335
|
}
|
363
|
-
|
364
|
-
// async executeActionsInParallel(dbId: string, collection: ConfigCollection) {
|
365
|
-
// const collectionExists = await checkForCollection(
|
366
|
-
// this.database,
|
367
|
-
// dbId,
|
368
|
-
// collection
|
369
|
-
// );
|
370
|
-
// if (!collectionExists) {
|
371
|
-
// logger.error(`No collection found for ${collection.name}`);
|
372
|
-
// return; // Skip this iteration
|
373
|
-
// }
|
374
|
-
// const operations = await getAfterImportOperations(
|
375
|
-
// this.database,
|
376
|
-
// collectionExists.$id
|
377
|
-
// );
|
378
|
-
|
379
|
-
// for (const operation of operations) {
|
380
|
-
// if (!operation.batches) {
|
381
|
-
// continue;
|
382
|
-
// }
|
383
|
-
// const batches = operation.batches;
|
384
|
-
// const promises = [];
|
385
|
-
// for (const batch of batches) {
|
386
|
-
// const batchId = batch;
|
387
|
-
// promises.push(
|
388
|
-
// this.database.getDocument("migrations", "batches", batchId)
|
389
|
-
// );
|
390
|
-
// }
|
391
|
-
// const results = await Promise.allSettled(promises);
|
392
|
-
// results.forEach((result) => {
|
393
|
-
// if (result.status === "rejected") {
|
394
|
-
// logger.error("A process batch promise was rejected:", result.reason);
|
395
|
-
// }
|
396
|
-
// });
|
397
|
-
// const resultsData = results
|
398
|
-
// .map((result) => (result.status === "fulfilled" ? result.value : null))
|
399
|
-
// .filter((result: any) => result !== null && !result.processed)
|
400
|
-
// .map((result) => BatchSchema.parse(result));
|
401
|
-
// for (const batch of resultsData) {
|
402
|
-
// const actionOperation = ContextObject.parse(JSON.parse(batch.data));
|
403
|
-
// const { context, finalItem, attributeMappings } = actionOperation;
|
404
|
-
// if (finalItem.$id && !context.docId) {
|
405
|
-
// context.docId =
|
406
|
-
// finalItem.$id || context.createdDoc.$id || context.$id || undefined;
|
407
|
-
// logger.info(
|
408
|
-
// `Setting docId to ${
|
409
|
-
// finalItem.$id
|
410
|
-
// } because docId not found in context, batch ${
|
411
|
-
// batch.$id
|
412
|
-
// }, context is ${JSON.stringify(context)}`
|
413
|
-
// );
|
414
|
-
// }
|
415
|
-
// try {
|
416
|
-
// await this.importDataActions.executeAfterImportActions(
|
417
|
-
// finalItem,
|
418
|
-
// attributeMappings,
|
419
|
-
// context
|
420
|
-
// );
|
421
|
-
// // Mark batch as processed
|
422
|
-
// await this.database.deleteDocument(
|
423
|
-
// "migrations",
|
424
|
-
// "batches",
|
425
|
-
// batch.$id
|
426
|
-
// );
|
427
|
-
// } catch (error) {
|
428
|
-
// logger.error(
|
429
|
-
// `Failed to execute batch ${batch.$id}:`,
|
430
|
-
// error,
|
431
|
-
// "Context is :",
|
432
|
-
// context
|
433
|
-
// );
|
434
|
-
// await this.database.deleteDocument(
|
435
|
-
// "migrations",
|
436
|
-
// "batches",
|
437
|
-
// batch.$id
|
438
|
-
// );
|
439
|
-
// }
|
440
|
-
// }
|
441
|
-
|
442
|
-
// // After processing all batches, update the operation status
|
443
|
-
// await updateOperation(this.database, operation.$id, {
|
444
|
-
// status: "completed", // Or determine based on batch success/failure
|
445
|
-
// });
|
446
|
-
// }
|
447
|
-
// }
|
448
|
-
}
|
336
|
+
}
|
@@ -14,7 +14,10 @@ export const setupMigrationDatabase = async (config: AppwriteConfig) => {
|
|
14
14
|
console.log("---------------------------------");
|
15
15
|
console.log("Starting Migrations Setup");
|
16
16
|
console.log("---------------------------------");
|
17
|
-
const database = new Databases(config.appwriteClient
|
17
|
+
const database = new Databases(config.appwriteClient);
|
18
|
+
if (!config.appwriteClient) {
|
19
|
+
throw new Error("Appwrite client is not initialized in the config");
|
20
|
+
}
|
18
21
|
let db: Models.Database | undefined;
|
19
22
|
const migrationCollectionsSetup = getMigrationCollectionSchemas();
|
20
23
|
|
@@ -103,9 +106,17 @@ export const setupMigrationDatabase = async (config: AppwriteConfig) => {
|
|
103
106
|
console.log("---------------------------------");
|
104
107
|
};
|
105
108
|
|
106
|
-
export const ensureDatabasesExist = async (config: AppwriteConfig) => {
|
107
|
-
|
108
|
-
|
109
|
+
export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEnsure?: Models.Database[]) => {
|
110
|
+
if (!config.appwriteClient) {
|
111
|
+
throw new Error("Appwrite client is not initialized in the config");
|
112
|
+
}
|
113
|
+
const database = new Databases(config.appwriteClient);
|
114
|
+
const databasesToCreate = databasesToEnsure || config.databases || [];
|
115
|
+
|
116
|
+
if (!databasesToCreate.length) {
|
117
|
+
console.log("No databases to create");
|
118
|
+
return;
|
119
|
+
}
|
109
120
|
|
110
121
|
const existingDatabases = await tryAwaitWithRetry(
|
111
122
|
async () => await database.list([Query.limit(500)])
|
@@ -116,10 +127,10 @@ export const ensureDatabasesExist = async (config: AppwriteConfig) => {
|
|
116
127
|
);
|
117
128
|
if (existingDatabases.databases.length !== 0 && migrationsDatabase) {
|
118
129
|
console.log("Creating all databases except migrations");
|
119
|
-
|
130
|
+
databasesToCreate.push(migrationsDatabase);
|
120
131
|
}
|
121
132
|
|
122
|
-
for (const db of
|
133
|
+
for (const db of databasesToCreate) {
|
123
134
|
if (!existingDatabases.databases.some((d) => d.name === db.name)) {
|
124
135
|
await tryAwaitWithRetry(
|
125
136
|
async () => await database.create(db.$id || ulid(), db.name, true)
|
@@ -133,7 +144,7 @@ export const wipeOtherDatabases = async (
|
|
133
144
|
database: Databases,
|
134
145
|
databasesToKeep: Models.Database[]
|
135
146
|
) => {
|
136
|
-
console.log(`Databases to keep: ${databasesToKeep.join(", ")}`);
|
147
|
+
console.log(`Databases to keep: ${databasesToKeep.map(db => db.name).join(", ")}`);
|
137
148
|
const allDatabases = await tryAwaitWithRetry(
|
138
149
|
async () => await database.list([Query.limit(500)])
|
139
150
|
);
|
@@ -151,3 +162,33 @@ export const wipeOtherDatabases = async (
|
|
151
162
|
}
|
152
163
|
}
|
153
164
|
};
|
165
|
+
|
166
|
+
export const ensureCollectionsExist = async (
|
167
|
+
config: AppwriteConfig,
|
168
|
+
database: Models.Database,
|
169
|
+
collectionsToEnsure?: Models.Collection[]
|
170
|
+
) => {
|
171
|
+
const databaseClient = new Databases(config.appwriteClient!);
|
172
|
+
const collectionsToCreate = collectionsToEnsure ||
|
173
|
+
(config.collections ? config.collections : []);
|
174
|
+
|
175
|
+
const existingCollections = await tryAwaitWithRetry(
|
176
|
+
async () => await databaseClient.listCollections(database.$id, [Query.limit(500)])
|
177
|
+
);
|
178
|
+
|
179
|
+
for (const collection of collectionsToCreate) {
|
180
|
+
if (!existingCollections.collections.some((c) => c.name === collection.name)) {
|
181
|
+
await tryAwaitWithRetry(
|
182
|
+
async () => await databaseClient.createCollection(
|
183
|
+
database.$id,
|
184
|
+
ulid(),
|
185
|
+
collection.name,
|
186
|
+
undefined,
|
187
|
+
true,
|
188
|
+
true
|
189
|
+
)
|
190
|
+
);
|
191
|
+
console.log(`${collection.name} collection created in ${database.name}`);
|
192
|
+
}
|
193
|
+
}
|
194
|
+
};
|
package/src/storage/methods.ts
CHANGED
@@ -155,10 +155,10 @@ export const ensureDatabaseConfigBucketsExist = async (
|
|
155
155
|
);
|
156
156
|
console.log(`Bucket ${database.bucket.$id} created successfully.`);
|
157
157
|
} catch (createError) {
|
158
|
-
console.error(
|
159
|
-
|
160
|
-
|
161
|
-
);
|
158
|
+
// console.error(
|
159
|
+
// `Failed to create bucket ${database.bucket.$id}:`,
|
160
|
+
// createError
|
161
|
+
// );
|
162
162
|
}
|
163
163
|
}
|
164
164
|
}
|
package/src/utils/setupFiles.ts
CHANGED
@@ -74,10 +74,13 @@ const baseConfig: AppwriteConfig = {
|
|
74
74
|
const collectionsConfig: { name: string; content: string }[] = [
|
75
75
|
{
|
76
76
|
name: "ExampleCollection",
|
77
|
-
content: `import { CollectionCreate } from "appwrite-utils";
|
77
|
+
content: `import type { CollectionCreate } from "appwrite-utils";
|
78
78
|
|
79
79
|
const ExampleCollection: Partial<CollectionCreate> = {
|
80
80
|
name: 'ExampleCollection',
|
81
|
+
$id: '${ulid()}',
|
82
|
+
documentSecurity: false,
|
83
|
+
enabled: true,
|
81
84
|
$permissions: [
|
82
85
|
{ permission: 'read', target: 'any' },
|
83
86
|
{ permission: 'create', target: 'users' },
|