@njdamstra/appwrite-utils-cli 1.11.1 → 1.11.2

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.
@@ -37,6 +37,30 @@ export const migrateCommands = {
37
37
  MessageFormatter.error("No database adapter available. Ensure a server connection is established.", undefined, { prefix: "Analyze" });
38
38
  return;
39
39
  }
40
+ // Prompt for database selection
41
+ const allDatabases = controller.config.databases || [];
42
+ let databaseIds;
43
+ if (allDatabases.length > 1) {
44
+ const { selectedDbs } = await inquirer.prompt([
45
+ {
46
+ type: "checkbox",
47
+ name: "selectedDbs",
48
+ message: "Select databases to include in the analysis:",
49
+ choices: allDatabases.map((db) => ({
50
+ name: `${db.name} (${db.$id})`,
51
+ value: db.$id,
52
+ checked: true,
53
+ })),
54
+ },
55
+ ]);
56
+ if (selectedDbs.length === 0) {
57
+ MessageFormatter.warning("No databases selected. Aborting.", { prefix: "Analyze" });
58
+ return;
59
+ }
60
+ if (selectedDbs.length < allDatabases.length) {
61
+ databaseIds = selectedDbs;
62
+ }
63
+ }
40
64
  // Prompt for output path
41
65
  const { outputPath } = await inquirer.prompt([
42
66
  {
@@ -46,7 +70,7 @@ export const migrateCommands = {
46
70
  default: path.join(process.cwd(), "migrate-strings-plan.yaml"),
47
71
  },
48
72
  ]);
49
- const options = { outputPath };
73
+ const options = { outputPath, databaseIds };
50
74
  try {
51
75
  await analyzeStringAttributes(controller.adapter, controller.config, options);
52
76
  MessageFormatter.success("Analysis complete. Review the YAML plan, edit targetType/action as needed, then run Execute.", { prefix: "Analyze" });
package/dist/main.js CHANGED
@@ -469,6 +469,11 @@ const argv = yargs(hideBin(process.argv))
469
469
  alias: ["migrate-strings-output"],
470
470
  type: "string",
471
471
  description: "Output path for the migration plan (default: ./migrate-strings-plan.yaml)",
472
+ })
473
+ .option("migrateStringsDbIds", {
474
+ alias: ["migrate-strings-db-ids"],
475
+ type: "string",
476
+ description: "Comma-separated database IDs to include in analysis (default: all)",
472
477
  })
