appwrite-utils-cli 0.10.81 → 0.10.83
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 +2 -0
- package/dist/collections/attributes.js +86 -41
- package/dist/collections/methods.d.ts +6 -0
- package/dist/collections/methods.js +159 -24
- package/dist/migrations/appwriteToX.js +1 -1
- package/dist/migrations/attributes.js +0 -1
- package/dist/migrations/converters.js +3 -4
- package/dist/migrations/dataLoader.js +3 -3
- package/dist/migrations/importController.js +0 -1
- package/dist/migrations/queue.js +1 -2
- package/dist/migrations/relationships.js +1 -1
- package/dist/migrations/users.js +5 -4
- package/dist/migrations/validationRules.js +30 -30
- package/package.json +2 -2
- package/src/collections/attributes.ts +126 -50
- package/src/collections/methods.ts +259 -28
- package/src/migrations/appwriteToX.ts +4 -4
- package/src/migrations/attributes.ts +0 -1
- package/src/migrations/converters.ts +3 -5
- package/src/migrations/dataLoader.ts +4 -4
- package/src/migrations/importController.ts +0 -1
- package/src/migrations/queue.ts +1 -2
- package/src/migrations/relationships.ts +1 -1
- package/src/migrations/users.ts +8 -7
- package/src/migrations/validationRules.ts +56 -31
- package/src/migrations/collections.ts +0 -545
@@ -1,11 +1,11 @@
|
|
1
|
-
import
|
1
|
+
import { isNumber, isString, isBoolean, isArray, isPlainObject, isNull, isUndefined, isDate, isEmpty, isInteger, isArrayLike, isArrayLikeObject, isFunction, isLength, isMap, isSet, isRegExp, isSymbol, isObjectLike, isSafeInteger, isTypedArray, isEqual, isMatch, has, get, } from "es-toolkit/compat";
|
2
2
|
export const validationRules = {
|
3
|
-
isNumber: (value) =>
|
4
|
-
isString: (value) =>
|
5
|
-
isBoolean: (value) =>
|
6
|
-
isArray: (value) =>
|
7
|
-
isObject: (value) =>
|
8
|
-
isNull: (value) =>
|
3
|
+
isNumber: (value) => isNumber(value),
|
4
|
+
isString: (value) => isString(value),
|
5
|
+
isBoolean: (value) => isBoolean(value),
|
6
|
+
isArray: (value) => isArray(value),
|
7
|
+
isObject: (value) => isPlainObject(value) && !isArray(value) && !isFunction(value),
|
8
|
+
isNull: (value) => isNull(value),
|
9
9
|
isValidEmail: (value) => value.match(/^[\w\-\.]+@([\w-]+\.)+[\w-]{2,}$/) !== null,
|
10
10
|
isValidPhone: (value) => value.match(/^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/im) !==
|
11
11
|
null,
|
@@ -16,27 +16,27 @@ export const validationRules = {
|
|
16
16
|
isValidHexAlpha: (value) => value.match(/^#([a-f0-9]{8}|[a-f0-9]{4})$/i) !== null,
|
17
17
|
isValidDate: (value) => value.match(/^\d{4}-\d{2}-\d{2}$/) !== null,
|
18
18
|
isValidTime: (value) => value.match(/^\d{2}:\d{2}(:\d{2})?$/) !== null,
|
19
|
-
isNullish: (value) =>
|
20
|
-
isUndefined: (value) =>
|
21
|
-
isDefined: (value) => !
|
22
|
-
isDate: (value) =>
|
23
|
-
isEmpty: (value) =>
|
24
|
-
isInteger: (value) =>
|
25
|
-
isFloat: (value) =>
|
26
|
-
isArrayLike: (value) =>
|
27
|
-
isArrayLikeObject: (value) =>
|
28
|
-
isFunction: (value) =>
|
29
|
-
isLength: (value) =>
|
30
|
-
isMap: (value) =>
|
31
|
-
isSet: (value) =>
|
32
|
-
isRegExp: (value) =>
|
33
|
-
isSymbol: (value) =>
|
34
|
-
isObjectLike: (value) =>
|
35
|
-
isPlainObject: (value) =>
|
36
|
-
isSafeInteger: (value) =>
|
37
|
-
isTypedArray: (value) =>
|
38
|
-
isEqual: (value, other) =>
|
39
|
-
isMatch: (object, source) =>
|
40
|
-
has: (object, path) =>
|
41
|
-
get: (object, path, defaultValue) =>
|
19
|
+
isNullish: (value) => isNull(value) || isUndefined(value),
|
20
|
+
isUndefined: (value) => isUndefined(value),
|
21
|
+
isDefined: (value) => !isUndefined(value) && !isNull(value) && !isEmpty(value),
|
22
|
+
isDate: (value) => isDate(value),
|
23
|
+
isEmpty: (value) => isEmpty(value),
|
24
|
+
isInteger: (value) => isInteger(value),
|
25
|
+
isFloat: (value) => isNumber(value) && !isInteger(value),
|
26
|
+
isArrayLike: (value) => isArrayLike(value),
|
27
|
+
isArrayLikeObject: (value) => isArrayLikeObject(value),
|
28
|
+
isFunction: (value) => isFunction(value),
|
29
|
+
isLength: (value) => isLength(value),
|
30
|
+
isMap: (value) => isMap(value),
|
31
|
+
isSet: (value) => isSet(value),
|
32
|
+
isRegExp: (value) => isRegExp(value),
|
33
|
+
isSymbol: (value) => isSymbol(value),
|
34
|
+
isObjectLike: (value) => isObjectLike(value),
|
35
|
+
isPlainObject: (value) => isPlainObject(value),
|
36
|
+
isSafeInteger: (value) => isSafeInteger(value),
|
37
|
+
isTypedArray: (value) => isTypedArray(value),
|
38
|
+
isEqual: (value, other) => isEqual(value, other),
|
39
|
+
isMatch: (object, source) => isMatch(object, source),
|
40
|
+
has: (object, path) => has(object, path),
|
41
|
+
get: (object, path, defaultValue) => get(object, path, defaultValue),
|
42
42
|
};
|
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.10.
|
4
|
+
"version": "0.10.83",
|
5
5
|
"main": "src/main.ts",
|
6
6
|
"type": "module",
|
7
7
|
"repository": {
|
@@ -35,10 +35,10 @@
|
|
35
35
|
"chalk": "^5.3.0",
|
36
36
|
"cli-progress": "^3.12.0",
|
37
37
|
"commander": "^12.1.0",
|
38
|
+
"es-toolkit": "^1.32.0",
|
38
39
|
"ignore": "^6.0.2",
|
39
40
|
"inquirer": "^9.3.6",
|
40
41
|
"js-yaml": "^4.1.0",
|
41
|
-
"lodash": "^4.17.21",
|
42
42
|
"luxon": "^3.5.0",
|
43
43
|
"nanostores": "^0.10.3",
|
44
44
|
"node-appwrite": "^14.1.0",
|
@@ -5,7 +5,6 @@ import {
|
|
5
5
|
type Attribute,
|
6
6
|
} from "appwrite-utils";
|
7
7
|
import { nameToIdMapping, enqueueOperation } from "../migrations/queue.js";
|
8
|
-
import _ from "lodash";
|
9
8
|
import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
10
9
|
import chalk from "chalk";
|
11
10
|
|
@@ -14,24 +13,24 @@ const attributesSame = (
|
|
14
13
|
configAttribute: Attribute
|
15
14
|
): boolean => {
|
16
15
|
const attributesToCheck = [
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
16
|
+
"key",
|
17
|
+
"type",
|
18
|
+
"array",
|
19
|
+
"encrypted",
|
20
|
+
"required",
|
21
|
+
"size",
|
22
|
+
"min",
|
23
|
+
"max",
|
24
|
+
"xdefault",
|
25
|
+
"elements",
|
26
|
+
"relationType",
|
27
|
+
"twoWay",
|
28
|
+
"twoWayKey",
|
29
|
+
"onDelete",
|
30
|
+
"relatedCollection",
|
32
31
|
];
|
33
32
|
|
34
|
-
return attributesToCheck.every(attr => {
|
33
|
+
return attributesToCheck.every((attr) => {
|
35
34
|
// Check if both objects have the attribute
|
36
35
|
const dbHasAttr = attr in databaseAttribute;
|
37
36
|
const configHasAttr = attr in configAttribute;
|
@@ -42,7 +41,10 @@ const attributesSame = (
|
|
42
41
|
const configValue = configAttribute[attr as keyof typeof configAttribute];
|
43
42
|
|
44
43
|
// Consider undefined and null as equivalent
|
45
|
-
if (
|
44
|
+
if (
|
45
|
+
(dbValue === undefined || dbValue === null) &&
|
46
|
+
(configValue === undefined || configValue === null)
|
47
|
+
) {
|
46
48
|
return true;
|
47
49
|
}
|
48
50
|
|
@@ -91,10 +93,18 @@ export const createOrUpdateAttribute = async (
|
|
91
93
|
foundAttribute = undefined;
|
92
94
|
}
|
93
95
|
|
94
|
-
if (
|
96
|
+
if (
|
97
|
+
foundAttribute &&
|
98
|
+
attributesSame(foundAttribute, attribute) &&
|
99
|
+
updateEnabled
|
100
|
+
) {
|
95
101
|
// No need to do anything, they are the same
|
96
102
|
return;
|
97
|
-
} else if (
|
103
|
+
} else if (
|
104
|
+
foundAttribute &&
|
105
|
+
!attributesSame(foundAttribute, attribute) &&
|
106
|
+
updateEnabled
|
107
|
+
) {
|
98
108
|
// console.log(
|
99
109
|
// `Updating attribute with same key ${attribute.key} but different values`
|
100
110
|
// );
|
@@ -103,9 +113,15 @@ export const createOrUpdateAttribute = async (
|
|
103
113
|
...attribute,
|
104
114
|
};
|
105
115
|
action = "update";
|
106
|
-
} else if (
|
116
|
+
} else if (
|
117
|
+
!updateEnabled &&
|
118
|
+
foundAttribute &&
|
119
|
+
!attributesSame(foundAttribute, attribute)
|
120
|
+
) {
|
107
121
|
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
108
|
-
console.log(
|
122
|
+
console.log(
|
123
|
+
`Deleted attribute: ${attribute.key} to recreate it because they diff (update disabled temporarily)`
|
124
|
+
);
|
109
125
|
return;
|
110
126
|
}
|
111
127
|
|
@@ -168,7 +184,9 @@ export const createOrUpdateAttribute = async (
|
|
168
184
|
finalAttribute.key,
|
169
185
|
finalAttribute.size,
|
170
186
|
finalAttribute.required || false,
|
171
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
187
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
188
|
+
? finalAttribute.xdefault
|
189
|
+
: null,
|
172
190
|
finalAttribute.array || false,
|
173
191
|
finalAttribute.encrypted
|
174
192
|
)
|
@@ -181,7 +199,9 @@ export const createOrUpdateAttribute = async (
|
|
181
199
|
collection.$id,
|
182
200
|
finalAttribute.key,
|
183
201
|
finalAttribute.required || false,
|
184
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
202
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
203
|
+
? finalAttribute.xdefault
|
204
|
+
: null
|
185
205
|
)
|
186
206
|
);
|
187
207
|
}
|
@@ -209,7 +229,9 @@ export const createOrUpdateAttribute = async (
|
|
209
229
|
finalAttribute.required || false,
|
210
230
|
finalAttribute.min || -2147483647,
|
211
231
|
finalAttribute.max || 2147483647,
|
212
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
232
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
233
|
+
? finalAttribute.xdefault
|
234
|
+
: null,
|
213
235
|
finalAttribute.array || false
|
214
236
|
)
|
215
237
|
);
|
@@ -235,7 +257,9 @@ export const createOrUpdateAttribute = async (
|
|
235
257
|
finalAttribute.required || false,
|
236
258
|
finalAttribute.min || -2147483647,
|
237
259
|
finalAttribute.max || 2147483647,
|
238
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
260
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
261
|
+
? finalAttribute.xdefault
|
262
|
+
: null
|
239
263
|
)
|
240
264
|
);
|
241
265
|
}
|
@@ -251,7 +275,9 @@ export const createOrUpdateAttribute = async (
|
|
251
275
|
finalAttribute.required || false,
|
252
276
|
finalAttribute.min || -2147483647,
|
253
277
|
finalAttribute.max || 2147483647,
|
254
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
278
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
279
|
+
? finalAttribute.xdefault
|
280
|
+
: null,
|
255
281
|
finalAttribute.array || false
|
256
282
|
)
|
257
283
|
);
|
@@ -265,7 +291,9 @@ export const createOrUpdateAttribute = async (
|
|
265
291
|
finalAttribute.required || false,
|
266
292
|
finalAttribute.min || -2147483647,
|
267
293
|
finalAttribute.max || 2147483647,
|
268
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
294
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
295
|
+
? finalAttribute.xdefault
|
296
|
+
: null
|
269
297
|
)
|
270
298
|
);
|
271
299
|
}
|
@@ -279,7 +307,9 @@ export const createOrUpdateAttribute = async (
|
|
279
307
|
collection.$id,
|
280
308
|
finalAttribute.key,
|
281
309
|
finalAttribute.required || false,
|
282
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
310
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
311
|
+
? finalAttribute.xdefault
|
312
|
+
: null,
|
283
313
|
finalAttribute.array || false
|
284
314
|
)
|
285
315
|
);
|
@@ -291,7 +321,9 @@ export const createOrUpdateAttribute = async (
|
|
291
321
|
collection.$id,
|
292
322
|
finalAttribute.key,
|
293
323
|
finalAttribute.required || false,
|
294
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
324
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
325
|
+
? finalAttribute.xdefault
|
326
|
+
: null
|
295
327
|
)
|
296
328
|
);
|
297
329
|
}
|
@@ -305,7 +337,9 @@ export const createOrUpdateAttribute = async (
|
|
305
337
|
collection.$id,
|
306
338
|
finalAttribute.key,
|
307
339
|
finalAttribute.required || false,
|
308
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
340
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
341
|
+
? finalAttribute.xdefault
|
342
|
+
: null,
|
309
343
|
finalAttribute.array || false
|
310
344
|
)
|
311
345
|
);
|
@@ -317,7 +351,9 @@ export const createOrUpdateAttribute = async (
|
|
317
351
|
collection.$id,
|
318
352
|
finalAttribute.key,
|
319
353
|
finalAttribute.required || false,
|
320
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
354
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
355
|
+
? finalAttribute.xdefault
|
356
|
+
: null
|
321
357
|
)
|
322
358
|
);
|
323
359
|
}
|
@@ -331,7 +367,9 @@ export const createOrUpdateAttribute = async (
|
|
331
367
|
collection.$id,
|
332
368
|
finalAttribute.key,
|
333
369
|
finalAttribute.required || false,
|
334
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
370
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
371
|
+
? finalAttribute.xdefault
|
372
|
+
: null,
|
335
373
|
finalAttribute.array || false
|
336
374
|
)
|
337
375
|
);
|
@@ -343,7 +381,9 @@ export const createOrUpdateAttribute = async (
|
|
343
381
|
collection.$id,
|
344
382
|
finalAttribute.key,
|
345
383
|
finalAttribute.required || false,
|
346
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
384
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
385
|
+
? finalAttribute.xdefault
|
386
|
+
: null
|
347
387
|
)
|
348
388
|
);
|
349
389
|
}
|
@@ -357,7 +397,9 @@ export const createOrUpdateAttribute = async (
|
|
357
397
|
collection.$id,
|
358
398
|
finalAttribute.key,
|
359
399
|
finalAttribute.required || false,
|
360
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
400
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
401
|
+
? finalAttribute.xdefault
|
402
|
+
: null,
|
361
403
|
finalAttribute.array || false
|
362
404
|
)
|
363
405
|
);
|
@@ -369,7 +411,9 @@ export const createOrUpdateAttribute = async (
|
|
369
411
|
collection.$id,
|
370
412
|
finalAttribute.key,
|
371
413
|
finalAttribute.required || false,
|
372
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
414
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
415
|
+
? finalAttribute.xdefault
|
416
|
+
: null
|
373
417
|
)
|
374
418
|
);
|
375
419
|
}
|
@@ -383,7 +427,9 @@ export const createOrUpdateAttribute = async (
|
|
383
427
|
collection.$id,
|
384
428
|
finalAttribute.key,
|
385
429
|
finalAttribute.required || false,
|
386
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
430
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
431
|
+
? finalAttribute.xdefault
|
432
|
+
: null,
|
387
433
|
finalAttribute.array || false
|
388
434
|
)
|
389
435
|
);
|
@@ -395,7 +441,9 @@ export const createOrUpdateAttribute = async (
|
|
395
441
|
collection.$id,
|
396
442
|
finalAttribute.key,
|
397
443
|
finalAttribute.required || false,
|
398
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
444
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
445
|
+
? finalAttribute.xdefault
|
446
|
+
: null
|
399
447
|
)
|
400
448
|
);
|
401
449
|
}
|
@@ -410,7 +458,9 @@ export const createOrUpdateAttribute = async (
|
|
410
458
|
finalAttribute.key,
|
411
459
|
finalAttribute.elements,
|
412
460
|
finalAttribute.required || false,
|
413
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
461
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
462
|
+
? finalAttribute.xdefault
|
463
|
+
: null,
|
414
464
|
finalAttribute.array || false
|
415
465
|
)
|
416
466
|
);
|
@@ -423,7 +473,9 @@ export const createOrUpdateAttribute = async (
|
|
423
473
|
finalAttribute.key,
|
424
474
|
finalAttribute.elements,
|
425
475
|
finalAttribute.required || false,
|
426
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
476
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
477
|
+
? finalAttribute.xdefault
|
478
|
+
: null
|
427
479
|
)
|
428
480
|
);
|
429
481
|
}
|
@@ -468,26 +520,47 @@ export const createUpdateCollectionAttributes = async (
|
|
468
520
|
attributes: Attribute[]
|
469
521
|
): Promise<void> => {
|
470
522
|
console.log(
|
471
|
-
chalk.green(
|
523
|
+
chalk.green(
|
524
|
+
`Creating/Updating attributes for collection: ${collection.name}`
|
525
|
+
)
|
472
526
|
);
|
473
527
|
|
474
|
-
|
475
|
-
|
528
|
+
const existingAttributes: Attribute[] =
|
529
|
+
// @ts-expect-error
|
530
|
+
collection.attributes.map((attr) => parseAttribute(attr)) || [];
|
476
531
|
|
477
|
-
const attributesToRemove = existingAttributes.filter(
|
478
|
-
|
532
|
+
const attributesToRemove = existingAttributes.filter(
|
533
|
+
(attr) => !attributes.some((a) => a.key === attr.key)
|
534
|
+
);
|
535
|
+
const indexesToRemove = collection.indexes.filter((index) =>
|
536
|
+
attributesToRemove.some((attr) => index.attributes.includes(attr.key))
|
537
|
+
);
|
479
538
|
|
480
539
|
if (attributesToRemove.length > 0) {
|
481
540
|
if (indexesToRemove.length > 0) {
|
482
|
-
console.log(
|
541
|
+
console.log(
|
542
|
+
chalk.red(
|
543
|
+
`Removing indexes as they rely on an attribute that is being removed: ${indexesToRemove
|
544
|
+
.map((index) => index.key)
|
545
|
+
.join(", ")}`
|
546
|
+
)
|
547
|
+
);
|
483
548
|
for (const index of indexesToRemove) {
|
484
|
-
await tryAwaitWithRetry(
|
549
|
+
await tryAwaitWithRetry(
|
550
|
+
async () => await db.deleteIndex(dbId, collection.$id, index.key)
|
551
|
+
);
|
485
552
|
await delay(100);
|
486
553
|
}
|
487
554
|
}
|
488
555
|
for (const attr of attributesToRemove) {
|
489
|
-
console.log(
|
490
|
-
|
556
|
+
console.log(
|
557
|
+
chalk.red(
|
558
|
+
`Removing attribute: ${attr.key} as it is no longer in the collection`
|
559
|
+
)
|
560
|
+
);
|
561
|
+
await tryAwaitWithRetry(
|
562
|
+
async () => await db.deleteAttribute(dbId, collection.$id, attr.key)
|
563
|
+
);
|
491
564
|
await delay(50);
|
492
565
|
}
|
493
566
|
}
|
@@ -496,7 +569,10 @@ export const createUpdateCollectionAttributes = async (
|
|
496
569
|
for (let i = 0; i < attributes.length; i += batchSize) {
|
497
570
|
const batch = attributes.slice(i, i + batchSize);
|
498
571
|
const attributePromises = batch.map((attribute) =>
|
499
|
-
tryAwaitWithRetry(
|
572
|
+
tryAwaitWithRetry(
|
573
|
+
async () =>
|
574
|
+
await createOrUpdateAttribute(db, dbId, collection, attribute)
|
575
|
+
)
|
500
576
|
);
|
501
577
|
|
502
578
|
const results = await Promise.allSettled(attributePromises);
|