appwrite-utils-cli 0.9.4 → 0.9.51
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 +2 -0
- package/dist/interactiveCLI.js +28 -14
- package/dist/migrations/transfer.js +86 -52
- package/dist/storage/methods.d.ts +1 -0
- package/dist/storage/methods.js +46 -0
- package/dist/utilsController.d.ts +1 -0
- package/dist/utilsController.js +11 -1
- package/package.json +53 -53
- package/src/interactiveCLI.ts +41 -15
- package/src/migrations/transfer.ts +160 -95
- package/src/storage/methods.ts +65 -0
- package/src/utilsController.ts +14 -0
- package/zlogs/announcements.json +397 -0
- package/zlogs/announcementscomments.json +36 -0
- package/zlogs/articles.json +138 -0
- package/zlogs/articlescomments.json +4 -0
- package/zlogs/businesscategories.json +7097 -0
- package/zlogs/contacts.json +517063 -0
- package/zlogs/contactscouncils.json +61905 -0
- package/zlogs/contactssociallinks.json +13776 -0
- package/zlogs/councils.json +5076 -0
- package/zlogs/documents.json +917 -0
- package/zlogs/emails.json +4 -0
- package/zlogs/events.json +132625 -0
- package/zlogs/knowledgebase.json +333 -0
- package/zlogs/knowledgebasecomments.json +4 -0
- package/zlogs/linkcategories.json +180 -0
- package/zlogs/links.json +4364 -0
- package/zlogs/memberrequests.json +83 -0
- package/zlogs/memberrequestscomments.json +65 -0
- package/zlogs/mergedUserMap.json +56 -0
- package/zlogs/oldIdToNewIdPerCollectionMap.json +27663 -0
- package/zlogs/regions.json +145 -0
- package/zlogs/testimonials.json +335 -0
- package/zlogs/users.json +25516 -0
@@ -194,16 +194,42 @@ export const transferDocumentsBetweenDbsLocalToLocal = async (
|
|
194
194
|
fromCollId: string,
|
195
195
|
toCollId: string
|
196
196
|
) => {
|
197
|
-
let fromCollDocs = await tryAwaitWithRetry(async () =>
|
198
|
-
db.listDocuments(fromDbId, fromCollId, [Query.limit(50)])
|
199
|
-
);
|
200
197
|
let totalDocumentsTransferred = 0;
|
198
|
+
let lastDocumentId: string | undefined;
|
199
|
+
let hasMoreDocuments = true;
|
201
200
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
201
|
+
while (hasMoreDocuments) {
|
202
|
+
const queryParams = [Query.limit(50)];
|
203
|
+
if (lastDocumentId) {
|
204
|
+
queryParams.push(Query.cursorAfter(lastDocumentId));
|
205
|
+
}
|
206
|
+
|
207
|
+
const fromCollDocs = await tryAwaitWithRetry(async () =>
|
208
|
+
db.listDocuments(fromDbId, fromCollId, queryParams)
|
209
|
+
);
|
210
|
+
|
211
|
+
if (fromCollDocs.documents.length === 0) {
|
212
|
+
if (totalDocumentsTransferred === 0) {
|
213
|
+
console.log(`No documents found in collection ${fromCollId}`);
|
214
|
+
}
|
215
|
+
break;
|
216
|
+
}
|
217
|
+
|
218
|
+
const allDocsToCreateCheck = await tryAwaitWithRetry(
|
219
|
+
async () =>
|
220
|
+
await db.listDocuments(toDbId, toCollId, [
|
221
|
+
Query.equal(
|
222
|
+
"$id",
|
223
|
+
fromCollDocs.documents.map((doc) => doc.$id)
|
224
|
+
),
|
225
|
+
])
|
226
|
+
);
|
227
|
+
|
228
|
+
const docsToCreate = fromCollDocs.documents.filter(
|
229
|
+
(doc) => !allDocsToCreateCheck.documents.some((d) => d.$id === doc.$id)
|
230
|
+
);
|
231
|
+
|
232
|
+
const batchedPromises = docsToCreate.map((doc) => {
|
207
233
|
const toCreateObject: Partial<typeof doc> = {
|
208
234
|
...doc,
|
209
235
|
};
|
@@ -224,64 +250,15 @@ export const transferDocumentsBetweenDbsLocalToLocal = async (
|
|
224
250
|
)
|
225
251
|
);
|
226
252
|
});
|
253
|
+
|
227
254
|
await Promise.all(batchedPromises);
|
228
|
-
totalDocumentsTransferred +=
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
delete toCreateObject.$collectionId;
|
236
|
-
delete toCreateObject.$createdAt;
|
237
|
-
delete toCreateObject.$updatedAt;
|
238
|
-
delete toCreateObject.$id;
|
239
|
-
delete toCreateObject.$permissions;
|
240
|
-
return tryAwaitWithRetry(async () =>
|
241
|
-
db.createDocument(
|
242
|
-
toDbId,
|
243
|
-
toCollId,
|
244
|
-
doc.$id,
|
245
|
-
toCreateObject,
|
246
|
-
doc.$permissions
|
247
|
-
)
|
248
|
-
);
|
249
|
-
});
|
250
|
-
await Promise.all(batchedPromises);
|
251
|
-
totalDocumentsTransferred += fromCollDocs.documents.length;
|
252
|
-
while (fromCollDocs.documents.length === 50) {
|
253
|
-
fromCollDocs = await tryAwaitWithRetry(
|
254
|
-
async () =>
|
255
|
-
await db.listDocuments(fromDbId, fromCollId, [
|
256
|
-
Query.limit(50),
|
257
|
-
Query.cursorAfter(
|
258
|
-
fromCollDocs.documents[fromCollDocs.documents.length - 1].$id
|
259
|
-
),
|
260
|
-
])
|
261
|
-
);
|
262
|
-
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
263
|
-
const toCreateObject: Partial<typeof doc> = {
|
264
|
-
...doc,
|
265
|
-
};
|
266
|
-
delete toCreateObject.$databaseId;
|
267
|
-
delete toCreateObject.$collectionId;
|
268
|
-
delete toCreateObject.$createdAt;
|
269
|
-
delete toCreateObject.$updatedAt;
|
270
|
-
delete toCreateObject.$id;
|
271
|
-
delete toCreateObject.$permissions;
|
272
|
-
return tryAwaitWithRetry(
|
273
|
-
async () =>
|
274
|
-
await db.createDocument(
|
275
|
-
toDbId,
|
276
|
-
toCollId,
|
277
|
-
doc.$id,
|
278
|
-
toCreateObject,
|
279
|
-
doc.$permissions
|
280
|
-
)
|
281
|
-
);
|
282
|
-
});
|
283
|
-
await Promise.all(batchedPromises);
|
284
|
-
totalDocumentsTransferred += fromCollDocs.documents.length;
|
255
|
+
totalDocumentsTransferred += docsToCreate.length;
|
256
|
+
|
257
|
+
if (fromCollDocs.documents.length < 50) {
|
258
|
+
hasMoreDocuments = false;
|
259
|
+
} else {
|
260
|
+
lastDocumentId =
|
261
|
+
fromCollDocs.documents[fromCollDocs.documents.length - 1].$id;
|
285
262
|
}
|
286
263
|
}
|
287
264
|
|
@@ -314,7 +291,19 @@ export const transferDocumentsBetweenDbsLocalToRemote = async (
|
|
314
291
|
console.log(`No documents found in collection ${fromCollId}`);
|
315
292
|
return;
|
316
293
|
} else if (fromCollDocs.documents.length < 50) {
|
317
|
-
const
|
294
|
+
const allDocsToCreateCheck = await tryAwaitWithRetry(
|
295
|
+
async () =>
|
296
|
+
await remoteDb.listDocuments(toDbId, toCollId, [
|
297
|
+
Query.equal(
|
298
|
+
"$id",
|
299
|
+
fromCollDocs.documents.map((doc) => doc.$id)
|
300
|
+
),
|
301
|
+
])
|
302
|
+
);
|
303
|
+
const docsToCreate = fromCollDocs.documents.filter(
|
304
|
+
(doc) => !allDocsToCreateCheck.documents.some((d) => d.$id === doc.$id)
|
305
|
+
);
|
306
|
+
const batchedPromises = docsToCreate.map((doc) => {
|
318
307
|
const toCreateObject: Partial<typeof doc> = {
|
319
308
|
...doc,
|
320
309
|
};
|
@@ -337,7 +326,19 @@ export const transferDocumentsBetweenDbsLocalToRemote = async (
|
|
337
326
|
await Promise.all(batchedPromises);
|
338
327
|
totalDocumentsTransferred += fromCollDocs.documents.length;
|
339
328
|
} else {
|
340
|
-
const
|
329
|
+
const allDocsToCreateCheck = await tryAwaitWithRetry(
|
330
|
+
async () =>
|
331
|
+
await remoteDb.listDocuments(toDbId, toCollId, [
|
332
|
+
Query.equal(
|
333
|
+
"$id",
|
334
|
+
fromCollDocs.documents.map((doc) => doc.$id)
|
335
|
+
),
|
336
|
+
])
|
337
|
+
);
|
338
|
+
const docsToCreate = fromCollDocs.documents.filter(
|
339
|
+
(doc) => !allDocsToCreateCheck.documents.some((d) => d.$id === doc.$id)
|
340
|
+
);
|
341
|
+
const batchedPromises = docsToCreate.map((doc) => {
|
341
342
|
const toCreateObject: Partial<typeof doc> = {
|
342
343
|
...doc,
|
343
344
|
};
|
@@ -533,8 +534,7 @@ export const transferDatabaseLocalToRemote = async (
|
|
533
534
|
async () => await localDb.listCollections(fromDbId, [Query.limit(50)])
|
534
535
|
);
|
535
536
|
const allFromCollections = fromCollections.collections;
|
536
|
-
if (fromCollections.collections.length
|
537
|
-
} else {
|
537
|
+
if (fromCollections.collections.length >= 50) {
|
538
538
|
lastCollectionId =
|
539
539
|
fromCollections.collections[fromCollections.collections.length - 1].$id;
|
540
540
|
while (lastCollectionId) {
|
@@ -555,43 +555,108 @@ export const transferDatabaseLocalToRemote = async (
|
|
555
555
|
}
|
556
556
|
|
557
557
|
for (const collection of allFromCollections) {
|
558
|
-
|
558
|
+
let toCollection: Models.Collection;
|
559
|
+
const toCollectionExists = await tryAwaitWithRetry(
|
559
560
|
async () =>
|
560
|
-
await remoteDb.
|
561
|
-
|
562
|
-
|
563
|
-
collection.name,
|
564
|
-
collection.$permissions,
|
565
|
-
collection.documentSecurity,
|
566
|
-
collection.enabled
|
567
|
-
)
|
561
|
+
await remoteDb.listCollections(toDbId, [
|
562
|
+
Query.equal("$id", collection.$id),
|
563
|
+
])
|
568
564
|
);
|
569
|
-
console.log(`Collection ${toCollection.name} created`);
|
570
565
|
|
571
|
-
|
572
|
-
|
566
|
+
if (toCollectionExists.collections.length > 0) {
|
567
|
+
console.log(`Collection ${collection.name} already exists. Updating...`);
|
568
|
+
toCollection = toCollectionExists.collections[0];
|
569
|
+
// Update collection if needed
|
570
|
+
if (
|
571
|
+
toCollection.name !== collection.name ||
|
572
|
+
toCollection.$permissions !== collection.$permissions ||
|
573
|
+
toCollection.documentSecurity !== collection.documentSecurity ||
|
574
|
+
toCollection.enabled !== collection.enabled
|
575
|
+
) {
|
576
|
+
toCollection = await tryAwaitWithRetry(
|
577
|
+
async () =>
|
578
|
+
await remoteDb.updateCollection(
|
579
|
+
toDbId,
|
580
|
+
collection.$id,
|
581
|
+
collection.name,
|
582
|
+
collection.$permissions,
|
583
|
+
collection.documentSecurity,
|
584
|
+
collection.enabled
|
585
|
+
)
|
586
|
+
);
|
587
|
+
console.log(`Collection ${toCollection.name} updated`);
|
588
|
+
}
|
589
|
+
} else {
|
590
|
+
toCollection = await tryAwaitWithRetry(
|
573
591
|
async () =>
|
574
|
-
await
|
575
|
-
remoteDb,
|
592
|
+
await remoteDb.createCollection(
|
576
593
|
toDbId,
|
577
|
-
|
578
|
-
|
594
|
+
collection.$id,
|
595
|
+
collection.name,
|
596
|
+
collection.$permissions,
|
597
|
+
collection.documentSecurity,
|
598
|
+
collection.enabled
|
579
599
|
)
|
580
600
|
);
|
601
|
+
console.log(`Collection ${toCollection.name} created`);
|
602
|
+
}
|
603
|
+
|
604
|
+
// Check and update attributes
|
605
|
+
const existingAttributes = await tryAwaitWithRetry(
|
606
|
+
async () => await remoteDb.listAttributes(toDbId, toCollection.$id)
|
607
|
+
);
|
608
|
+
for (const attribute of collection.attributes) {
|
609
|
+
const parsedAttribute = parseAttribute(attribute as any);
|
610
|
+
const existingAttribute = existingAttributes.attributes.find(
|
611
|
+
// @ts-expect-error
|
612
|
+
(attr) => attr.key === parsedAttribute.key
|
613
|
+
);
|
614
|
+
if (!existingAttribute) {
|
615
|
+
await tryAwaitWithRetry(
|
616
|
+
async () =>
|
617
|
+
await createOrUpdateAttribute(
|
618
|
+
remoteDb,
|
619
|
+
toDbId,
|
620
|
+
toCollection,
|
621
|
+
parsedAttribute
|
622
|
+
)
|
623
|
+
);
|
624
|
+
console.log(`Attribute ${parsedAttribute.key} created`);
|
625
|
+
} else {
|
626
|
+
// Check if attribute needs updating
|
627
|
+
// Note: Appwrite doesn't allow updating most attribute properties
|
628
|
+
// You might need to delete and recreate the attribute if significant changes are needed
|
629
|
+
console.log(`Attribute ${parsedAttribute.key} already exists`);
|
630
|
+
}
|
581
631
|
}
|
582
632
|
|
633
|
+
// Check and update indexes
|
634
|
+
const existingIndexes = await tryAwaitWithRetry(
|
635
|
+
async () => await remoteDb.listIndexes(toDbId, toCollection.$id)
|
636
|
+
);
|
583
637
|
for (const index of collection.indexes) {
|
584
|
-
|
585
|
-
|
586
|
-
await remoteDb.createIndex(
|
587
|
-
toDbId,
|
588
|
-
toCollection.$id,
|
589
|
-
index.key,
|
590
|
-
index.type as IndexType,
|
591
|
-
index.attributes,
|
592
|
-
index.orders
|
593
|
-
)
|
638
|
+
const existingIndex = existingIndexes.indexes.find(
|
639
|
+
(idx) => idx.key === index.key
|
594
640
|
);
|
641
|
+
if (!existingIndex) {
|
642
|
+
await tryAwaitWithRetry(
|
643
|
+
async () =>
|
644
|
+
await remoteDb.createIndex(
|
645
|
+
toDbId,
|
646
|
+
toCollection.$id,
|
647
|
+
index.key,
|
648
|
+
index.type as IndexType,
|
649
|
+
index.attributes,
|
650
|
+
index.orders
|
651
|
+
)
|
652
|
+
);
|
653
|
+
console.log(`Index ${index.key} created`);
|
654
|
+
} else {
|
655
|
+
// Check if index needs updating
|
656
|
+
// Note: Appwrite doesn't allow updating indexes
|
657
|
+
// You might need to delete and recreate the index if changes are needed
|
658
|
+
console.log(`Index ${index.key} already exists`);
|
659
|
+
}
|
595
660
|
}
|
596
661
|
|
597
662
|
await transferDocumentsBetweenDbsLocalToRemote(
|
package/src/storage/methods.ts
CHANGED
@@ -100,6 +100,71 @@ export const deleteFile = async (
|
|
100
100
|
return await storage.deleteFile(bucketId, fileId);
|
101
101
|
};
|
102
102
|
|
103
|
+
export const ensureDatabaseConfigBucketsExist = async (
|
104
|
+
storage: Storage,
|
105
|
+
config: AppwriteConfig,
|
106
|
+
databases: Models.Database[] = []
|
107
|
+
) => {
|
108
|
+
for (const db of databases) {
|
109
|
+
const database = config.databases?.find((d) => d.$id === db.$id);
|
110
|
+
if (database?.bucket) {
|
111
|
+
try {
|
112
|
+
await storage.getBucket(database.bucket.$id);
|
113
|
+
console.log(`Bucket ${database.bucket.$id} already exists.`);
|
114
|
+
} catch (e) {
|
115
|
+
const permissions: string[] = [];
|
116
|
+
if (
|
117
|
+
database.bucket.permissions &&
|
118
|
+
database.bucket.permissions.length > 0
|
119
|
+
) {
|
120
|
+
for (const permission of database.bucket.permissions) {
|
121
|
+
switch (permission.permission) {
|
122
|
+
case "read":
|
123
|
+
permissions.push(Permission.read(permission.target));
|
124
|
+
break;
|
125
|
+
case "create":
|
126
|
+
permissions.push(Permission.create(permission.target));
|
127
|
+
break;
|
128
|
+
case "update":
|
129
|
+
permissions.push(Permission.update(permission.target));
|
130
|
+
break;
|
131
|
+
case "delete":
|
132
|
+
permissions.push(Permission.delete(permission.target));
|
133
|
+
break;
|
134
|
+
case "write":
|
135
|
+
permissions.push(Permission.write(permission.target));
|
136
|
+
break;
|
137
|
+
default:
|
138
|
+
console.warn(`Unknown permission: ${permission.permission}`);
|
139
|
+
break;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
try {
|
144
|
+
await storage.createBucket(
|
145
|
+
database.bucket.$id,
|
146
|
+
database.bucket.name,
|
147
|
+
permissions,
|
148
|
+
database.bucket.fileSecurity,
|
149
|
+
database.bucket.enabled,
|
150
|
+
database.bucket.maximumFileSize,
|
151
|
+
database.bucket.allowedFileExtensions,
|
152
|
+
database.bucket.compression as Compression,
|
153
|
+
database.bucket.encryption,
|
154
|
+
database.bucket.antivirus
|
155
|
+
);
|
156
|
+
console.log(`Bucket ${database.bucket.$id} created successfully.`);
|
157
|
+
} catch (createError) {
|
158
|
+
console.error(
|
159
|
+
`Failed to create bucket ${database.bucket.$id}:`,
|
160
|
+
createError
|
161
|
+
);
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
};
|
167
|
+
|
103
168
|
export const wipeDocumentStorage = async (
|
104
169
|
storage: Storage,
|
105
170
|
bucketId: string
|
package/src/utilsController.ts
CHANGED
@@ -18,6 +18,7 @@ import {
|
|
18
18
|
} from "./collections/methods.js";
|
19
19
|
import {
|
20
20
|
backupDatabase,
|
21
|
+
ensureDatabaseConfigBucketsExist,
|
21
22
|
initOrGetBackupStorage,
|
22
23
|
wipeDocumentStorage,
|
23
24
|
} from "./storage/methods.js";
|
@@ -101,10 +102,22 @@ export class UtilsController {
|
|
101
102
|
await setupMigrationDatabase(this.config);
|
102
103
|
}
|
103
104
|
|
105
|
+
async ensureDatabaseConfigBucketsExist(databases: Models.Database[] = []) {
|
106
|
+
await this.init();
|
107
|
+
if (!this.storage) throw new Error("Storage not initialized");
|
108
|
+
if (!this.config) throw new Error("Config not initialized");
|
109
|
+
await ensureDatabaseConfigBucketsExist(
|
110
|
+
this.storage,
|
111
|
+
this.config,
|
112
|
+
databases
|
113
|
+
);
|
114
|
+
}
|
115
|
+
|
104
116
|
async ensureDatabasesExist(databases?: Models.Database[]) {
|
105
117
|
await this.init();
|
106
118
|
if (!this.config) throw new Error("Config not initialized");
|
107
119
|
await this.setupMigrationDatabase();
|
120
|
+
await this.ensureDatabaseConfigBucketsExist(databases);
|
108
121
|
await ensureDatabasesExist(this.config);
|
109
122
|
}
|
110
123
|
|
@@ -231,6 +244,7 @@ export class UtilsController {
|
|
231
244
|
if (!this.database) throw new Error("Database not initialized");
|
232
245
|
const databases = await fetchAllDatabases(this.database);
|
233
246
|
await this.ensureDatabasesExist(databases);
|
247
|
+
await this.ensureDatabaseConfigBucketsExist(databases);
|
234
248
|
await this.createOrUpdateCollectionsForDatabases(databases);
|
235
249
|
}
|
236
250
|
|