473
478
  .option("migrateStringsKeepBackups", {
474
479
  alias: ["migrate-strings-keep-backups"],
@@ -652,8 +657,12 @@ async function main() {
652
657
  MessageFormatter.error("No database adapter available. Ensure config has valid credentials.", undefined, { prefix: "Migration" });
653
658
  return;
654
659
  }
660
+ const databaseIds = argv.migrateStringsDbIds
661
+ ? argv.migrateStringsDbIds.split(",").map((s) => s.trim()).filter(Boolean)
662
+ : undefined;
655
663
  await analyzeStringAttributes(controller.adapter, controller.config, {
656
664
  outputPath: argv.migrateStringsOutput,
665
+ databaseIds,
657
666
  });
658
667
  }
659
668
  else if (argv.migrateStringsExecute) {
@@ -11,7 +11,11 @@ import { MigrationPlanSchema, MigrationCheckpointSchema, suggestTargetType, gene
11
11
  // Phase 1: Analyze — queries Appwrite server for real state
12
12
  // ────────────────────────────────────────────────────────
13
13
  export async function analyzeStringAttributes(adapter, config, options = {}) {
14
- const databases = config.databases || [];
14
+ let databasesToScan = config.databases || [];
15
+ if (options.databaseIds?.length) {
16
+ databasesToScan = databasesToScan.filter(db => options.databaseIds.includes(db.$id));
17
+ }
18
+ const databases = databasesToScan;
15
19
  if (databases.length === 0) {
16
20
  MessageFormatter.warning("No databases configured. Nothing to analyze.", {
17
21
  prefix: "Analyze",
@@ -182,6 +182,7 @@ export type MigrationCheckpoint = z.infer<typeof MigrationCheckpointSchema>;
182
182
  export interface AnalyzeOptions {
183
183
  outputPath?: string;
184
184
  verbose?: boolean;
185
+ databaseIds?: string[];
185
186
  }
186
187
  export interface ExecuteOptions {
187
188
  planPath: string;
@@ -97,16 +97,17 @@ export function suggestTargetType(size, hasIndex) {
97
97
  }
98
98
  // ── Helper: generate backup key with length limits ──
99
99
  const MAX_KEY_LENGTH = 36;
100
- const BACKUP_PREFIX = "_mig_";
100
+ const BACKUP_PREFIX = "mig_";
101
101
  export function generateBackupKey(originalKey) {
102
102
  const candidate = `${BACKUP_PREFIX}${originalKey}`;
103
103
  if (candidate.length <= MAX_KEY_LENGTH) {
104
104
  return candidate;
105
105
  }
106
- // Truncate + 4-char hash for uniqueness
106
+ // Truncate + 4-char hash for uniqueness: m_ + orig + _ + hash(4)
107
107
  const hash = simpleHash(originalKey);
108
- const maxOrigLen = MAX_KEY_LENGTH - BACKUP_PREFIX.length - 1 - 4; // _mig_ + _ + hash4
109
- return `_m_${originalKey.slice(0, maxOrigLen)}_${hash}`;
108
+ const TRUNC_PREFIX = "m_";
109
+ const maxOrigLen = MAX_KEY_LENGTH - TRUNC_PREFIX.length - 1 - 4;
110
+ return `${TRUNC_PREFIX}${originalKey.slice(0, maxOrigLen)}_${hash}`;
110
111
  }
111
112
  function simpleHash(str) {
112
113
  let h = 0;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@njdamstra/appwrite-utils-cli",
3
3
  "description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
4
- "version": "1.11.1",
4
+ "version": "1.11.2",
5
5
  "main": "dist/main.js",
6
6
  "type": "module",
7
7
  "repository": {
@@ -48,6 +48,31 @@ export const migrateCommands = {
48
48
  return;
49
49
  }
50
50
 
51
+ // Prompt for database selection
52
+ const allDatabases = controller.config.databases || [];
53
+ let databaseIds: string[] | undefined;
54
+ if (allDatabases.length > 1) {
55
+ const { selectedDbs } = await inquirer.prompt([
56
+ {
57
+ type: "checkbox",
58
+ name: "selectedDbs",
59
+ message: "Select databases to include in the analysis:",
60
+ choices: allDatabases.map((db: any) => ({
61
+ name: `${db.name} (${db.$id})`,
62
+ value: db.$id,
63
+ checked: true,
64
+ })),
65
+ },
66
+ ]);
67
+ if (selectedDbs.length === 0) {
68
+ MessageFormatter.warning("No databases selected. Aborting.", { prefix: "Analyze" });
69
+ return;
70
+ }
71
+ if (selectedDbs.length < allDatabases.length) {
72
+ databaseIds = selectedDbs;
73
+ }
74
+ }
75
+
51
76
  // Prompt for output path
52
77
  const { outputPath } = await inquirer.prompt([
53
78
  {
@@ -58,7 +83,7 @@ export const migrateCommands = {
58
83
  },
59
84
  ]);
60
85
 
61
- const options: AnalyzeOptions = { outputPath };
86
+ const options: AnalyzeOptions = { outputPath, databaseIds };
62
87
 
63
88
  try {
64
89
  await analyzeStringAttributes(controller.adapter, controller.config, options);
package/src/main.ts CHANGED
@@ -86,6 +86,7 @@ interface CliOptions {
86
86
  migrateStringsAnalyze?: boolean;
87
87
  migrateStringsExecute?: string;
88
88
  migrateStringsOutput?: string;
89
+ migrateStringsDbIds?: string;
89
90
  migrateStringsKeepBackups?: boolean;
90
91
  migrateStringsDryRun?: boolean;
91
92
  }
@@ -642,6 +643,11 @@ const argv = yargs(hideBin(process.argv))
642
643
  type: "string",
643
644
  description: "Output path for the migration plan (default: ./migrate-strings-plan.yaml)",
644
645
  })
646
+ .option("migrateStringsDbIds", {
647
+ alias: ["migrate-strings-db-ids"],
648
+ type: "string",
649
+ description: "Comma-separated database IDs to include in analysis (default: all)",
650
+ })
645
651
  .option("migrateStringsKeepBackups", {
646
652
  alias: ["migrate-strings-keep-backups"],
647
653
  type: "boolean",
@@ -889,8 +895,12 @@ async function main() {
889
895
  );
890
896
  return;
891
897
  }
898
+ const databaseIds = argv.migrateStringsDbIds
899
+ ? argv.migrateStringsDbIds.split(",").map((s: string) => s.trim()).filter(Boolean)
900
+ : undefined;
892
901
  await analyzeStringAttributes(controller.adapter, controller.config, {
893
902
  outputPath: argv.migrateStringsOutput,
903
+ databaseIds,
894
904
  });
895
905
  } else if (argv.migrateStringsExecute) {
896
906
  if (!controller.adapter) {
@@ -34,7 +34,11 @@ export async function analyzeStringAttributes(
34
34
  config: AppwriteConfig,
35
35
  options: AnalyzeOptions = {}
36
36
  ): Promise<MigrationPlan> {
37
- const databases = config.databases || [];
37
+ let databasesToScan = config.databases || [];
38
+ if (options.databaseIds?.length) {
39
+ databasesToScan = databasesToScan.filter(db => options.databaseIds!.includes(db.$id));
40
+ }
41
+ const databases = databasesToScan;
38
42
  if (databases.length === 0) {
39
43
  MessageFormatter.warning("No databases configured. Nothing to analyze.", {
40
44
  prefix: "Analyze",
@@ -108,6 +108,7 @@ export type MigrationCheckpoint = z.infer<typeof MigrationCheckpointSchema>;
108
108
  export interface AnalyzeOptions {
109
109
  outputPath?: string;
110
110
  verbose?: boolean;
111
+ databaseIds?: string[];
111
112
  }
112
113
 
113
114
  export interface ExecuteOptions {
@@ -136,17 +137,18 @@ export function suggestTargetType(
136
137
  // ── Helper: generate backup key with length limits ──
137
138
 
138
139
  const MAX_KEY_LENGTH = 36;
139
- const BACKUP_PREFIX = "_mig_";
140
+ const BACKUP_PREFIX = "mig_";
140
141
 
141
142
  export function generateBackupKey(originalKey: string): string {
142
143
  const candidate = `${BACKUP_PREFIX}${originalKey}`;
143
144
  if (candidate.length <= MAX_KEY_LENGTH) {
144
145
  return candidate;
145
146
  }
146
- // Truncate + 4-char hash for uniqueness
147
+ // Truncate + 4-char hash for uniqueness: m_ + orig + _ + hash(4)
147
148
  const hash = simpleHash(originalKey);
148
- const maxOrigLen = MAX_KEY_LENGTH - BACKUP_PREFIX.length - 1 - 4; // _mig_ + _ + hash4
149
- return `_m_${originalKey.slice(0, maxOrigLen)}_${hash}`;
149
+ const TRUNC_PREFIX = "m_";
150
+ const maxOrigLen = MAX_KEY_LENGTH - TRUNC_PREFIX.length - 1 - 4;
151
+ return `${TRUNC_PREFIX}${originalKey.slice(0, maxOrigLen)}_${hash}`;
150
152
  }
151
153
 
152
154
  function simpleHash(str: string): string {