appwrite-utils-cli 1.6.5 → 1.6.7

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.
@@ -153,6 +153,64 @@ export class ConfigLoaderService {
153
153
  }
154
154
  }
155
155
 
156
+ // Load collections and tables from their respective directories
157
+ const configDir = path.dirname(yamlPath);
158
+ const collectionsDir = path.join(configDir, config.schemaConfig?.collectionsDirectory || "collections");
159
+ const tablesDir = path.join(configDir, config.schemaConfig?.tablesDirectory || "tables");
160
+
161
+ // Detect API mode to determine priority order
162
+ let apiMode: 'legacy' | 'tablesdb' = 'legacy';
163
+ try {
164
+ const { detectAppwriteVersionCached } = await import('../../utils/versionDetection.js');
165
+ const detection = await detectAppwriteVersionCached(
166
+ config.appwriteEndpoint,
167
+ config.appwriteProject,
168
+ config.appwriteKey
169
+ );
170
+ apiMode = detection.apiMode;
171
+ } catch {
172
+ // Fallback to legacy if detection fails
173
+ }
174
+
175
+ // Load with correct priority based on API mode
176
+ const { items, conflicts, fromCollections, fromTables } = apiMode === 'tablesdb'
177
+ ? await this.loadTablesFirst(tablesDir, collectionsDir)
178
+ : await this.loadCollectionsAndTables(collectionsDir, tablesDir);
179
+
180
+ config.collections = items;
181
+
182
+ // Report what was loaded
183
+ if (fromTables > 0 && fromCollections > 0) {
184
+ MessageFormatter.success(
185
+ `Loaded ${items.length} total items: ${fromCollections} from collections/, ${fromTables} from tables/`,
186
+ { prefix: "Config" }
187
+ );
188
+ } else if (fromCollections > 0) {
189
+ MessageFormatter.success(
190
+ `Loaded ${fromCollections} collections from collections/`,
191
+ { prefix: "Config" }
192
+ );
193
+ } else if (fromTables > 0) {
194
+ MessageFormatter.success(
195
+ `Loaded ${fromTables} tables from tables/`,
196
+ { prefix: "Config" }
197
+ );
198
+ }
199
+
200
+ // Report conflicts
201
+ if (conflicts.length > 0) {
202
+ MessageFormatter.warning(
203
+ `Found ${conflicts.length} naming conflicts`,
204
+ { prefix: "Config" }
205
+ );
206
+ conflicts.forEach(conflict => {
207
+ MessageFormatter.info(
208
+ ` - '${conflict.name}': ${conflict.source1} (used) vs ${conflict.source2} (skipped)`,
209
+ { prefix: "Config" }
210
+ );
211
+ });
212
+ }
213
+
156
214
  MessageFormatter.success(`Loaded YAML config from: ${yamlPath}`, {
157
215
  prefix: "Config",
158
216
  });
@@ -523,6 +581,67 @@ export class ConfigLoaderService {
523
581
  };
524
582
  }
525
583
 
584
+ /**
585
+ * Loads tables first (higher priority), then collections (backward compatibility)
586
+ * Used for TablesDB projects (>= 1.8.0)
587
+ * @param tablesDir Path to the tables directory
588
+ * @param collectionsDir Path to the collections directory
589
+ * @returns Loading result with items, counts, and conflicts
590
+ */
591
+ public async loadTablesFirst(
592
+ tablesDir: string,
593
+ collectionsDir: string
594
+ ): Promise<{
595
+ items: Collection[];
596
+ fromCollections: number;
597
+ fromTables: number;
598
+ conflicts: Array<{ name: string; source1: string; source2: string }>;
599
+ }> {
600
+ const items: Collection[] = [];
601
+ const loadedNames = new Set<string>();
602
+ const conflicts: Array<{ name: string; source1: string; source2: string }> = [];
603
+
604
+ // Load from tables/ directory first (HIGHER priority for TablesDB)
605
+ if (fs.existsSync(tablesDir)) {
606
+ const tables = await this.loadTables(tablesDir, { markAsTablesDir: true });
607
+ for (const table of tables) {
608
+ const name = table.name || table.tableId || table.$id || "";
609
+ loadedNames.add(name);
610
+ items.push(table);
611
+ }
612
+ }
613
+
614
+ // Load from collections/ directory second (LOWER priority, backward compatibility)
615
+ if (fs.existsSync(collectionsDir)) {
616
+ const collections = await this.loadCollections(collectionsDir);
617
+ for (const collection of collections) {
618
+ const name = collection.name || collection.$id || "";
619
+
620
+ // Check for conflicts - tables win
621
+ if (loadedNames.has(name)) {
622
+ conflicts.push({
623
+ name,
624
+ source1: "tables/",
625
+ source2: "collections/",
626
+ });
627
+ } else {
628
+ loadedNames.add(name);
629
+ items.push(collection);
630
+ }
631
+ }
632
+ }
633
+
634
+ const fromTables = items.filter((item: any) => item._isFromTablesDir).length;
635
+ const fromCollections = items.filter((item: any) => !item._isFromTablesDir).length;
636
+
637
+ return {
638
+ items,
639
+ fromCollections,
640
+ fromTables,
641
+ conflicts,
642
+ };
643
+ }
644
+
526
645
  /**
527
646
  * Validates that a configuration file can be loaded
528
647
  * @param configPath Path to the configuration file