appwrite-utils-cli 0.0.262 → 0.0.264

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.
@@ -99,7 +99,7 @@ export class DataLoader {
99
99
  return result;
100
100
  }
101
101
  // Method to load data from a file specified in the import definition
102
- async loadData(importDef) {
102
+ loadData(importDef) {
103
103
  // Resolve the file path and check if the file exists
104
104
  const filePath = path.resolve(this.appwriteFolderPath, importDef.filePath);
105
105
  if (!fs.existsSync(filePath)) {
@@ -150,7 +150,7 @@ export class DataLoader {
150
150
  * @param attributeMappings - The mappings that define how each attribute should be transformed.
151
151
  * @returns The transformed item.
152
152
  */
153
- async transformData(item, attributeMappings) {
153
+ transformData(item, attributeMappings) {
154
154
  // Convert the item using the attribute mappings provided
155
155
  const convertedItem = convertObjectByAttributeMappings(item, attributeMappings);
156
156
  // Run additional converter functions on the converted item, if any
@@ -285,28 +285,24 @@ export class DataLoader {
285
285
  const oldIds = Array.isArray(item.context[idMapping.sourceField])
286
286
  ? item.context[idMapping.sourceField]
287
287
  : [item.context[idMapping.sourceField]];
288
+ const resolvedNewIds = [];
288
289
  oldIds.forEach((oldId) => {
289
- let newIdForOldId;
290
- // Handling users merged into a new ID
291
- newIdForOldId = this.findNewIdForOldId(oldId, idMapping);
292
- if (newIdForOldId) {
293
- const targetField = idMapping.fieldToSet || idMapping.targetField;
294
- const isArray = collectionConfig.attributes.some((attribute) => attribute.key === targetField && attribute.array);
295
- // Properly update the target field based on whether it should be an array
296
- if (isArray) {
297
- if (!Array.isArray(item.finalData[targetField])) {
298
- item.finalData[targetField] = [newIdForOldId];
299
- }
300
- else if (!item.finalData[targetField].includes(newIdForOldId)) {
301
- item.finalData[targetField].push(newIdForOldId);
302
- }
303
- }
304
- else {
305
- item.finalData[targetField] = newIdForOldId;
306
- }
307
- needsUpdate = true;
290
+ // Attempt to find a new ID for the old ID
291
+ let newIdForOldId = this.findNewIdForOldId(oldId, idMapping, importDef);
292
+ if (newIdForOldId && !resolvedNewIds.includes(newIdForOldId)) {
293
+ resolvedNewIds.push(newIdForOldId);
294
+ }
295
+ else {
296
+ logger.error(`No new ID found for old ID ${oldId} in collection ${collectionConfig.name}`);
308
297
  }
309
298
  });
299
+ if (resolvedNewIds.length) {
300
+ const targetField = idMapping.fieldToSet || idMapping.targetField;
301
+ const isArray = collectionConfig.attributes.some(attribute => attribute.key === targetField && attribute.array);
302
+ // Set the target field based on whether it's an array or single value
303
+ item.finalData[targetField] = isArray ? resolvedNewIds : resolvedNewIds[0];
304
+ needsUpdate = true;
305
+ }
310
306
  }
311
307
  }
312
308
  }
@@ -319,37 +315,47 @@ export class DataLoader {
319
315
  }
320
316
  }
321
317
  }
322
- findNewIdForOldId(oldId, idMapping) {
323
- // Check merged users first for any corresponding new ID
324
- let newIdForOldId;
325
- for (const [newUserId, oldIds] of this.mergedUserMap.entries()) {
326
- if (oldIds.includes(oldId)) {
327
- newIdForOldId = newUserId;
328
- break;
318
+ findNewIdForOldId(oldId, idMapping, importDef) {
319
+ // First, check if this ID mapping is related to the users collection.
320
+ const targetCollectionKey = this.getCollectionKey(idMapping.targetCollection);
321
+ const isUsersCollection = targetCollectionKey === this.getCollectionKey(this.config.usersCollectionName);
322
+ // If handling users, check the mergedUserMap for any existing new ID.
323
+ if (isUsersCollection) {
324
+ for (const [newUserId, oldIds] of this.mergedUserMap.entries()) {
325
+ if (oldIds.includes(oldId)) {
326
+ return newUserId;
327
+ }
329
328
  }
330
329
  }
331
- // If no new ID found in merged users, check the old-to-new ID map for the target collection
332
- if (!newIdForOldId) {
333
- const targetCollectionKey = this.getCollectionKey(idMapping.targetCollection);
334
- const targetOldIdToNewIdMap = this.oldIdToNewIdPerCollectionMap.get(targetCollectionKey);
335
- if (targetOldIdToNewIdMap && targetOldIdToNewIdMap.has(oldId)) {
336
- newIdForOldId = targetOldIdToNewIdMap.get(oldId);
330
+ // If not a user or no merged ID found, check the regular ID mapping from old to new.
331
+ const targetCollectionData = this.importMap.get(targetCollectionKey);
332
+ if (targetCollectionData) {
333
+ const foundEntry = targetCollectionData.data.find(entry => entry.context[importDef.primaryKeyField] === oldId);
334
+ if (foundEntry) {
335
+ return foundEntry.context.docId; // Assuming `docId` stores the new ID after import
337
336
  }
338
337
  }
339
- return newIdForOldId;
338
+ logger.error(`No corresponding new ID found for ${oldId} in ${targetCollectionKey}`);
339
+ return null; // Return null if no new ID is found
340
340
  }
341
341
  writeMapsToJsonFile() {
342
342
  const outputDir = path.resolve(process.cwd());
343
343
  const outputFile = path.join(outputDir, "dataLoaderOutput.json");
344
344
  const dataToWrite = {
345
+ // Convert Maps to arrays of entries for serialization
346
+ oldIdToNewIdPerCollectionMap: Array.from(this.oldIdToNewIdPerCollectionMap.entries()).map(([key, value]) => {
347
+ return {
348
+ collection: key,
349
+ data: Array.from(value.entries()),
350
+ };
351
+ }),
352
+ mergedUserMap: Array.from(this.mergedUserMap.entries()),
345
353
  dataFromCollections: Array.from(this.importMap.entries()).map(([key, value]) => {
346
354
  return {
347
355
  collection: key,
348
356
  data: value.data.map((item) => item.finalData),
349
357
  };
350
358
  }),
351
- // Convert Maps to arrays of entries for serialization
352
- mergedUserMap: Array.from(this.mergedUserMap.entries()),
353
359
  // emailToUserIdMap: Array.from(this.emailToUserIdMap.entries()),
354
360
  // phoneToUserIdMap: Array.from(this.phoneToUserIdMap.entries()),
355
361
  };
@@ -378,7 +384,7 @@ export class DataLoader {
378
384
  */
379
385
  async prepareUserData(item, attributeMappings, primaryKeyField, newId) {
380
386
  // Transform the item data based on the attribute mappings
381
- let transformedItem = await this.transformData(item, attributeMappings);
387
+ let transformedItem = this.transformData(item, attributeMappings);
382
388
  const userData = AuthUserCreateSchema.safeParse(transformedItem);
383
389
  if (!userData.success) {
384
390
  logger.error(`Invalid user data: ${JSON.stringify(userData.error.errors, undefined, 2)}`);
@@ -444,7 +450,7 @@ export class DataLoader {
444
450
  */
445
451
  async prepareUserCollectionCreateData(db, collection, importDef) {
446
452
  // Load the raw data based on the import definition
447
- const rawData = await this.loadData(importDef);
453
+ const rawData = this.loadData(importDef);
448
454
  const operationId = this.collectionImportOperations.get(this.getCollectionKey(collection.name));
449
455
  // Initialize a new map for old ID to new ID mappings
450
456
  const oldIdToNewIdMap = new Map();
@@ -562,7 +568,7 @@ export class DataLoader {
562
568
  */
563
569
  async prepareCreateData(db, collection, importDef) {
564
570
  // Load the raw data based on the import definition
565
- const rawData = await this.loadData(importDef);
571
+ const rawData = this.loadData(importDef);
566
572
  const operationId = this.collectionImportOperations.get(this.getCollectionKey(collection.name));
567
573
  if (!operationId) {
568
574
  throw new Error(`No import operation found for collection ${collection.name}`);
@@ -588,7 +594,7 @@ export class DataLoader {
588
594
  // Create a context object for the item, including the new ID
589
595
  let context = this.createContext(db, collection, item, itemIdNew);
590
596
  // Transform the item data based on the attribute mappings
591
- const transformedData = await this.transformData(item, importDef.attributeMappings);
597
+ const transformedData = this.transformData(item, importDef.attributeMappings);
592
598
  // If a primary key field is defined, handle the ID mapping and check for duplicates
593
599
  if (importDef.primaryKeyField) {
594
600
  const oldId = item[importDef.primaryKeyField];
@@ -650,14 +656,14 @@ export class DataLoader {
650
656
  return;
651
657
  }
652
658
  // Load the raw data based on the import definition
653
- const rawData = await this.loadData(importDef);
659
+ const rawData = this.loadData(importDef);
654
660
  const operationId = this.collectionImportOperations.get(this.getCollectionKey(collection.name));
655
661
  if (!operationId) {
656
662
  throw new Error(`No import operation found for collection ${collection.name}`);
657
663
  }
658
664
  for (const item of rawData) {
659
665
  // Transform the item data based on the attribute mappings
660
- let transformedData = await this.transformData(item, importDef.attributeMappings);
666
+ let transformedData = this.transformData(item, importDef.attributeMappings);
661
667
  let newId;
662
668
  let oldId;
663
669
  // Determine the new ID for the item based on the primary key field or update mapping
@@ -0,0 +1,2 @@
1
+ import { Databases, type Models } from "node-appwrite";
2
+ export declare const fetchAllDatabases: (database: Databases) => Promise<Models.Database[]>;
@@ -0,0 +1,23 @@
1
+ import { Databases, Query } from "node-appwrite";
2
+ export const fetchAllDatabases = async (database) => {
3
+ const databases = await database.list([Query.limit(25)]);
4
+ const allDatabases = databases.databases;
5
+ let lastDatabaseId = allDatabases[allDatabases.length - 1].$id;
6
+ if (databases.databases.length < 25) {
7
+ return allDatabases;
8
+ }
9
+ else {
10
+ while (lastDatabaseId) {
11
+ const databases = await database.list([
12
+ Query.limit(25),
13
+ Query.cursorAfter(lastDatabaseId),
14
+ ]);
15
+ allDatabases.push(...databases.databases);
16
+ if (databases.databases.length < 25) {
17
+ break;
18
+ }
19
+ lastDatabaseId = databases.databases[databases.databases.length - 1].$id;
20
+ }
21
+ }
22
+ return allDatabases;
23
+ };
@@ -8,6 +8,13 @@ export const createOrUpdateIndex = async (dbId, db, collectionId, index) => {
8
8
  if (existingIndex.total > 0) {
9
9
  await db.deleteIndex(dbId, collectionId, existingIndex.indexes[0].key);
10
10
  }
11
+ if (index.type === "fulltext" && index.attributes.length > 1) {
12
+ throw new Error(`Fulltext index can only be created on a single attribute. Index: ${index.key}`);
13
+ }
14
+ else if (index.type === "fulltext") {
15
+ // @ts-ignore
16
+ index.attributes = index.attributes[0];
17
+ }
11
18
  const newIndex = await db.createIndex(dbId, collectionId, index.key, index.type, index.attributes, index.orders);
12
19
  return newIndex;
13
20
  };