appwrite-utils-cli 1.6.0 → 1.6.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.
@@ -14,8 +14,9 @@ export const databaseCommands = {
14
14
  MessageFormatter.warning("No databases selected. Skipping database sync.", { prefix: "Database" });
15
15
  return;
16
16
  }
17
- const collections = await cli.selectCollectionsAndTables(databases[0], cli.controller.database, chalk.blue("Select local collections/tables to push:"), true, true, // prefer local
18
- true // filter by selected database
17
+ const collections = await cli.selectCollectionsAndTables(databases[0], cli.controller.database, chalk.blue("Select local collections/tables to push:"), true, // multiSelect
18
+ true // prefer local
19
+ // shouldFilterByDatabase removed - user will be prompted interactively
19
20
  );
20
21
  const { syncFunctions } = await inquirer.prompt([
21
22
  {
@@ -253,19 +253,13 @@ export class InteractiveCLI {
253
253
  ...configCollections.filter((c) => !remoteCollections.some((rc) => rc.name === c.name)),
254
254
  ];
255
255
  if (shouldFilterByDatabase) {
256
- // Enhanced filtering for tables with optional databaseId
256
+ // Show collections that EITHER exist in the remote database OR have matching local databaseId metadata
257
257
  allCollections = allCollections.filter((c) => {
258
- // For remote collections, they should match the selected database
259
- if (remoteCollections.some((rc) => rc.name === c.name)) {
260
- return c.databaseId === database.$id;
261
- }
262
- // For local collections/tables:
263
- // - Collections without databaseId are kept (backward compatibility)
264
- // - Tables with databaseId must match the selected database
265
- // - Tables without databaseId are kept (fallback for misconfigured tables)
266
- if (!c.databaseId)
267
- return true;
268
- return c.databaseId === database.$id;
258
+ // Include if it exists remotely in this database
259
+ const existsInRemoteDb = remoteCollections.some((rc) => rc.name === c.name);
260
+ // Include if local metadata claims it belongs to this database
261
+ const hasMatchingLocalMetadata = c.databaseId === database.$id;
262
+ return existsInRemoteDb || hasMatchingLocalMetadata;
269
263
  });
270
264
  }
271
265
  // Filter out system tables (those starting with underscore)
@@ -341,26 +335,54 @@ export class InteractiveCLI {
341
335
  const configCollections = this.getLocalCollections();
342
336
  const collectionsCount = configCollections.filter(c => !c._isFromTablesDir).length;
343
337
  const tablesCount = configCollections.filter(c => c._isFromTablesDir).length;
338
+ const totalCount = collectionsCount + tablesCount;
344
339
  // Provide context about what's available
345
340
  if (collectionsCount > 0 && tablesCount > 0) {
346
- MessageFormatter.info(`\nšŸ“‹ Available items for database "${database.name}":`, { prefix: "Collections" });
341
+ MessageFormatter.info(`\nšŸ“‹ ${totalCount} total items available:`, { prefix: "Collections" });
347
342
  MessageFormatter.info(` Collections: ${collectionsCount} (from collections/ folder)`, { prefix: "Collections" });
348
343
  MessageFormatter.info(` Tables: ${tablesCount} (from tables/ folder)`, { prefix: "Collections" });
349
- if (shouldFilterByDatabase) {
344
+ }
345
+ else if (collectionsCount > 0) {
346
+ MessageFormatter.info(`šŸ“ ${collectionsCount} collections available from collections/ folder`, { prefix: "Collections" });
347
+ }
348
+ else if (tablesCount > 0) {
349
+ MessageFormatter.info(`šŸ“Š ${tablesCount} tables available from tables/ folder`, { prefix: "Collections" });
350
+ }
351
+ // Ask user if they want to filter by database or show all
352
+ const { filterChoice } = await inquirer.prompt([
353
+ {
354
+ type: "list",
355
+ name: "filterChoice",
356
+ message: chalk.blue("How would you like to view collections/tables?"),
357
+ choices: [
358
+ {
359
+ name: `Show all available collections/tables (${totalCount} total) - You can push any collection to any database`,
360
+ value: "all"
361
+ },
362
+ {
363
+ name: `Filter by database "${database.name}" - Show only related collections/tables`,
364
+ value: "filter"
365
+ }
366
+ ],
367
+ default: "all"
368
+ }
369
+ ]);
370
+ // User's choice overrides the parameter
371
+ const userWantsFiltering = filterChoice === "filter";
372
+ // Show appropriate informational message
373
+ if (userWantsFiltering) {
374
+ MessageFormatter.info(`ā„¹ļø Showing collections/tables related to database "${database.name}"`, { prefix: "Collections" });
375
+ if (tablesCount > 0) {
350
376
  const filteredTables = configCollections.filter(c => c._isFromTablesDir && (!c.databaseId || c.databaseId === database.$id)).length;
351
377
  if (filteredTables !== tablesCount) {
352
- MessageFormatter.warning(` Note: ${filteredTables}/${tablesCount} tables match this database`, { prefix: "Collections" });
378
+ MessageFormatter.info(` ${filteredTables}/${tablesCount} tables match this database`, { prefix: "Collections" });
353
379
  }
354
380
  }
355
- MessageFormatter.info('', { prefix: "Collections" });
356
381
  }
357
- else if (collectionsCount > 0) {
358
- MessageFormatter.info(`šŸ“ ${collectionsCount} collections available from collections/ folder\n`, { prefix: "Collections" });
359
- }
360
- else if (tablesCount > 0) {
361
- MessageFormatter.info(`šŸ“Š ${tablesCount} tables available from tables/ folder\n`, { prefix: "Collections" });
382
+ else {
383
+ MessageFormatter.info(`ā„¹ļø Showing all available collections/tables - you can push any collection to any database\n`, { prefix: "Collections" });
362
384
  }
363
- return this.selectCollections(database, databasesClient, message, multiSelect, preferLocal, shouldFilterByDatabase);
385
+ return this.selectCollections(database, databasesClient, message, multiSelect, preferLocal, userWantsFiltering);
364
386
  }
365
387
  getTemplateDefaults(template) {
366
388
  const defaults = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "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.6.0",
4
+ "version": "1.6.2",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -27,9 +27,9 @@ export const databaseCommands = {
27
27
  databases[0],
28
28
  (cli as any).controller!.database!,
29
29
  chalk.blue("Select local collections/tables to push:"),
30
- true,
31
- true, // prefer local
32
- true // filter by selected database
30
+ true, // multiSelect
31
+ true // prefer local
32
+ // shouldFilterByDatabase removed - user will be prompted interactively
33
33
  );
34
34
 
35
35
  const { syncFunctions } = await inquirer.prompt([
@@ -324,19 +324,15 @@ export class InteractiveCLI {
324
324
  ];
325
325
 
326
326
  if (shouldFilterByDatabase) {
327
- // Enhanced filtering for tables with optional databaseId
327
+ // Show collections that EITHER exist in the remote database OR have matching local databaseId metadata
328
328
  allCollections = allCollections.filter((c: any) => {
329
- // For remote collections, they should match the selected database
330
- if (remoteCollections.some((rc) => rc.name === c.name)) {
331
- return c.databaseId === database.$id;
332
- }
329
+ // Include if it exists remotely in this database
330
+ const existsInRemoteDb = remoteCollections.some((rc) => rc.name === c.name);
331
+
332
+ // Include if local metadata claims it belongs to this database
333
+ const hasMatchingLocalMetadata = c.databaseId === database.$id;
333
334
 
334
- // For local collections/tables:
335
- // - Collections without databaseId are kept (backward compatibility)
336
- // - Tables with databaseId must match the selected database
337
- // - Tables without databaseId are kept (fallback for misconfigured tables)
338
- if (!c.databaseId) return true;
339
- return c.databaseId === database.$id;
335
+ return existsInRemoteDb || hasMatchingLocalMetadata;
340
336
  });
341
337
  }
342
338
 
@@ -436,29 +432,58 @@ export class InteractiveCLI {
436
432
  const configCollections = this.getLocalCollections();
437
433
  const collectionsCount = configCollections.filter(c => !c._isFromTablesDir).length;
438
434
  const tablesCount = configCollections.filter(c => c._isFromTablesDir).length;
435
+ const totalCount = collectionsCount + tablesCount;
439
436
 
440
437
  // Provide context about what's available
441
438
  if (collectionsCount > 0 && tablesCount > 0) {
442
- MessageFormatter.info(`\nšŸ“‹ Available items for database "${database.name}":`, { prefix: "Collections" });
439
+ MessageFormatter.info(`\nšŸ“‹ ${totalCount} total items available:`, { prefix: "Collections" });
443
440
  MessageFormatter.info(` Collections: ${collectionsCount} (from collections/ folder)`, { prefix: "Collections" });
444
441
  MessageFormatter.info(` Tables: ${tablesCount} (from tables/ folder)`, { prefix: "Collections" });
442
+ } else if (collectionsCount > 0) {
443
+ MessageFormatter.info(`šŸ“ ${collectionsCount} collections available from collections/ folder`, { prefix: "Collections" });
444
+ } else if (tablesCount > 0) {
445
+ MessageFormatter.info(`šŸ“Š ${tablesCount} tables available from tables/ folder`, { prefix: "Collections" });
446
+ }
447
+
448
+ // Ask user if they want to filter by database or show all
449
+ const { filterChoice } = await inquirer.prompt([
450
+ {
451
+ type: "list",
452
+ name: "filterChoice",
453
+ message: chalk.blue("How would you like to view collections/tables?"),
454
+ choices: [
455
+ {
456
+ name: `Show all available collections/tables (${totalCount} total) - You can push any collection to any database`,
457
+ value: "all"
458
+ },
459
+ {
460
+ name: `Filter by database "${database.name}" - Show only related collections/tables`,
461
+ value: "filter"
462
+ }
463
+ ],
464
+ default: "all"
465
+ }
466
+ ]);
445
467
 
446
- if (shouldFilterByDatabase) {
468
+ // User's choice overrides the parameter
469
+ const userWantsFiltering = filterChoice === "filter";
470
+
471
+ // Show appropriate informational message
472
+ if (userWantsFiltering) {
473
+ MessageFormatter.info(`ā„¹ļø Showing collections/tables related to database "${database.name}"`, { prefix: "Collections" });
474
+ if (tablesCount > 0) {
447
475
  const filteredTables = configCollections.filter(c =>
448
476
  c._isFromTablesDir && (!c.databaseId || c.databaseId === database.$id)
449
477
  ).length;
450
478
  if (filteredTables !== tablesCount) {
451
- MessageFormatter.warning(` Note: ${filteredTables}/${tablesCount} tables match this database`, { prefix: "Collections" });
479
+ MessageFormatter.info(` ${filteredTables}/${tablesCount} tables match this database`, { prefix: "Collections" });
452
480
  }
453
481
  }
454
- MessageFormatter.info('', { prefix: "Collections" });
455
- } else if (collectionsCount > 0) {
456
- MessageFormatter.info(`šŸ“ ${collectionsCount} collections available from collections/ folder\n`, { prefix: "Collections" });
457
- } else if (tablesCount > 0) {
458
- MessageFormatter.info(`šŸ“Š ${tablesCount} tables available from tables/ folder\n`, { prefix: "Collections" });
482
+ } else {
483
+ MessageFormatter.info(`ā„¹ļø Showing all available collections/tables - you can push any collection to any database\n`, { prefix: "Collections" });
459
484
  }
460
485
 
461
- return this.selectCollections(database, databasesClient, message, multiSelect, preferLocal, shouldFilterByDatabase);
486
+ return this.selectCollections(database, databasesClient, message, multiSelect, preferLocal, userWantsFiltering);
462
487
  }
463
488
 
464
489
  private getTemplateDefaults(template: string) {