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 +1 -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 +2 -0
- package/dist/interactiveCLI.js +108 -52
- 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 +142 -73
- 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
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 =
|
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(
|
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 =
|
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
|
110
|
-
if (!
|
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
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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",
|
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: ${
|
179
|
+
console.log(`Creating collection: ${collectionData.name}`);
|
150
180
|
let foundColl = deletedCollections?.find((coll) => coll.collectionName.toLowerCase().trim().replace(" ", "") ===
|
151
|
-
|
152
|
-
if (
|
153
|
-
collectionId =
|
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,
|
165
|
-
|
166
|
-
nameToIdMapping.set(
|
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 ${
|
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 ${
|
175
|
-
await tryAwaitWithRetry(async () => await database.updateCollection(databaseId, collectionToUse.$id,
|
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,
|
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
|
}
|
package/dist/interactiveCLI.d.ts
CHANGED
@@ -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
|
}
|
package/dist/interactiveCLI.js
CHANGED
@@ -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("
|
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
|
-
|
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
|
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)
|
406
|
-
|
407
|
-
|
408
|
-
const
|
409
|
-
|
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
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
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
|
-
|
435
|
-
|
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
|
-
|
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
|
}
|