appwrite-utils-cli 0.9.77 → 0.9.78

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.78: Added colored text! And also added a lot more customization options as to what to wipe, update, etc.
127
128
  - 0.9.75: Fixed attribute bug
128
129
  - 0.9.72: Fixed my own null bug
129
130
  - 0.9.71: Reverted `node-appwrite` to 14, this seems to fix the xdefault error
@@ -3,6 +3,7 @@ import { attributeSchema, parseAttribute, } from "appwrite-utils";
3
3
  import { nameToIdMapping, enqueueOperation } from "../migrations/queue.js";
4
4
  import _ from "lodash";
5
5
  import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
6
+ import chalk from "chalk";
6
7
  const attributesSame = (databaseAttribute, configAttribute) => {
7
8
  const attributesToCheck = [
8
9
  'key',
@@ -62,6 +63,7 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
62
63
  // @ts-expect-error
63
64
  (attr) => attr.key === attribute.key);
64
65
  foundAttribute = parseAttribute(collectionAttr);
66
+ // console.log(`Found attribute: ${JSON.stringify(foundAttribute)}`);
65
67
  }
66
68
  catch (error) {
67
69
  foundAttribute = undefined;
@@ -74,7 +76,10 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
74
76
  // console.log(
75
77
  // `Updating attribute with same key ${attribute.key} but different values`
76
78
  // );
77
- finalAttribute = attribute;
79
+ finalAttribute = {
80
+ ...foundAttribute,
81
+ ...attribute,
82
+ };
78
83
  action = "update";
79
84
  }
80
85
  else if (!updateEnabled && foundAttribute && !attributesSame(foundAttribute, attribute)) {
@@ -93,7 +98,9 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
93
98
  collectionFoundViaRelatedCollection = await db.getCollection(dbId, relatedCollectionId);
94
99
  }
95
100
  catch (e) {
96
- console.log(`Collection not found: ${finalAttribute.relatedCollection} when nameToIdMapping was set`);
101
+ // console.log(
102
+ // `Collection not found: ${finalAttribute.relatedCollection} when nameToIdMapping was set`
103
+ // );
97
104
  collectionFoundViaRelatedCollection = undefined;
98
105
  }
99
106
  }
@@ -108,7 +115,7 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
108
115
  }
109
116
  }
110
117
  if (!(relatedCollectionId && collectionFoundViaRelatedCollection)) {
111
- console.log(`Enqueueing operation for attribute: ${finalAttribute.key}`);
118
+ // console.log(`Enqueueing operation for attribute: ${finalAttribute.key}`);
112
119
  enqueueOperation({
113
120
  type: "attribute",
114
121
  collectionId: collection.$id,
@@ -119,7 +126,7 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
119
126
  return;
120
127
  }
121
128
  }
122
- finalAttribute = attributeSchema.parse(finalAttribute);
129
+ finalAttribute = parseAttribute(finalAttribute);
123
130
  // console.log(`Final Attribute: ${JSON.stringify(finalAttribute)}`);
124
131
  switch (finalAttribute.type) {
125
132
  case "string":
@@ -224,7 +231,7 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
224
231
  }
225
232
  };
226
233
  export const createUpdateCollectionAttributes = async (db, dbId, collection, attributes) => {
227
- console.log(`Creating/Updating attributes for collection: ${collection.name}`);
234
+ console.log(chalk.green(`Creating/Updating attributes for collection: ${collection.name}`));
228
235
  const batchSize = 3;
229
236
  for (let i = 0; i < attributes.length; i += batchSize) {
230
237
  const batch = attributes.slice(i, i + batchSize);
@@ -7,10 +7,11 @@ export declare const wipeDatabase: (database: Databases, databaseId: string) =>
7
7
  collectionId: string;
8
8
  collectionName: string;
9
9
  }[]>;
10
+ export declare const wipeCollection: (database: Databases, databaseId: string, collectionId: string) => Promise<void>;
10
11
  export declare const generateSchemas: (config: AppwriteConfig, appwriteFolderPath: string) => Promise<void>;
11
12
  export declare const createOrUpdateCollections: (database: Databases, databaseId: string, config: AppwriteConfig, deletedCollections?: {
12
13
  collectionId: string;
13
14
  collectionName: string;
14
- }[]) => Promise<void>;
15
+ }[], selectedCollections?: Models.Collection[]) => Promise<void>;
15
16
  export declare const generateMockData: (database: Databases, databaseId: string, configCollections: any[]) => Promise<void>;
