@njdamstra/appwrite-utils-cli 1.10.0 → 1.11.0
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/dist/cli/commands/migrateCommands.d.ts +6 -0
- package/dist/cli/commands/migrateCommands.js +118 -0
- package/dist/collections/attributes.js +83 -0
- package/dist/collections/indexes.js +1 -1
- package/dist/collections/tableOperations.js +35 -0
- package/dist/interactiveCLI.js +7 -1
- package/dist/main.js +56 -0
- package/dist/migrations/appwriteToX.d.ts +96 -0
- package/dist/migrations/dataLoader.d.ts +194 -2
- package/dist/migrations/migrateStrings.d.ts +9 -0
- package/dist/migrations/migrateStrings.js +724 -0
- package/dist/migrations/migrateStringsTypes.d.ts +195 -0
- package/dist/migrations/migrateStringsTypes.js +117 -0
- package/dist/storage/schemas.d.ts +384 -0
- package/package.json +4 -4
- package/src/cli/commands/migrateCommands.ts +157 -0
- package/src/collections/attributes.ts +152 -0
- package/src/collections/indexes.ts +3 -3
- package/src/collections/tableOperations.ts +35 -0
- package/src/functions/methods.ts +2 -2
- package/src/interactiveCLI.ts +9 -3
- package/src/main.ts +69 -0
- package/src/migrations/migrateStrings.ts +1064 -0
- package/src/migrations/migrateStringsTypes.ts +158 -0
|
@@ -593,6 +593,74 @@ const createLegacyAttribute = async (
|
|
|
593
593
|
attribute.array || false
|
|
594
594
|
);
|
|
595
595
|
break;
|
|
596
|
+
case "varchar":
|
|
597
|
+
await db.createVarcharAttribute(
|
|
598
|
+
dbId,
|
|
599
|
+
collectionId,
|
|
600
|
+
attribute.key,
|
|
601
|
+
(attribute as any).size || 255,
|
|
602
|
+
attribute.required || false,
|
|
603
|
+
(attribute as any).xdefault !== undefined && !attribute.required
|
|
604
|
+
? (attribute as any).xdefault
|
|
605
|
+
: undefined,
|
|
606
|
+
attribute.array || false,
|
|
607
|
+
(attribute as any).encrypt
|
|
608
|
+
);
|
|
609
|
+
break;
|
|
610
|
+
case "text":
|
|
611
|
+
case "mediumtext":
|
|
612
|
+
case "longtext": {
|
|
613
|
+
const createFn = attribute.type === "text"
|
|
614
|
+
? db.createTextAttribute.bind(db)
|
|
615
|
+
: attribute.type === "mediumtext"
|
|
616
|
+
? db.createMediumtextAttribute.bind(db)
|
|
617
|
+
: db.createLongtextAttribute.bind(db);
|
|
618
|
+
await createFn(
|
|
619
|
+
dbId,
|
|
620
|
+
collectionId,
|
|
621
|
+
attribute.key,
|
|
622
|
+
attribute.required || false,
|
|
623
|
+
(attribute as any).xdefault !== undefined && !attribute.required
|
|
624
|
+
? (attribute as any).xdefault
|
|
625
|
+
: undefined,
|
|
626
|
+
attribute.array || false,
|
|
627
|
+
(attribute as any).encrypt
|
|
628
|
+
);
|
|
629
|
+
break;
|
|
630
|
+
}
|
|
631
|
+
case "point":
|
|
632
|
+
await db.createPointAttribute(
|
|
633
|
+
dbId,
|
|
634
|
+
collectionId,
|
|
635
|
+
attribute.key,
|
|
636
|
+
attribute.required || false,
|
|
637
|
+
(attribute as any).xdefault !== undefined && !attribute.required
|
|
638
|
+
? (attribute as any).xdefault
|
|
639
|
+
: undefined
|
|
640
|
+
);
|
|
641
|
+
break;
|
|
642
|
+
case "line":
|
|
643
|
+
await db.createLineAttribute(
|
|
644
|
+
dbId,
|
|
645
|
+
collectionId,
|
|
646
|
+
attribute.key,
|
|
647
|
+
attribute.required || false,
|
|
648
|
+
(attribute as any).xdefault !== undefined && !attribute.required
|
|
649
|
+
? (attribute as any).xdefault
|
|
650
|
+
: undefined
|
|
651
|
+
);
|
|
652
|
+
break;
|
|
653
|
+
case "polygon":
|
|
654
|
+
await db.createPolygonAttribute(
|
|
655
|
+
dbId,
|
|
656
|
+
collectionId,
|
|
657
|
+
attribute.key,
|
|
658
|
+
attribute.required || false,
|
|
659
|
+
(attribute as any).xdefault !== undefined && !attribute.required
|
|
660
|
+
? (attribute as any).xdefault
|
|
661
|
+
: undefined
|
|
662
|
+
);
|
|
663
|
+
break;
|
|
596
664
|
case "relationship":
|
|
597
665
|
await db.createRelationshipAttribute(
|
|
598
666
|
dbId,
|
|
@@ -615,6 +683,10 @@ const createLegacyAttribute = async (
|
|
|
615
683
|
type: (attribute as any).type,
|
|
616
684
|
supportedTypes: [
|
|
617
685
|
"string",
|
|
686
|
+
"varchar",
|
|
687
|
+
"text",
|
|
688
|
+
"mediumtext",
|
|
689
|
+
"longtext",
|
|
618
690
|
"integer",
|
|
619
691
|
"double",
|
|
620
692
|
"float",
|
|
@@ -624,6 +696,9 @@ const createLegacyAttribute = async (
|
|
|
624
696
|
"ip",
|
|
625
697
|
"url",
|
|
626
698
|
"enum",
|
|
699
|
+
"point",
|
|
700
|
+
"line",
|
|
701
|
+
"polygon",
|
|
627
702
|
"relationship",
|
|
628
703
|
],
|
|
629
704
|
operation: "createLegacyAttribute",
|
|
@@ -770,6 +845,70 @@ const updateLegacyAttribute = async (
|
|
|
770
845
|
: null
|
|
771
846
|
);
|
|
772
847
|
break;
|
|
848
|
+
case "varchar":
|
|
849
|
+
await db.updateVarcharAttribute(
|
|
850
|
+
dbId,
|
|
851
|
+
collectionId,
|
|
852
|
+
attribute.key,
|
|
853
|
+
attribute.required || false,
|
|
854
|
+
!attribute.required && (attribute as any).xdefault !== undefined
|
|
855
|
+
? (attribute as any).xdefault
|
|
856
|
+
: null,
|
|
857
|
+
(attribute as any).size
|
|
858
|
+
);
|
|
859
|
+
break;
|
|
860
|
+
case "text":
|
|
861
|
+
case "mediumtext":
|
|
862
|
+
case "longtext": {
|
|
863
|
+
const updateFn = attribute.type === "text"
|
|
864
|
+
? db.updateTextAttribute.bind(db)
|
|
865
|
+
: attribute.type === "mediumtext"
|
|
866
|
+
? db.updateMediumtextAttribute.bind(db)
|
|
867
|
+
: db.updateLongtextAttribute.bind(db);
|
|
868
|
+
await updateFn(
|
|
869
|
+
dbId,
|
|
870
|
+
collectionId,
|
|
871
|
+
attribute.key,
|
|
872
|
+
attribute.required || false,
|
|
873
|
+
!attribute.required && (attribute as any).xdefault !== undefined
|
|
874
|
+
? (attribute as any).xdefault
|
|
875
|
+
: null
|
|
876
|
+
);
|
|
877
|
+
break;
|
|
878
|
+
}
|
|
879
|
+
case "point":
|
|
880
|
+
await db.updatePointAttribute(
|
|
881
|
+
dbId,
|
|
882
|
+
collectionId,
|
|
883
|
+
attribute.key,
|
|
884
|
+
attribute.required || false,
|
|
885
|
+
!attribute.required && (attribute as any).xdefault !== undefined
|
|
886
|
+
? (attribute as any).xdefault
|
|
887
|
+
: null
|
|
888
|
+
);
|
|
889
|
+
break;
|
|
890
|
+
case "line":
|
|
891
|
+
await db.updateLineAttribute(
|
|
892
|
+
dbId,
|
|
893
|
+
collectionId,
|
|
894
|
+
attribute.key,
|
|
895
|
+
attribute.required || false,
|
|
896
|
+
!attribute.required && (attribute as any).xdefault !== undefined
|
|
897
|
+
? (attribute as any).xdefault
|
|
898
|
+
: null
|
|
899
|
+
);
|
|
900
|
+
break;
|
|
901
|
+
case "polygon":
|
|
902
|
+
await db.updatePolygonAttribute(
|
|
903
|
+
dbId,
|
|
904
|
+
collectionId,
|
|
905
|
+
attribute.key,
|
|
906
|
+
attribute.required || false,
|
|
907
|
+
!attribute.required && (attribute as any).xdefault !== undefined
|
|
908
|
+
? (attribute as any).xdefault
|
|
909
|
+
: null
|
|
910
|
+
);
|
|
911
|
+
break;
|
|
773
912
|
case "relationship":
|
|
774
913
|
await db.updateRelationshipAttribute(
|
|
775
914
|
dbId,
|
|
@@ -1048,6 +1187,14 @@ const getComparableFields = (type: string): string[] => {
|
|
|
1048
1187
|
case "string":
|
|
1049
1188
|
return [...baseFields, "size", "encrypt"];
|
|
1050
1189
|
|
|
1190
|
+
case "varchar":
|
|
1191
|
+
return [...baseFields, "size", "encrypt"];
|
|
1192
|
+
|
|
1193
|
+
case "text":
|
|
1194
|
+
case "mediumtext":
|
|
1195
|
+
case "longtext":
|
|
1196
|
+
return [...baseFields, "encrypt"];
|
|
1197
|
+
|
|
1051
1198
|
case "integer":
|
|
1052
1199
|
case "double":
|
|
1053
1200
|
case "float":
|
|
@@ -1056,6 +1203,11 @@ const getComparableFields = (type: string): string[] => {
|
|
|
1056
1203
|
case "enum":
|
|
1057
1204
|
return [...baseFields, "elements"];
|
|
1058
1205
|
|
|
1206
|
+
case "point":
|
|
1207
|
+
case "line":
|
|
1208
|
+
case "polygon":
|
|
1209
|
+
return baseFields;
|
|
1210
|
+
|
|
1059
1211
|
case "relationship":
|
|
1060
1212
|
return [
|
|
1061
1213
|
...baseFields,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { indexSchema, type Index } from "@njdamstra/appwrite-utils";
|
|
2
|
-
import { Databases, IndexType, Query, type Models } from "node-appwrite";
|
|
2
|
+
import { Databases, IndexType, OrderBy, Query, type Models } from "node-appwrite";
|
|
3
3
|
import type { DatabaseAdapter } from "@njdamstra/appwrite-utils-helpers";
|
|
4
4
|
import { delay, tryAwaitWithRetry, calculateExponentialBackoff, isLegacyDatabases, MessageFormatter } from "@njdamstra/appwrite-utils-helpers";
|
|
5
5
|
|
|
@@ -327,10 +327,10 @@ export const createOrUpdateIndex = async (
|
|
|
327
327
|
index.key,
|
|
328
328
|
index.type as IndexType,
|
|
329
329
|
index.attributes,
|
|
330
|
-
orders
|
|
330
|
+
orders as OrderBy[]
|
|
331
331
|
);
|
|
332
332
|
}
|
|
333
|
-
|
|
333
|
+
|
|
334
334
|
return newIndex;
|
|
335
335
|
};
|
|
336
336
|
|
|
@@ -32,6 +32,10 @@ interface ColumnOperationPlan {
|
|
|
32
32
|
// Property configuration for different column types
|
|
33
33
|
const MUTABLE_PROPERTIES = {
|
|
34
34
|
string: ["required", "default", "size", "array"],
|
|
35
|
+
varchar: ["required", "default", "size", "array"],
|
|
36
|
+
text: ["required", "default", "array"],
|
|
37
|
+
mediumtext: ["required", "default", "array"],
|
|
38
|
+
longtext: ["required", "default", "array"],
|
|
35
39
|
integer: ["required", "default", "min", "max", "array"],
|
|
36
40
|
float: ["required", "default", "min", "max", "array"],
|
|
37
41
|
double: ["required", "default", "min", "max", "array"],
|
|
@@ -41,11 +45,18 @@ const MUTABLE_PROPERTIES = {
|
|
|
41
45
|
ip: ["required", "default", "array"],
|
|
42
46
|
url: ["required", "default", "array"],
|
|
43
47
|
enum: ["required", "default", "elements", "array"],
|
|
48
|
+
point: ["required", "default"],
|
|
49
|
+
line: ["required", "default"],
|
|
50
|
+
polygon: ["required", "default"],
|
|
44
51
|
relationship: ["required", "default"],
|
|
45
52
|
} as const;
|
|
46
53
|
|
|
47
54
|
const IMMUTABLE_PROPERTIES = {
|
|
48
55
|
string: ["encrypt", "key"],
|
|
56
|
+
varchar: ["encrypt", "key"],
|
|
57
|
+
text: ["encrypt", "key"],
|
|
58
|
+
mediumtext: ["encrypt", "key"],
|
|
59
|
+
longtext: ["encrypt", "key"],
|
|
49
60
|
integer: ["encrypt", "key"],
|
|
50
61
|
float: ["encrypt", "key"],
|
|
51
62
|
double: ["encrypt", "key"],
|
|
@@ -55,11 +66,18 @@ const IMMUTABLE_PROPERTIES = {
|
|
|
55
66
|
ip: ["key"],
|
|
56
67
|
url: ["key"],
|
|
57
68
|
enum: ["key"],
|
|
69
|
+
point: ["key"],
|
|
70
|
+
line: ["key"],
|
|
71
|
+
polygon: ["key"],
|
|
58
72
|
relationship: ["key", "relatedCollection", "relationType", "twoWay", "twoWayKey", "onDelete"],
|
|
59
73
|
} as const;
|
|
60
74
|
|
|
61
75
|
const TYPE_CHANGE_REQUIRES_RECREATE = [
|
|
62
76
|
"string",
|
|
77
|
+
"varchar",
|
|
78
|
+
"text",
|
|
79
|
+
"mediumtext",
|
|
80
|
+
"longtext",
|
|
63
81
|
"integer",
|
|
64
82
|
"float",
|
|
65
83
|
"double",
|
|
@@ -69,6 +87,9 @@ const TYPE_CHANGE_REQUIRES_RECREATE = [
|
|
|
69
87
|
"ip",
|
|
70
88
|
"url",
|
|
71
89
|
"enum",
|
|
90
|
+
"point",
|
|
91
|
+
"line",
|
|
92
|
+
"polygon",
|
|
72
93
|
"relationship",
|
|
73
94
|
];
|
|
74
95
|
|
|
@@ -117,6 +138,13 @@ export function normalizeAttributeToComparable(attr: Attribute): ComparableColum
|
|
|
117
138
|
base.size = (attr as any).size ?? 255;
|
|
118
139
|
base.encrypt = !!((attr as any).encrypt);
|
|
119
140
|
}
|
|
141
|
+
if (t === 'varchar') {
|
|
142
|
+
base.size = (attr as any).size ?? 255;
|
|
143
|
+
base.encrypt = !!((attr as any).encrypt);
|
|
144
|
+
}
|
|
145
|
+
if (t === 'text' || t === 'mediumtext' || t === 'longtext') {
|
|
146
|
+
base.encrypt = !!((attr as any).encrypt);
|
|
147
|
+
}
|
|
120
148
|
if (t === 'integer' || t === 'float' || t === 'double') {
|
|
121
149
|
const min = toNumber((attr as any).min);
|
|
122
150
|
const max = toNumber((attr as any).max);
|
|
@@ -162,6 +190,13 @@ export function normalizeColumnToComparable(col: any): ComparableColumn {
|
|
|
162
190
|
base.size = typeof col?.size === 'number' ? col.size : undefined;
|
|
163
191
|
base.encrypt = !!col?.encrypt;
|
|
164
192
|
}
|
|
193
|
+
if (t === 'varchar') {
|
|
194
|
+
base.size = typeof col?.size === 'number' ? col.size : undefined;
|
|
195
|
+
base.encrypt = !!col?.encrypt;
|
|
196
|
+
}
|
|
197
|
+
if (t === 'text' || t === 'mediumtext' || t === 'longtext') {
|
|
198
|
+
base.encrypt = !!col?.encrypt;
|
|
199
|
+
}
|
|
165
200
|
if (t === 'integer' || t === 'float' || t === 'double') {
|
|
166
201
|
// Preserve raw min/max without forcing extremes; compare with Decimal in shallowEqual
|
|
167
202
|
const rawMin = (col as any)?.min;
|
package/src/functions/methods.ts
CHANGED
|
@@ -137,7 +137,7 @@ export const createFunction = async (
|
|
|
137
137
|
functionConfig.logging,
|
|
138
138
|
functionConfig.entrypoint,
|
|
139
139
|
functionConfig.commands,
|
|
140
|
-
functionConfig.scopes,
|
|
140
|
+
functionConfig.scopes as any[],
|
|
141
141
|
functionConfig.installationId,
|
|
142
142
|
functionConfig.providerRepositoryId,
|
|
143
143
|
functionConfig.providerBranch,
|
|
@@ -217,7 +217,7 @@ export const updateFunction = async (
|
|
|
217
217
|
functionConfig.logging,
|
|
218
218
|
functionConfig.entrypoint,
|
|
219
219
|
functionConfig.commands,
|
|
220
|
-
functionConfig.scopes,
|
|
220
|
+
functionConfig.scopes as any[],
|
|
221
221
|
functionConfig.installationId,
|
|
222
222
|
functionConfig.providerRepositoryId,
|
|
223
223
|
functionConfig.providerBranch,
|
package/src/interactiveCLI.ts
CHANGED
|
@@ -46,6 +46,7 @@ import { storageCommands } from "./cli/commands/storageCommands.js";
|
|
|
46
46
|
import { transferCommands } from "./cli/commands/transferCommands.js";
|
|
47
47
|
import { schemaCommands } from "./cli/commands/schemaCommands.js";
|
|
48
48
|
import { importFileCommands } from "./cli/commands/importFileCommands.js";
|
|
49
|
+
import { migrateCommands } from "./cli/commands/migrateCommands.js";
|
|
49
50
|
|
|
50
51
|
enum CHOICES {
|
|
51
52
|
MIGRATE_CONFIG = "🔄 Migrate TypeScript config to YAML (.appwrite structure)",
|
|
@@ -71,6 +72,7 @@ enum CHOICES {
|
|
|
71
72
|
RELOAD_CONFIG = "🔄 Reload configuration files",
|
|
72
73
|
UPDATE_FUNCTION_SPEC = "⚙️ Update function specifications",
|
|
73
74
|
MANAGE_BUCKETS = "🪣 Manage storage buckets",
|
|
75
|
+
MIGRATE_STRINGS = "🔄 Migrate string attributes to varchar/text types",
|
|
74
76
|
EXIT = "👋 Exit",
|
|
75
77
|
}
|
|
76
78
|
|
|
@@ -92,7 +94,7 @@ export class InteractiveCLI {
|
|
|
92
94
|
async run(): Promise<void> {
|
|
93
95
|
MessageFormatter.banner(
|
|
94
96
|
"Appwrite Utils CLI",
|
|
95
|
-
"Welcome to Appwrite Utils CLI Tool
|
|
97
|
+
"Welcome to Appwrite Utils CLI Tool"
|
|
96
98
|
);
|
|
97
99
|
MessageFormatter.info(
|
|
98
100
|
"For more information, visit https://github.com/njdamstra/AppwriteUtils"
|
|
@@ -203,6 +205,10 @@ export class InteractiveCLI {
|
|
|
203
205
|
case CHOICES.MANAGE_BUCKETS:
|
|
204
206
|
await this.manageBuckets();
|
|
205
207
|
break;
|
|
208
|
+
case CHOICES.MIGRATE_STRINGS:
|
|
209
|
+
await this.initControllerIfNeeded();
|
|
210
|
+
await migrateCommands.migrateStrings(this);
|
|
211
|
+
break;
|
|
206
212
|
case CHOICES.EXIT:
|
|
207
213
|
MessageFormatter.success("Goodbye!");
|
|
208
214
|
process.exit(0);
|
|
@@ -1069,7 +1075,7 @@ export class InteractiveCLI {
|
|
|
1069
1075
|
compression: bucketCompressionType as Compression,
|
|
1070
1076
|
encryption: bucketEncryption,
|
|
1071
1077
|
antivirus: bucketAntivirus,
|
|
1072
|
-
},
|
|
1078
|
+
} as any,
|
|
1073
1079
|
bucketId.length > 0 ? bucketId : ulid()
|
|
1074
1080
|
);
|
|
1075
1081
|
}
|
|
@@ -1111,7 +1117,7 @@ export class InteractiveCLI {
|
|
|
1111
1117
|
name: db.name,
|
|
1112
1118
|
enabled: true,
|
|
1113
1119
|
type: "tablesdb" as DatabaseType,
|
|
1114
|
-
}));
|
|
1120
|
+
} as Models.Database));
|
|
1115
1121
|
}
|
|
1116
1122
|
|
|
1117
1123
|
|
package/src/main.ts
CHANGED
|
@@ -82,6 +82,12 @@ interface CliOptions {
|
|
|
82
82
|
importFile?: string;
|
|
83
83
|
targetDb?: string;
|
|
84
84
|
targetTable?: string;
|
|
85
|
+
// String attribute migration
|
|
86
|
+
migrateStringsAnalyze?: boolean;
|
|
87
|
+
migrateStringsExecute?: string;
|
|
88
|
+
migrateStringsOutput?: string;
|
|
89
|
+
migrateStringsKeepBackups?: boolean;
|
|
90
|
+
migrateStringsDryRun?: boolean;
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
type ParsedArgv = ArgumentsCamelCase<CliOptions>;
|
|
@@ -621,6 +627,32 @@ const argv = yargs(hideBin(process.argv))
|
|
|
621
627
|
type: "string",
|
|
622
628
|
description: "Target table ID for --importFile (prompted if omitted)",
|
|
623
629
|
})
|
|
630
|
+
.option("migrateStringsAnalyze", {
|
|
631
|
+
alias: ["migrate-strings-analyze"],
|
|
632
|
+
type: "boolean",
|
|
633
|
+
description: "Analyze local configs and generate a string-to-varchar/text migration plan (YAML)",
|
|
634
|
+
})
|
|
635
|
+
.option("migrateStringsExecute", {
|
|
636
|
+
alias: ["migrate-strings-execute"],
|
|
637
|
+
type: "string",
|
|
638
|
+
description: "Execute a string migration plan from the given YAML path",
|
|
639
|
+
})
|
|
640
|
+
.option("migrateStringsOutput", {
|
|
641
|
+
alias: ["migrate-strings-output"],
|
|
642
|
+
type: "string",
|
|
643
|
+
description: "Output path for the migration plan (default: ./migrate-strings-plan.yaml)",
|
|
644
|
+
})
|
|
645
|
+
.option("migrateStringsKeepBackups", {
|
|
646
|
+
alias: ["migrate-strings-keep-backups"],
|
|
647
|
+
type: "boolean",
|
|
648
|
+
default: true,
|
|
649
|
+
description: "Keep backup attributes after migration (default: true)",
|
|
650
|
+
})
|
|
651
|
+
.option("migrateStringsDryRun", {
|
|
652
|
+
alias: ["migrate-strings-dry-run"],
|
|
653
|
+
type: "boolean",
|
|
654
|
+
description: "Dry run — show what would happen without making changes",
|
|
655
|
+
})
|
|
624
656
|
.parse() as ParsedArgv;
|
|
625
657
|
|
|
626
658
|
async function main() {
|
|
@@ -842,6 +874,43 @@ async function main() {
|
|
|
842
874
|
return;
|
|
843
875
|
}
|
|
844
876
|
|
|
877
|
+
// String attribute migration (analyze or execute)
|
|
878
|
+
if (argv.migrateStringsAnalyze || argv.migrateStringsExecute) {
|
|
879
|
+
const { analyzeStringAttributes, executeMigrationPlan } = await import(
|
|
880
|
+
"./migrations/migrateStrings.js"
|
|
881
|
+
);
|
|
882
|
+
|
|
883
|
+
if (argv.migrateStringsAnalyze) {
|
|
884
|
+
if (!controller.config) {
|
|
885
|
+
MessageFormatter.error("No Appwrite configuration found", undefined, {
|
|
886
|
+
prefix: "Migration",
|
|
887
|
+
});
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
analyzeStringAttributes(controller.config, {
|
|
891
|
+
outputPath: argv.migrateStringsOutput,
|
|
892
|
+
});
|
|
893
|
+
} else if (argv.migrateStringsExecute) {
|
|
894
|
+
if (!controller.adapter) {
|
|
895
|
+
MessageFormatter.error(
|
|
896
|
+
"No database adapter available. Ensure config has valid credentials.",
|
|
897
|
+
undefined,
|
|
898
|
+
{ prefix: "Migration" }
|
|
899
|
+
);
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
const results = await executeMigrationPlan(controller.adapter, {
|
|
903
|
+
planPath: argv.migrateStringsExecute,
|
|
904
|
+
keepBackups: argv.migrateStringsKeepBackups ?? true,
|
|
905
|
+
dryRun: argv.migrateStringsDryRun ?? false,
|
|
906
|
+
});
|
|
907
|
+
if (results.failed > 0) {
|
|
908
|
+
process.exit(1);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
|
|
845
914
|
// List backups if requested
|
|
846
915
|
if (parsedArgv.listBackups) {
|
|
847
916
|
const { AdapterFactory } = await import("@njdamstra/appwrite-utils-helpers");
|