appwrite-utils-cli 0.0.274 → 0.0.276
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 +4 -39
- package/dist/init.d.ts +2 -0
- package/dist/init.js +57 -0
- package/dist/main.js +62 -100
- package/dist/migrations/afterImportActions.d.ts +1 -4
- package/dist/migrations/afterImportActions.js +1 -0
- package/dist/migrations/appwriteToX.d.ts +46 -46
- package/dist/migrations/appwriteToX.js +6 -2
- package/dist/migrations/attributes.d.ts +1 -1
- package/dist/migrations/attributes.js +97 -71
- package/dist/migrations/backup.d.ts +240 -240
- package/dist/migrations/backup.js +1 -1
- package/dist/migrations/collections.d.ts +1 -1
- package/dist/migrations/collections.js +4 -4
- package/dist/migrations/converters.d.ts +9 -127
- package/dist/migrations/converters.js +1 -504
- package/dist/migrations/dataLoader.d.ts +470 -453
- package/dist/migrations/dataLoader.js +19 -1
- package/dist/migrations/dbHelpers.d.ts +1 -1
- package/dist/migrations/dbHelpers.js +3 -0
- package/dist/migrations/importController.d.ts +1 -1
- package/dist/migrations/importController.js +4 -7
- package/dist/migrations/importDataActions.d.ts +4 -6
- package/dist/migrations/importDataActions.js +6 -4
- package/dist/migrations/indexes.d.ts +1 -1
- package/dist/migrations/indexes.js +1 -1
- package/dist/migrations/migrationHelper.d.ts +29 -29
- package/dist/migrations/migrationHelper.js +1 -1
- package/dist/migrations/openapi.d.ts +1 -1
- package/dist/migrations/openapi.js +4 -1
- package/dist/migrations/queue.d.ts +1 -1
- package/dist/migrations/relationships.d.ts +5 -5
- package/dist/migrations/relationships.js +3 -0
- package/dist/migrations/schemaStrings.d.ts +2 -2
- package/dist/migrations/schemaStrings.js +93 -8
- package/dist/migrations/setupDatabase.d.ts +1 -1
- package/dist/migrations/setupDatabase.js +1 -1
- package/dist/migrations/storage.d.ts +1 -1
- package/dist/migrations/users.d.ts +1 -1
- package/dist/schemas/authUser.d.ts +12 -10
- package/dist/types.d.ts +0 -5
- package/dist/types.js +0 -2
- package/dist/utils/helperFunctions.d.ts +2 -3
- package/dist/utils/loadConfigs.d.ts +13 -0
- package/dist/utils/loadConfigs.js +47 -0
- package/dist/utils/setupFiles.d.ts +1 -0
- package/dist/utils/setupFiles.js +98 -223
- package/dist/utilsController.d.ts +1 -3
- package/dist/utilsController.js +14 -18
- package/package.json +9 -2
- package/src/init.ts +64 -0
- package/src/main.ts +73 -98
- package/src/migrations/afterImportActions.ts +1 -5
- package/src/migrations/appwriteToX.ts +6 -2
- package/src/migrations/attributes.ts +198 -150
- package/src/migrations/backup.ts +1 -1
- package/src/migrations/collections.ts +5 -11
- package/src/migrations/converters.ts +1 -540
- package/src/migrations/dataLoader.ts +19 -2
- package/src/migrations/dbHelpers.ts +4 -1
- package/src/migrations/importController.ts +5 -15
- package/src/migrations/importDataActions.ts +10 -14
- package/src/migrations/indexes.ts +1 -1
- package/src/migrations/migrationHelper.ts +1 -1
- package/src/migrations/openapi.ts +4 -1
- package/src/migrations/queue.ts +1 -1
- package/src/migrations/relationships.ts +4 -1
- package/src/migrations/schemaStrings.ts +106 -9
- package/src/migrations/setupDatabase.ts +1 -1
- package/src/migrations/storage.ts +1 -1
- package/src/migrations/users.ts +1 -1
- package/src/types.ts +0 -5
- package/src/utils/helperFunctions.ts +2 -3
- package/src/utils/loadConfigs.ts +55 -0
- package/src/utils/setupFiles.ts +114 -225
- package/src/utilsController.ts +27 -35
- package/src/migrations/schema.ts +0 -748
@@ -1,544 +1,8 @@
|
|
1
|
-
import { DateTime } from "luxon";
|
2
1
|
import _ from "lodash";
|
3
|
-
import
|
2
|
+
import { converterFunctions, type AttributeMappings } from "appwrite-utils";
|
4
3
|
|
5
4
|
const { cloneDeep, isObject } = _;
|
6
5
|
|
7
|
-
export interface ConverterFunctions {
|
8
|
-
[key: string]: (value: any) => any;
|
9
|
-
}
|
10
|
-
|
11
|
-
export const converterFunctions = {
|
12
|
-
/**
|
13
|
-
* Converts any value to a string. Handles null and undefined explicitly.
|
14
|
-
* @param {any} value The value to convert.
|
15
|
-
* @return {string | null} The converted string or null if the value is null or undefined.
|
16
|
-
*/
|
17
|
-
anyToString(value: any): string | null {
|
18
|
-
if (value == null) return null;
|
19
|
-
return typeof value === "string" ? value : `${value}`;
|
20
|
-
},
|
21
|
-
|
22
|
-
/**
|
23
|
-
* Converts any value to a number. Returns null for non-numeric values, null, or undefined.
|
24
|
-
* @param {any} value The value to convert.
|
25
|
-
* @return {number | null} The converted number or null.
|
26
|
-
*/
|
27
|
-
anyToNumber(value: any): number | null {
|
28
|
-
if (value == null) return null;
|
29
|
-
const number = Number(value);
|
30
|
-
return isNaN(number) ? null : number;
|
31
|
-
},
|
32
|
-
|
33
|
-
/**
|
34
|
-
* Converts any value to a boolean. Specifically handles string representations.
|
35
|
-
* @param {any} value The value to convert.
|
36
|
-
* @return {boolean | null} The converted boolean or null if conversion is not possible.
|
37
|
-
*/
|
38
|
-
anyToBoolean(value: any): boolean | null {
|
39
|
-
if (value == null) return null;
|
40
|
-
if (typeof value === "string") {
|
41
|
-
const trimmedValue = value.trim().toLowerCase();
|
42
|
-
if (["true", "yes", "1"].includes(trimmedValue)) return true;
|
43
|
-
if (["false", "no", "0"].includes(trimmedValue)) return false;
|
44
|
-
return null; // Return null for strings that don't explicitly match
|
45
|
-
}
|
46
|
-
return Boolean(value);
|
47
|
-
},
|
48
|
-
|
49
|
-
/**
|
50
|
-
* Converts any value to an array, attempting to split strings by a specified separator.
|
51
|
-
* @param {any} value The value to convert.
|
52
|
-
* @param {string | undefined} separator The separator to use when splitting strings.
|
53
|
-
* @return {any[]} The resulting array after conversion.
|
54
|
-
*/
|
55
|
-
anyToAnyArray(value: any): any[] {
|
56
|
-
if (Array.isArray(value)) {
|
57
|
-
return value;
|
58
|
-
} else if (typeof value === "string") {
|
59
|
-
// Let's try a few
|
60
|
-
return converterFunctions.trySplitByDifferentSeparators(value);
|
61
|
-
}
|
62
|
-
return [value];
|
63
|
-
},
|
64
|
-
|
65
|
-
/**
|
66
|
-
* Converts any value to an array of strings. If the input is already an array, returns it as is.
|
67
|
-
* Otherwise, if the input is a string, returns an array with the string as the only element.
|
68
|
-
* Otherwise, returns an empty array.
|
69
|
-
* @param {any} value The value to convert.
|
70
|
-
* @return {string[]} The resulting array after conversion.
|
71
|
-
*/
|
72
|
-
anyToStringArray(value: any): string[] {
|
73
|
-
if (Array.isArray(value)) {
|
74
|
-
return value.map((item) => String(item));
|
75
|
-
} else if (typeof value === "string" && value.length > 0) {
|
76
|
-
return [value];
|
77
|
-
}
|
78
|
-
return [];
|
79
|
-
},
|
80
|
-
|
81
|
-
/**
|
82
|
-
* A function that converts any type of value to an array of numbers.
|
83
|
-
*
|
84
|
-
* @param {any} value - the value to be converted
|
85
|
-
* @return {number[]} an array of numbers
|
86
|
-
*/
|
87
|
-
anyToNumberArray(value: any): number[] {
|
88
|
-
if (Array.isArray(value)) {
|
89
|
-
return value.map((item) => Number(item));
|
90
|
-
} else if (typeof value === "string") {
|
91
|
-
return [Number(value)];
|
92
|
-
}
|
93
|
-
return [];
|
94
|
-
},
|
95
|
-
|
96
|
-
trim(value: string): string {
|
97
|
-
try {
|
98
|
-
return value.trim();
|
99
|
-
} catch (error) {
|
100
|
-
return value;
|
101
|
-
}
|
102
|
-
},
|
103
|
-
|
104
|
-
/**
|
105
|
-
* Removes the start and end quotes from a string.
|
106
|
-
* @param value The string to remove quotes from.
|
107
|
-
* @return The string with quotes removed.
|
108
|
-
**/
|
109
|
-
removeStartEndQuotes(value: string): string {
|
110
|
-
return value.replace(/^["']|["']$/g, "");
|
111
|
-
},
|
112
|
-
|
113
|
-
/**
|
114
|
-
* Tries to split a string by different separators and returns the split that has the most uniform segment lengths.
|
115
|
-
* This can be particularly useful for structured data like phone numbers.
|
116
|
-
* @param value The string to split.
|
117
|
-
* @return The split string array that has the most uniform segment lengths.
|
118
|
-
*/
|
119
|
-
trySplitByDifferentSeparators(value: string): string[] {
|
120
|
-
const separators = [",", ";", "|", ":", "/", "\\"];
|
121
|
-
let bestSplit: string[] = [];
|
122
|
-
let bestScore = -Infinity;
|
123
|
-
|
124
|
-
for (const separator of separators) {
|
125
|
-
const split = value.split(separator).map((s) => s.trim()); // Ensure we trim spaces
|
126
|
-
if (split.length <= 1) continue; // Skip if no actual splitting occurred
|
127
|
-
|
128
|
-
// Calculate uniformity in segment length
|
129
|
-
const lengths = split.map((segment) => segment.length);
|
130
|
-
const averageLength = lengths.reduce((a, b) => a + b, 0) / lengths.length;
|
131
|
-
const lengthVariance =
|
132
|
-
lengths.reduce(
|
133
|
-
(total, length) => total + Math.pow(length - averageLength, 2),
|
134
|
-
0
|
135
|
-
) / lengths.length;
|
136
|
-
|
137
|
-
// Adjust scoring to prioritize splits with lower variance and/or specific segment count if needed
|
138
|
-
const score = split.length / (1 + lengthVariance); // Adjusted to prioritize lower variance
|
139
|
-
|
140
|
-
// Update bestSplit if this split has a better score
|
141
|
-
if (score > bestScore) {
|
142
|
-
bestSplit = split;
|
143
|
-
bestScore = score;
|
144
|
-
}
|
145
|
-
}
|
146
|
-
|
147
|
-
// If no suitable split was found, return the original value as a single-element array
|
148
|
-
if (bestSplit.length === 0) {
|
149
|
-
return [value];
|
150
|
-
}
|
151
|
-
|
152
|
-
return bestSplit;
|
153
|
-
},
|
154
|
-
|
155
|
-
joinValues(values: any[]): any {
|
156
|
-
try {
|
157
|
-
return values.join("");
|
158
|
-
} catch (error) {
|
159
|
-
return values;
|
160
|
-
}
|
161
|
-
},
|
162
|
-
|
163
|
-
joinBySpace(values: any[]): any {
|
164
|
-
try {
|
165
|
-
return values.join(" ");
|
166
|
-
} catch (error) {
|
167
|
-
return values;
|
168
|
-
}
|
169
|
-
},
|
170
|
-
|
171
|
-
joinByComma(values: any[]): any {
|
172
|
-
try {
|
173
|
-
return values.join(",");
|
174
|
-
} catch (error) {
|
175
|
-
return values;
|
176
|
-
}
|
177
|
-
},
|
178
|
-
|
179
|
-
joinByPipe(values: any[]): any {
|
180
|
-
try {
|
181
|
-
return values.join("|");
|
182
|
-
} catch (error) {
|
183
|
-
return values;
|
184
|
-
}
|
185
|
-
},
|
186
|
-
|
187
|
-
joinBySemicolon(values: any[]): any {
|
188
|
-
try {
|
189
|
-
return values.join(";");
|
190
|
-
} catch (error) {
|
191
|
-
return values;
|
192
|
-
}
|
193
|
-
},
|
194
|
-
|
195
|
-
joinByColon(values: any[]): any {
|
196
|
-
try {
|
197
|
-
return values.join(":");
|
198
|
-
} catch (error) {
|
199
|
-
return values;
|
200
|
-
}
|
201
|
-
},
|
202
|
-
|
203
|
-
joinBySlash(values: any[]): any {
|
204
|
-
try {
|
205
|
-
return values.join("/");
|
206
|
-
} catch (error) {
|
207
|
-
return values;
|
208
|
-
}
|
209
|
-
},
|
210
|
-
|
211
|
-
joinByHyphen(values: any[]): any {
|
212
|
-
try {
|
213
|
-
return values.join("-");
|
214
|
-
} catch (error) {
|
215
|
-
return values;
|
216
|
-
}
|
217
|
-
},
|
218
|
-
|
219
|
-
splitByComma(value: string): any {
|
220
|
-
try {
|
221
|
-
return value.split(",");
|
222
|
-
} catch (error) {
|
223
|
-
return value;
|
224
|
-
}
|
225
|
-
},
|
226
|
-
|
227
|
-
splitByPipe(value: string): any {
|
228
|
-
try {
|
229
|
-
return value.split("|");
|
230
|
-
} catch (error) {
|
231
|
-
return value;
|
232
|
-
}
|
233
|
-
},
|
234
|
-
|
235
|
-
splitBySemicolon(value: string): any {
|
236
|
-
try {
|
237
|
-
return value.split(";");
|
238
|
-
} catch (error) {
|
239
|
-
return value;
|
240
|
-
}
|
241
|
-
},
|
242
|
-
|
243
|
-
splitByColon(value: string): any {
|
244
|
-
try {
|
245
|
-
return value.split(":");
|
246
|
-
} catch (error) {
|
247
|
-
return value;
|
248
|
-
}
|
249
|
-
},
|
250
|
-
|
251
|
-
splitBySlash(value: string): any {
|
252
|
-
try {
|
253
|
-
return value.split("/");
|
254
|
-
} catch (error) {
|
255
|
-
return value;
|
256
|
-
}
|
257
|
-
},
|
258
|
-
|
259
|
-
splitByBackslash(value: string): any {
|
260
|
-
try {
|
261
|
-
return value.split("\\");
|
262
|
-
} catch (error) {
|
263
|
-
return value;
|
264
|
-
}
|
265
|
-
},
|
266
|
-
|
267
|
-
splitBySpace(value: string): any {
|
268
|
-
try {
|
269
|
-
return value.split(" ");
|
270
|
-
} catch (error) {
|
271
|
-
return value;
|
272
|
-
}
|
273
|
-
},
|
274
|
-
|
275
|
-
splitByDot(value: string): any {
|
276
|
-
try {
|
277
|
-
return value.split(".");
|
278
|
-
} catch (error) {
|
279
|
-
return value;
|
280
|
-
}
|
281
|
-
},
|
282
|
-
|
283
|
-
splitByUnderscore(value: string): any {
|
284
|
-
try {
|
285
|
-
return value.split("_");
|
286
|
-
} catch (error) {
|
287
|
-
return value;
|
288
|
-
}
|
289
|
-
},
|
290
|
-
|
291
|
-
splitByHyphen(value: string): any {
|
292
|
-
try {
|
293
|
-
return value.split("-");
|
294
|
-
} catch (error) {
|
295
|
-
return value;
|
296
|
-
}
|
297
|
-
},
|
298
|
-
|
299
|
-
/**
|
300
|
-
* Takes the first element of an array and returns it.
|
301
|
-
* @param {any[]} value The array to take the first element from.
|
302
|
-
* @return {any} The first element of the array.
|
303
|
-
*/
|
304
|
-
pickFirstElement(value: any[]): any {
|
305
|
-
try {
|
306
|
-
return value[0];
|
307
|
-
} catch (error) {
|
308
|
-
return value;
|
309
|
-
}
|
310
|
-
},
|
311
|
-
|
312
|
-
/**
|
313
|
-
* Takes the last element of an array and returns it.
|
314
|
-
* @param {any[]} value The array to take the last element from.
|
315
|
-
* @return {any} The last element of the array.
|
316
|
-
*/
|
317
|
-
pickLastElement(value: any[]): any {
|
318
|
-
try {
|
319
|
-
return value[value.length - 1];
|
320
|
-
} catch (error) {
|
321
|
-
return value;
|
322
|
-
}
|
323
|
-
},
|
324
|
-
|
325
|
-
/**
|
326
|
-
* Converts an object to a JSON string.
|
327
|
-
* @param {any} object The object to convert.
|
328
|
-
* @return {string} The JSON string representation of the object.
|
329
|
-
*/
|
330
|
-
stringifyObject(object: any): string {
|
331
|
-
return JSON.stringify(object);
|
332
|
-
},
|
333
|
-
|
334
|
-
/**
|
335
|
-
* Converts a JSON string to an object.
|
336
|
-
* @param {string} jsonString The JSON string to convert.
|
337
|
-
* @return {any} The object representation of the JSON string.
|
338
|
-
*/
|
339
|
-
parseObject(jsonString: string): any {
|
340
|
-
return JSON.parse(jsonString);
|
341
|
-
},
|
342
|
-
|
343
|
-
convertPhoneStringToUSInternational(value: string): string {
|
344
|
-
// Normalize input: Remove all non-digit characters except the leading +
|
345
|
-
const normalizedValue = value.startsWith("+")
|
346
|
-
? "+" + value.slice(1).replace(/\D/g, "")
|
347
|
-
: value.replace(/\D/g, "");
|
348
|
-
|
349
|
-
// Check if the value is not a string or doesn't contain digits, return as is
|
350
|
-
if (typeof normalizedValue !== "string" || !/\d/.test(normalizedValue))
|
351
|
-
return value;
|
352
|
-
|
353
|
-
// Handle numbers with a leading + (indicating an international format)
|
354
|
-
if (normalizedValue.startsWith("+")) {
|
355
|
-
// If the number is already in a valid international format, return as is
|
356
|
-
if (normalizedValue.length > 11 && normalizedValue.length <= 15) {
|
357
|
-
return normalizedValue;
|
358
|
-
}
|
359
|
-
} else {
|
360
|
-
// For numbers without a leading +, check the length and format
|
361
|
-
if (normalizedValue.length === 10) {
|
362
|
-
// US numbers without country code, prepend +1
|
363
|
-
return `+1${normalizedValue}`;
|
364
|
-
} else if (
|
365
|
-
normalizedValue.length === 11 &&
|
366
|
-
normalizedValue.startsWith("1")
|
367
|
-
) {
|
368
|
-
// US numbers with country code but missing +, prepend +
|
369
|
-
return `+${normalizedValue}`;
|
370
|
-
}
|
371
|
-
}
|
372
|
-
|
373
|
-
// For numbers that don't fit expected formats, return the original value
|
374
|
-
return value;
|
375
|
-
},
|
376
|
-
|
377
|
-
convertEmptyToNull(value: any): any {
|
378
|
-
if (Array.isArray(value)) {
|
379
|
-
return value.map((item) => this.convertEmptyToNull(item));
|
380
|
-
}
|
381
|
-
if (_.isEmpty(value)) return null;
|
382
|
-
return value;
|
383
|
-
},
|
384
|
-
|
385
|
-
/**
|
386
|
-
* A function that removes invalid elements from an array
|
387
|
-
*
|
388
|
-
* @param {any[]} array - the input array
|
389
|
-
* @return {any[]} the filtered array without invalid elements
|
390
|
-
*/
|
391
|
-
removeInvalidElements(array: any[]): any[] {
|
392
|
-
if (!Array.isArray(array)) return array;
|
393
|
-
return _.filter(
|
394
|
-
array,
|
395
|
-
(element) =>
|
396
|
-
element !== null &&
|
397
|
-
element !== undefined &&
|
398
|
-
element !== "" &&
|
399
|
-
element !== "undefined" &&
|
400
|
-
element !== "null" &&
|
401
|
-
!_.isEmpty(element)
|
402
|
-
);
|
403
|
-
},
|
404
|
-
|
405
|
-
validateOrNullEmail(email: string): string | null {
|
406
|
-
if (!email) return null;
|
407
|
-
const emailRegex = /^[\w\-\.]+@([\w-]+\.)+[\w-]{2,}$/;
|
408
|
-
return emailRegex.test(email) ? email : null;
|
409
|
-
},
|
410
|
-
|
411
|
-
/**
|
412
|
-
* Tries to parse a date from various formats using Luxon with enhanced error reporting.
|
413
|
-
* @param {string | number} input The input date as a string or timestamp.
|
414
|
-
* @return {string | null} The parsed date in ISO 8601 format or null if parsing failed.
|
415
|
-
*/
|
416
|
-
safeParseDate(input: string | number): number | null {
|
417
|
-
const formats = [
|
418
|
-
"M/d/yyyy HH:mm:ss", // U.S. style with time
|
419
|
-
"d/M/yyyy HH:mm:ss", // Rest of the world style with time
|
420
|
-
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", // ISO 8601 format
|
421
|
-
"yyyy-MM-dd'T'HH:mm:ss", // ISO 8601 without milliseconds
|
422
|
-
"yyyy-MM-dd HH:mm:ss", // SQL datetime format (common log format)
|
423
|
-
"M/d/yyyy", // U.S. style without time
|
424
|
-
"d/M/yyyy", // Rest of the world style without time
|
425
|
-
"yyyy-MM-dd", // ISO date format
|
426
|
-
"dd-MM-yyyy",
|
427
|
-
"MM-dd-yyyy",
|
428
|
-
"dd/MM/yyyy",
|
429
|
-
"MM/dd/yyyy",
|
430
|
-
"dd.MM.yyyy",
|
431
|
-
"MM.dd.yyyy",
|
432
|
-
"yyyy.MM.dd",
|
433
|
-
"yyyy/MM/dd",
|
434
|
-
"yyyy/MM/dd HH:mm",
|
435
|
-
"yyyy-MM-dd HH:mm",
|
436
|
-
"M/d/yyyy h:mm:ss tt", // U.S. style with 12-hour clock
|
437
|
-
"d/M/yyyy h:mm:ss tt", // Rest of the world style with 12-hour clock
|
438
|
-
"h:mm tt", // Time only with 12-hour clock
|
439
|
-
"HH:mm:ss", // Time only with 24-hour clock
|
440
|
-
"HH:mm", // Time only without seconds, 24-hour clock
|
441
|
-
"h:mm tt M/d/yyyy", // 12-hour clock time followed by U.S. style date
|
442
|
-
"h:mm tt d/M/yyyy", // 12-hour clock time followed by Rest of the world style date
|
443
|
-
"yyyy-MM-dd'T'HH:mm:ss.SSSZ", // ISO 8601 with timezone offset
|
444
|
-
"yyyy-MM-dd'T'HH:mm:ssZ", // ISO 8601 without milliseconds but with timezone offset
|
445
|
-
"E, dd MMM yyyy HH:mm:ss z", // RFC 2822 format
|
446
|
-
"EEEE, MMMM d, yyyy", // Full textual date
|
447
|
-
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", // ISO 8601 with extended timezone offset
|
448
|
-
"yyyy-MM-dd'T'HH:mm:ssXXX", // ISO 8601 without milliseconds but with extended timezone offset
|
449
|
-
"dd-MMM-yyyy", // Textual month with day and year
|
450
|
-
];
|
451
|
-
|
452
|
-
// Attempt to parse as a timestamp first if input is a number
|
453
|
-
if (typeof input === "number") {
|
454
|
-
const dateFromMillis = DateTime.fromMillis(input);
|
455
|
-
if (dateFromMillis.isValid) {
|
456
|
-
return dateFromMillis.toMillis();
|
457
|
-
}
|
458
|
-
}
|
459
|
-
|
460
|
-
// Attempt to parse as an ISO string or SQL string
|
461
|
-
let date = DateTime.fromISO(String(input));
|
462
|
-
if (!date.isValid) date = DateTime.fromSQL(String(input));
|
463
|
-
|
464
|
-
// Try each custom format if still not valid
|
465
|
-
for (const format of formats) {
|
466
|
-
if (!date.isValid) {
|
467
|
-
date = DateTime.fromFormat(String(input), format);
|
468
|
-
}
|
469
|
-
}
|
470
|
-
|
471
|
-
// Return null if no valid date could be parsed
|
472
|
-
if (!date.isValid) {
|
473
|
-
return null;
|
474
|
-
}
|
475
|
-
|
476
|
-
return date.toMillis();
|
477
|
-
},
|
478
|
-
safeParseDateToYYYYMMDD(input: string | number): string | null {
|
479
|
-
const formats = [
|
480
|
-
"M/d/yyyy HH:mm:ss", // U.S. style with time
|
481
|
-
"d/M/yyyy HH:mm:ss", // Rest of the world style with time
|
482
|
-
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", // ISO 8601 format
|
483
|
-
"yyyy-MM-dd'T'HH:mm:ss", // ISO 8601 without milliseconds
|
484
|
-
"yyyy-MM-dd HH:mm:ss", // SQL datetime format (common log format)
|
485
|
-
"M/d/yyyy", // U.S. style without time
|
486
|
-
"d/M/yyyy", // Rest of the world style without time
|
487
|
-
"yyyy-MM-dd", // ISO date format
|
488
|
-
"dd-MM-yyyy",
|
489
|
-
"MM-dd-yyyy",
|
490
|
-
"dd/MM/yyyy",
|
491
|
-
"MM/dd/yyyy",
|
492
|
-
"dd.MM.yyyy",
|
493
|
-
"MM.dd.yyyy",
|
494
|
-
"yyyy.MM.dd",
|
495
|
-
"yyyy/MM/dd",
|
496
|
-
"yyyy/MM/dd HH:mm",
|
497
|
-
"yyyy-MM-dd HH:mm",
|
498
|
-
"M/d/yyyy h:mm:ss tt", // U.S. style with 12-hour clock
|
499
|
-
"d/M/yyyy h:mm:ss tt", // Rest of the world style with 12-hour clock
|
500
|
-
"h:mm tt", // Time only with 12-hour clock
|
501
|
-
"HH:mm:ss", // Time only with 24-hour clock
|
502
|
-
"HH:mm", // Time only without seconds, 24-hour clock
|
503
|
-
"h:mm tt M/d/yyyy", // 12-hour clock time followed by U.S. style date
|
504
|
-
"h:mm tt d/M/yyyy", // 12-hour clock time followed by Rest of the world style date
|
505
|
-
"yyyy-MM-dd'T'HH:mm:ss.SSSZ", // ISO 8601 with timezone offset
|
506
|
-
"yyyy-MM-dd'T'HH:mm:ssZ", // ISO 8601 without milliseconds but with timezone offset
|
507
|
-
"E, dd MMM yyyy HH:mm:ss z", // RFC 2822 format
|
508
|
-
"EEEE, MMMM d, yyyy", // Full textual date
|
509
|
-
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", // ISO 8601 with extended timezone offset
|
510
|
-
"yyyy-MM-dd'T'HH:mm:ssXXX", // ISO 8601 without milliseconds but with extended timezone offset
|
511
|
-
"dd-MMM-yyyy", // Textual month with day and year
|
512
|
-
];
|
513
|
-
|
514
|
-
// Attempt to parse as a timestamp first if input is a number
|
515
|
-
if (typeof input === "number") {
|
516
|
-
const dateFromMillis = DateTime.fromMillis(input);
|
517
|
-
if (dateFromMillis.isValid) {
|
518
|
-
return dateFromMillis.toISODate();
|
519
|
-
}
|
520
|
-
}
|
521
|
-
|
522
|
-
// Attempt to parse as an ISO string or SQL string
|
523
|
-
let date = DateTime.fromISO(String(input));
|
524
|
-
if (!date.isValid) date = DateTime.fromSQL(String(input));
|
525
|
-
|
526
|
-
// Try each custom format if still not valid
|
527
|
-
for (const format of formats) {
|
528
|
-
if (!date.isValid) {
|
529
|
-
date = DateTime.fromFormat(String(input), format);
|
530
|
-
}
|
531
|
-
}
|
532
|
-
|
533
|
-
// Return null if no valid date could be parsed
|
534
|
-
if (!date.isValid) {
|
535
|
-
return null;
|
536
|
-
}
|
537
|
-
|
538
|
-
return date.toISODate(); // Corrected to return the date in YYYY-MM-DD format
|
539
|
-
},
|
540
|
-
};
|
541
|
-
|
542
6
|
/**
|
543
7
|
* Deeply converts all properties of an object (or array) to strings.
|
544
8
|
* @param data The input data to convert.
|
@@ -597,9 +61,6 @@ export const convertObjectBySchema = (
|
|
597
61
|
}, {});
|
598
62
|
};
|
599
63
|
|
600
|
-
type AttributeMappings =
|
601
|
-
AppwriteConfig["collections"][number]["importDefs"][number]["attributeMappings"];
|
602
|
-
|
603
64
|
/**
|
604
65
|
* Converts the keys of an object based on a provided attributeMappings.
|
605
66
|
* Each key in the object is checked against attributeMappings; if a matching entry is found,
|
@@ -11,7 +11,7 @@ import {
|
|
11
11
|
type ImportDef,
|
12
12
|
type ImportDefs,
|
13
13
|
type RelationshipAttribute,
|
14
|
-
} from "
|
14
|
+
} from "appwrite-utils";
|
15
15
|
import path from "path";
|
16
16
|
import fs from "fs";
|
17
17
|
import { convertObjectByAttributeMappings } from "./converters.js";
|
@@ -216,6 +216,9 @@ export class DataLoader {
|
|
216
216
|
if (db.$id !== dbId) {
|
217
217
|
continue;
|
218
218
|
}
|
219
|
+
if (!this.config.collections) {
|
220
|
+
continue;
|
221
|
+
}
|
219
222
|
for (let index = 0; index < this.config.collections.length; index++) {
|
220
223
|
const collectionConfig = this.config.collections[index];
|
221
224
|
let collection = CollectionCreateSchema.parse(collectionConfig);
|
@@ -285,6 +288,9 @@ export class DataLoader {
|
|
285
288
|
if (db.$id !== dbId) {
|
286
289
|
continue;
|
287
290
|
}
|
291
|
+
if (!this.config.collections) {
|
292
|
+
continue;
|
293
|
+
}
|
288
294
|
// Iterate over the configured collections to process each
|
289
295
|
for (const collectionConfig of this.config.collections) {
|
290
296
|
const collection = collectionConfig;
|
@@ -345,7 +351,9 @@ export class DataLoader {
|
|
345
351
|
this.config.usersCollectionName
|
346
352
|
);
|
347
353
|
const usersCollectionPrimaryKeyFields = new Set();
|
348
|
-
|
354
|
+
if (!this.config.collections) {
|
355
|
+
return;
|
356
|
+
}
|
349
357
|
// Collect primary key fields from the users collection definitions
|
350
358
|
this.config.collections.forEach((collection) => {
|
351
359
|
if (this.getCollectionKey(collection.name) === usersCollectionKey) {
|
@@ -390,6 +398,9 @@ export class DataLoader {
|
|
390
398
|
}
|
391
399
|
|
392
400
|
async updateOldReferencesForNew() {
|
401
|
+
if (!this.config.collections) {
|
402
|
+
return;
|
403
|
+
}
|
393
404
|
for (const collectionConfig of this.config.collections) {
|
394
405
|
const collectionKey = this.getCollectionKey(collectionConfig.name);
|
395
406
|
const collectionData = this.importMap.get(collectionKey);
|
@@ -472,6 +483,9 @@ export class DataLoader {
|
|
472
483
|
}
|
473
484
|
|
474
485
|
async updateReferencesInRelatedCollections() {
|
486
|
+
if (!this.config.collections) {
|
487
|
+
return;
|
488
|
+
}
|
475
489
|
// Iterate over each collection configuration
|
476
490
|
for (const collectionConfig of this.config.collections) {
|
477
491
|
const collectionKey = this.getCollectionKey(collectionConfig.name);
|
@@ -1174,6 +1188,9 @@ export class DataLoader {
|
|
1174
1188
|
}
|
1175
1189
|
|
1176
1190
|
private updateReferencesBasedOnAttributeMappings() {
|
1191
|
+
if (!this.config.collections) {
|
1192
|
+
return;
|
1193
|
+
}
|
1177
1194
|
this.config.collections.forEach((collectionConfig) => {
|
1178
1195
|
const collectionName = collectionConfig.name;
|
1179
1196
|
const collectionData = this.importMap.get(
|
@@ -2,7 +2,7 @@ import type {
|
|
2
2
|
AppwriteConfig,
|
3
3
|
Attribute,
|
4
4
|
RelationshipAttribute,
|
5
|
-
} from "
|
5
|
+
} from "appwrite-utils";
|
6
6
|
|
7
7
|
// Helper function to categorize collections based on relationship sides
|
8
8
|
export const categorizeCollectionByRelationshipSide = (
|
@@ -40,6 +40,9 @@ export const getDependencies = (attributes: Attribute[]): string[] => {
|
|
40
40
|
export const sortCollections = (
|
41
41
|
configCollections: AppwriteConfig["collections"]
|
42
42
|
): AppwriteConfig["collections"] => {
|
43
|
+
if (!configCollections) {
|
44
|
+
return [];
|
45
|
+
}
|
43
46
|
// Categorize collections based on their relationship sides
|
44
47
|
const parentCollections = configCollections.filter(
|
45
48
|
({ attributes }) =>
|
@@ -9,29 +9,16 @@ import type {
|
|
9
9
|
AppwriteConfig,
|
10
10
|
ConfigCollection,
|
11
11
|
ConfigDatabase,
|
12
|
-
ImportDef,
|
13
12
|
AttributeMappings,
|
14
|
-
} from "
|
13
|
+
} from "appwrite-utils";
|
15
14
|
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
15
|
import _ from "lodash";
|
21
|
-
import { documentExists } from "./collections.js";
|
22
16
|
import { areCollectionNamesSame } from "../utils/index.js";
|
23
17
|
import type { SetupOptions } from "../utilsController.js";
|
24
18
|
import { resolveAndUpdateRelationships } from "./relationships.js";
|
25
|
-
import { AuthUserCreateSchema, type AuthUserCreate } from "../types.js";
|
26
19
|
import { UsersController } from "./users.js";
|
27
20
|
import { logger } from "./logging.js";
|
28
|
-
import {
|
29
|
-
ContextObject,
|
30
|
-
createOrFindAfterImportOperation,
|
31
|
-
getAfterImportOperations,
|
32
|
-
splitIntoBatches,
|
33
|
-
updateOperation,
|
34
|
-
} from "./migrationHelper.js";
|
21
|
+
import { updateOperation } from "./migrationHelper.js";
|
35
22
|
import {
|
36
23
|
BatchSchema,
|
37
24
|
OperationCreateSchema,
|
@@ -121,6 +108,9 @@ export class ImportController {
|
|
121
108
|
}
|
122
109
|
|
123
110
|
async importCollections(db: ConfigDatabase, dataLoader: DataLoader) {
|
111
|
+
if (!this.config.collections) {
|
112
|
+
return;
|
113
|
+
}
|
124
114
|
for (const collection of this.config.collections) {
|
125
115
|
let isUsersCollection =
|
126
116
|
dataLoader.getCollectionKey(this.config.usersCollectionName) ===
|