16
17
  export declare const fetchAllCollections: (dbId: string, database: Databases) => Promise<Models.Collection[]>;
@@ -86,6 +86,21 @@ export const fetchAndCacheCollectionByName = async (db, dbId, collectionName) =>
86
86
  }
87
87
  }
88
88
  };
89
+ async function wipeDocumentsFromCollection(database, databaseId, collectionId) {
90
+ const initialDocuments = await database.listDocuments(databaseId, collectionId, [Query.limit(1000)]);
91
+ let documents = initialDocuments.documents;
92
+ while (documents.length === 1000) {
93
+ const docsResponse = await database.listDocuments(databaseId, collectionId, [Query.limit(1000)]);
94
+ documents = documents.concat(docsResponse.documents);
95
+ }
96
+ const batchDeletePromises = documents.map(doc => database.deleteDocument(databaseId, collectionId, doc.$id));
97
+ const maxStackSize = 100;
98
+ for (let i = 0; i < batchDeletePromises.length; i += maxStackSize) {
99
+ await Promise.all(batchDeletePromises.slice(i, i + maxStackSize));
100
+ await delay(100);
101
+ }
102
+ console.log(`Deleted ${documents.length} documents from collection ${collectionId}`);
103
+ }
89
104
  export const wipeDatabase = async (database, databaseId) => {
90
105
  console.log(`Wiping database: ${databaseId}`);
91
106
  const existingCollections = await fetchAllCollections(databaseId, database);
@@ -101,56 +116,71 @@ export const wipeDatabase = async (database, databaseId) => {
101
116
  }
102
117
  return collectionsDeleted;
103
118
  };
119
+ export const wipeCollection = async (database, databaseId, collectionId) => {
120
+ const collections = await database.listCollections(databaseId, [Query.equal("$id", collectionId)]);
121
+ if (collections.total === 0) {
122
+ console.log(`Collection ${collectionId} not found`);
123
+ return;
124
+ }
125
+ const collection = collections.collections[0];
126
+ await wipeDocumentsFromCollection(database, databaseId, collection.$id);
127
+ };
104
128
  export const generateSchemas = async (config, appwriteFolderPath) => {
105
129
  const schemaGenerator = new SchemaGenerator(config, appwriteFolderPath);
106
130
  schemaGenerator.generateSchemas();
107
131
  };
