appwrite-utils-cli 0.0.1
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.
- package/README.md +80 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +74 -0
- package/dist/migrations/afterImportActions.d.ts +12 -0
- package/dist/migrations/afterImportActions.js +196 -0
- package/dist/migrations/attributes.d.ts +4 -0
- package/dist/migrations/attributes.js +158 -0
- package/dist/migrations/backup.d.ts +621 -0
- package/dist/migrations/backup.js +159 -0
- package/dist/migrations/collections.d.ts +16 -0
- package/dist/migrations/collections.js +207 -0
- package/dist/migrations/converters.d.ts +179 -0
- package/dist/migrations/converters.js +575 -0
- package/dist/migrations/dbHelpers.d.ts +5 -0
- package/dist/migrations/dbHelpers.js +54 -0
- package/dist/migrations/importController.d.ts +44 -0
- package/dist/migrations/importController.js +312 -0
- package/dist/migrations/importDataActions.d.ts +44 -0
- package/dist/migrations/importDataActions.js +219 -0
- package/dist/migrations/indexes.d.ts +4 -0
- package/dist/migrations/indexes.js +18 -0
- package/dist/migrations/logging.d.ts +2 -0
- package/dist/migrations/logging.js +14 -0
- package/dist/migrations/migrationHelper.d.ts +18 -0
- package/dist/migrations/migrationHelper.js +66 -0
- package/dist/migrations/queue.d.ts +13 -0
- package/dist/migrations/queue.js +79 -0
- package/dist/migrations/relationships.d.ts +90 -0
- package/dist/migrations/relationships.js +209 -0
- package/dist/migrations/schema.d.ts +3142 -0
- package/dist/migrations/schema.js +485 -0
- package/dist/migrations/schemaStrings.d.ts +12 -0
- package/dist/migrations/schemaStrings.js +261 -0
- package/dist/migrations/setupDatabase.d.ts +7 -0
- package/dist/migrations/setupDatabase.js +151 -0
- package/dist/migrations/storage.d.ts +8 -0
- package/dist/migrations/storage.js +241 -0
- package/dist/migrations/users.d.ts +11 -0
- package/dist/migrations/users.js +114 -0
- package/dist/migrations/validationRules.d.ts +43 -0
- package/dist/migrations/validationRules.js +42 -0
- package/dist/schemas/authUser.d.ts +62 -0
- package/dist/schemas/authUser.js +17 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.js +5 -0
- package/dist/types.d.ts +9 -0
- package/dist/types.js +5 -0
- package/dist/utils/configSchema.json +742 -0
- package/dist/utils/helperFunctions.d.ts +34 -0
- package/dist/utils/helperFunctions.js +72 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/setupFiles.d.ts +2 -0
- package/dist/utils/setupFiles.js +276 -0
- package/dist/utilsController.d.ts +30 -0
- package/dist/utilsController.js +106 -0
- package/package.json +34 -0
- package/src/main.ts +77 -0
- package/src/migrations/afterImportActions.ts +300 -0
- package/src/migrations/attributes.ts +315 -0
- package/src/migrations/backup.ts +189 -0
- package/src/migrations/collections.ts +303 -0
- package/src/migrations/converters.ts +628 -0
- package/src/migrations/dbHelpers.ts +89 -0
- package/src/migrations/importController.ts +509 -0
- package/src/migrations/importDataActions.ts +313 -0
- package/src/migrations/indexes.ts +37 -0
- package/src/migrations/logging.ts +15 -0
- package/src/migrations/migrationHelper.ts +100 -0
- package/src/migrations/queue.ts +119 -0
- package/src/migrations/relationships.ts +336 -0
- package/src/migrations/schema.ts +590 -0
- package/src/migrations/schemaStrings.ts +310 -0
- package/src/migrations/setupDatabase.ts +219 -0
- package/src/migrations/storage.ts +351 -0
- package/src/migrations/users.ts +148 -0
- package/src/migrations/validationRules.ts +63 -0
- package/src/schemas/authUser.ts +23 -0
- package/src/setup.ts +8 -0
- package/src/types.ts +14 -0
- package/src/utils/configSchema.json +742 -0
- package/src/utils/helperFunctions.ts +111 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/setupFiles.ts +295 -0
- package/src/utilsController.ts +173 -0
- package/tsconfig.json +37 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ID,
|
|
3
|
+
Query,
|
|
4
|
+
type Databases,
|
|
5
|
+
type Models,
|
|
6
|
+
type Storage,
|
|
7
|
+
} from "node-appwrite";
|
|
8
|
+
import type {
|
|
9
|
+
AppwriteConfig,
|
|
10
|
+
ConfigCollection,
|
|
11
|
+
ConfigDatabase,
|
|
12
|
+
ImportDef,
|
|
13
|
+
AttributeMappings,
|
|
14
|
+
} from "./schema.js";
|
|
15
|
+
import type { ImportDataActions } from "./importDataActions.js";
|
|
16
|
+
import { checkForCollection } from "./collections.js";
|
|
17
|
+
import path from "path";
|
|
18
|
+
import fs from "fs";
|
|
19
|
+
import { convertObjectByAttributeMappings } from "./converters.js";
|
|
20
|
+
import _ from "lodash";
|
|
21
|
+
import { documentExists } from "./collections.js";
|
|
22
|
+
import { areCollectionNamesSame } from "../utils/index.js";
|
|
23
|
+
import type { SetupOptions } from "../utilsController.js";
|
|
24
|
+
import { resolveAndUpdateRelationships } from "./relationships.js";
|
|
25
|
+
import { AuthUserCreateSchema } from "../types.js";
|
|
26
|
+
import { UsersController } from "./users.js";
|
|
27
|
+
|
|
28
|
+
export class ImportController {
|
|
29
|
+
private config: AppwriteConfig;
|
|
30
|
+
private database: Databases;
|
|
31
|
+
private storage: Storage;
|
|
32
|
+
private appwriteFolderPath: string;
|
|
33
|
+
private importDataActions: ImportDataActions;
|
|
34
|
+
private setupOptions: SetupOptions;
|
|
35
|
+
private documentCache: Map<string, any>;
|
|
36
|
+
private batchLimit: number = 25; // Define batch size limit
|
|
37
|
+
private postImportActionsQueue: {
|
|
38
|
+
context: any;
|
|
39
|
+
finalItem: any;
|
|
40
|
+
attributeMappings: AttributeMappings;
|
|
41
|
+
}[] = [];
|
|
42
|
+
|
|
43
|
+
constructor(
|
|
44
|
+
config: AppwriteConfig,
|
|
45
|
+
database: Databases,
|
|
46
|
+
storage: Storage,
|
|
47
|
+
appwriteFolderPath: string,
|
|
48
|
+
importDataActions: ImportDataActions,
|
|
49
|
+
setupOptions: SetupOptions
|
|
50
|
+
) {
|
|
51
|
+
this.config = config;
|
|
52
|
+
this.database = database;
|
|
53
|
+
this.storage = storage;
|
|
54
|
+
this.appwriteFolderPath = appwriteFolderPath;
|
|
55
|
+
this.importDataActions = importDataActions;
|
|
56
|
+
this.setupOptions = setupOptions;
|
|
57
|
+
this.documentCache = new Map();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async run() {
|
|
61
|
+
const databasesToRun = this.config.databases
|
|
62
|
+
.filter(
|
|
63
|
+
(db) =>
|
|
64
|
+
(areCollectionNamesSame(db.name, this.config!.databases[0].name) &&
|
|
65
|
+
this.setupOptions.runProd) ||
|
|
66
|
+
(areCollectionNamesSame(db.name, this.config!.databases[1].name) &&
|
|
67
|
+
this.setupOptions.runStaging) ||
|
|
68
|
+
(areCollectionNamesSame(db.name, this.config!.databases[2].name) &&
|
|
69
|
+
this.setupOptions.runDev)
|
|
70
|
+
)
|
|
71
|
+
.map((db) => db.name);
|
|
72
|
+
|
|
73
|
+
for (let db of this.config.databases) {
|
|
74
|
+
if (
|
|
75
|
+
db.name.toLowerCase().trim().replace(" ", "") === "migrations" ||
|
|
76
|
+
!databasesToRun.includes(db.name)
|
|
77
|
+
) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (!db.$id) {
|
|
81
|
+
const databases = await this.database!.list([
|
|
82
|
+
Query.equal("name", db.name),
|
|
83
|
+
]);
|
|
84
|
+
if (databases.databases.length > 0) {
|
|
85
|
+
db.$id = databases.databases[0].$id;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
console.log(`---------------------------------`);
|
|
89
|
+
console.log(`Starting import data for database: ${db.name}`);
|
|
90
|
+
console.log(`---------------------------------`);
|
|
91
|
+
await this.importCollections(db);
|
|
92
|
+
await resolveAndUpdateRelationships(db.$id, this.database!, this.config!);
|
|
93
|
+
await this.executePostImportActions();
|
|
94
|
+
console.log(`---------------------------------`);
|
|
95
|
+
console.log(`Finished import data for database: ${db.name}`);
|
|
96
|
+
console.log(`---------------------------------`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async importCollections(db: ConfigDatabase) {
|
|
101
|
+
const maxParallel = 3; // Maximum number of collections to process in parallel
|
|
102
|
+
let activePromises: Promise<void>[] = []; // Array to keep track of active promises
|
|
103
|
+
|
|
104
|
+
for (const collection of this.config.collections) {
|
|
105
|
+
// Function that returns a promise for processing a single collection
|
|
106
|
+
const processCollection = async (col: ConfigCollection) => {
|
|
107
|
+
let isMembersCollection = false;
|
|
108
|
+
if (
|
|
109
|
+
this.config.usersCollectionName.toLowerCase().replace(" ", "") ===
|
|
110
|
+
col.name.toLowerCase().replace(" ", "")
|
|
111
|
+
) {
|
|
112
|
+
isMembersCollection = true;
|
|
113
|
+
}
|
|
114
|
+
const collectionExists = await checkForCollection(
|
|
115
|
+
this.database,
|
|
116
|
+
db.$id,
|
|
117
|
+
col
|
|
118
|
+
);
|
|
119
|
+
if (!collectionExists) {
|
|
120
|
+
console.warn(`No collection found for ${col.name}`);
|
|
121
|
+
return; // Skip this iteration
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const updatedCollection = { ...col, $id: collectionExists.$id };
|
|
125
|
+
await this.processImportDefinitions(
|
|
126
|
+
db,
|
|
127
|
+
updatedCollection,
|
|
128
|
+
isMembersCollection
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Add the current collection's processing promise to the activePromises array
|
|
133
|
+
activePromises.push(processCollection(collection));
|
|
134
|
+
|
|
135
|
+
// If the number of active promises reaches the limit, wait for one to finish
|
|
136
|
+
if (activePromises.length >= maxParallel) {
|
|
137
|
+
await Promise.race(activePromises).then(() => {
|
|
138
|
+
// Remove the promise that finished from the activePromises array
|
|
139
|
+
activePromises = activePromises.filter(
|
|
140
|
+
(p) => p !== Promise.race(activePromises)
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// After the loop, wait for the remaining promises to finish
|
|
147
|
+
await Promise.all(activePromises);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async processImportDefinitions(
|
|
151
|
+
db: ConfigDatabase,
|
|
152
|
+
collection: ConfigCollection,
|
|
153
|
+
isMembersCollection: boolean = false
|
|
154
|
+
) {
|
|
155
|
+
this.documentCache.clear();
|
|
156
|
+
const updateDefs: ImportDef[] = collection.importDefs.filter(
|
|
157
|
+
(def) => def.type === "update"
|
|
158
|
+
);
|
|
159
|
+
const createDefs: ImportDef[] = collection.importDefs.filter(
|
|
160
|
+
(def) => def.type === "create" || !def.type
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Process create import definitions first
|
|
164
|
+
for (const importDef of createDefs) {
|
|
165
|
+
const dataToImport = await this.loadData(importDef);
|
|
166
|
+
if (!dataToImport) continue;
|
|
167
|
+
|
|
168
|
+
console.log(
|
|
169
|
+
`Processing create definitions for collection ID: ${collection.$id}`
|
|
170
|
+
);
|
|
171
|
+
await this.processBatch(
|
|
172
|
+
db,
|
|
173
|
+
collection,
|
|
174
|
+
importDef,
|
|
175
|
+
dataToImport,
|
|
176
|
+
updateDefs,
|
|
177
|
+
isMembersCollection
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Process update import definitions
|
|
182
|
+
for (const importDef of updateDefs) {
|
|
183
|
+
const dataToImport = await this.loadData(importDef);
|
|
184
|
+
if (!dataToImport) continue;
|
|
185
|
+
|
|
186
|
+
console.log(
|
|
187
|
+
`Processing update definitions for collection ID: ${collection.$id}`
|
|
188
|
+
);
|
|
189
|
+
await this.processBatch(db, collection, importDef, dataToImport);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async loadData(importDef: ImportDef): Promise<any[]> {
|
|
194
|
+
const filePath = path.resolve(this.appwriteFolderPath, importDef.filePath);
|
|
195
|
+
if (!fs.existsSync(filePath)) {
|
|
196
|
+
console.error(`File not found: ${filePath}`);
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const rawData = fs.readFileSync(filePath, "utf8");
|
|
201
|
+
return importDef.basePath
|
|
202
|
+
? JSON.parse(rawData)[importDef.basePath]
|
|
203
|
+
: JSON.parse(rawData);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
createContext(db: ConfigDatabase, collection: ConfigCollection, item: any) {
|
|
207
|
+
return {
|
|
208
|
+
...item, // Spread the item data for easy access to its properties
|
|
209
|
+
dbId: db.$id,
|
|
210
|
+
dbName: db.name,
|
|
211
|
+
collId: collection.$id,
|
|
212
|
+
collName: collection.name,
|
|
213
|
+
docId: "", // Initially empty, will be filled once the document is created or identified
|
|
214
|
+
createdDoc: {}, // Initially null, to be updated when the document is created
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async transformData(
|
|
219
|
+
item: any,
|
|
220
|
+
attributeMappings: AttributeMappings
|
|
221
|
+
): Promise<any> {
|
|
222
|
+
const convertedItem = convertObjectByAttributeMappings(
|
|
223
|
+
item,
|
|
224
|
+
attributeMappings
|
|
225
|
+
);
|
|
226
|
+
return this.importDataActions.runConverterFunctions(
|
|
227
|
+
convertedItem,
|
|
228
|
+
attributeMappings
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async processBatch(
|
|
233
|
+
db: ConfigDatabase,
|
|
234
|
+
collection: ConfigCollection,
|
|
235
|
+
importDef: ImportDef,
|
|
236
|
+
dataToImport: any[],
|
|
237
|
+
updateDefs: ImportDef[] = [],
|
|
238
|
+
isMembersCollection: boolean = false
|
|
239
|
+
) {
|
|
240
|
+
for (let i = 0; i < dataToImport.length; i += this.batchLimit) {
|
|
241
|
+
const batch = dataToImport.slice(i, i + this.batchLimit);
|
|
242
|
+
const results = await Promise.allSettled(
|
|
243
|
+
batch.map(async (item: any) => {
|
|
244
|
+
let context = this.createContext(db, collection, item);
|
|
245
|
+
let finalItem = await this.transformData(
|
|
246
|
+
item,
|
|
247
|
+
importDef.attributeMappings
|
|
248
|
+
);
|
|
249
|
+
let createIdToUse: string | undefined = undefined;
|
|
250
|
+
let associatedDoc: Models.Document | undefined;
|
|
251
|
+
if (
|
|
252
|
+
isMembersCollection &&
|
|
253
|
+
(finalItem.hasOwnProperty("email") || item.hasOwnProperty("phone"))
|
|
254
|
+
) {
|
|
255
|
+
console.log("Found members collection, creating user...");
|
|
256
|
+
const usersController = new UsersController(
|
|
257
|
+
this.config,
|
|
258
|
+
this.database
|
|
259
|
+
);
|
|
260
|
+
const userToCreate = AuthUserCreateSchema.safeParse({
|
|
261
|
+
...finalItem,
|
|
262
|
+
});
|
|
263
|
+
if (!userToCreate.success) {
|
|
264
|
+
console.error(userToCreate.error);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const user = await usersController.createUserAndReturn(
|
|
268
|
+
userToCreate.data
|
|
269
|
+
);
|
|
270
|
+
createIdToUse = user.$id;
|
|
271
|
+
context = { ...context, ...user };
|
|
272
|
+
console.log(
|
|
273
|
+
"Created user, deleting keys in finalItem that exist in user..."
|
|
274
|
+
);
|
|
275
|
+
const associatedDocFound = await this.database.listDocuments(
|
|
276
|
+
db.$id,
|
|
277
|
+
context.collId,
|
|
278
|
+
[Query.equal("$id", createIdToUse)]
|
|
279
|
+
);
|
|
280
|
+
if (associatedDocFound.documents.length > 0) {
|
|
281
|
+
associatedDoc = associatedDocFound.documents[0];
|
|
282
|
+
}
|
|
283
|
+
// Delete keys in finalItem that also exist in user
|
|
284
|
+
let deletedKeys: string[] = [];
|
|
285
|
+
Object.keys(finalItem).forEach((key) => {
|
|
286
|
+
if (user.hasOwnProperty(key)) {
|
|
287
|
+
delete finalItem[key];
|
|
288
|
+
deletedKeys.push(key);
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
console.log(
|
|
292
|
+
`Set createIdToUse to ${createIdToUse}. Deleted keys: ${deletedKeys.join(
|
|
293
|
+
", "
|
|
294
|
+
)}.`
|
|
295
|
+
);
|
|
296
|
+
} else if (isMembersCollection) {
|
|
297
|
+
console.log(
|
|
298
|
+
`Skipping user & contact creation for ${item} due to lack of email...`
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
context = { ...context, ...finalItem };
|
|
303
|
+
|
|
304
|
+
if (
|
|
305
|
+
!(await this.importDataActions.validateItem(
|
|
306
|
+
finalItem,
|
|
307
|
+
importDef.attributeMappings,
|
|
308
|
+
context
|
|
309
|
+
))
|
|
310
|
+
) {
|
|
311
|
+
console.error("Validation failed for item:", finalItem);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let afterContext;
|
|
316
|
+
if (
|
|
317
|
+
(importDef.type === "create" || !importDef.type) &&
|
|
318
|
+
!associatedDoc
|
|
319
|
+
) {
|
|
320
|
+
const createdContext = await this.handleCreate(
|
|
321
|
+
context,
|
|
322
|
+
finalItem,
|
|
323
|
+
updateDefs,
|
|
324
|
+
createIdToUse
|
|
325
|
+
);
|
|
326
|
+
if (createdContext) {
|
|
327
|
+
afterContext = createdContext;
|
|
328
|
+
}
|
|
329
|
+
} else {
|
|
330
|
+
const updatedContext = await this.handleUpdate(
|
|
331
|
+
context,
|
|
332
|
+
finalItem,
|
|
333
|
+
importDef
|
|
334
|
+
);
|
|
335
|
+
if (updatedContext) {
|
|
336
|
+
afterContext = updatedContext;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (afterContext) {
|
|
340
|
+
context = { ...context, ...afterContext };
|
|
341
|
+
}
|
|
342
|
+
const afterImportActionContext = structuredClone(context);
|
|
343
|
+
const attributeMappingsWithActions =
|
|
344
|
+
this.getAttributeMappingsWithActions(
|
|
345
|
+
importDef.attributeMappings,
|
|
346
|
+
context,
|
|
347
|
+
finalItem
|
|
348
|
+
);
|
|
349
|
+
if (attributeMappingsWithActions.some((m) => m.postImportActions)) {
|
|
350
|
+
this.postImportActionsQueue.push({
|
|
351
|
+
context: afterImportActionContext,
|
|
352
|
+
finalItem: finalItem,
|
|
353
|
+
attributeMappings: attributeMappingsWithActions,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
})
|
|
357
|
+
);
|
|
358
|
+
results.forEach((result) => {
|
|
359
|
+
if (result.status === "rejected") {
|
|
360
|
+
console.error("A process batch promise was rejected:", result.reason);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async handleCreate(
|
|
367
|
+
context: any,
|
|
368
|
+
finalItem: any,
|
|
369
|
+
updateDefs?: ImportDef[],
|
|
370
|
+
id?: string
|
|
371
|
+
) {
|
|
372
|
+
const existing = await documentExists(
|
|
373
|
+
this.database,
|
|
374
|
+
context.dbId,
|
|
375
|
+
context.collId,
|
|
376
|
+
finalItem
|
|
377
|
+
);
|
|
378
|
+
if (!existing) {
|
|
379
|
+
if (id) {
|
|
380
|
+
console.log(`Creating document with provided ID (member): ${id}`);
|
|
381
|
+
}
|
|
382
|
+
const createdDoc = await this.database.createDocument(
|
|
383
|
+
context.dbId,
|
|
384
|
+
context.collId,
|
|
385
|
+
id || ID.unique(),
|
|
386
|
+
finalItem
|
|
387
|
+
);
|
|
388
|
+
context.docId = createdDoc.$id;
|
|
389
|
+
context.createdDoc = createdDoc;
|
|
390
|
+
context = { ...context, ...createdDoc };
|
|
391
|
+
|
|
392
|
+
// Populate document cache for updates
|
|
393
|
+
if (updateDefs) {
|
|
394
|
+
updateDefs.forEach((def) => {
|
|
395
|
+
if (def.updateMapping) {
|
|
396
|
+
this.documentCache.set(
|
|
397
|
+
`${finalItem[def.updateMapping.targetField]}`,
|
|
398
|
+
context
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
console.log(`Created document ID: ${createdDoc.$id}`);
|
|
405
|
+
return context;
|
|
406
|
+
} else {
|
|
407
|
+
console.log("Document already exists, skipping creation.");
|
|
408
|
+
return existing;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
async handleUpdate(context: any, finalItem: any, importDef: ImportDef) {
|
|
413
|
+
const updateMapping = importDef.updateMapping;
|
|
414
|
+
if (updateMapping) {
|
|
415
|
+
const keyToMatch = updateMapping.originalIdField;
|
|
416
|
+
const origId = context[keyToMatch];
|
|
417
|
+
const targetId = finalItem[updateMapping.targetField];
|
|
418
|
+
const cachedContext = this.documentCache.get(`${origId}`);
|
|
419
|
+
context = { ...context, ...cachedContext };
|
|
420
|
+
|
|
421
|
+
if (cachedContext) {
|
|
422
|
+
const updatedDoc = await this.database.updateDocument(
|
|
423
|
+
context.dbId,
|
|
424
|
+
context.collId,
|
|
425
|
+
context.docId,
|
|
426
|
+
finalItem
|
|
427
|
+
);
|
|
428
|
+
context = { ...context, ...updatedDoc };
|
|
429
|
+
console.log(`Updated document ID: ${updatedDoc.$id}`);
|
|
430
|
+
return context;
|
|
431
|
+
} else {
|
|
432
|
+
console.error(
|
|
433
|
+
`Document to update not found in cache targeting ${keyToMatch}:${origId}`
|
|
434
|
+
);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
getAttributeMappingsWithActions(
|
|
441
|
+
attributeMappings: AttributeMappings,
|
|
442
|
+
context: any,
|
|
443
|
+
item: any
|
|
444
|
+
) {
|
|
445
|
+
return attributeMappings.map((mapping) => {
|
|
446
|
+
if (mapping.fileData) {
|
|
447
|
+
console.log("Adding after-import action for fileData attribute");
|
|
448
|
+
let mappingFilePath = this.importDataActions.resolveTemplate(
|
|
449
|
+
mapping.fileData.path,
|
|
450
|
+
context,
|
|
451
|
+
item
|
|
452
|
+
);
|
|
453
|
+
if (!mappingFilePath.toLowerCase().startsWith("http")) {
|
|
454
|
+
console.log(`Resolving file path: ${mappingFilePath}`);
|
|
455
|
+
mappingFilePath = path.resolve(
|
|
456
|
+
this.appwriteFolderPath,
|
|
457
|
+
mappingFilePath
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
const afterImportAction = {
|
|
461
|
+
action: "createFileAndUpdateField",
|
|
462
|
+
params: [
|
|
463
|
+
"{dbId}",
|
|
464
|
+
"{collId}",
|
|
465
|
+
"{docId}",
|
|
466
|
+
mapping.targetKey,
|
|
467
|
+
`${this.config!.documentBucketId}_${context.dbName
|
|
468
|
+
.toLowerCase()
|
|
469
|
+
.replace(" ", "")}`, // Assuming 'images' is your bucket ID
|
|
470
|
+
mappingFilePath,
|
|
471
|
+
mapping.fileData.name,
|
|
472
|
+
],
|
|
473
|
+
};
|
|
474
|
+
const postImportActions = mapping.postImportActions
|
|
475
|
+
? [...mapping.postImportActions, afterImportAction]
|
|
476
|
+
: [afterImportAction];
|
|
477
|
+
return { ...mapping, postImportActions };
|
|
478
|
+
}
|
|
479
|
+
return mapping;
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
async executePostImportActions() {
|
|
484
|
+
const results = await Promise.allSettled(
|
|
485
|
+
this.postImportActionsQueue.map(async (action) => {
|
|
486
|
+
const { context, finalItem, attributeMappings } = action;
|
|
487
|
+
console.log(
|
|
488
|
+
`Executing post-import actions for document: ${context.docId}`
|
|
489
|
+
);
|
|
490
|
+
return this.importDataActions.executeAfterImportActions(
|
|
491
|
+
finalItem,
|
|
492
|
+
attributeMappings,
|
|
493
|
+
context
|
|
494
|
+
);
|
|
495
|
+
})
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
results.forEach((result) => {
|
|
499
|
+
if (result.status === "rejected") {
|
|
500
|
+
console.error(
|
|
501
|
+
"A post-import action promise was rejected:",
|
|
502
|
+
result.reason
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
this.postImportActionsQueue = [];
|
|
508
|
+
}
|
|
509
|
+
}
|