appwrite-utils-cli 0.9.77 → 0.9.79
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 +3 -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 +4 -0
- package/dist/interactiveCLI.js +141 -53
- 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 +179 -75
- 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/src/interactiveCLI.ts
CHANGED
@@ -13,8 +13,10 @@ import {
|
|
13
13
|
} from "node-appwrite";
|
14
14
|
import { getClient } from "./utils/getClientFromConfig.js";
|
15
15
|
import type { TransferOptions } from "./migrations/transfer.js";
|
16
|
-
import type
|
16
|
+
import { parseAttribute, PermissionToAppwritePermission, type AppwriteConfig, type ConfigDatabases } from "appwrite-utils";
|
17
17
|
import { ulid } from "ulidx";
|
18
|
+
import chalk from "chalk";
|
19
|
+
import { DateTime } from "luxon";
|
18
20
|
|
19
21
|
enum CHOICES {
|
20
22
|
CREATE_COLLECTION_CONFIG = "Create collection config file",
|
@@ -25,8 +27,10 @@ enum CHOICES {
|
|
25
27
|
TRANSFER_DATA = "Transfer data",
|
26
28
|
BACKUP_DATABASE = "Backup database",
|
27
29
|
WIPE_DATABASE = "Wipe database",
|
30
|
+
WIPE_COLLECTIONS = "Wipe collections",
|
28
31
|
GENERATE_SCHEMAS = "Generate schemas",
|
29
32
|
IMPORT_DATA = "Import data",
|
33
|
+
RELOAD_CONFIG = "Reload configuration files",
|
30
34
|
EXIT = "Exit",
|
31
35
|
}
|
32
36
|
|
@@ -36,9 +40,9 @@ export class InteractiveCLI {
|
|
36
40
|
constructor(private currentDir: string) {}
|
37
41
|
|
38
42
|
async run(): Promise<void> {
|
39
|
-
console.log("Welcome to Appwrite Utils CLI Tool by Zach Handley");
|
43
|
+
console.log(chalk.green("Welcome to Appwrite Utils CLI Tool by Zach Handley"));
|
40
44
|
console.log(
|
41
|
-
"For more information, visit https://github.com/zachhandley/AppwriteUtils"
|
45
|
+
chalk.blue("For more information, visit https://github.com/zachhandley/AppwriteUtils")
|
42
46
|
);
|
43
47
|
|
44
48
|
while (true) {
|
@@ -46,11 +50,13 @@ export class InteractiveCLI {
|
|
46
50
|
{
|
47
51
|
type: "list",
|
48
52
|
name: "action",
|
49
|
-
message: "What would you like to do?",
|
53
|
+
message: chalk.yellow("What would you like to do?"),
|
50
54
|
choices: Object.values(CHOICES),
|
51
55
|
},
|
52
56
|
]);
|
53
57
|
|
58
|
+
await this.initControllerIfNeeded();
|
59
|
+
|
54
60
|
switch (action) {
|
55
61
|
case CHOICES.CREATE_COLLECTION_CONFIG:
|
56
62
|
await this.createCollectionConfig();
|
@@ -81,6 +87,10 @@ export class InteractiveCLI {
|
|
81
87
|
await this.initControllerIfNeeded();
|
82
88
|
await this.wipeDatabase();
|
83
89
|
break;
|
90
|
+
case CHOICES.WIPE_COLLECTIONS:
|
91
|
+
await this.initControllerIfNeeded();
|
92
|
+
await this.wipeCollections();
|
93
|
+
break;
|
84
94
|
case CHOICES.GENERATE_SCHEMAS:
|
85
95
|
await this.initControllerIfNeeded();
|
86
96
|
await this.generateSchemas();
|
@@ -89,14 +99,18 @@ export class InteractiveCLI {
|
|
89
99
|
await this.initControllerIfNeeded();
|
90
100
|
await this.importData();
|
91
101
|
break;
|
102
|
+
case CHOICES.RELOAD_CONFIG:
|
103
|
+
await this.initControllerIfNeeded();
|
104
|
+
await this.reloadConfig();
|
105
|
+
break;
|
92
106
|
case CHOICES.EXIT:
|
93
|
-
console.log("
|
107
|
+
console.log(chalk.green("Goodbye!"));
|
94
108
|
return;
|
95
109
|
}
|
96
110
|
}
|
97
111
|
}
|
98
112
|
|
99
|
-
private async initControllerIfNeeded() {
|
113
|
+
private async initControllerIfNeeded(): Promise<void> {
|
100
114
|
if (!this.controller) {
|
101
115
|
this.controller = new UtilsController(this.currentDir);
|
102
116
|
await this.controller.init();
|
@@ -108,13 +122,16 @@ export class InteractiveCLI {
|
|
108
122
|
message: string,
|
109
123
|
multiSelect = true
|
110
124
|
): Promise<Models.Database[]> {
|
111
|
-
const choices = databases.map((db) => ({ name: db.name, value: db }));
|
125
|
+
const choices = databases.map((db) => ({ name: db.name, value: db })).filter((db) => db.name.toLowerCase() !== "migrations");
|
126
|
+
const configDatabases = this.getLocalDatabases();
|
127
|
+
const allDatabases = Array.from(new Set([...databases, ...configDatabases]));
|
128
|
+
|
112
129
|
|
113
130
|
const { selectedDatabases } = await inquirer.prompt([
|
114
131
|
{
|
115
132
|
type: multiSelect ? "checkbox" : "list",
|
116
133
|
name: "selectedDatabases",
|
117
|
-
message,
|
134
|
+
message: chalk.blue(message),
|
118
135
|
choices,
|
119
136
|
loop: false,
|
120
137
|
pageSize: 10,
|
@@ -134,7 +151,9 @@ export class InteractiveCLI {
|
|
134
151
|
database.$id,
|
135
152
|
databasesClient
|
136
153
|
);
|
137
|
-
const
|
154
|
+
const configCollections = this.getLocalCollections();
|
155
|
+
const allCollections = Array.from(new Set([...collections, ...configCollections]));
|
156
|
+
const choices = allCollections.map((collection) => ({
|
138
157
|
name: collection.name,
|
139
158
|
value: collection,
|
140
159
|
}));
|
@@ -143,7 +162,7 @@ export class InteractiveCLI {
|
|
143
162
|
{
|
144
163
|
type: multiSelect ? "checkbox" : "list",
|
145
164
|
name: "selectedCollections",
|
146
|
-
message,
|
165
|
+
message: chalk.blue(message),
|
147
166
|
choices,
|
148
167
|
loop: false,
|
149
168
|
pageSize: 10,
|
@@ -167,7 +186,7 @@ export class InteractiveCLI {
|
|
167
186
|
{
|
168
187
|
type: multiSelect ? "checkbox" : "list",
|
169
188
|
name: "selectedBuckets",
|
170
|
-
message,
|
189
|
+
message: chalk.blue(message),
|
171
190
|
choices,
|
172
191
|
loop: false,
|
173
192
|
pageSize: 10,
|
@@ -182,12 +201,12 @@ export class InteractiveCLI {
|
|
182
201
|
{
|
183
202
|
type: "input",
|
184
203
|
name: "collectionName",
|
185
|
-
message: "Enter the name of the collection:",
|
204
|
+
message: chalk.blue("Enter the name of the collection:"),
|
186
205
|
validate: (input) =>
|
187
206
|
input.trim() !== "" || "Collection name cannot be empty.",
|
188
207
|
},
|
189
208
|
]);
|
190
|
-
console.log(`Creating collection config file for '${collectionName}'...`);
|
209
|
+
console.log(chalk.green(`Creating collection config file for '${collectionName}'...`));
|
191
210
|
createEmptyCollection(collectionName);
|
192
211
|
}
|
193
212
|
|
@@ -211,7 +230,7 @@ export class InteractiveCLI {
|
|
211
230
|
{
|
212
231
|
type: "confirm",
|
213
232
|
name: "wantCreateBucket",
|
214
|
-
message: `There are no buckets. Do you want to create a bucket for the database "${database.name}"
|
233
|
+
message: chalk.blue(`There are no buckets. Do you want to create a bucket for the database "${database.name}"?`),
|
215
234
|
default: true,
|
216
235
|
},
|
217
236
|
]);
|
@@ -414,7 +433,20 @@ export class InteractiveCLI {
|
|
414
433
|
}
|
415
434
|
|
416
435
|
private async syncDb(): Promise<void> {
|
417
|
-
|
436
|
+
console.log(chalk.yellow("Syncing database..."));
|
437
|
+
const databases = await this.selectDatabases(
|
438
|
+
await fetchAllDatabases(this.controller!.database!),
|
439
|
+
chalk.blue("Select databases to synchronize:"),
|
440
|
+
true,
|
441
|
+
);
|
442
|
+
const collections = await this.selectCollections(
|
443
|
+
databases[0],
|
444
|
+
this.controller!.database!,
|
445
|
+
chalk.blue("Select collections to synchronize:"),
|
446
|
+
true,
|
447
|
+
);
|
448
|
+
await this.controller!.syncDb(databases, collections);
|
449
|
+
console.log(chalk.green("Database sync completed."));
|
418
450
|
}
|
419
451
|
|
420
452
|
private async synchronizeConfigurations(): Promise<void> {
|
@@ -430,17 +462,18 @@ export class InteractiveCLI {
|
|
430
462
|
"Select databases to synchronize:"
|
431
463
|
);
|
432
464
|
|
433
|
-
console.log("Configuring storage buckets...");
|
465
|
+
console.log(chalk.yellow("Configuring storage buckets..."));
|
434
466
|
const updatedConfig = await this.configureBuckets(
|
435
467
|
this.controller!.config!,
|
436
468
|
selectedDatabases
|
437
469
|
);
|
438
470
|
|
439
|
-
console.log("Synchronizing configurations...");
|
471
|
+
console.log(chalk.yellow("Synchronizing configurations..."));
|
440
472
|
await this.controller!.synchronizeConfigurations(
|
441
473
|
selectedDatabases,
|
442
474
|
updatedConfig
|
443
475
|
);
|
476
|
+
console.log(chalk.green("Configuration synchronization completed."));
|
444
477
|
}
|
445
478
|
|
446
479
|
private async backupDatabase(): Promise<void> {
|
@@ -457,9 +490,10 @@ export class InteractiveCLI {
|
|
457
490
|
);
|
458
491
|
|
459
492
|
for (const db of selectedDatabases) {
|
460
|
-
console.log(`Backing up database: ${db.name}`);
|
493
|
+
console.log(chalk.yellow(`Backing up database: ${db.name}`));
|
461
494
|
await this.controller!.backupDatabase(db);
|
462
495
|
}
|
496
|
+
console.log(chalk.green("Database backup completed."));
|
463
497
|
}
|
464
498
|
|
465
499
|
private async wipeDatabase(): Promise<void> {
|
@@ -498,14 +532,15 @@ export class InteractiveCLI {
|
|
498
532
|
{
|
499
533
|
type: "confirm",
|
500
534
|
name: "confirm",
|
501
|
-
message:
|
502
|
-
"Are you sure you want to wipe the selected items? This action cannot be undone."
|
535
|
+
message: chalk.red(
|
536
|
+
"Are you sure you want to wipe the selected items? This action cannot be undone."
|
537
|
+
),
|
503
538
|
default: false,
|
504
539
|
},
|
505
540
|
]);
|
506
541
|
|
507
542
|
if (confirm) {
|
508
|
-
console.log("Wiping selected items...");
|
543
|
+
console.log(chalk.yellow("Wiping selected items..."));
|
509
544
|
for (const db of selectedDatabases) {
|
510
545
|
await this.controller!.wipeDatabase(db);
|
511
546
|
}
|
@@ -515,39 +550,87 @@ export class InteractiveCLI {
|
|
515
550
|
if (wipeUsers) {
|
516
551
|
await this.controller!.wipeUsers();
|
517
552
|
}
|
553
|
+
console.log(chalk.green("Wipe operation completed."));
|
518
554
|
} else {
|
519
|
-
console.log("Wipe operation cancelled.");
|
555
|
+
console.log(chalk.blue("Wipe operation cancelled."));
|
520
556
|
}
|
521
557
|
}
|
522
558
|
|
523
|
-
private async
|
524
|
-
console.log("Generating schemas...");
|
525
|
-
await this.controller!.generateSchemas();
|
526
|
-
}
|
527
|
-
|
528
|
-
private async importData(): Promise<void> {
|
559
|
+
private async wipeCollections(): Promise<void> {
|
529
560
|
if (!this.controller!.database) {
|
530
561
|
throw new Error(
|
531
562
|
"Database is not initialized, is the config file correct & created?"
|
532
563
|
);
|
533
564
|
}
|
534
565
|
const databases = await fetchAllDatabases(this.controller!.database);
|
535
|
-
|
536
566
|
const selectedDatabases = await this.selectDatabases(
|
537
567
|
databases,
|
538
|
-
"Select the database(s)
|
568
|
+
"Select the database(s) containing the collections to wipe:",
|
569
|
+
true
|
539
570
|
);
|
540
571
|
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
db,
|
572
|
+
for (const database of selectedDatabases) {
|
573
|
+
const collections = await this.selectCollections(
|
574
|
+
database,
|
545
575
|
this.controller!.database,
|
546
|
-
`Select collections to
|
576
|
+
`Select collections to wipe from ${database.name}:`,
|
547
577
|
true
|
548
578
|
);
|
549
|
-
|
579
|
+
|
580
|
+
const { confirm } = await inquirer.prompt([
|
581
|
+
{
|
582
|
+
type: "confirm",
|
583
|
+
name: "confirm",
|
584
|
+
message: chalk.red(
|
585
|
+
`Are you sure you want to wipe the selected collections from ${database.name}? This action cannot be undone.`
|
586
|
+
),
|
587
|
+
default: false,
|
588
|
+
},
|
589
|
+
]);
|
590
|
+
|
591
|
+
if (confirm) {
|
592
|
+
console.log(chalk.yellow(`Wiping selected collections from ${database.name}...`));
|
593
|
+
for (const collection of collections) {
|
594
|
+
await this.controller!.wipeCollection(database, collection);
|
595
|
+
console.log(chalk.green(`Collection ${collection.name} wiped successfully.`));
|
596
|
+
}
|
597
|
+
} else {
|
598
|
+
console.log(chalk.blue(`Wipe operation cancelled for ${database.name}.`));
|
599
|
+
}
|
550
600
|
}
|
601
|
+
console.log(chalk.green("Wipe collections operation completed."));
|
602
|
+
}
|
603
|
+
|
604
|
+
private async generateSchemas(): Promise<void> {
|
605
|
+
console.log(chalk.yellow("Generating schemas..."));
|
606
|
+
await this.controller!.generateSchemas();
|
607
|
+
console.log(chalk.green("Schema generation completed."));
|
608
|
+
}
|
609
|
+
|
610
|
+
private async importData(): Promise<void> {
|
611
|
+
console.log(chalk.yellow("Importing data..."));
|
612
|
+
|
613
|
+
const { doBackup } = await inquirer.prompt([
|
614
|
+
{
|
615
|
+
type: "confirm",
|
616
|
+
name: "doBackup",
|
617
|
+
message: "Do you want to perform a backup before importing?",
|
618
|
+
default: true,
|
619
|
+
},
|
620
|
+
]);
|
621
|
+
|
622
|
+
const databases = await this.selectDatabases(
|
623
|
+
await fetchAllDatabases(this.controller!.database!),
|
624
|
+
"Select databases to import data into:",
|
625
|
+
true
|
626
|
+
);
|
627
|
+
|
628
|
+
const collections = await this.selectCollections(
|
629
|
+
databases[0],
|
630
|
+
this.controller!.database!,
|
631
|
+
"Select collections to import data into (leave empty for all):",
|
632
|
+
true
|
633
|
+
);
|
551
634
|
|
552
635
|
const { shouldWriteFile } = await inquirer.prompt([
|
553
636
|
{
|
@@ -558,26 +641,20 @@ export class InteractiveCLI {
|
|
558
641
|
},
|
559
642
|
]);
|
560
643
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
// default: true,
|
567
|
-
// },
|
568
|
-
// ]);
|
569
|
-
|
570
|
-
console.log("Importing data...");
|
571
|
-
await this.controller!.importData({
|
572
|
-
databases: selectedDatabases,
|
573
|
-
collections:
|
574
|
-
selectedCollections.length > 0
|
575
|
-
? selectedCollections.map((c) => c.$id)
|
576
|
-
: undefined,
|
644
|
+
const options = {
|
645
|
+
databases,
|
646
|
+
collections: collections.map(c => c.name),
|
647
|
+
doBackup,
|
648
|
+
importData: true,
|
577
649
|
shouldWriteFile,
|
578
|
-
|
579
|
-
|
580
|
-
|
650
|
+
};
|
651
|
+
|
652
|
+
try {
|
653
|
+
await this.controller!.importData(options);
|
654
|
+
console.log(chalk.green("Data import completed successfully."));
|
655
|
+
} catch (error) {
|
656
|
+
console.error(chalk.red("Error importing data:"), error);
|
657
|
+
}
|
581
658
|
}
|
582
659
|
|
583
660
|
private async transferData(): Promise<void> {
|
@@ -647,14 +724,7 @@ export class InteractiveCLI {
|
|
647
724
|
"Select the source database:",
|
648
725
|
false
|
649
726
|
);
|
650
|
-
|
651
|
-
const fromDb = fromDbs as unknown as {
|
652
|
-
$id: string;
|
653
|
-
name: string;
|
654
|
-
$createdAt: string;
|
655
|
-
$updatedAt: string;
|
656
|
-
enabled: boolean;
|
657
|
-
};
|
727
|
+
const fromDb = fromDbs[0];
|
658
728
|
if (!fromDb) {
|
659
729
|
throw new Error("No source database selected");
|
660
730
|
}
|
@@ -664,13 +734,7 @@ export class InteractiveCLI {
|
|
664
734
|
"Select the target database:",
|
665
735
|
false
|
666
736
|
);
|
667
|
-
const targetDb = targetDbs
|
668
|
-
$id: string;
|
669
|
-
name: string;
|
670
|
-
$createdAt: string;
|
671
|
-
$updatedAt: string;
|
672
|
-
enabled: boolean;
|
673
|
-
};
|
737
|
+
const targetDb = targetDbs[0];
|
674
738
|
if (!targetDb) {
|
675
739
|
throw new Error("No target database selected");
|
676
740
|
}
|
@@ -678,7 +742,7 @@ export class InteractiveCLI {
|
|
678
742
|
const selectedCollections = await this.selectCollections(
|
679
743
|
fromDb,
|
680
744
|
sourceClient,
|
681
|
-
"Select collections to transfer
|
745
|
+
"Select collections to transfer:"
|
682
746
|
);
|
683
747
|
|
684
748
|
const { transferStorage } = await inquirer.prompt([
|
@@ -719,8 +783,8 @@ export class InteractiveCLI {
|
|
719
783
|
"Select the target bucket:",
|
720
784
|
false
|
721
785
|
);
|
722
|
-
sourceBucket = sourceBucketPicked
|
723
|
-
targetBucket = targetBucketPicked
|
786
|
+
sourceBucket = sourceBucketPicked[0];
|
787
|
+
targetBucket = targetBucketPicked[0];
|
724
788
|
}
|
725
789
|
|
726
790
|
let transferOptions: TransferOptions = {
|
@@ -742,7 +806,47 @@ export class InteractiveCLI {
|
|
742
806
|
};
|
743
807
|
}
|
744
808
|
|
745
|
-
console.log("Transferring data...");
|
809
|
+
console.log(chalk.yellow("Transferring data..."));
|
746
810
|
await this.controller!.transferData(transferOptions);
|
811
|
+
console.log(chalk.green("Data transfer completed."));
|
747
812
|
}
|
748
|
-
|
813
|
+
|
814
|
+
|
815
|
+
private getLocalCollections(): Models.Collection[] {
|
816
|
+
const configCollections = this.controller!.config!.collections || [];
|
817
|
+
// @ts-expect-error - appwrite invalid types
|
818
|
+
return configCollections.map(c => ({
|
819
|
+
$id: c.$id || ulid(),
|
820
|
+
$createdAt: DateTime.now().toISO(),
|
821
|
+
$updatedAt: DateTime.now().toISO(),
|
822
|
+
name: c.name,
|
823
|
+
enabled: c.enabled || true,
|
824
|
+
documentSecurity: c.documentSecurity || false,
|
825
|
+
attributes: c.attributes || [],
|
826
|
+
indexes: c.indexes || [],
|
827
|
+
$permissions: PermissionToAppwritePermission(c.$permissions) || [],
|
828
|
+
databaseId: c.databaseId!,
|
829
|
+
}));
|
830
|
+
}
|
831
|
+
|
832
|
+
private getLocalDatabases(): Models.Database[] {
|
833
|
+
const configDatabases = this.controller!.config!.databases || [];
|
834
|
+
return configDatabases.map(db => ({
|
835
|
+
$id: db.$id || ulid(),
|
836
|
+
$createdAt: DateTime.now().toISO(),
|
837
|
+
$updatedAt: DateTime.now().toISO(),
|
838
|
+
name: db.name,
|
839
|
+
enabled: true,
|
840
|
+
}));
|
841
|
+
}
|
842
|
+
|
843
|
+
private async reloadConfig(): Promise<void> {
|
844
|
+
console.log(chalk.yellow("Reloading configuration files..."));
|
845
|
+
try {
|
846
|
+
await this.controller!.reloadConfig();
|
847
|
+
console.log(chalk.green("Configuration files reloaded successfully."));
|
848
|
+
} catch (error) {
|
849
|
+
console.error(chalk.red("Error reloading configuration files:"), error);
|
850
|
+
}
|
851
|
+
}
|
852
|
+
}
|
package/src/main.ts
CHANGED
@@ -7,6 +7,9 @@ import { UtilsController, type SetupOptions } from "./utilsController.js";
|
|
7
7
|
import type { TransferOptions } from "./migrations/transfer.js";
|
8
8
|
import { Databases, Storage, type Models } from "node-appwrite";
|
9
9
|
import { getClient } from "./utils/getClientFromConfig.js";
|
10
|
+
import { fetchAllDatabases } from "./migrations/databases.js";
|
11
|
+
import { setupDirsFiles } from "./utils/setupFiles.js";
|
12
|
+
import { fetchAllCollections } from "./collections/methods.js";
|
10
13
|
|
11
14
|
interface CliOptions {
|
12
15
|
it?: boolean;
|
@@ -14,6 +17,7 @@ interface CliOptions {
|
|
14
17
|
collectionIds?: string;
|
15
18
|
bucketIds?: string;
|
16
19
|
wipe?: "all" | "docs" | "users";
|
20
|
+
wipeCollections?: boolean;
|
17
21
|
generate?: boolean;
|
18
22
|
import?: boolean;
|
19
23
|
backup?: boolean;
|
@@ -62,6 +66,10 @@ const argv = yargs(hideBin(process.argv))
|
|
62
66
|
description:
|
63
67
|
"Wipe data (all: everything, docs: only documents, users: only user data)",
|
64
68
|
})
|
69
|
+
.option("wipeCollections", {
|
70
|
+
type: "boolean",
|
71
|
+
description: "Wipe collections, uses collectionIds option to get the collections to wipe",
|
72
|
+
})
|
65
73
|
.option("generate", {
|
66
74
|
type: "boolean",
|
67
75
|
description: "Generate TypeScript schemas from database schemas",
|
@@ -125,86 +133,88 @@ const argv = yargs(hideBin(process.argv))
|
|
125
133
|
description: "Set the destination collection ID for transfer",
|
126
134
|
})
|
127
135
|
.option("fromBucketId", {
|
128
|
-
alias: ["fromBucket"],
|
129
136
|
type: "string",
|
130
137
|
description: "Set the source bucket ID for transfer",
|
131
138
|
})
|
132
139
|
.option("toBucketId", {
|
133
|
-
alias: ["toBucket"],
|
134
140
|
type: "string",
|
135
141
|
description: "Set the destination bucket ID for transfer",
|
136
142
|
})
|
137
143
|
.option("remoteEndpoint", {
|
138
144
|
type: "string",
|
139
|
-
description: "Set the remote Appwrite endpoint for
|
145
|
+
description: "Set the remote Appwrite endpoint for transfer",
|
140
146
|
})
|
141
147
|
.option("remoteProjectId", {
|
142
148
|
type: "string",
|
143
|
-
description: "Set the remote Appwrite project ID for
|
149
|
+
description: "Set the remote Appwrite project ID for transfer",
|
144
150
|
})
|
145
151
|
.option("remoteApiKey", {
|
146
152
|
type: "string",
|
147
|
-
description: "Set the remote Appwrite API key for
|
153
|
+
description: "Set the remote Appwrite API key for transfer",
|
148
154
|
})
|
149
155
|
.option("setup", {
|
150
156
|
type: "boolean",
|
151
|
-
description: "Setup
|
157
|
+
description: "Setup directories and files",
|
152
158
|
})
|
153
|
-
.
|
154
|
-
.parse();
|
159
|
+
.parse() as ParsedArgv;
|
155
160
|
|
156
161
|
async function main() {
|
157
|
-
const
|
158
|
-
let controller: UtilsController | undefined;
|
162
|
+
const controller = new UtilsController(process.cwd());
|
159
163
|
|
160
|
-
if (
|
161
|
-
try {
|
162
|
-
controller = new UtilsController(process.cwd());
|
163
|
-
await controller.init();
|
164
|
-
} catch (error: any) {
|
165
|
-
// If it fails, that means there's no config, more than likely
|
166
|
-
console.log(
|
167
|
-
"No config found, you probably need to create the setup files"
|
168
|
-
);
|
169
|
-
}
|
164
|
+
if (argv.it) {
|
170
165
|
const cli = new InteractiveCLI(process.cwd());
|
171
166
|
await cli.run();
|
172
167
|
} else {
|
173
|
-
|
174
|
-
|
175
|
-
|
168
|
+
await controller.init();
|
169
|
+
|
170
|
+
if (argv.setup) {
|
171
|
+
await setupDirsFiles(false, process.cwd());
|
172
|
+
return;
|
176
173
|
}
|
177
|
-
|
174
|
+
|
175
|
+
const parsedArgv = argv;
|
176
|
+
|
178
177
|
const options: SetupOptions = {
|
179
178
|
databases: parsedArgv.dbIds
|
180
|
-
? await controller.getDatabasesByIds(
|
181
|
-
parsedArgv.dbIds.replace(" ", "").split(",")
|
182
|
-
)
|
183
|
-
: undefined,
|
184
|
-
collections: parsedArgv.collectionIds
|
185
|
-
? parsedArgv.collectionIds.replace(" ", "").split(",")
|
179
|
+
? await controller.getDatabasesByIds(parsedArgv.dbIds.split(","))
|
186
180
|
: undefined,
|
181
|
+
collections: parsedArgv.collectionIds?.split(","),
|
187
182
|
doBackup: parsedArgv.backup,
|
188
183
|
wipeDatabase: parsedArgv.wipe === "all" || parsedArgv.wipe === "docs",
|
189
184
|
wipeDocumentStorage: parsedArgv.wipe === "all",
|
190
185
|
wipeUsers: parsedArgv.wipe === "all" || parsedArgv.wipe === "users",
|
191
186
|
generateSchemas: parsedArgv.generate,
|
192
187
|
importData: parsedArgv.import,
|
193
|
-
checkDuplicates: false,
|
194
188
|
shouldWriteFile: parsedArgv.writeData,
|
189
|
+
wipeCollections: parsedArgv.wipeCollections,
|
195
190
|
};
|
196
191
|
|
197
|
-
if (parsedArgv.push) {
|
198
|
-
await controller.
|
192
|
+
if (parsedArgv.push || parsedArgv.sync) {
|
193
|
+
const databases = options.databases || await fetchAllDatabases(controller.database!);
|
194
|
+
let collections: Models.Collection[] = [];
|
195
|
+
|
196
|
+
if (options.collections) {
|
197
|
+
for (const db of databases) {
|
198
|
+
const dbCollections = await fetchAllCollections(db.$id, controller.database!);
|
199
|
+
collections = collections.concat(dbCollections.filter(c => options.collections!.includes(c.$id)));
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
if (parsedArgv.push) {
|
204
|
+
await controller.syncDb(databases, collections);
|
205
|
+
} else if (parsedArgv.sync) {
|
206
|
+
await controller.synchronizeConfigurations(databases);
|
207
|
+
}
|
199
208
|
}
|
200
209
|
|
201
210
|
if (
|
202
211
|
options.wipeDatabase ||
|
203
212
|
options.wipeDocumentStorage ||
|
204
|
-
options.wipeUsers
|
213
|
+
options.wipeUsers ||
|
214
|
+
options.wipeCollections
|
205
215
|
) {
|
206
|
-
if (options.wipeDatabase) {
|
207
|
-
for (const db of options.databases
|
216
|
+
if (options.wipeDatabase && options.databases) {
|
217
|
+
for (const db of options.databases) {
|
208
218
|
await controller.wipeDatabase(db);
|
209
219
|
}
|
210
220
|
}
|
@@ -216,10 +226,19 @@ async function main() {
|
|
216
226
|
if (options.wipeUsers) {
|
217
227
|
await controller.wipeUsers();
|
218
228
|
}
|
229
|
+
if (options.wipeCollections && options.databases) {
|
230
|
+
for (const db of options.databases) {
|
231
|
+
const dbCollections = await fetchAllCollections(db.$id, controller.database!);
|
232
|
+
const collectionsToWipe = dbCollections.filter(c => options.collections!.includes(c.$id));
|
233
|
+
for (const collection of collectionsToWipe) {
|
234
|
+
await controller.wipeCollection(db, collection);
|
235
|
+
}
|
236
|
+
}
|
237
|
+
}
|
219
238
|
}
|
220
239
|
|
221
|
-
if (options.doBackup) {
|
222
|
-
for (const db of options.databases
|
240
|
+
if (options.doBackup && options.databases) {
|
241
|
+
for (const db of options.databases) {
|
223
242
|
await controller.backupDatabase(db);
|
224
243
|
}
|
225
244
|
}
|
@@ -254,8 +273,8 @@ async function main() {
|
|
254
273
|
);
|
255
274
|
targetDatabases = new Databases(remoteClient);
|
256
275
|
targetStorage = new Storage(remoteClient);
|
257
|
-
const remoteDbs = await targetDatabases
|
258
|
-
toDb = remoteDbs.
|
276
|
+
const remoteDbs = await fetchAllDatabases(targetDatabases);
|
277
|
+
toDb = remoteDbs.find((db) => db.$id === parsedArgv.toDbId);
|
259
278
|
} else {
|
260
279
|
toDb = (await controller.getDatabasesByIds([parsedArgv.toDbId!]))[0];
|
261
280
|
}
|
@@ -293,14 +312,10 @@ async function main() {
|
|
293
312
|
|
294
313
|
await controller.transferData(transferOptions);
|
295
314
|
}
|
296
|
-
|
297
|
-
if (parsedArgv.sync) {
|
298
|
-
await controller.synchronizeConfigurations(options.databases);
|
299
|
-
}
|
300
315
|
}
|
301
316
|
}
|
302
317
|
|
303
318
|
main().catch((error) => {
|
304
319
|
console.error("An error occurred:", error);
|
305
320
|
process.exit(1);
|
306
|
-
});
|
321
|
+
});
|