@njdamstra/appwrite-utils-cli 1.10.1 → 1.11.1
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 +109 -0
- package/dist/interactiveCLI.js +6 -0
- package/dist/main.js +54 -0
- package/dist/migrations/migrateStrings.d.ts +9 -0
- package/dist/migrations/migrateStrings.js +735 -0
- package/dist/migrations/migrateStringsTypes.d.ts +195 -0
- package/dist/migrations/migrateStringsTypes.js +117 -0
- package/package.json +1 -1
- package/src/cli/commands/migrateCommands.ts +143 -0
- package/src/interactiveCLI.ts +6 -0
- package/src/main.ts +71 -0
- package/src/migrations/migrateStrings.ts +1084 -0
- package/src/migrations/migrateStringsTypes.ts +158 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { MessageFormatter } from "@njdamstra/appwrite-utils-helpers";
|
|
4
|
+
import { analyzeStringAttributes, executeMigrationPlan, } from "../../migrations/migrateStrings.js";
|
|
5
|
+
export const migrateCommands = {
|
|
6
|
+
async migrateStrings(cli) {
|
|
7
|
+
const { phase } = await inquirer.prompt([
|
|
8
|
+
{
|
|
9
|
+
type: "list",
|
|
10
|
+
name: "phase",
|
|
11
|
+
message: "String attribute migration:",
|
|
12
|
+
choices: [
|
|
13
|
+
{
|
|
14
|
+
name: "Analyze — scan Appwrite server, generate migration plan (YAML)",
|
|
15
|
+
value: "analyze",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: "Execute — run a migration plan against Appwrite server",
|
|
19
|
+
value: "execute",
|
|
20
|
+
},
|
|
21
|
+
{ name: "Back", value: "back" },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
]);
|
|
25
|
+
if (phase === "back")
|
|
26
|
+
return;
|
|
27
|
+
if (phase === "analyze") {
|
|
28
|
+
await migrateCommands.analyzePhase(cli);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
await migrateCommands.executePhase(cli);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
async analyzePhase(cli) {
|
|
35
|
+
const controller = cli.controller;
|
|
36
|
+
if (!controller?.adapter) {
|
|
37
|
+
MessageFormatter.error("No database adapter available. Ensure a server connection is established.", undefined, { prefix: "Analyze" });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Prompt for output path
|
|
41
|
+
const { outputPath } = await inquirer.prompt([
|
|
42
|
+
{
|
|
43
|
+
type: "input",
|
|
44
|
+
name: "outputPath",
|
|
45
|
+
message: "Output path for migration plan:",
|
|
46
|
+
default: path.join(process.cwd(), "migrate-strings-plan.yaml"),
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
const options = { outputPath };
|
|
50
|
+
try {
|
|
51
|
+
await analyzeStringAttributes(controller.adapter, controller.config, options);
|
|
52
|
+
MessageFormatter.success("Analysis complete. Review the YAML plan, edit targetType/action as needed, then run Execute.", { prefix: "Analyze" });
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
MessageFormatter.error(`Analysis failed: ${err.message}`, undefined, { prefix: "Analyze" });
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
async executePhase(cli) {
|
|
59
|
+
const controller = cli.controller;
|
|
60
|
+
if (!controller?.adapter) {
|
|
61
|
+
MessageFormatter.error("No database adapter available. Ensure a server connection is established.", undefined, { prefix: "Execute" });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Prompt for plan path
|
|
65
|
+
const { planPath } = await inquirer.prompt([
|
|
66
|
+
{
|
|
67
|
+
type: "input",
|
|
68
|
+
name: "planPath",
|
|
69
|
+
message: "Path to migration plan YAML:",
|
|
70
|
+
default: path.join(process.cwd(), "migrate-strings-plan.yaml"),
|
|
71
|
+
},
|
|
72
|
+
]);
|
|
73
|
+
const { keepBackups } = await inquirer.prompt([
|
|
74
|
+
{
|
|
75
|
+
type: "confirm",
|
|
76
|
+
name: "keepBackups",
|
|
77
|
+
message: "Keep backup attributes after migration? (safer, uses more attribute slots)",
|
|
78
|
+
default: true,
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
const { dryRun } = await inquirer.prompt([
|
|
82
|
+
{
|
|
83
|
+
type: "confirm",
|
|
84
|
+
name: "dryRun",
|
|
85
|
+
message: "Dry run? (no actual changes)",
|
|
86
|
+
default: false,
|
|
87
|
+
},
|
|
88
|
+
]);
|
|
89
|
+
const options = {
|
|
90
|
+
planPath,
|
|
91
|
+
keepBackups,
|
|
92
|
+
dryRun,
|
|
93
|
+
};
|
|
94
|
+
try {
|
|
95
|
+
const results = await executeMigrationPlan(controller.adapter, options);
|
|
96
|
+
if (results.failed > 0) {
|
|
97
|
+
MessageFormatter.warning(`Migration completed with ${results.failed} failure(s). Check checkpoint file to resume.`, { prefix: "Execute" });
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
MessageFormatter.success("Migration completed successfully.", {
|
|
101
|
+
prefix: "Execute",
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
MessageFormatter.error(`Execution failed: ${err.message}`, undefined, { prefix: "Execute" });
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
};
|
package/dist/interactiveCLI.js
CHANGED
|
@@ -22,6 +22,7 @@ import { storageCommands } from "./cli/commands/storageCommands.js";
|
|
|
22
22
|
import { transferCommands } from "./cli/commands/transferCommands.js";
|
|
23
23
|
import { schemaCommands } from "./cli/commands/schemaCommands.js";
|
|
24
24
|
import { importFileCommands } from "./cli/commands/importFileCommands.js";
|
|
25
|
+
import { migrateCommands } from "./cli/commands/migrateCommands.js";
|
|
25
26
|
var CHOICES;
|
|
26
27
|
(function (CHOICES) {
|
|
27
28
|
CHOICES["MIGRATE_CONFIG"] = "\uD83D\uDD04 Migrate TypeScript config to YAML (.appwrite structure)";
|
|
@@ -47,6 +48,7 @@ var CHOICES;
|
|
|
47
48
|
CHOICES["RELOAD_CONFIG"] = "\uD83D\uDD04 Reload configuration files";
|
|
48
49
|
CHOICES["UPDATE_FUNCTION_SPEC"] = "\u2699\uFE0F Update function specifications";
|
|
49
50
|
CHOICES["MANAGE_BUCKETS"] = "\uD83E\uDEA3 Manage storage buckets";
|
|
51
|
+
CHOICES["MIGRATE_STRINGS"] = "\uD83D\uDD04 Migrate string attributes to varchar/text types";
|
|
50
52
|
CHOICES["EXIT"] = "\uD83D\uDC4B Exit";
|
|
51
53
|
})(CHOICES || (CHOICES = {}));
|
|
52
54
|
export class InteractiveCLI {
|
|
@@ -165,6 +167,10 @@ export class InteractiveCLI {
|
|
|
165
167
|
case CHOICES.MANAGE_BUCKETS:
|
|
166
168
|
await this.manageBuckets();
|
|
167
169
|
break;
|
|
170
|
+
case CHOICES.MIGRATE_STRINGS:
|
|
171
|
+
await this.initControllerIfNeeded();
|
|
172
|
+
await migrateCommands.migrateStrings(this);
|
|
173
|
+
break;
|
|
168
174
|
case CHOICES.EXIT:
|
|
169
175
|
MessageFormatter.success("Goodbye!");
|
|
170
176
|
process.exit(0);
|
package/dist/main.js
CHANGED
|
@@ -454,6 +454,32 @@ const argv = yargs(hideBin(process.argv))
|
|
|
454
454
|
alias: ["target-table"],
|
|
455
455
|
type: "string",
|
|
456
456
|
description: "Target table ID for --importFile (prompted if omitted)",
|
|
457
|
+
})
|
|
458
|
+
.option("migrateStringsAnalyze", {
|
|
459
|
+
alias: ["migrate-strings-analyze"],
|
|
460
|
+
type: "boolean",
|
|
461
|
+
description: "Analyze local configs and generate a string-to-varchar/text migration plan (YAML)",
|
|
462
|
+
})
|
|
463
|
+
.option("migrateStringsExecute", {
|
|
464
|
+
alias: ["migrate-strings-execute"],
|
|
465
|
+
type: "string",
|
|
466
|
+
description: "Execute a string migration plan from the given YAML path",
|
|
467
|
+
})
|
|
468
|
+
.option("migrateStringsOutput", {
|
|
469
|
+
alias: ["migrate-strings-output"],
|
|
470
|
+
type: "string",
|
|
471
|
+
description: "Output path for the migration plan (default: ./migrate-strings-plan.yaml)",
|
|
472
|
+
})
|
|
473
|
+
.option("migrateStringsKeepBackups", {
|
|
474
|
+
alias: ["migrate-strings-keep-backups"],
|
|
475
|
+
type: "boolean",
|
|
476
|
+
default: true,
|
|
477
|
+
description: "Keep backup attributes after migration (default: true)",
|
|
478
|
+
})
|
|
479
|
+
.option("migrateStringsDryRun", {
|
|
480
|
+
alias: ["migrate-strings-dry-run"],
|
|
481
|
+
type: "boolean",
|
|
482
|
+
description: "Dry run — show what would happen without making changes",
|
|
457
483
|
})
|
|
458
484
|
.parse();
|
|
459
485
|
async function main() {
|
|
@@ -618,6 +644,34 @@ async function main() {
|
|
|
618
644
|
}
|
|
619
645
|
return;
|
|
620
646
|
}
|
|
647
|
+
// String attribute migration (analyze or execute)
|
|
648
|
+
if (argv.migrateStringsAnalyze || argv.migrateStringsExecute) {
|
|
649
|
+
const { analyzeStringAttributes, executeMigrationPlan } = await import("./migrations/migrateStrings.js");
|
|
650
|
+
if (argv.migrateStringsAnalyze) {
|
|
651
|
+
if (!controller.adapter) {
|
|
652
|
+
MessageFormatter.error("No database adapter available. Ensure config has valid credentials.", undefined, { prefix: "Migration" });
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
await analyzeStringAttributes(controller.adapter, controller.config, {
|
|
656
|
+
outputPath: argv.migrateStringsOutput,
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
else if (argv.migrateStringsExecute) {
|
|
660
|
+
if (!controller.adapter) {
|
|
661
|
+
MessageFormatter.error("No database adapter available. Ensure config has valid credentials.", undefined, { prefix: "Migration" });
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
const results = await executeMigrationPlan(controller.adapter, {
|
|
665
|
+
planPath: argv.migrateStringsExecute,
|
|
666
|
+
keepBackups: argv.migrateStringsKeepBackups ?? true,
|
|
667
|
+
dryRun: argv.migrateStringsDryRun ?? false,
|
|
668
|
+
});
|
|
669
|
+
if (results.failed > 0) {
|
|
670
|
+
process.exit(1);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
621
675
|
// List backups if requested
|
|
622
676
|
if (parsedArgv.listBackups) {
|
|
623
677
|
const { AdapterFactory } = await import("@njdamstra/appwrite-utils-helpers");
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type DatabaseAdapter } from "@njdamstra/appwrite-utils-helpers";
|
|
2
|
+
import type { AppwriteConfig } from "@njdamstra/appwrite-utils";
|
|
3
|
+
import { type MigrationPlan, type AnalyzeOptions, type ExecuteOptions } from "./migrateStringsTypes.js";
|
|
4
|
+
export declare function analyzeStringAttributes(adapter: DatabaseAdapter, config: AppwriteConfig, options?: AnalyzeOptions): Promise<MigrationPlan>;
|
|
5
|
+
export declare function executeMigrationPlan(adapter: DatabaseAdapter, options: ExecuteOptions): Promise<{
|
|
6
|
+
succeeded: number;
|
|
7
|
+
failed: number;
|
|
8
|
+
skipped: number;
|
|
9
|
+
}>;
|