appwrite-utils-cli 0.0.42 → 0.0.44

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.
@@ -110,16 +110,10 @@ export const convertObjectByAttributeMappings = (obj, attributeMappings) => {
110
110
  : value;
111
111
  }
112
112
  else {
113
- result[mapping.targetKey] = null;
113
+ result[mapping.targetKey] = value ? value : null;
114
114
  }
115
115
  }
116
116
  }
117
- // Ensure any keys in the original object that are not mapped are copied over
118
- for (const key of Object.keys(obj)) {
119
- if (!Object.keys(result).includes(key)) {
120
- result[key] = obj[key];
121
- }
122
- }
123
117
  return result;
124
118
  };
125
119
  /**
@@ -310,7 +310,7 @@ export class DataLoader {
310
310
  continue;
311
311
  }
312
312
  // Prepare the update data for the collection
313
- await this.prepareUpdateData(db, collection, updateDef);
313
+ this.prepareUpdateData(db, collection, updateDef);
314
314
  }
315
315
  }
316
316
  console.log("Running update references");
@@ -12,6 +12,7 @@ export declare class ImportController {
12
12
  private setupOptions;
13
13
  private documentCache;
14
14
  private batchLimit;
15
+ private hasImportedUsers;
15
16
  private postImportActionsQueue;
16
17
  constructor(config: AppwriteConfig, database: Databases, storage: Storage, appwriteFolderPath: string, importDataActions: ImportDataActions, setupOptions: SetupOptions);
17
18
  run(): Promise<void>;
@@ -16,6 +16,7 @@ export class ImportController {
16
16
  setupOptions;
17
17
  documentCache;
18
18
  batchLimit = 25; // Define batch size limit
19
+ hasImportedUsers = false;
19
20
  postImportActionsQueue = [];
20
21
  constructor(config, database, storage, appwriteFolderPath, importDataActions, setupOptions) {
21
22
  this.config = config;
@@ -35,6 +36,7 @@ export class ImportController {
35
36
  (areCollectionNamesSame(db.name, this.config.databases[2].name) &&
36
37
  this.setupOptions.runDev))
37
38
  .map((db) => db.name);
39
+ let dataLoader;
38
40
  for (let db of this.config.databases) {
39
41
  if (db.name.toLowerCase().trim().replace(" ", "") === "migrations" ||
40
42
  !databasesToRun.includes(db.name)) {
@@ -52,8 +54,13 @@ export class ImportController {
52
54
  console.log(`Starting import data for database: ${db.name}`);
53
55
  console.log(`---------------------------------`);
54
56
  // await this.importCollections(db);
55
- const dataLoader = new DataLoader(this.appwriteFolderPath, this.importDataActions, this.database, this.config, this.setupOptions.shouldWriteFile);
56
- await dataLoader.start(db.$id);
57
+ if (!dataLoader) {
58
+ dataLoader = new DataLoader(this.appwriteFolderPath, this.importDataActions, this.database, this.config, this.setupOptions.shouldWriteFile);
59
+ await dataLoader.start(db.$id);
60
+ }
61
+ else {
62
+ console.log(`Using data from previous import run`);
63
+ }
57
64
  await this.importCollections(db, dataLoader);
58
65
  await resolveAndUpdateRelationships(db.$id, this.database, this.config);
59
66
  await this.executePostImportActions(db.$id, dataLoader);
@@ -81,7 +88,7 @@ export class ImportController {
81
88
  }
82
89
  return finalBatches;
83
90
  };
84
- if (isUsersCollection) {
91
+ if (isUsersCollection && !this.hasImportedUsers) {
85
92
  const usersDataMap = dataLoader.importMap.get(dataLoader.getCollectionKey("users"));
86
93
  const usersData = usersDataMap?.data;
87
94
  const usersController = new UsersController(this.config, this.database);
@@ -107,6 +114,10 @@ export class ImportController {
107
114
  !dataLoader.userExistsMap.has(itemId));
108
115
  })
109
116
  .map((item) => {
117
+ dataLoader.userExistsMap.set(item.finalData.userId ||
118
+ item.finalData.docId ||
119
+ item.context.userId ||
120
+ item.context.docId, true);
110
121
  return usersController.createUserAndReturn(item.finalData);
111
122
  });
112
123
  const promiseResults = await Promise.allSettled(userBatchPromises);
@@ -120,6 +131,7 @@ export class ImportController {
120
131
  }
121
132
  console.log("Finished importing users batch");
122
133
  }
134
+ this.hasImportedUsers = true;
123
135
  console.log("Finished importing users");
124
136
  }
125
137
  }
@@ -142,23 +154,29 @@ export class ImportController {
142
154
  const batches = dataSplit[i];
143
155
  console.log(`Processing batch ${i + 1} of ${dataSplit.length}`);
144
156
  const batchPromises = batches.map((item) => {
145
- const id = item.finalData.docId ||
146
- item.finalData.userId ||
147
- item.context.docId ||
148
- item.context.userId;
149
- if (item.finalData.hasOwnProperty("userId")) {
150
- delete item.finalData.userId;
151
- }
152
- if (item.finalData.hasOwnProperty("docId")) {
153
- delete item.finalData.docId;
157
+ try {
158
+ const id = item.finalData.docId ||
159
+ item.finalData.userId ||
160
+ item.context.docId ||
161
+ item.context.userId;
162
+ if (item.finalData.hasOwnProperty("userId")) {
163
+ delete item.finalData.userId;
164
+ }
165
+ if (item.finalData.hasOwnProperty("docId")) {
166
+ delete item.finalData.docId;
167
+ }
168
+ if (!item.finalData) {
169
+ return Promise.resolve();
170
+ }
171
+ return tryAwaitWithRetry(async () => await this.database.createDocument(db.$id, collection.$id, id, item.finalData));
154
172
  }
155
- if (!item.finalData) {
173
+ catch (error) {
174
+ console.error(error);
156
175
  return Promise.resolve();
157
176
  }
158
- return tryAwaitWithRetry(async () => await this.database.createDocument(db.$id, collection.$id, id, item.finalData));
159
177
  });
160
178
  // Wait for all promises in the current batch to resolve
161
- await Promise.allSettled(batchPromises);
179
+ await Promise.all(batchPromises);
162
180
  console.log(`Completed batch ${i + 1} of ${dataSplit.length}`);
163
181
  await updateOperation(this.database, importOperation.$id, {
164
182
  progress: processedItems,
@@ -45,7 +45,7 @@ export class UsersController {
45
45
  }
46
46
  async getAllUsers() {
47
47
  const allUsers = [];
48
- const users = await this.users.list([Query.limit(200)]);
48
+ const users = await tryAwaitWithRetry(async () => await this.users.list([Query.limit(200)]));
49
49
  if (users.users.length === 0) {
50
50
  return [];
51
51
  }
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": "0.0.42",
4
+ "version": "0.0.44",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -123,18 +123,11 @@ export const convertObjectByAttributeMappings = (
123
123
  ? value.flat(Infinity)
124
124
  : value;
125
125
  } else {
126
- result[mapping.targetKey] = null;
126
+ result[mapping.targetKey] = value ? value : null;
127
127
  }
128
128
  }
129
129
  }
130
130
 
131
- // Ensure any keys in the original object that are not mapped are copied over
132
- for (const key of Object.keys(obj)) {
133
- if (!Object.keys(result).includes(key)) {
134
- result[key] = obj[key];
135
- }
136
- }
137
-
138
131
  return result;
139
132
  };
140
133
 
@@ -389,7 +389,7 @@ export class DataLoader {
389
389
  continue;
390
390
  }
391
391
  // Prepare the update data for the collection
392
- await this.prepareUpdateData(db, collection, updateDef);
392
+ this.prepareUpdateData(db, collection, updateDef);
393
393
  }
394
394
  }
395
395
  console.log("Running update references");
@@ -36,6 +36,7 @@ export class ImportController {
36
36
  private setupOptions: SetupOptions;
37
37
  private documentCache: Map<string, any>;
38
38
  private batchLimit: number = 25; // Define batch size limit
39
+ private hasImportedUsers = false;
39
40
  private postImportActionsQueue: {
40
41
  context: any;
41
42
  finalItem: any;
@@ -71,7 +72,7 @@ export class ImportController {
71
72
  this.setupOptions.runDev)
72
73
  )
73
74
  .map((db) => db.name);
74
-
75
+ let dataLoader: DataLoader | undefined;
75
76
  for (let db of this.config.databases) {
76
77
  if (
77
78
  db.name.toLowerCase().trim().replace(" ", "") === "migrations" ||
@@ -91,14 +92,18 @@ export class ImportController {
91
92
  console.log(`Starting import data for database: ${db.name}`);
92
93
  console.log(`---------------------------------`);
93
94
  // await this.importCollections(db);
94
- const dataLoader = new DataLoader(
95
- this.appwriteFolderPath,
96
- this.importDataActions,
97
- this.database,
98
- this.config,
99
- this.setupOptions.shouldWriteFile
100
- );
101
- await dataLoader.start(db.$id);
95
+ if (!dataLoader) {
96
+ dataLoader = new DataLoader(
97
+ this.appwriteFolderPath,
98
+ this.importDataActions,
99
+ this.database,
100
+ this.config,
101
+ this.setupOptions.shouldWriteFile
102
+ );
103
+ await dataLoader.start(db.$id);
104
+ } else {
105
+ console.log(`Using data from previous import run`);
106
+ }
102
107
  await this.importCollections(db, dataLoader);
103
108
  await resolveAndUpdateRelationships(db.$id, this.database, this.config);
104
109
  await this.executePostImportActions(db.$id, dataLoader);
@@ -131,7 +136,7 @@ export class ImportController {
131
136
  return finalBatches;
132
137
  };
133
138
 
134
- if (isUsersCollection) {
139
+ if (isUsersCollection && !this.hasImportedUsers) {
135
140
  const usersDataMap = dataLoader.importMap.get(
136
141
  dataLoader.getCollectionKey("users")
137
142
  );
@@ -160,6 +165,13 @@ export class ImportController {
160
165
  );
161
166
  })
162
167
  .map((item) => {
168
+ dataLoader.userExistsMap.set(
169
+ item.finalData.userId ||
170
+ item.finalData.docId ||
171
+ item.context.userId ||
172
+ item.context.docId,
173
+ true
174
+ );
163
175
  return usersController.createUserAndReturn(item.finalData);
164
176
  });
165
177
  const promiseResults = await Promise.allSettled(userBatchPromises);
@@ -176,6 +188,7 @@ export class ImportController {
176
188
  }
177
189
  console.log("Finished importing users batch");
178
190
  }
191
+ this.hasImportedUsers = true;
179
192
  console.log("Finished importing users");
180
193
  }
181
194
  }
@@ -207,32 +220,37 @@ export class ImportController {
207
220
  const batches = dataSplit[i];
208
221
  console.log(`Processing batch ${i + 1} of ${dataSplit.length}`);
209
222
  const batchPromises = batches.map((item) => {
210
- const id =
211
- item.finalData.docId ||
212
- item.finalData.userId ||
213
- item.context.docId ||
214
- item.context.userId;
215
- if (item.finalData.hasOwnProperty("userId")) {
216
- delete item.finalData.userId;
217
- }
218
- if (item.finalData.hasOwnProperty("docId")) {
219
- delete item.finalData.docId;
220
- }
221
- if (!item.finalData) {
223
+ try {
224
+ const id =
225
+ item.finalData.docId ||
226
+ item.finalData.userId ||
227
+ item.context.docId ||
228
+ item.context.userId;
229
+ if (item.finalData.hasOwnProperty("userId")) {
230
+ delete item.finalData.userId;
231
+ }
232
+ if (item.finalData.hasOwnProperty("docId")) {
233
+ delete item.finalData.docId;
234
+ }
235
+ if (!item.finalData) {
236
+ return Promise.resolve();
237
+ }
238
+ return tryAwaitWithRetry(
239
+ async () =>
240
+ await this.database.createDocument(
241
+ db.$id,
242
+ collection.$id,
243
+ id,
244
+ item.finalData
245
+ )
246
+ );
247
+ } catch (error) {
248
+ console.error(error);
222
249
  return Promise.resolve();
223
250
  }
224
- return tryAwaitWithRetry(
225
- async () =>
226
- await this.database.createDocument(
227
- db.$id,
228
- collection.$id,
229
- id,
230
- item.finalData
231
- )
232
- );
233
251
  });
234
252
  // Wait for all promises in the current batch to resolve
235
- await Promise.allSettled(batchPromises);
253
+ await Promise.all(batchPromises);
236
254
  console.log(`Completed batch ${i + 1} of ${dataSplit.length}`);
237
255
  await updateOperation(this.database, importOperation.$id, {
238
256
  progress: processedItems,
@@ -68,7 +68,9 @@ export class UsersController {
68
68
 
69
69
  async getAllUsers() {
70
70
  const allUsers: Models.User<Models.Preferences>[] = [];
71
- const users = await this.users.list([Query.limit(200)]);
71
+ const users = await tryAwaitWithRetry(
72
+ async () => await this.users.list([Query.limit(200)])
73
+ );
72
74
  if (users.users.length === 0) {
73
75
  return [];
74
76
  }