108
- export const createOrUpdateCollections = async (database, databaseId, config, deletedCollections) => {
109
- const configCollections = config.collections;
110
- if (!configCollections) {
132
+ export const createOrUpdateCollections = async (database, databaseId, config, deletedCollections, selectedCollections = []) => {
133
+ const collectionsToProcess = selectedCollections.length > 0 ? selectedCollections : config.collections;
134
+ if (!collectionsToProcess) {
111
135
  return;
112
136
  }
113
137
  const usedIds = new Set();
114
- for (const { attributes, indexes, ...collection } of configCollections) {
138
+ for (const collection of collectionsToProcess) {
139
+ const { attributes, indexes, ...collectionData } = collection;
115
140
  // Prepare permissions for the collection
116
141
  const permissions = [];
117
142
  if (collection.$permissions && collection.$permissions.length > 0) {
118
143
  for (const permission of collection.$permissions) {
119
- switch (permission.permission) {
120
- case "read":
121
- permissions.push(Permission.read(permission.target));
122
- break;
123
- case "create":
124
- permissions.push(Permission.create(permission.target));
125
- break;
126
- case "update":
127
- permissions.push(Permission.update(permission.target));
128
- break;
129
- case "delete":
130
- permissions.push(Permission.delete(permission.target));
131
- break;
132
- case "write":
133
- permissions.push(Permission.write(permission.target));
134
- break;
135
- default:
136
- console.log(`Unknown permission: ${permission.permission}`);
137
- break;
144
+ if (typeof permission === 'string') {
145
+ permissions.push(permission);
146
+ }
147
+ else {
148
+ switch (permission.permission) {
149
+ case "read":
150
+ permissions.push(Permission.read(permission.target));
151
+ break;
152
+ case "create":
153
+ permissions.push(Permission.create(permission.target));
154
+ break;
155
+ case "update":
156
+ permissions.push(Permission.update(permission.target));
157
+ break;
158
+ case "delete":
159
+ permissions.push(Permission.delete(permission.target));
160
+ break;
161
+ case "write":
162
+ permissions.push(Permission.write(permission.target));
163
+ break;
164
+ default:
165
+ console.log(`Unknown permission: ${permission.permission}`);
166
+ break;
167
+ }
138
168
  }
139
169
  }
140
170
  }
141
171
  // Check if the collection already exists by name
142
172
  let collectionsFound = await tryAwaitWithRetry(async () => await database.listCollections(databaseId, [
143
- Query.equal("name", collection.name),
173
+ Query.equal("name", collectionData.name),
144
174
  ]));
145
175
  let collectionToUse = collectionsFound.total > 0 ? collectionsFound.collections[0] : null;
146
176
  // Determine the correct ID for the collection
147
177
  let collectionId;
148
178
  if (!collectionToUse) {
149
- console.log(`Creating collection: ${collection.name}`);
179
+ console.log(`Creating collection: ${collectionData.name}`);
150
180
  let foundColl = deletedCollections?.find((coll) => coll.collectionName.toLowerCase().trim().replace(" ", "") ===
151
- collection.name.toLowerCase().trim().replace(" ", ""));
152
- if (collection.$id) {
153
- collectionId = collection.$id;
181
+ collectionData.name.toLowerCase().trim().replace(" ", ""));
182
+ if (collectionData.$id) {
183
+ collectionId = collectionData.$id;
154
184
  }
155
185
  else if (foundColl && !usedIds.has(foundColl.collectionId)) {
156
186
  collectionId = foundColl.collectionId;
@@ -161,28 +191,30 @@ export const createOrUpdateCollections = async (database, databaseId, config, de
161
191
  usedIds.add(collectionId);
162
192
  // Create the collection with the determined ID
163
193
  try {
164
- collectionToUse = await tryAwaitWithRetry(async () => await database.createCollection(databaseId, collectionId, collection.name, permissions, collection.documentSecurity ?? false, collection.enabled ?? true));
165
- collection.$id = collectionToUse.$id;
166
- nameToIdMapping.set(collection.name, collectionToUse.$id);
194
+ collectionToUse = await tryAwaitWithRetry(async () => await database.createCollection(databaseId, collectionId, collectionData.name, permissions, collectionData.documentSecurity ?? false, collectionData.enabled ?? true));
195
+ collectionData.$id = collectionToUse.$id;
196
+ nameToIdMapping.set(collectionData.name, collectionToUse.$id);
167
197
  }
168
198
  catch (error) {
169
- console.error(`Failed to create collection ${collection.name} with ID ${collectionId}: ${error}`);
199
+ console.error(`Failed to create collection ${collectionData.name} with ID ${collectionId}: ${error}`);
170
200
  continue;
171
201
  }
172
202
  }
173
203
  else {
174
- console.log(`Collection ${collection.name} exists, updating it`);
175
- await tryAwaitWithRetry(async () => await database.updateCollection(databaseId, collectionToUse.$id, collection.name, permissions, collection.documentSecurity ?? false, collection.enabled ?? true));
204
+ console.log(`Collection ${collectionData.name} exists, updating it`);
205
+ await tryAwaitWithRetry(async () => await database.updateCollection(databaseId, collectionToUse.$id, collectionData.name, permissions, collectionData.documentSecurity ?? false, collectionData.enabled ?? true));
176
206
  }
177
207
  // Add delay after creating/updating collection
178
208
  await delay(250);
179
209
  // Update attributes and indexes for the collection
180
210
  console.log("Creating Attributes");
181
- await createUpdateCollectionAttributes(database, databaseId, collectionToUse, attributes);
211
+ await createUpdateCollectionAttributes(database, databaseId, collectionToUse,
212
+ // @ts-expect-error
213
+ attributes);
182
214
  // Add delay after creating attributes
183
215
  await delay(250);
184
216
  console.log("Creating Indexes");
185
- await createOrUpdateIndexes(databaseId, database, collectionToUse.$id, indexes ?? []);
217
+ await createOrUpdateIndexes(databaseId, database, collectionToUse.$id, (indexes ?? []));
186
218
  // Add delay after creating indexes
187
219
  await delay(250);
188
220
  }
@@ -14,7 +14,9 @@ export declare class InteractiveCLI {
14
14
  private synchronizeConfigurations;
15
15
  private backupDatabase;
16
16
  private wipeDatabase;
17
+ private wipeCollections;
17
18
  private generateSchemas;
18
19
  private importData;
19
20
  private transferData;
21
+ private reloadConfig;
20
22
  }
@@ -7,6 +7,7 @@ import { listBuckets, createBucket } from "./storage/methods.js";
7
7
  import { Databases, Storage, Client, Compression, } from "node-appwrite";
8
8
  import { getClient } from "./utils/getClientFromConfig.js";
9
9
  import { ulid } from "ulidx";
10
+ import chalk from "chalk";
10
11
  var CHOICES;
11
12
  (function (CHOICES) {
12
13
  CHOICES["CREATE_COLLECTION_CONFIG"] = "Create collection config file";
@@ -17,8 +18,10 @@ var CHOICES;
17
18
  CHOICES["TRANSFER_DATA"] = "Transfer data";
18
19
  CHOICES["BACKUP_DATABASE"] = "Backup database";
19
20
  CHOICES["WIPE_DATABASE"] = "Wipe database";
21
+ CHOICES["WIPE_COLLECTIONS"] = "Wipe collections";
20
22
  CHOICES["GENERATE_SCHEMAS"] = "Generate schemas";
21
23
  CHOICES["IMPORT_DATA"] = "Import data";
24
+ CHOICES["RELOAD_CONFIG"] = "Reload configuration files";
22
25
  CHOICES["EXIT"] = "Exit";
23
26
  })(CHOICES || (CHOICES = {}));
24
27
  export class InteractiveCLI {
@@ -28,17 +31,18 @@ export class InteractiveCLI {
28
31
  this.currentDir = currentDir;
29
32
  }
30
33
  async run() {
31
- console.log("Welcome to Appwrite Utils CLI Tool by Zach Handley");
32
- console.log("For more information, visit https://github.com/zachhandley/AppwriteUtils");
34
+ console.log(chalk.green("Welcome to Appwrite Utils CLI Tool by Zach Handley"));
35
+ console.log(chalk.blue("For more information, visit https://github.com/zachhandley/AppwriteUtils"));
33
36
  while (true) {
34
37
  const { action } = await inquirer.prompt([
35
38
  {
36
39
  type: "list",
37
40
  name: "action",
38
- message: "What would you like to do?",
41
+ message: chalk.yellow("What would you like to do?"),
39
42
  choices: Object.values(CHOICES),
40
43
  },
41
44
  ]);
45
+ await this.initControllerIfNeeded();
42
46
  switch (action) {
43
47
  case CHOICES.CREATE_COLLECTION_CONFIG:
44
48
  await this.createCollectionConfig();
@@ -69,6 +73,10 @@ export class InteractiveCLI {
69
73
  await this.initControllerIfNeeded();
70
74
  await this.wipeDatabase();
71
75
  break;
76
+ case CHOICES.WIPE_COLLECTIONS:
77
+ await this.initControllerIfNeeded();
78
+ await this.wipeCollections();
79
+ break;
72
80
  case CHOICES.GENERATE_SCHEMAS:
73
81
  await this.initControllerIfNeeded();
74
82
  await this.generateSchemas();
@@ -77,8 +85,12 @@ export class InteractiveCLI {
77
85
  await this.initControllerIfNeeded();
78
86
  await this.importData();
79
87
  break;
88
+ case CHOICES.RELOAD_CONFIG:
89
+ await this.initControllerIfNeeded();
90
+ await this.reloadConfig();
91
+ break;
80
92
  case CHOICES.EXIT:
81
- console.log("Exiting...");
93
+ console.log(chalk.green("Goodbye!"));
82
94
  return;
83
95
  }
84
96
  }
@@ -90,12 +102,12 @@ export class InteractiveCLI {
90
102
  }
91
103
  }
92
104
  async selectDatabases(databases, message, multiSelect = true) {
93
- const choices = databases.map((db) => ({ name: db.name, value: db }));
105
+ const choices = databases.map((db) => ({ name: db.name, value: db })).filter((db) => db.name.toLowerCase() !== "migrations");
94
106
  const { selectedDatabases } = await inquirer.prompt([
95
107
  {
96
108
  type: multiSelect ? "checkbox" : "list",
97
109
  name: "selectedDatabases",
98
- message,
110
+ message: chalk.blue(message),
99
111
  choices,
100
112
  loop: false,
101
113
  pageSize: 10,
@@ -113,7 +125,7 @@ export class InteractiveCLI {
113
125
  {
114
126
  type: multiSelect ? "checkbox" : "list",
115
127
  name: "selectedCollections",
116
- message,
128
+ message: chalk.blue(message),
117
129
  choices,
118
130
  loop: false,
119
131
  pageSize: 10,
@@ -130,7 +142,7 @@ export class InteractiveCLI {
130
142
  {
131
143
  type: multiSelect ? "checkbox" : "list",
132
144
  name: "selectedBuckets",
133
- message,
145
+ message: chalk.blue(message),
134
146
  choices,
135
147
  loop: false,
136
148
  pageSize: 10,
@@ -143,11 +155,11 @@ export class InteractiveCLI {
143
155
  {
144
156
  type: "input",
145
157
  name: "collectionName",
146
- message: "Enter the name of the collection:",
158
+ message: chalk.blue("Enter the name of the collection:"),
147
159
  validate: (input) => input.trim() !== "" || "Collection name cannot be empty.",
148
160
  },
149
161
  ]);
150
- console.log(`Creating collection config file for '${collectionName}'...`);
162
+ console.log(chalk.green(`Creating collection config file for '${collectionName}'...`));
151
163
  createEmptyCollection(collectionName);
152
164
  }
153
165
  async configureBuckets(config, databases) {
@@ -163,7 +175,7 @@ export class InteractiveCLI {
163
175
  {
164
176
  type: "confirm",
165
177
  name: "wantCreateBucket",
166
- message: `There are no buckets. Do you want to create a bucket for the database "${database.name}"?`,
178
+ message: chalk.blue(`There are no buckets. Do you want to create a bucket for the database "${database.name}"?`),
167
179
  default: true,
168
180
  },
169
181
  ]);
@@ -322,7 +334,11 @@ export class InteractiveCLI {
322
334
  }, bucketId.length > 0 ? bucketId : ulid());
323
335
  }
324
336
  async syncDb() {
325
- await this.controller.syncDb();
337
+ console.log(chalk.yellow("Syncing database..."));
338
+ const databases = await this.selectDatabases(await fetchAllDatabases(this.controller.database), chalk.blue("Select databases to synchronize:"), true);
339
+ const collections = await this.selectCollections(databases[0], this.controller.database, chalk.blue("Select collections to synchronize:"), true);
340
+ await this.controller.syncDb(databases, collections);
341
+ console.log(chalk.green("Database sync completed."));
326
342
  }
327
343
  async synchronizeConfigurations() {
328
344
  if (!this.controller.database) {
@@ -330,10 +346,11 @@ export class InteractiveCLI {
330
346
  }
331
347
  const databases = await fetchAllDatabases(this.controller.database);
332
348
  const selectedDatabases = await this.selectDatabases(databases, "Select databases to synchronize:");
333
- console.log("Configuring storage buckets...");
349
+ console.log(chalk.yellow("Configuring storage buckets..."));
334
350
  const updatedConfig = await this.configureBuckets(this.controller.config, selectedDatabases);
335
- console.log("Synchronizing configurations...");
351
+ console.log(chalk.yellow("Synchronizing configurations..."));
336
352
  await this.controller.synchronizeConfigurations(selectedDatabases, updatedConfig);
353
+ console.log(chalk.green("Configuration synchronization completed."));
337
354
  }
338
355
  async backupDatabase() {
339
356
  if (!this.controller.database) {
@@ -342,9 +359,10 @@ export class InteractiveCLI {
342
359
  const databases = await fetchAllDatabases(this.controller.database);
343
360
  const selectedDatabases = await this.selectDatabases(databases, "Select databases to backup:");
344
361
  for (const db of selectedDatabases) {
345
- console.log(`Backing up database: ${db.name}`);
362
+ console.log(chalk.yellow(`Backing up database: ${db.name}`));
346
363
  await this.controller.backupDatabase(db);
347
364
  }
365
+ console.log(chalk.green("Database backup completed."));
348
366
  }
349
367
  async wipeDatabase() {
350
368
  if (!this.controller.database || !this.controller.storage) {
@@ -373,12 +391,12 @@ export class InteractiveCLI {
373
391
  {
374
392
  type: "confirm",
375
393
  name: "confirm",
376
- message: "Are you sure you want to wipe the selected items? This action cannot be undone.",
394
+ message: chalk.red("Are you sure you want to wipe the selected items? This action cannot be undone."),
377
395
  default: false,
378
396
  },
379
397
  ]);
380
398
  if (confirm) {
381
- console.log("Wiping selected items...");
399
+ console.log(chalk.yellow("Wiping selected items..."));
382
400
  for (const db of selectedDatabases) {
383
401
  await this.controller.wipeDatabase(db);
384
402
  }
@@ -388,26 +406,58 @@ export class InteractiveCLI {
388
406
  if (wipeUsers) {
389
407
  await this.controller.wipeUsers();
390
408
  }
409
+ console.log(chalk.green("Wipe operation completed."));
391
410
  }
392
411
  else {
393
- console.log("Wipe operation cancelled.");
412
+ console.log(chalk.blue("Wipe operation cancelled."));
394
413
  }
395
414
  }
396
- async generateSchemas() {
397
- console.log("Generating schemas...");
398
- await this.controller.generateSchemas();
399
- }
400
- async importData() {
415
+ async wipeCollections() {
401
416
  if (!this.controller.database) {
402
417
  throw new Error("Database is not initialized, is the config file correct & created?");
403
418
  }
404
419
  const databases = await fetchAllDatabases(this.controller.database);
405
- const selectedDatabases = await this.selectDatabases(databases, "Select the database(s) to import data into:");
406
- let selectedCollections = [];
407
- for (const db of selectedDatabases) {
408
- const dbCollections = await this.selectCollections(db, this.controller.database, `Select collections to import data into for database ${db.name}:`, true);
409
- selectedCollections = [...selectedCollections, ...dbCollections];
420
+ const selectedDatabases = await this.selectDatabases(databases, "Select the database(s) containing the collections to wipe:", true);
421
+ for (const database of selectedDatabases) {
422
+ const collections = await this.selectCollections(database, this.controller.database, `Select collections to wipe from ${database.name}:`, true);
423
+ const { confirm } = await inquirer.prompt([
424
+ {
425
+ type: "confirm",
426
+ name: "confirm",
427
+ message: chalk.red(`Are you sure you want to wipe the selected collections from ${database.name}? This action cannot be undone.`),
428
+ default: false,
429
+ },
430
+ ]);
431
+ if (confirm) {
432
+ console.log(chalk.yellow(`Wiping selected collections from ${database.name}...`));
433
+ for (const collection of collections) {
434
+ await this.controller.wipeCollection(database, collection);
435
+ console.log(chalk.green(`Collection ${collection.name} wiped successfully.`));
436
+ }
437
+ }
438
+ else {
439
+ console.log(chalk.blue(`Wipe operation cancelled for ${database.name}.`));
440
+ }
410
441
  }
442
+ console.log(chalk.green("Wipe collections operation completed."));
443
+ }
444
+ async generateSchemas() {
445
+ console.log(chalk.yellow("Generating schemas..."));
446
+ await this.controller.generateSchemas();
447
+ console.log(chalk.green("Schema generation completed."));
448
+ }
449
+ async importData() {
450
+ console.log(chalk.yellow("Importing data..."));
451
+ const { doBackup } = await inquirer.prompt([
452
+ {
453
+ type: "confirm",
454
+ name: "doBackup",
455
+ message: "Do you want to perform a backup before importing?",
456
+ default: true,
457
+ },
458
+ ]);
459
+ const databases = await this.selectDatabases(await fetchAllDatabases(this.controller.database), "Select databases to import data into:", true);
460
+ const collections = await this.selectCollections(databases[0], this.controller.database, "Select collections to import data into (leave empty for all):", true);
411
461
  const { shouldWriteFile } = await inquirer.prompt([
412
462
  {
413
463
  type: "confirm",
@@ -416,24 +466,20 @@ export class InteractiveCLI {
416
466
  default: false,
417
467
  },
418
468
  ]);
419
- // const { checkDuplicates } = await inquirer.prompt([
420
- // {
421
- // type: "confirm",
422
- // name: "checkDuplicates",
423
- // message: "Do you want to check for duplicates during import?",
424
- // default: true,
425
- // },
426
- // ]);
427
- console.log("Importing data...");
428
- await this.controller.importData({
429
- databases: selectedDatabases,
430
- collections: selectedCollections.length > 0
431
- ? selectedCollections.map((c) => c.$id)
432
- : undefined,
469
+ const options = {
470
+ databases,
471
+ collections: collections.map(c => c.name),
472
+ doBackup,
473
+ importData: true,
433
474
  shouldWriteFile,
434
- checkDuplicates: false,
435
- // checkDuplicates,
436
- });
475
+ };
476
+ try {
477
+ await this.controller.importData(options);
478
+ console.log(chalk.green("Data import completed successfully."));
479
+ }
480
+ catch (error) {
481
+ console.error(chalk.red("Error importing data:"), error);
482
+ }
437
483
  }
438
484
  async transferData() {
439
485
  if (!this.controller.database) {
@@ -481,18 +527,17 @@ export class InteractiveCLI {
481
527
  sourceDatabases = targetDatabases = allDatabases;
482
528
  }
483
529
  const fromDbs = await this.selectDatabases(sourceDatabases, "Select the source database:", false);
484
- console.log(fromDbs);
485
- const fromDb = fromDbs;
530
+ const fromDb = fromDbs[0];
486
531
  if (!fromDb) {
487
532
  throw new Error("No source database selected");
488
533
  }
489
534
  const availableDbs = targetDatabases.filter((db) => db.$id !== fromDb.$id);
490
535
  const targetDbs = await this.selectDatabases(availableDbs, "Select the target database:", false);
491
- const targetDb = targetDbs;
536
+ const targetDb = targetDbs[0];
492
537
  if (!targetDb) {
493
538
  throw new Error("No target database selected");
494
539
  }
495
- const selectedCollections = await this.selectCollections(fromDb, sourceClient, "Select collections to transfer):");
540
+ const selectedCollections = await this.selectCollections(fromDb, sourceClient, "Select collections to transfer:");
496
541
  const { transferStorage } = await inquirer.prompt([
497
542
  {
498
543
  type: "confirm",
@@ -513,8 +558,8 @@ export class InteractiveCLI {
513
558
  : sourceBuckets;
514
559
  const sourceBucketPicked = await this.selectBuckets(sourceBuckets.buckets, "Select the source bucket:", false);
515
560
  const targetBucketPicked = await this.selectBuckets(targetBuckets.buckets, "Select the target bucket:", false);
516
- sourceBucket = sourceBucketPicked;
517
- targetBucket = targetBucketPicked;
561
+ sourceBucket = sourceBucketPicked[0];
562
+ targetBucket = targetBucketPicked[0];
518
563
  }
519
564
  let transferOptions = {
520
565
  fromDb,
@@ -532,7 +577,18 @@ export class InteractiveCLI {
532
577
  ...remoteOptions,
533
578
  };
534
579
  }
535
- console.log("Transferring data...");
580
+ console.log(chalk.yellow("Transferring data..."));
536
581
  await this.controller.transferData(transferOptions);
582
+ console.log(chalk.green("Data transfer completed."));
583
+ }
584
+ async reloadConfig() {
585
+ console.log(chalk.yellow("Reloading configuration files..."));
586
+ try {
587
+ await this.controller.reloadConfig();
588
+ console.log(chalk.green("Configuration files reloaded successfully."));
589
+ }
590
+ catch (error) {
591
+ console.error(chalk.red("Error reloading configuration files:"), error);
592
+ }
537
593
  }
538
594
  }