appwrite-utils-cli 0.9.53 → 0.9.55
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 +14 -27
- package/dist/collections/indexes.js +5 -5
- package/dist/collections/methods.js +4 -3
- package/dist/migrations/setupDatabase.js +2 -1
- package/package.json +2 -2
- package/src/collections/attributes.ts +17 -37
- package/src/collections/indexes.ts +7 -7
- package/src/collections/methods.ts +4 -3
- package/src/migrations/setupDatabase.ts +2 -0
package/README.md
CHANGED
@@ -124,6 +124,8 @@ This updated CLI ensures that developers have robust tools at their fingertips t
|
|
124
124
|
|
125
125
|
## Changelog
|
126
126
|
|
127
|
+
- 0.9.55: Updated to use `node-appwrite@14` for appwrite 1.6.0
|
128
|
+
- 0.9.54: Added small delay (`100ms`) between collection deletions, reduced other delays from `1000` to `500/250ms`
|
127
129
|
- 0.9.53: Reduced delay, went too far
|
128
130
|
- 0.9.52: Add delay after creating indexes, attributes, and others to prevent `fetch failed` errors during large-scale collection creation
|
129
131
|
- 0.9.51: Fix transfer databases, remove "ensure duplicates" check
|
@@ -11,61 +11,48 @@ const attributesSame = (databaseAttribute, configAttribute) => {
|
|
11
11
|
export const createOrUpdateAttribute = async (db, dbId, collection, attribute) => {
|
12
12
|
let action = "create";
|
13
13
|
let foundAttribute;
|
14
|
-
const updateEnabled = false;
|
15
14
|
let finalAttribute = attribute;
|
16
15
|
try {
|
17
16
|
const collectionAttr = collection.attributes.find(
|
18
|
-
// @ts-
|
17
|
+
// @ts-ignore
|
19
18
|
(attr) => attr.key === attribute.key);
|
20
19
|
foundAttribute = parseAttribute(collectionAttr);
|
21
20
|
}
|
22
21
|
catch (error) {
|
23
22
|
foundAttribute = undefined;
|
24
23
|
}
|
25
|
-
if (foundAttribute
|
26
|
-
|
27
|
-
updateEnabled) {
|
28
|
-
// Check if mutable properties have changed and set action to "update" if necessary
|
24
|
+
if (foundAttribute) {
|
25
|
+
// Check if any properties have changed
|
29
26
|
const requiredChanged = "required" in foundAttribute && "required" in attribute
|
30
27
|
? foundAttribute.required !== attribute.required
|
31
28
|
: false;
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
// : false;
|
29
|
+
const xdefaultChanged = "xdefault" in foundAttribute && "xdefault" in attribute
|
30
|
+
? foundAttribute.xdefault !== attribute.xdefault
|
31
|
+
: false;
|
36
32
|
const onDeleteChanged = foundAttribute.type === "relationship" &&
|
37
33
|
attribute.type === "relationship" &&
|
38
34
|
"onDelete" in foundAttribute &&
|
39
35
|
"onDelete" in attribute
|
40
36
|
? foundAttribute.onDelete !== attribute.onDelete
|
41
37
|
: false;
|
42
|
-
if (requiredChanged ||
|
43
|
-
|
38
|
+
if (requiredChanged ||
|
39
|
+
xdefaultChanged ||
|
40
|
+
onDeleteChanged ||
|
41
|
+
!attributesSame(foundAttribute, attribute)) {
|
42
|
+
console.log(`Updating attribute: ${attribute.key}\nRequired changed: ${requiredChanged}\nDefault changed: ${xdefaultChanged}\nOnDelete changed: ${onDeleteChanged}`);
|
44
43
|
console.log(`Found attribute: ${JSON.stringify(foundAttribute, null, 2)}`);
|
45
|
-
console.log(`
|
44
|
+
console.log(`New attribute: ${JSON.stringify(attribute, null, 2)}`);
|
46
45
|
finalAttribute = {
|
47
|
-
...attribute,
|
48
46
|
...foundAttribute,
|
47
|
+
...attribute,
|
49
48
|
};
|
50
49
|
action = "update";
|
51
50
|
}
|
52
51
|
else {
|
53
|
-
// If no properties
|
52
|
+
// If no properties have changed, return early
|
54
53
|
return;
|
55
54
|
}
|
56
55
|
}
|
57
|
-
else if (foundAttribute &&
|
58
|
-
!attributesSame(foundAttribute, attribute) &&
|
59
|
-
updateEnabled) {
|
60
|
-
console.log(`Deleting attribute with same key ${attribute.key} -- but different values -- ${JSON.stringify(attribute, null, 2)} -- ${JSON.stringify(foundAttribute, null, 2)}`);
|
61
|
-
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
62
|
-
// After deletion, you might want to create the attribute anew
|
63
|
-
finalAttribute = attribute;
|
64
|
-
action = "create";
|
65
|
-
}
|
66
|
-
else if (!updateEnabled && foundAttribute) {
|
67
|
-
return;
|
68
|
-
}
|
69
56
|
// Relationship attribute logic with adjustments
|
70
57
|
let collectionFoundViaRelatedCollection;
|
71
58
|
let relatedCollectionId;
|
@@ -8,10 +8,10 @@ export const createOrUpdateIndex = async (dbId, db, collectionId, index) => {
|
|
8
8
|
let createIndex = false;
|
9
9
|
let newIndex = null;
|
10
10
|
if (existingIndex.total > 0 &&
|
11
|
-
existingIndex.indexes.some((
|
12
|
-
|
13
|
-
|
14
|
-
JSON.stringify(
|
11
|
+
!existingIndex.indexes.some((existingIndex) => (existingIndex.key === index.key &&
|
12
|
+
existingIndex.type === index.type &&
|
13
|
+
existingIndex.attributes === index.attributes) ||
|
14
|
+
JSON.stringify(existingIndex) === JSON.stringify(index))) {
|
15
15
|
await db.deleteIndex(dbId, collectionId, existingIndex.indexes[0].key);
|
16
16
|
createIndex = true;
|
17
17
|
}
|
@@ -24,6 +24,6 @@ export const createOrUpdateIndexes = async (dbId, db, collectionId, indexes) =>
|
|
24
24
|
for (const index of indexes) {
|
25
25
|
await tryAwaitWithRetry(async () => await createOrUpdateIndex(dbId, db, collectionId, index));
|
26
26
|
// Add delay after each index creation/update
|
27
|
-
await delay(
|
27
|
+
await delay(500);
|
28
28
|
}
|
29
29
|
};
|
@@ -97,6 +97,7 @@ export const wipeDatabase = async (database, databaseId) => {
|
|
97
97
|
collectionName: name,
|
98
98
|
});
|
99
99
|
tryAwaitWithRetry(async () => await database.deleteCollection(databaseId, collectionId)); // Try to delete the collection and ignore errors if it doesn't exist or if it's already being deleted
|
100
|
+
await delay(100);
|
100
101
|
}
|
101
102
|
return collectionsDeleted;
|
102
103
|
};
|
@@ -174,16 +175,16 @@ export const createOrUpdateCollections = async (database, databaseId, config, de
|
|
174
175
|
await tryAwaitWithRetry(async () => await database.updateCollection(databaseId, collectionToUse.$id, collection.name, permissions, collection.documentSecurity ?? false, collection.enabled ?? true));
|
175
176
|
}
|
176
177
|
// Add delay after creating/updating collection
|
177
|
-
await delay(
|
178
|
+
await delay(250);
|
178
179
|
// Update attributes and indexes for the collection
|
179
180
|
console.log("Creating Attributes");
|
180
181
|
await createUpdateCollectionAttributes(database, databaseId, collectionToUse, attributes);
|
181
182
|
// Add delay after creating attributes
|
182
|
-
await delay(
|
183
|
+
await delay(250);
|
183
184
|
console.log("Creating Indexes");
|
184
185
|
await createOrUpdateIndexes(databaseId, database, collectionToUse.$id, indexes ?? []);
|
185
186
|
// Add delay after creating indexes
|
186
|
-
await delay(
|
187
|
+
await delay(250);
|
187
188
|
}
|
188
189
|
// Process any remaining tasks in the queue
|
189
190
|
await processQueue(database, databaseId);
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { Databases, Query } from "node-appwrite";
|
2
2
|
import { createOrUpdateAttribute } from "./attributes.js";
|
3
3
|
import { getMigrationCollectionSchemas } from "./backup.js";
|
4
|
-
import { areCollectionNamesSame, toCamelCase, tryAwaitWithRetry, } from "../utils/index.js";
|
4
|
+
import { areCollectionNamesSame, delay, toCamelCase, tryAwaitWithRetry, } from "../utils/index.js";
|
5
5
|
import {} from "appwrite-utils";
|
6
6
|
import { ulid } from "ulidx";
|
7
7
|
export const setupMigrationDatabase = async (config) => {
|
@@ -48,6 +48,7 @@ export const setupMigrationDatabase = async (config) => {
|
|
48
48
|
for (const attribute of attributes) {
|
49
49
|
try {
|
50
50
|
await createOrUpdateAttribute(database, db.$id, collectionFound, attribute);
|
51
|
+
await delay(100);
|
51
52
|
console.log(`Attribute created/updated: ${attribute.key}`);
|
52
53
|
}
|
53
54
|
catch (attrError) {
|
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.9.
|
4
|
+
"version": "0.9.55",
|
5
5
|
"main": "src/main.ts",
|
6
6
|
"type": "module",
|
7
7
|
"repository": {
|
@@ -38,7 +38,7 @@
|
|
38
38
|
"lodash": "^4.17.21",
|
39
39
|
"luxon": "^3.5.0",
|
40
40
|
"nanostores": "^0.10.3",
|
41
|
-
"node-appwrite": "^
|
41
|
+
"node-appwrite": "^14.1.0",
|
42
42
|
"tsx": "^4.17.0",
|
43
43
|
"ulidx": "^2.4.0",
|
44
44
|
"winston": "^3.14.2",
|
@@ -27,11 +27,10 @@ export const createOrUpdateAttribute = async (
|
|
27
27
|
): Promise<void> => {
|
28
28
|
let action = "create";
|
29
29
|
let foundAttribute: Attribute | undefined;
|
30
|
-
const updateEnabled = false;
|
31
30
|
let finalAttribute: any = attribute;
|
32
31
|
try {
|
33
32
|
const collectionAttr = collection.attributes.find(
|
34
|
-
// @ts-
|
33
|
+
// @ts-ignore
|
35
34
|
(attr) => attr.key === attribute.key
|
36
35
|
) as unknown as any;
|
37
36
|
foundAttribute = parseAttribute(collectionAttr);
|
@@ -39,21 +38,17 @@ export const createOrUpdateAttribute = async (
|
|
39
38
|
foundAttribute = undefined;
|
40
39
|
}
|
41
40
|
|
42
|
-
if (
|
43
|
-
|
44
|
-
attributesSame(foundAttribute, attribute) &&
|
45
|
-
updateEnabled
|
46
|
-
) {
|
47
|
-
// Check if mutable properties have changed and set action to "update" if necessary
|
41
|
+
if (foundAttribute) {
|
42
|
+
// Check if any properties have changed
|
48
43
|
const requiredChanged =
|
49
44
|
"required" in foundAttribute && "required" in attribute
|
50
45
|
? foundAttribute.required !== attribute.required
|
51
46
|
: false;
|
52
47
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
48
|
+
const xdefaultChanged =
|
49
|
+
"xdefault" in foundAttribute && "xdefault" in attribute
|
50
|
+
? foundAttribute.xdefault !== attribute.xdefault
|
51
|
+
: false;
|
57
52
|
|
58
53
|
const onDeleteChanged =
|
59
54
|
foundAttribute.type === "relationship" &&
|
@@ -63,43 +58,28 @@ export const createOrUpdateAttribute = async (
|
|
63
58
|
? foundAttribute.onDelete !== attribute.onDelete
|
64
59
|
: false;
|
65
60
|
|
66
|
-
if (
|
61
|
+
if (
|
62
|
+
requiredChanged ||
|
63
|
+
xdefaultChanged ||
|
64
|
+
onDeleteChanged ||
|
65
|
+
!attributesSame(foundAttribute, attribute)
|
66
|
+
) {
|
67
67
|
console.log(
|
68
|
-
`
|
68
|
+
`Updating attribute: ${attribute.key}\nRequired changed: ${requiredChanged}\nDefault changed: ${xdefaultChanged}\nOnDelete changed: ${onDeleteChanged}`
|
69
69
|
);
|
70
70
|
console.log(
|
71
71
|
`Found attribute: ${JSON.stringify(foundAttribute, null, 2)}`
|
72
72
|
);
|
73
|
-
console.log(`
|
73
|
+
console.log(`New attribute: ${JSON.stringify(attribute, null, 2)}`);
|
74
74
|
finalAttribute = {
|
75
|
-
...attribute,
|
76
75
|
...foundAttribute,
|
76
|
+
...attribute,
|
77
77
|
};
|
78
78
|
action = "update";
|
79
79
|
} else {
|
80
|
-
// If no properties
|
80
|
+
// If no properties have changed, return early
|
81
81
|
return;
|
82
82
|
}
|
83
|
-
} else if (
|
84
|
-
foundAttribute &&
|
85
|
-
!attributesSame(foundAttribute, attribute) &&
|
86
|
-
updateEnabled
|
87
|
-
) {
|
88
|
-
console.log(
|
89
|
-
`Deleting attribute with same key ${
|
90
|
-
attribute.key
|
91
|
-
} -- but different values -- ${JSON.stringify(
|
92
|
-
attribute,
|
93
|
-
null,
|
94
|
-
2
|
95
|
-
)} -- ${JSON.stringify(foundAttribute, null, 2)}`
|
96
|
-
);
|
97
|
-
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
98
|
-
// After deletion, you might want to create the attribute anew
|
99
|
-
finalAttribute = attribute;
|
100
|
-
action = "create";
|
101
|
-
} else if (!updateEnabled && foundAttribute) {
|
102
|
-
return;
|
103
83
|
}
|
104
84
|
|
105
85
|
// Relationship attribute logic with adjustments
|
@@ -15,12 +15,12 @@ export const createOrUpdateIndex = async (
|
|
15
15
|
let newIndex: Models.Index | null = null;
|
16
16
|
if (
|
17
17
|
existingIndex.total > 0 &&
|
18
|
-
existingIndex.indexes.some(
|
19
|
-
(
|
20
|
-
(
|
21
|
-
|
22
|
-
|
23
|
-
JSON.stringify(
|
18
|
+
!existingIndex.indexes.some(
|
19
|
+
(existingIndex) =>
|
20
|
+
(existingIndex.key === index.key &&
|
21
|
+
existingIndex.type === index.type &&
|
22
|
+
existingIndex.attributes === index.attributes) ||
|
23
|
+
JSON.stringify(existingIndex) === JSON.stringify(index)
|
24
24
|
)
|
25
25
|
) {
|
26
26
|
await db.deleteIndex(dbId, collectionId, existingIndex.indexes[0].key);
|
@@ -50,6 +50,6 @@ export const createOrUpdateIndexes = async (
|
|
50
50
|
async () => await createOrUpdateIndex(dbId, db, collectionId, index)
|
51
51
|
);
|
52
52
|
// Add delay after each index creation/update
|
53
|
-
await delay(
|
53
|
+
await delay(500);
|
54
54
|
}
|
55
55
|
};
|
@@ -141,6 +141,7 @@ export const wipeDatabase = async (
|
|
141
141
|
tryAwaitWithRetry(
|
142
142
|
async () => await database.deleteCollection(databaseId, collectionId)
|
143
143
|
); // Try to delete the collection and ignore errors if it doesn't exist or if it's already being deleted
|
144
|
+
await delay(100);
|
144
145
|
}
|
145
146
|
return collectionsDeleted;
|
146
147
|
};
|
@@ -261,7 +262,7 @@ export const createOrUpdateCollections = async (
|
|
261
262
|
}
|
262
263
|
|
263
264
|
// Add delay after creating/updating collection
|
264
|
-
await delay(
|
265
|
+
await delay(250);
|
265
266
|
|
266
267
|
// Update attributes and indexes for the collection
|
267
268
|
console.log("Creating Attributes");
|
@@ -273,7 +274,7 @@ export const createOrUpdateCollections = async (
|
|
273
274
|
);
|
274
275
|
|
275
276
|
// Add delay after creating attributes
|
276
|
-
await delay(
|
277
|
+
await delay(250);
|
277
278
|
|
278
279
|
console.log("Creating Indexes");
|
279
280
|
await createOrUpdateIndexes(
|
@@ -284,7 +285,7 @@ export const createOrUpdateCollections = async (
|
|
284
285
|
);
|
285
286
|
|
286
287
|
// Add delay after creating indexes
|
287
|
-
await delay(
|
288
|
+
await delay(250);
|
288
289
|
}
|
289
290
|
// Process any remaining tasks in the queue
|
290
291
|
await processQueue(database, databaseId);
|
@@ -3,6 +3,7 @@ import { createOrUpdateAttribute } from "./attributes.js";
|
|
3
3
|
import { getMigrationCollectionSchemas } from "./backup.js";
|
4
4
|
import {
|
5
5
|
areCollectionNamesSame,
|
6
|
+
delay,
|
6
7
|
toCamelCase,
|
7
8
|
tryAwaitWithRetry,
|
8
9
|
} from "../utils/index.js";
|
@@ -87,6 +88,7 @@ export const setupMigrationDatabase = async (config: AppwriteConfig) => {
|
|
87
88
|
collectionFound,
|
88
89
|
attribute
|
89
90
|
);
|
91
|
+
await delay(100);
|
90
92
|
console.log(`Attribute created/updated: ${attribute.key}`);
|
91
93
|
} catch (attrError) {
|
92
94
|
console.error(
|