appwrite-utils-cli 0.9.982 → 0.9.984
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 +1 -0
- package/dist/main.js +56 -42
- package/dist/migrations/dataLoader.d.ts +2 -42
- package/dist/migrations/dataLoader.js +57 -12
- package/dist/migrations/importController.js +24 -9
- package/dist/migrations/migrationHelper.d.ts +2 -2
- package/dist/migrations/transfer.d.ts +2 -2
- package/dist/utilsController.js +39 -26
- package/package.json +1 -1
- package/src/appwrite.zip +0 -0
- package/src/main.ts +77 -52
- package/src/migrations/dataLoader.ts +74 -23
- package/src/migrations/importController.ts +37 -22
- package/src/migrations/transfer.ts +2 -2
- package/src/utilsController.ts +62 -53
- package/zlogs/album.json +0 -4
- package/zlogs/announcements.json +0 -397
- package/zlogs/announcementscomments.json +0 -36
- package/zlogs/articles.json +0 -138
- package/zlogs/articlescomments.json +0 -4
- package/zlogs/artist.json +0 -4
- package/zlogs/businesscategories.json +0 -7097
- package/zlogs/contacts.json +0 -517063
- package/zlogs/contactscouncils.json +0 -61905
- package/zlogs/contactssociallinks.json +0 -13776
- package/zlogs/councils.json +0 -5076
- package/zlogs/documents.json +0 -917
- package/zlogs/emails.json +0 -4
- package/zlogs/events.json +0 -132625
- package/zlogs/genre.json +0 -4
- package/zlogs/knowledgebase.json +0 -333
- package/zlogs/knowledgebasecomments.json +0 -4
- package/zlogs/linkcategories.json +0 -180
- package/zlogs/links.json +0 -4364
- package/zlogs/memberrequests.json +0 -83
- package/zlogs/memberrequestscomments.json +0 -65
- package/zlogs/mergedUserMap.json +0 -1
- package/zlogs/oldIdToNewIdPerCollectionMap.json +0 -1
- package/zlogs/playlist.json +0 -4
- package/zlogs/regions.json +0 -145
- package/zlogs/song.json +0 -4
- package/zlogs/testimonials.json +0 -335
- package/zlogs/useractivity.json +0 -4
- package/zlogs/userdata.json +0 -4
- package/zlogs/users.json +0 -4
@@ -1086,6 +1086,7 @@ export class DataLoader {
|
|
1086
1086
|
}
|
1087
1087
|
}
|
1088
1088
|
// Update the attribute mappings with any actions that need to be performed post-import
|
1089
|
+
// We added the basePath to get the folder from the filePath
|
1089
1090
|
const mappingsWithActions = this.getAttributeMappingsWithActions(
|
1090
1091
|
importDef.attributeMappings,
|
1091
1092
|
context,
|
@@ -1247,6 +1248,7 @@ export class DataLoader {
|
|
1247
1248
|
continue;
|
1248
1249
|
}
|
1249
1250
|
// Update the attribute mappings with any actions that need to be performed post-import
|
1251
|
+
// We added the basePath to get the folder from the filePath
|
1250
1252
|
const mappingsWithActions = this.getAttributeMappingsWithActions(
|
1251
1253
|
importDef.attributeMappings,
|
1252
1254
|
context,
|
@@ -1462,6 +1464,7 @@ export class DataLoader {
|
|
1462
1464
|
}
|
1463
1465
|
|
1464
1466
|
// Update the attribute mappings with any actions that need to be performed post-import
|
1467
|
+
// We added the basePath to get the folder from the filePath
|
1465
1468
|
const mappingsWithActions = this.getAttributeMappingsWithActions(
|
1466
1469
|
importDef.attributeMappings,
|
1467
1470
|
context,
|
@@ -1480,26 +1483,42 @@ export class DataLoader {
|
|
1480
1483
|
transformedData
|
1481
1484
|
);
|
1482
1485
|
itemDataToUpdate.context = context;
|
1483
|
-
|
1486
|
+
|
1487
|
+
// Fix: Ensure we properly merge the attribute mappings and their actions
|
1488
|
+
const mergedAttributeMappings = newImportDef.attributeMappings.map(
|
1489
|
+
(newMapping) => {
|
1490
|
+
const existingMapping =
|
1491
|
+
itemDataToUpdate.importDef?.attributeMappings.find(
|
1492
|
+
(m) => m.targetKey === newMapping.targetKey
|
1493
|
+
);
|
1494
|
+
|
1495
|
+
return {
|
1496
|
+
...newMapping,
|
1497
|
+
postImportActions: [
|
1498
|
+
...(existingMapping?.postImportActions || []),
|
1499
|
+
...(newMapping.postImportActions || []),
|
1500
|
+
],
|
1501
|
+
};
|
1502
|
+
}
|
1503
|
+
);
|
1504
|
+
|
1484
1505
|
itemDataToUpdate.importDef = {
|
1485
|
-
...
|
1486
|
-
attributeMappings:
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1501
|
-
`Mappings in update councils: ${JSON.stringify(
|
1502
|
-
itemDataToUpdate.importDef.attributeMappings,
|
1506
|
+
...newImportDef,
|
1507
|
+
attributeMappings: mergedAttributeMappings,
|
1508
|
+
};
|
1509
|
+
|
1510
|
+
// Debug logging
|
1511
|
+
if (
|
1512
|
+
mergedAttributeMappings.some((m) => m.postImportActions?.length > 0)
|
1513
|
+
) {
|
1514
|
+
logger.info(
|
1515
|
+
`Post-import actions for ${collection.name}: ${JSON.stringify(
|
1516
|
+
mergedAttributeMappings
|
1517
|
+
.filter((m) => m.postImportActions?.length > 0)
|
1518
|
+
.map((m) => ({
|
1519
|
+
targetKey: m.targetKey,
|
1520
|
+
actions: m.postImportActions,
|
1521
|
+
})),
|
1503
1522
|
null,
|
1504
1523
|
2
|
1505
1524
|
)}`
|
@@ -1603,10 +1622,42 @@ export class DataLoader {
|
|
1603
1622
|
);
|
1604
1623
|
// Ensure the file path is absolute if it doesn't start with "http"
|
1605
1624
|
if (!mappingFilePath.toLowerCase().startsWith("http")) {
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1625
|
+
// First try the direct path
|
1626
|
+
let fullPath = path.resolve(this.appwriteFolderPath, mappingFilePath);
|
1627
|
+
|
1628
|
+
// If file doesn't exist, search in subdirectories
|
1629
|
+
if (!fs.existsSync(fullPath)) {
|
1630
|
+
const findFileInDir = (dir: string): string | null => {
|
1631
|
+
const files = fs.readdirSync(dir);
|
1632
|
+
|
1633
|
+
for (const file of files) {
|
1634
|
+
const filePath = path.join(dir, file);
|
1635
|
+
const stat = fs.statSync(filePath);
|
1636
|
+
|
1637
|
+
if (stat.isDirectory()) {
|
1638
|
+
// Recursively search subdirectories
|
1639
|
+
const found = findFileInDir(filePath);
|
1640
|
+
if (found) return found;
|
1641
|
+
} else if (file === path.basename(mappingFilePath)) {
|
1642
|
+
return filePath;
|
1643
|
+
}
|
1644
|
+
}
|
1645
|
+
return null;
|
1646
|
+
};
|
1647
|
+
|
1648
|
+
const foundPath = findFileInDir(this.appwriteFolderPath);
|
1649
|
+
if (foundPath) {
|
1650
|
+
mappingFilePath = foundPath;
|
1651
|
+
} else {
|
1652
|
+
logger.warn(
|
1653
|
+
`File not found in any subdirectory: ${mappingFilePath}`
|
1654
|
+
);
|
1655
|
+
// Keep the original resolved path as fallback
|
1656
|
+
mappingFilePath = fullPath;
|
1657
|
+
}
|
1658
|
+
} else {
|
1659
|
+
mappingFilePath = fullPath;
|
1660
|
+
}
|
1610
1661
|
}
|
1611
1662
|
// Define the after-import action to create a file and update the field
|
1612
1663
|
const afterImportAction = {
|
@@ -119,27 +119,38 @@ export class ImportController {
|
|
119
119
|
updatedDb: Models.Database,
|
120
120
|
targetDb: Models.Database
|
121
121
|
) {
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
const updatedDbConfig = this.config.databases.find(
|
130
|
-
(db) => db.$id === updatedDb.$id
|
131
|
-
);
|
132
|
-
const targetDbConfig = this.config.databases.find(
|
133
|
-
(db) => db.$id === targetDb.$id
|
134
|
-
);
|
122
|
+
if (this.database) {
|
123
|
+
await transferDatabaseLocalToLocal(
|
124
|
+
this.database,
|
125
|
+
updatedDb.$id,
|
126
|
+
targetDb.$id
|
127
|
+
);
|
128
|
+
}
|
135
129
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
updatedDbConfig.bucket.$id,
|
141
|
-
targetDbConfig.bucket.$id
|
130
|
+
if (this.storage) {
|
131
|
+
// Find the corresponding database configs
|
132
|
+
const updatedDbConfig = this.config.databases.find(
|
133
|
+
(db) => db.$id === updatedDb.$id
|
142
134
|
);
|
135
|
+
const targetDbConfig = this.config.databases.find(
|
136
|
+
(db) => db.$id === targetDb.$id
|
137
|
+
);
|
138
|
+
|
139
|
+
const sourceBucketId = updatedDbConfig?.bucket?.$id ||
|
140
|
+
(this.config.documentBucketId &&
|
141
|
+
`${this.config.documentBucketId}_${updatedDb.$id.toLowerCase().trim().replace(" ", "")}`);
|
142
|
+
|
143
|
+
const targetBucketId = targetDbConfig?.bucket?.$id ||
|
144
|
+
(this.config.documentBucketId &&
|
145
|
+
`${this.config.documentBucketId}_${targetDb.$id.toLowerCase().trim().replace(" ", "")}`);
|
146
|
+
|
147
|
+
if (sourceBucketId && targetBucketId) {
|
148
|
+
await transferStorageLocalToLocal(
|
149
|
+
this.storage,
|
150
|
+
sourceBucketId,
|
151
|
+
targetBucketId
|
152
|
+
);
|
153
|
+
}
|
143
154
|
}
|
144
155
|
}
|
145
156
|
|
@@ -298,11 +309,13 @@ export class ImportController {
|
|
298
309
|
}
|
299
310
|
|
300
311
|
async executePostImportActions(dbId: string, dataLoader: DataLoader, specificCollections?: string[]) {
|
301
|
-
|
302
|
-
|
312
|
+
console.log("Executing post-import actions...");
|
313
|
+
const collectionsToProcess = specificCollections && specificCollections.length > 0 ? specificCollections : (this.config.collections ? this.config.collections.map(c => c.name) : Array.from(dataLoader.importMap.keys()));
|
314
|
+
console.log("Collections to process:", collectionsToProcess);
|
303
315
|
// Iterate over each collection in the importMap
|
304
316
|
for (const [collectionKey, collectionData] of dataLoader.importMap.entries()) {
|
305
|
-
|
317
|
+
const allCollectionKeys = collectionsToProcess.map(c => dataLoader.getCollectionKey(c));
|
318
|
+
if (allCollectionKeys.includes(collectionKey)) {
|
306
319
|
console.log(
|
307
320
|
`Processing post-import actions for collection: ${collectionKey}`
|
308
321
|
);
|
@@ -330,6 +343,8 @@ export class ImportController {
|
|
330
343
|
}
|
331
344
|
}
|
332
345
|
}
|
346
|
+
} else {
|
347
|
+
console.log(`Skipping collection: ${collectionKey} because it's not valid for post-import actions`);
|
333
348
|
}
|
334
349
|
}
|
335
350
|
}
|
@@ -13,8 +13,8 @@ import { createOrUpdateAttribute } from "../collections/attributes.js";
|
|
13
13
|
import { parseAttribute } from "appwrite-utils";
|
14
14
|
|
15
15
|
export interface TransferOptions {
|
16
|
-
fromDb: Models.Database;
|
17
|
-
targetDb: Models.Database;
|
16
|
+
fromDb: Models.Database | undefined;
|
17
|
+
targetDb: Models.Database | undefined;
|
18
18
|
isRemote: boolean;
|
19
19
|
collections?: string[];
|
20
20
|
transferEndpoint?: string;
|
package/src/utilsController.ts
CHANGED
@@ -145,6 +145,7 @@ export class UtilsController {
|
|
145
145
|
async getDatabasesByIds(ids: string[]) {
|
146
146
|
await this.init();
|
147
147
|
if (!this.database) throw new Error("Database not initialized");
|
148
|
+
if (ids.length === 0) return [];
|
148
149
|
const dbs = await this.database.list([
|
149
150
|
Query.limit(500),
|
150
151
|
Query.equal("$id", ids),
|
@@ -289,16 +290,11 @@ export class UtilsController {
|
|
289
290
|
}
|
290
291
|
|
291
292
|
async transferData(options: TransferOptions): Promise<void> {
|
292
|
-
|
293
|
-
throw new Error(
|
294
|
-
"Database is not initialized, is the config file correct & created?"
|
295
|
-
);
|
296
|
-
}
|
297
|
-
|
293
|
+
// Remove database requirement check
|
298
294
|
let sourceClient = this.database;
|
299
|
-
let targetClient: Databases;
|
300
|
-
let sourceDatabases: Models.Database[];
|
301
|
-
let targetDatabases: Models.Database[];
|
295
|
+
let targetClient: Databases | undefined;
|
296
|
+
let sourceDatabases: Models.Database[] = [];
|
297
|
+
let targetDatabases: Models.Database[] = [];
|
302
298
|
|
303
299
|
if (options.isRemote) {
|
304
300
|
if (
|
@@ -314,63 +310,76 @@ export class UtilsController {
|
|
314
310
|
options.transferProject,
|
315
311
|
options.transferKey
|
316
312
|
);
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
313
|
+
|
314
|
+
if (this.database) {
|
315
|
+
targetClient = new Databases(remoteClient);
|
316
|
+
sourceDatabases = await fetchAllDatabases(sourceClient!);
|
317
|
+
targetDatabases = await fetchAllDatabases(targetClient);
|
318
|
+
}
|
319
|
+
} else if (this.database) {
|
322
320
|
targetClient = sourceClient;
|
323
|
-
sourceDatabases = targetDatabases = await fetchAllDatabases(sourceClient);
|
324
|
-
}
|
325
|
-
|
326
|
-
// Validate that the provided databases exist in the fetched lists
|
327
|
-
const fromDb = sourceDatabases.find((db) => db.$id === options.fromDb.$id);
|
328
|
-
const targetDb = targetDatabases.find(
|
329
|
-
(db) => db.$id === options.targetDb.$id
|
330
|
-
);
|
331
|
-
|
332
|
-
if (!fromDb || !targetDb) {
|
333
|
-
throw new Error("Source or target database not found");
|
321
|
+
sourceDatabases = targetDatabases = await fetchAllDatabases(sourceClient!);
|
334
322
|
}
|
335
323
|
|
336
|
-
if
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
options.
|
341
|
-
options.transferProject!,
|
342
|
-
options.transferKey!,
|
343
|
-
fromDb.$id,
|
344
|
-
targetDb.$id
|
324
|
+
// Only validate databases if they're provided in options
|
325
|
+
if (options.fromDb && options.targetDb) {
|
326
|
+
const fromDb = sourceDatabases.find((db) => db.$id === options.fromDb!.$id);
|
327
|
+
const targetDb = targetDatabases.find(
|
328
|
+
(db) => db.$id === options.targetDb!.$id
|
345
329
|
);
|
346
330
|
|
347
|
-
if (
|
348
|
-
|
349
|
-
|
331
|
+
if (!fromDb || !targetDb) {
|
332
|
+
throw new Error("Source or target database not found");
|
333
|
+
}
|
334
|
+
|
335
|
+
if (options.isRemote && targetClient) {
|
336
|
+
await transferDatabaseLocalToRemote(
|
337
|
+
sourceClient!,
|
350
338
|
options.transferEndpoint!,
|
351
339
|
options.transferProject!,
|
352
340
|
options.transferKey!,
|
353
|
-
|
354
|
-
|
341
|
+
fromDb.$id,
|
342
|
+
targetDb.$id
|
343
|
+
);
|
344
|
+
} else if (targetClient) {
|
345
|
+
await transferDatabaseLocalToLocal(
|
346
|
+
sourceClient!,
|
347
|
+
fromDb.$id,
|
348
|
+
targetDb.$id
|
355
349
|
);
|
356
350
|
}
|
357
|
-
}
|
358
|
-
// Local transfer
|
359
|
-
await transferDatabaseLocalToLocal(
|
360
|
-
sourceClient,
|
361
|
-
fromDb.$id,
|
362
|
-
targetDb.$id
|
363
|
-
);
|
351
|
+
}
|
364
352
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
options.
|
370
|
-
|
353
|
+
// Handle storage transfer separately
|
354
|
+
if (this.storage && (options.sourceBucket || options.fromDb)) {
|
355
|
+
const sourceBucketId = options.sourceBucket?.$id ||
|
356
|
+
(options.fromDb && this.config?.documentBucketId &&
|
357
|
+
`${this.config.documentBucketId}_${options.fromDb.$id.toLowerCase().trim().replace(" ", "")}`);
|
358
|
+
|
359
|
+
const targetBucketId = options.targetBucket?.$id ||
|
360
|
+
(options.targetDb && this.config?.documentBucketId &&
|
361
|
+
`${this.config.documentBucketId}_${options.targetDb.$id.toLowerCase().trim().replace(" ", "")}`);
|
362
|
+
|
363
|
+
if (sourceBucketId && targetBucketId) {
|
364
|
+
if (options.isRemote) {
|
365
|
+
await transferStorageLocalToRemote(
|
366
|
+
this.storage,
|
367
|
+
options.transferEndpoint!,
|
368
|
+
options.transferProject!,
|
369
|
+
options.transferKey!,
|
370
|
+
sourceBucketId,
|
371
|
+
targetBucketId
|
372
|
+
);
|
373
|
+
} else {
|
374
|
+
await transferStorageLocalToLocal(
|
375
|
+
this.storage,
|
376
|
+
sourceBucketId,
|
377
|
+
targetBucketId
|
378
|
+
);
|
379
|
+
}
|
371
380
|
}
|
372
381
|
}
|
373
382
|
|
374
|
-
console.log("
|
383
|
+
console.log("Transfer completed");
|
375
384
|
}
|
376
385
|
}
|
package/zlogs/album.json
DELETED