appwrite-utils-cli 0.0.286 → 0.9.2
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 +162 -96
- package/dist/collections/attributes.d.ts +4 -0
- package/dist/collections/attributes.js +224 -0
- package/dist/collections/indexes.d.ts +4 -0
- package/dist/collections/indexes.js +27 -0
- package/dist/collections/methods.d.ts +16 -0
- package/dist/collections/methods.js +216 -0
- package/dist/databases/methods.d.ts +6 -0
- package/dist/databases/methods.js +33 -0
- package/dist/interactiveCLI.d.ts +19 -0
- package/dist/interactiveCLI.js +555 -0
- package/dist/main.js +224 -62
- package/dist/migrations/afterImportActions.js +37 -40
- package/dist/migrations/appwriteToX.d.ts +26 -25
- package/dist/migrations/appwriteToX.js +42 -6
- package/dist/migrations/attributes.js +21 -20
- package/dist/migrations/backup.d.ts +93 -87
- package/dist/migrations/collections.d.ts +6 -0
- package/dist/migrations/collections.js +149 -20
- package/dist/migrations/converters.d.ts +2 -18
- package/dist/migrations/converters.js +13 -2
- package/dist/migrations/dataLoader.d.ts +276 -161
- package/dist/migrations/dataLoader.js +535 -292
- package/dist/migrations/databases.js +8 -2
- package/dist/migrations/helper.d.ts +3 -0
- package/dist/migrations/helper.js +21 -0
- package/dist/migrations/importController.d.ts +5 -2
- package/dist/migrations/importController.js +125 -88
- package/dist/migrations/importDataActions.d.ts +9 -1
- package/dist/migrations/importDataActions.js +15 -3
- package/dist/migrations/indexes.js +3 -2
- package/dist/migrations/logging.js +20 -8
- package/dist/migrations/migrationHelper.d.ts +9 -4
- package/dist/migrations/migrationHelper.js +6 -5
- package/dist/migrations/openapi.d.ts +1 -1
- package/dist/migrations/openapi.js +33 -18
- package/dist/migrations/queue.js +3 -2
- package/dist/migrations/relationships.d.ts +2 -2
- package/dist/migrations/schemaStrings.js +53 -41
- package/dist/migrations/setupDatabase.d.ts +2 -4
- package/dist/migrations/setupDatabase.js +24 -105
- package/dist/migrations/storage.d.ts +3 -1
- package/dist/migrations/storage.js +110 -16
- package/dist/migrations/transfer.d.ts +30 -0
- package/dist/migrations/transfer.js +337 -0
- package/dist/migrations/users.d.ts +2 -1
- package/dist/migrations/users.js +78 -43
- package/dist/schemas/authUser.d.ts +2 -2
- package/dist/storage/methods.d.ts +15 -0
- package/dist/storage/methods.js +207 -0
- package/dist/storage/schemas.d.ts +687 -0
- package/dist/storage/schemas.js +175 -0
- package/dist/utils/getClientFromConfig.d.ts +4 -0
- package/dist/utils/getClientFromConfig.js +16 -0
- package/dist/utils/helperFunctions.d.ts +11 -1
- package/dist/utils/helperFunctions.js +38 -0
- package/dist/utils/retryFailedPromises.d.ts +2 -0
- package/dist/utils/retryFailedPromises.js +21 -0
- package/dist/utils/schemaStrings.d.ts +13 -0
- package/dist/utils/schemaStrings.js +403 -0
- package/dist/utils/setupFiles.js +110 -61
- package/dist/utilsController.d.ts +40 -22
- package/dist/utilsController.js +164 -84
- package/package.json +13 -15
- package/src/collections/attributes.ts +483 -0
- package/src/collections/indexes.ts +53 -0
- package/src/collections/methods.ts +331 -0
- package/src/databases/methods.ts +47 -0
- package/src/init.ts +64 -64
- package/src/interactiveCLI.ts +767 -0
- package/src/main.ts +289 -83
- package/src/migrations/afterImportActions.ts +553 -490
- package/src/migrations/appwriteToX.ts +237 -174
- package/src/migrations/attributes.ts +483 -422
- package/src/migrations/backup.ts +205 -205
- package/src/migrations/collections.ts +545 -300
- package/src/migrations/converters.ts +161 -150
- package/src/migrations/dataLoader.ts +1615 -1304
- package/src/migrations/databases.ts +44 -25
- package/src/migrations/dbHelpers.ts +92 -92
- package/src/migrations/helper.ts +40 -0
- package/src/migrations/importController.ts +448 -384
- package/src/migrations/importDataActions.ts +315 -307
- package/src/migrations/indexes.ts +40 -37
- package/src/migrations/logging.ts +29 -16
- package/src/migrations/migrationHelper.ts +207 -201
- package/src/migrations/openapi.ts +83 -70
- package/src/migrations/queue.ts +118 -119
- package/src/migrations/relationships.ts +324 -324
- package/src/migrations/schemaStrings.ts +472 -460
- package/src/migrations/setupDatabase.ts +118 -219
- package/src/migrations/storage.ts +538 -358
- package/src/migrations/transfer.ts +608 -0
- package/src/migrations/users.ts +362 -285
- package/src/migrations/validationRules.ts +63 -63
- package/src/schemas/authUser.ts +23 -23
- package/src/setup.ts +8 -8
- package/src/storage/methods.ts +371 -0
- package/src/storage/schemas.ts +205 -0
- package/src/types.ts +9 -9
- package/src/utils/getClientFromConfig.ts +17 -0
- package/src/utils/helperFunctions.ts +181 -127
- package/src/utils/index.ts +2 -2
- package/src/utils/loadConfigs.ts +59 -59
- package/src/utils/retryFailedPromises.ts +27 -0
- package/src/utils/schemaStrings.ts +473 -0
- package/src/utils/setupFiles.ts +228 -182
- package/src/utilsController.ts +325 -194
- package/tsconfig.json +37 -37
@@ -0,0 +1,608 @@
|
|
1
|
+
import { tryAwaitWithRetry } from "appwrite-utils";
|
2
|
+
import {
|
3
|
+
Client,
|
4
|
+
Databases,
|
5
|
+
IndexType,
|
6
|
+
Query,
|
7
|
+
Storage,
|
8
|
+
type Models,
|
9
|
+
} from "node-appwrite";
|
10
|
+
import { InputFile } from "node-appwrite/file";
|
11
|
+
import { getAppwriteClient } from "../utils/helperFunctions.js";
|
12
|
+
import { createOrUpdateAttribute } from "./attributes.js";
|
13
|
+
import { parseAttribute } from "appwrite-utils";
|
14
|
+
|
15
|
+
export interface TransferOptions {
|
16
|
+
fromDb: Models.Database;
|
17
|
+
targetDb: Models.Database;
|
18
|
+
isRemote: boolean;
|
19
|
+
collections?: string[];
|
20
|
+
transferEndpoint?: string;
|
21
|
+
transferProject?: string;
|
22
|
+
transferKey?: string;
|
23
|
+
sourceBucket?: Models.Bucket;
|
24
|
+
targetBucket?: Models.Bucket;
|
25
|
+
}
|
26
|
+
|
27
|
+
export const transferStorageLocalToLocal = async (
|
28
|
+
storage: Storage,
|
29
|
+
fromBucketId: string,
|
30
|
+
toBucketId: string
|
31
|
+
) => {
|
32
|
+
console.log(`Transferring files from ${fromBucketId} to ${toBucketId}`);
|
33
|
+
let lastFileId: string | undefined;
|
34
|
+
let fromFiles = await tryAwaitWithRetry(
|
35
|
+
async () => await storage.listFiles(fromBucketId, [Query.limit(100)])
|
36
|
+
);
|
37
|
+
const allFromFiles = fromFiles.files;
|
38
|
+
let numberOfFiles = 0;
|
39
|
+
|
40
|
+
const downloadFileWithRetry = async (bucketId: string, fileId: string) => {
|
41
|
+
let attempts = 3;
|
42
|
+
while (attempts > 0) {
|
43
|
+
try {
|
44
|
+
return await storage.getFileDownload(bucketId, fileId);
|
45
|
+
} catch (error) {
|
46
|
+
console.error(`Error downloading file ${fileId}: ${error}`);
|
47
|
+
attempts--;
|
48
|
+
if (attempts === 0) throw error;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
};
|
52
|
+
|
53
|
+
if (fromFiles.files.length < 100) {
|
54
|
+
for (const file of allFromFiles) {
|
55
|
+
const fileData = await tryAwaitWithRetry(
|
56
|
+
async () => await downloadFileWithRetry(file.bucketId, file.$id)
|
57
|
+
);
|
58
|
+
if (!fileData) {
|
59
|
+
console.error(`Error downloading file ${file.$id}`);
|
60
|
+
continue;
|
61
|
+
}
|
62
|
+
const fileToCreate = InputFile.fromBuffer(
|
63
|
+
new Uint8Array(fileData),
|
64
|
+
file.name
|
65
|
+
);
|
66
|
+
console.log(`Creating file: ${file.name}`);
|
67
|
+
tryAwaitWithRetry(
|
68
|
+
async () =>
|
69
|
+
await storage.createFile(
|
70
|
+
toBucketId,
|
71
|
+
file.$id,
|
72
|
+
fileToCreate,
|
73
|
+
file.$permissions
|
74
|
+
)
|
75
|
+
);
|
76
|
+
numberOfFiles++;
|
77
|
+
}
|
78
|
+
} else {
|
79
|
+
lastFileId = fromFiles.files[fromFiles.files.length - 1].$id;
|
80
|
+
while (lastFileId) {
|
81
|
+
const files = await tryAwaitWithRetry(
|
82
|
+
async () =>
|
83
|
+
await storage.listFiles(fromBucketId, [
|
84
|
+
Query.limit(100),
|
85
|
+
Query.cursorAfter(lastFileId!),
|
86
|
+
])
|
87
|
+
);
|
88
|
+
allFromFiles.push(...files.files);
|
89
|
+
if (files.files.length < 100) {
|
90
|
+
lastFileId = undefined;
|
91
|
+
} else {
|
92
|
+
lastFileId = files.files[files.files.length - 1].$id;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
for (const file of allFromFiles) {
|
96
|
+
const fileData = await tryAwaitWithRetry(
|
97
|
+
async () => await downloadFileWithRetry(file.bucketId, file.$id)
|
98
|
+
);
|
99
|
+
if (!fileData) {
|
100
|
+
console.error(`Error downloading file ${file.$id}`);
|
101
|
+
continue;
|
102
|
+
}
|
103
|
+
const fileToCreate = InputFile.fromBuffer(
|
104
|
+
new Uint8Array(fileData),
|
105
|
+
file.name
|
106
|
+
);
|
107
|
+
await tryAwaitWithRetry(
|
108
|
+
async () =>
|
109
|
+
await storage.createFile(
|
110
|
+
toBucketId,
|
111
|
+
file.$id,
|
112
|
+
fileToCreate,
|
113
|
+
file.$permissions
|
114
|
+
)
|
115
|
+
);
|
116
|
+
numberOfFiles++;
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
console.log(
|
121
|
+
`Transferred ${numberOfFiles} files from ${fromBucketId} to ${toBucketId}`
|
122
|
+
);
|
123
|
+
};
|
124
|
+
|
125
|
+
export const transferStorageLocalToRemote = async (
|
126
|
+
localStorage: Storage,
|
127
|
+
endpoint: string,
|
128
|
+
projectId: string,
|
129
|
+
apiKey: string,
|
130
|
+
fromBucketId: string,
|
131
|
+
toBucketId: string
|
132
|
+
) => {
|
133
|
+
console.log(
|
134
|
+
`Transferring files from current storage ${fromBucketId} to ${endpoint} bucket ${toBucketId}`
|
135
|
+
);
|
136
|
+
const client = getAppwriteClient(endpoint, apiKey, projectId);
|
137
|
+
const remoteStorage = new Storage(client);
|
138
|
+
let numberOfFiles = 0;
|
139
|
+
let lastFileId: string | undefined;
|
140
|
+
let fromFiles = await tryAwaitWithRetry(
|
141
|
+
async () => await localStorage.listFiles(fromBucketId, [Query.limit(100)])
|
142
|
+
);
|
143
|
+
const allFromFiles = fromFiles.files;
|
144
|
+
if (fromFiles.files.length === 100) {
|
145
|
+
lastFileId = fromFiles.files[fromFiles.files.length - 1].$id;
|
146
|
+
while (lastFileId) {
|
147
|
+
const files = await tryAwaitWithRetry(
|
148
|
+
async () =>
|
149
|
+
await localStorage.listFiles(fromBucketId, [
|
150
|
+
Query.limit(100),
|
151
|
+
Query.cursorAfter(lastFileId!),
|
152
|
+
])
|
153
|
+
);
|
154
|
+
allFromFiles.push(...files.files);
|
155
|
+
if (files.files.length < 100) {
|
156
|
+
break;
|
157
|
+
}
|
158
|
+
lastFileId = files.files[files.files.length - 1].$id;
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
for (const file of allFromFiles) {
|
163
|
+
const fileData = await tryAwaitWithRetry(
|
164
|
+
async () => await localStorage.getFileDownload(file.bucketId, file.$id)
|
165
|
+
);
|
166
|
+
const fileToCreate = InputFile.fromBuffer(
|
167
|
+
new Uint8Array(fileData),
|
168
|
+
file.name
|
169
|
+
);
|
170
|
+
await tryAwaitWithRetry(
|
171
|
+
async () =>
|
172
|
+
await remoteStorage.createFile(
|
173
|
+
toBucketId,
|
174
|
+
file.$id,
|
175
|
+
fileToCreate,
|
176
|
+
file.$permissions
|
177
|
+
)
|
178
|
+
);
|
179
|
+
numberOfFiles++;
|
180
|
+
}
|
181
|
+
console.log(
|
182
|
+
`Transferred ${numberOfFiles} files from ${fromBucketId} to ${toBucketId}`
|
183
|
+
);
|
184
|
+
};
|
185
|
+
|
186
|
+
/**
|
187
|
+
* Transfers all documents from one collection to another in a different database
|
188
|
+
* within the same Appwrite Project
|
189
|
+
*/
|
190
|
+
export const transferDocumentsBetweenDbsLocalToLocal = async (
|
191
|
+
db: Databases,
|
192
|
+
fromDbId: string,
|
193
|
+
toDbId: string,
|
194
|
+
fromCollId: string,
|
195
|
+
toCollId: string
|
196
|
+
) => {
|
197
|
+
let fromCollDocs = await tryAwaitWithRetry(async () =>
|
198
|
+
db.listDocuments(fromDbId, fromCollId, [Query.limit(50)])
|
199
|
+
);
|
200
|
+
let totalDocumentsTransferred = 0;
|
201
|
+
|
202
|
+
if (fromCollDocs.documents.length === 0) {
|
203
|
+
console.log(`No documents found in collection ${fromCollId}`);
|
204
|
+
return;
|
205
|
+
} else if (fromCollDocs.documents.length < 50) {
|
206
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
207
|
+
const toCreateObject: Partial<typeof doc> = {
|
208
|
+
...doc,
|
209
|
+
};
|
210
|
+
delete toCreateObject.$databaseId;
|
211
|
+
delete toCreateObject.$collectionId;
|
212
|
+
delete toCreateObject.$createdAt;
|
213
|
+
delete toCreateObject.$updatedAt;
|
214
|
+
delete toCreateObject.$id;
|
215
|
+
delete toCreateObject.$permissions;
|
216
|
+
return tryAwaitWithRetry(
|
217
|
+
async () =>
|
218
|
+
await db.createDocument(
|
219
|
+
toDbId,
|
220
|
+
toCollId,
|
221
|
+
doc.$id,
|
222
|
+
toCreateObject,
|
223
|
+
doc.$permissions
|
224
|
+
)
|
225
|
+
);
|
226
|
+
});
|
227
|
+
await Promise.all(batchedPromises);
|
228
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
229
|
+
} else {
|
230
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
231
|
+
const toCreateObject: Partial<typeof doc> = {
|
232
|
+
...doc,
|
233
|
+
};
|
234
|
+
delete toCreateObject.$databaseId;
|
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;
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
console.log(
|
289
|
+
`Transferred ${totalDocumentsTransferred} documents from database ${fromDbId} to database ${toDbId} -- collection ${fromCollId} to collection ${toCollId}`
|
290
|
+
);
|
291
|
+
};
|
292
|
+
|
293
|
+
export const transferDocumentsBetweenDbsLocalToRemote = async (
|
294
|
+
localDb: Databases,
|
295
|
+
endpoint: string,
|
296
|
+
projectId: string,
|
297
|
+
apiKey: string,
|
298
|
+
fromDbId: string,
|
299
|
+
toDbId: string,
|
300
|
+
fromCollId: string,
|
301
|
+
toCollId: string
|
302
|
+
) => {
|
303
|
+
const client = new Client()
|
304
|
+
.setEndpoint(endpoint)
|
305
|
+
.setProject(projectId)
|
306
|
+
.setKey(apiKey);
|
307
|
+
let totalDocumentsTransferred = 0;
|
308
|
+
const remoteDb = new Databases(client);
|
309
|
+
let fromCollDocs = await tryAwaitWithRetry(async () =>
|
310
|
+
localDb.listDocuments(fromDbId, fromCollId, [Query.limit(50)])
|
311
|
+
);
|
312
|
+
|
313
|
+
if (fromCollDocs.documents.length === 0) {
|
314
|
+
console.log(`No documents found in collection ${fromCollId}`);
|
315
|
+
return;
|
316
|
+
} else if (fromCollDocs.documents.length < 50) {
|
317
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
318
|
+
const toCreateObject: Partial<typeof doc> = {
|
319
|
+
...doc,
|
320
|
+
};
|
321
|
+
delete toCreateObject.$databaseId;
|
322
|
+
delete toCreateObject.$collectionId;
|
323
|
+
delete toCreateObject.$createdAt;
|
324
|
+
delete toCreateObject.$updatedAt;
|
325
|
+
delete toCreateObject.$id;
|
326
|
+
delete toCreateObject.$permissions;
|
327
|
+
return tryAwaitWithRetry(async () =>
|
328
|
+
remoteDb.createDocument(
|
329
|
+
toDbId,
|
330
|
+
toCollId,
|
331
|
+
doc.$id,
|
332
|
+
toCreateObject,
|
333
|
+
doc.$permissions
|
334
|
+
)
|
335
|
+
);
|
336
|
+
});
|
337
|
+
await Promise.all(batchedPromises);
|
338
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
339
|
+
} else {
|
340
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
341
|
+
const toCreateObject: Partial<typeof doc> = {
|
342
|
+
...doc,
|
343
|
+
};
|
344
|
+
delete toCreateObject.$databaseId;
|
345
|
+
delete toCreateObject.$collectionId;
|
346
|
+
delete toCreateObject.$createdAt;
|
347
|
+
delete toCreateObject.$updatedAt;
|
348
|
+
delete toCreateObject.$id;
|
349
|
+
delete toCreateObject.$permissions;
|
350
|
+
return tryAwaitWithRetry(async () =>
|
351
|
+
remoteDb.createDocument(
|
352
|
+
toDbId,
|
353
|
+
toCollId,
|
354
|
+
doc.$id,
|
355
|
+
toCreateObject,
|
356
|
+
doc.$permissions
|
357
|
+
)
|
358
|
+
);
|
359
|
+
});
|
360
|
+
await Promise.all(batchedPromises);
|
361
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
362
|
+
while (fromCollDocs.documents.length === 50) {
|
363
|
+
fromCollDocs = await tryAwaitWithRetry(async () =>
|
364
|
+
localDb.listDocuments(fromDbId, fromCollId, [
|
365
|
+
Query.limit(50),
|
366
|
+
Query.cursorAfter(
|
367
|
+
fromCollDocs.documents[fromCollDocs.documents.length - 1].$id
|
368
|
+
),
|
369
|
+
])
|
370
|
+
);
|
371
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
372
|
+
const toCreateObject: Partial<typeof doc> = {
|
373
|
+
...doc,
|
374
|
+
};
|
375
|
+
delete toCreateObject.$databaseId;
|
376
|
+
delete toCreateObject.$collectionId;
|
377
|
+
delete toCreateObject.$createdAt;
|
378
|
+
delete toCreateObject.$updatedAt;
|
379
|
+
delete toCreateObject.$id;
|
380
|
+
delete toCreateObject.$permissions;
|
381
|
+
return tryAwaitWithRetry(async () =>
|
382
|
+
remoteDb.createDocument(
|
383
|
+
toDbId,
|
384
|
+
toCollId,
|
385
|
+
doc.$id,
|
386
|
+
toCreateObject,
|
387
|
+
doc.$permissions
|
388
|
+
)
|
389
|
+
);
|
390
|
+
});
|
391
|
+
await Promise.all(batchedPromises);
|
392
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
393
|
+
}
|
394
|
+
}
|
395
|
+
console.log(
|
396
|
+
`Total documents transferred from database ${fromDbId} to database ${toDbId} -- collection ${fromCollId} to collection ${toCollId}: ${totalDocumentsTransferred}`
|
397
|
+
);
|
398
|
+
};
|
399
|
+
|
400
|
+
/**
|
401
|
+
* Transfers all collections and documents from one local database to another local database.
|
402
|
+
*
|
403
|
+
* @param {Databases} localDb - The local database instance.
|
404
|
+
* @param {string} fromDbId - The ID of the source database.
|
405
|
+
* @param {string} targetDbId - The ID of the target database.
|
406
|
+
* @return {Promise<void>} A promise that resolves when the transfer is complete.
|
407
|
+
*/
|
408
|
+
export const transferDatabaseLocalToLocal = async (
|
409
|
+
localDb: Databases,
|
410
|
+
fromDbId: string,
|
411
|
+
targetDbId: string
|
412
|
+
) => {
|
413
|
+
let lastCollectionId: string | undefined;
|
414
|
+
let fromCollections = await tryAwaitWithRetry(
|
415
|
+
async () => await localDb.listCollections(fromDbId, [Query.limit(50)])
|
416
|
+
);
|
417
|
+
const allFromCollections = fromCollections.collections;
|
418
|
+
if (fromCollections.collections.length < 50) {
|
419
|
+
lastCollectionId = undefined;
|
420
|
+
} else {
|
421
|
+
lastCollectionId =
|
422
|
+
fromCollections.collections[fromCollections.collections.length - 1].$id;
|
423
|
+
while (lastCollectionId) {
|
424
|
+
const collections = await localDb.listCollections(fromDbId, [
|
425
|
+
Query.limit(50),
|
426
|
+
Query.cursorAfter(lastCollectionId),
|
427
|
+
]);
|
428
|
+
allFromCollections.push(...collections.collections);
|
429
|
+
if (collections.collections.length < 50) {
|
430
|
+
break;
|
431
|
+
}
|
432
|
+
lastCollectionId =
|
433
|
+
collections.collections[collections.collections.length - 1].$id;
|
434
|
+
}
|
435
|
+
}
|
436
|
+
lastCollectionId = undefined;
|
437
|
+
let toCollections = await tryAwaitWithRetry(
|
438
|
+
async () => await localDb.listCollections(targetDbId, [Query.limit(50)])
|
439
|
+
);
|
440
|
+
const allToCollections = toCollections.collections;
|
441
|
+
if (toCollections.collections.length < 50) {
|
442
|
+
} else {
|
443
|
+
lastCollectionId =
|
444
|
+
toCollections.collections[toCollections.collections.length - 1].$id;
|
445
|
+
while (lastCollectionId) {
|
446
|
+
const collections = await localDb.listCollections(targetDbId, [
|
447
|
+
Query.limit(50),
|
448
|
+
Query.cursorAfter(lastCollectionId),
|
449
|
+
]);
|
450
|
+
allToCollections.push(...collections.collections);
|
451
|
+
if (collections.collections.length < 50) {
|
452
|
+
lastCollectionId = undefined;
|
453
|
+
} else {
|
454
|
+
lastCollectionId =
|
455
|
+
collections.collections[collections.collections.length - 1].$id;
|
456
|
+
}
|
457
|
+
}
|
458
|
+
}
|
459
|
+
for (const collection of allFromCollections) {
|
460
|
+
const toCollection = allToCollections.find((c) => c.$id === collection.$id);
|
461
|
+
if (toCollection) {
|
462
|
+
await transferDocumentsBetweenDbsLocalToLocal(
|
463
|
+
localDb,
|
464
|
+
fromDbId,
|
465
|
+
targetDbId,
|
466
|
+
collection.$id,
|
467
|
+
toCollection.$id
|
468
|
+
);
|
469
|
+
} else {
|
470
|
+
console.log(
|
471
|
+
`Collection ${collection.name} not found in destination database, creating...`
|
472
|
+
);
|
473
|
+
const newCollection = await tryAwaitWithRetry(
|
474
|
+
async () =>
|
475
|
+
await localDb.createCollection(
|
476
|
+
targetDbId,
|
477
|
+
collection.$id,
|
478
|
+
collection.name,
|
479
|
+
collection.$permissions,
|
480
|
+
collection.documentSecurity,
|
481
|
+
collection.enabled
|
482
|
+
)
|
483
|
+
);
|
484
|
+
console.log(`Collection ${newCollection.name} created`);
|
485
|
+
for (const attribute of collection.attributes) {
|
486
|
+
await tryAwaitWithRetry(
|
487
|
+
async () =>
|
488
|
+
await createOrUpdateAttribute(
|
489
|
+
localDb,
|
490
|
+
targetDbId,
|
491
|
+
newCollection,
|
492
|
+
parseAttribute(attribute as any)
|
493
|
+
)
|
494
|
+
);
|
495
|
+
}
|
496
|
+
for (const index of collection.indexes) {
|
497
|
+
await tryAwaitWithRetry(
|
498
|
+
async () =>
|
499
|
+
await localDb.createIndex(
|
500
|
+
targetDbId,
|
501
|
+
newCollection.$id,
|
502
|
+
index.key,
|
503
|
+
index.type as IndexType,
|
504
|
+
index.attributes,
|
505
|
+
index.orders
|
506
|
+
)
|
507
|
+
);
|
508
|
+
}
|
509
|
+
await transferDocumentsBetweenDbsLocalToLocal(
|
510
|
+
localDb,
|
511
|
+
fromDbId,
|
512
|
+
targetDbId,
|
513
|
+
collection.$id,
|
514
|
+
newCollection.$id
|
515
|
+
);
|
516
|
+
}
|
517
|
+
}
|
518
|
+
};
|
519
|
+
|
520
|
+
export const transferDatabaseLocalToRemote = async (
|
521
|
+
localDb: Databases,
|
522
|
+
endpoint: string,
|
523
|
+
projectId: string,
|
524
|
+
apiKey: string,
|
525
|
+
fromDbId: string,
|
526
|
+
toDbId: string
|
527
|
+
) => {
|
528
|
+
const client = getAppwriteClient(endpoint, projectId, apiKey);
|
529
|
+
const remoteDb = new Databases(client);
|
530
|
+
|
531
|
+
let lastCollectionId: string | undefined;
|
532
|
+
let fromCollections = await tryAwaitWithRetry(
|
533
|
+
async () => await localDb.listCollections(fromDbId, [Query.limit(50)])
|
534
|
+
);
|
535
|
+
const allFromCollections = fromCollections.collections;
|
536
|
+
if (fromCollections.collections.length < 50) {
|
537
|
+
} else {
|
538
|
+
lastCollectionId =
|
539
|
+
fromCollections.collections[fromCollections.collections.length - 1].$id;
|
540
|
+
while (lastCollectionId) {
|
541
|
+
const collections = await tryAwaitWithRetry(
|
542
|
+
async () =>
|
543
|
+
await localDb.listCollections(fromDbId, [
|
544
|
+
Query.limit(50),
|
545
|
+
Query.cursorAfter(lastCollectionId!),
|
546
|
+
])
|
547
|
+
);
|
548
|
+
allFromCollections.push(...collections.collections);
|
549
|
+
if (collections.collections.length < 50) {
|
550
|
+
break;
|
551
|
+
}
|
552
|
+
lastCollectionId =
|
553
|
+
collections.collections[collections.collections.length - 1].$id;
|
554
|
+
}
|
555
|
+
}
|
556
|
+
|
557
|
+
for (const collection of allFromCollections) {
|
558
|
+
const toCollection = await tryAwaitWithRetry(
|
559
|
+
async () =>
|
560
|
+
await remoteDb.createCollection(
|
561
|
+
toDbId,
|
562
|
+
collection.$id,
|
563
|
+
collection.name,
|
564
|
+
collection.$permissions,
|
565
|
+
collection.documentSecurity,
|
566
|
+
collection.enabled
|
567
|
+
)
|
568
|
+
);
|
569
|
+
console.log(`Collection ${toCollection.name} created`);
|
570
|
+
|
571
|
+
for (const attribute of collection.attributes) {
|
572
|
+
await tryAwaitWithRetry(
|
573
|
+
async () =>
|
574
|
+
await createOrUpdateAttribute(
|
575
|
+
remoteDb,
|
576
|
+
toDbId,
|
577
|
+
toCollection,
|
578
|
+
parseAttribute(attribute as any)
|
579
|
+
)
|
580
|
+
);
|
581
|
+
}
|
582
|
+
|
583
|
+
for (const index of collection.indexes) {
|
584
|
+
await tryAwaitWithRetry(
|
585
|
+
async () =>
|
586
|
+
await remoteDb.createIndex(
|
587
|
+
toDbId,
|
588
|
+
toCollection.$id,
|
589
|
+
index.key,
|
590
|
+
index.type as IndexType,
|
591
|
+
index.attributes,
|
592
|
+
index.orders
|
593
|
+
)
|
594
|
+
);
|
595
|
+
}
|
596
|
+
|
597
|
+
await transferDocumentsBetweenDbsLocalToRemote(
|
598
|
+
localDb,
|
599
|
+
endpoint,
|
600
|
+
projectId,
|
601
|
+
apiKey,
|
602
|
+
fromDbId,
|
603
|
+
toDbId,
|
604
|
+
collection.$id,
|
605
|
+
toCollection.$id
|
606
|
+
);
|
607
|
+
}
|
608
|
+
};
|