appwrite-utils-cli 0.9.74 → 0.9.76
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 +1 -0
- package/dist/collections/attributes.js +82 -54
- package/dist/init.js +0 -0
- package/dist/main.js +0 -0
- package/dist/migrations/attributes.js +2 -1
- package/dist/migrations/databases.js +0 -3
- package/dist/migrations/setupDatabase.js +1 -1
- package/dist/migrations/transfer.js +1 -1
- package/package.json +1 -1
- package/src/collections/attributes.ts +105 -79
- package/src/migrations/attributes.ts +2 -1
- package/src/migrations/databases.ts +0 -6
- package/src/migrations/setupDatabase.ts +1 -1
- package/src/migrations/transfer.ts +1 -1
package/README.md
CHANGED
@@ -124,6 +124,7 @@ This updated CLI ensures that developers have robust tools at their fingertips t
|
|
124
124
|
|
125
125
|
## Changelog
|
126
126
|
|
127
|
+
- 0.9.75: Fixed attribute bug
|
127
128
|
- 0.9.72: Fixed my own null bug
|
128
129
|
- 0.9.71: Reverted `node-appwrite` to 14, this seems to fix the xdefault error
|
129
130
|
- 0.9.70: I think I stopped it from deleting attributes, my bad on that
|
@@ -4,52 +4,83 @@ import { nameToIdMapping, enqueueOperation } from "../migrations/queue.js";
|
|
4
4
|
import _ from "lodash";
|
5
5
|
import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
6
6
|
const attributesSame = (databaseAttribute, configAttribute) => {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
const attributesToCheck = [
|
8
|
+
'key',
|
9
|
+
'type',
|
10
|
+
'array',
|
11
|
+
'encrypted',
|
12
|
+
'required',
|
13
|
+
'size',
|
14
|
+
'min',
|
15
|
+
'max',
|
16
|
+
'xdefault',
|
17
|
+
'elements',
|
18
|
+
'relationType',
|
19
|
+
'twoWay',
|
20
|
+
'twoWayKey',
|
21
|
+
'onDelete',
|
22
|
+
'relatedCollection'
|
23
|
+
];
|
24
|
+
return attributesToCheck.every(attr => {
|
25
|
+
// Check if both objects have the attribute
|
26
|
+
const dbHasAttr = attr in databaseAttribute;
|
27
|
+
const configHasAttr = attr in configAttribute;
|
28
|
+
// If both have the attribute, compare values
|
29
|
+
if (dbHasAttr && configHasAttr) {
|
30
|
+
const dbValue = databaseAttribute[attr];
|
31
|
+
const configValue = configAttribute[attr];
|
32
|
+
// Consider undefined and null as equivalent
|
33
|
+
if ((dbValue === undefined || dbValue === null) && (configValue === undefined || configValue === null)) {
|
34
|
+
return true;
|
35
|
+
}
|
36
|
+
return dbValue === configValue;
|
37
|
+
}
|
38
|
+
// If neither has the attribute, consider it the same
|
39
|
+
if (!dbHasAttr && !configHasAttr) {
|
40
|
+
return true;
|
41
|
+
}
|
42
|
+
// If one has the attribute and the other doesn't, check if it's undefined or null
|
43
|
+
if (dbHasAttr && !configHasAttr) {
|
44
|
+
const dbValue = databaseAttribute[attr];
|
45
|
+
return dbValue === undefined || dbValue === null;
|
46
|
+
}
|
47
|
+
if (!dbHasAttr && configHasAttr) {
|
48
|
+
const configValue = configAttribute[attr];
|
49
|
+
return configValue === undefined || configValue === null;
|
50
|
+
}
|
51
|
+
// If we reach here, the attributes are different
|
52
|
+
return false;
|
53
|
+
});
|
10
54
|
};
|
11
55
|
export const createOrUpdateAttribute = async (db, dbId, collection, attribute) => {
|
12
56
|
let action = "create";
|
13
57
|
let foundAttribute;
|
58
|
+
const updateEnabled = true;
|
14
59
|
let finalAttribute = attribute;
|
15
60
|
try {
|
16
61
|
const collectionAttr = collection.attributes.find(
|
17
|
-
// @ts-
|
62
|
+
// @ts-expect-error
|
18
63
|
(attr) => attr.key === attribute.key);
|
19
64
|
foundAttribute = parseAttribute(collectionAttr);
|
20
65
|
}
|
21
66
|
catch (error) {
|
22
67
|
foundAttribute = undefined;
|
23
68
|
}
|
24
|
-
if (foundAttribute) {
|
25
|
-
//
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
: false;
|
38
|
-
if (requiredChanged || xdefaultChanged || onDeleteChanged) {
|
39
|
-
console.log(`Updating attribute: ${attribute.key}\nRequired changed: ${requiredChanged}\nDefault changed: ${xdefaultChanged}\nOnDelete changed: ${onDeleteChanged}`);
|
40
|
-
console.log(`Found attribute: ${JSON.stringify(foundAttribute, null, 2)}`);
|
41
|
-
console.log(`New attribute: ${JSON.stringify(attribute, null, 2)}`);
|
42
|
-
finalAttribute = {
|
43
|
-
...foundAttribute,
|
44
|
-
...attribute,
|
45
|
-
};
|
46
|
-
action = "update";
|
47
|
-
}
|
48
|
-
else {
|
49
|
-
// If no properties have changed, return early
|
50
|
-
return;
|
51
|
-
}
|
69
|
+
if (foundAttribute && attributesSame(foundAttribute, attribute) && updateEnabled) {
|
70
|
+
// No need to do anything, they are the same
|
71
|
+
return;
|
72
|
+
}
|
73
|
+
else if (foundAttribute && !attributesSame(foundAttribute, attribute) && updateEnabled) {
|
74
|
+
console.log(`Updating attribute with same key ${attribute.key} but different values`);
|
75
|
+
finalAttribute = attribute;
|
76
|
+
action = "update";
|
77
|
+
}
|
78
|
+
else if (!updateEnabled && foundAttribute && !attributesSame(foundAttribute, attribute)) {
|
79
|
+
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
80
|
+
console.log(`Deleted attribute: ${attribute.key} to recreate it because they diff (update disabled temporarily)`);
|
81
|
+
return;
|
52
82
|
}
|
83
|
+
// console.log(`${action}-ing attribute: ${finalAttribute.key}`);
|
53
84
|
// Relationship attribute logic with adjustments
|
54
85
|
let collectionFoundViaRelatedCollection;
|
55
86
|
let relatedCollectionId;
|
@@ -87,17 +118,14 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
|
|
87
118
|
}
|
88
119
|
}
|
89
120
|
finalAttribute = attributeSchema.parse(finalAttribute);
|
121
|
+
// console.log(`Final Attribute: ${JSON.stringify(finalAttribute)}`);
|
90
122
|
switch (finalAttribute.type) {
|
91
123
|
case "string":
|
92
124
|
if (action === "create") {
|
93
|
-
await tryAwaitWithRetry(async () => await db.createStringAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.size, finalAttribute.required || false, finalAttribute.xdefault
|
94
|
-
? `${finalAttribute.xdefault}`
|
95
|
-
: undefined, finalAttribute.array || false, finalAttribute.encrypted));
|
125
|
+
await tryAwaitWithRetry(async () => await db.createStringAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.size, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null, finalAttribute.array || false, finalAttribute.encrypted));
|
96
126
|
}
|
97
127
|
else {
|
98
|
-
await tryAwaitWithRetry(async () => await db.updateStringAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
99
|
-
? `${finalAttribute.xdefault}`
|
100
|
-
: undefined));
|
128
|
+
await tryAwaitWithRetry(async () => await db.updateStringAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null));
|
101
129
|
}
|
102
130
|
break;
|
103
131
|
case "integer":
|
@@ -110,7 +138,7 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
|
|
110
138
|
BigInt(finalAttribute.max) === BigInt(9223372036854776000)) {
|
111
139
|
delete finalAttribute.max;
|
112
140
|
}
|
113
|
-
await tryAwaitWithRetry(async () => await db.createIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min, finalAttribute.max, finalAttribute.xdefault
|
141
|
+
await tryAwaitWithRetry(async () => await db.createIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min || -2147483647, finalAttribute.max || 2147483647, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null, finalAttribute.array || false));
|
114
142
|
}
|
115
143
|
else {
|
116
144
|
if (finalAttribute.min &&
|
@@ -121,63 +149,63 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
|
|
121
149
|
BigInt(finalAttribute.max) === BigInt(9223372036854776000)) {
|
122
150
|
delete finalAttribute.max;
|
123
151
|
}
|
124
|
-
await tryAwaitWithRetry(async () => await db.updateIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min ||
|
152
|
+
await tryAwaitWithRetry(async () => await db.updateIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min || -2147483647, finalAttribute.max || 2147483647, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null));
|
125
153
|
}
|
126
154
|
break;
|
127
155
|
case "float":
|
128
156
|
if (action === "create") {
|
129
|
-
await tryAwaitWithRetry(async () => await db.createFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min, finalAttribute.max, finalAttribute.xdefault
|
157
|
+
await tryAwaitWithRetry(async () => await db.createFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min || -2147483647, finalAttribute.max || 2147483647, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null, finalAttribute.array || false));
|
130
158
|
}
|
131
159
|
else {
|
132
|
-
await tryAwaitWithRetry(async () => await db.updateFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min ||
|
160
|
+
await tryAwaitWithRetry(async () => await db.updateFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min || -2147483647, finalAttribute.max || 2147483647, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null));
|
133
161
|
}
|
134
162
|
break;
|
135
163
|
case "boolean":
|
136
164
|
if (action === "create") {
|
137
|
-
await tryAwaitWithRetry(async () => await db.createBooleanAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
165
|
+
await tryAwaitWithRetry(async () => await db.createBooleanAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null, finalAttribute.array || false));
|
138
166
|
}
|
139
167
|
else {
|
140
|
-
await tryAwaitWithRetry(async () => await db.updateBooleanAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
168
|
+
await tryAwaitWithRetry(async () => await db.updateBooleanAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null));
|
141
169
|
}
|
142
170
|
break;
|
143
171
|
case "datetime":
|
144
172
|
if (action === "create") {
|
145
|
-
await tryAwaitWithRetry(async () => await db.createDatetimeAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
173
|
+
await tryAwaitWithRetry(async () => await db.createDatetimeAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null, finalAttribute.array || false));
|
146
174
|
}
|
147
175
|
else {
|
148
|
-
await tryAwaitWithRetry(async () => await db.updateDatetimeAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
176
|
+
await tryAwaitWithRetry(async () => await db.updateDatetimeAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null));
|
149
177
|
}
|
150
178
|
break;
|
151
179
|
case "email":
|
152
180
|
if (action === "create") {
|
153
|
-
await tryAwaitWithRetry(async () => await db.createEmailAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
181
|
+
await tryAwaitWithRetry(async () => await db.createEmailAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null, finalAttribute.array || false));
|
154
182
|
}
|
155
183
|
else {
|
156
|
-
await tryAwaitWithRetry(async () => await db.updateEmailAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
184
|
+
await tryAwaitWithRetry(async () => await db.updateEmailAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null));
|
157
185
|
}
|
158
186
|
break;
|
159
187
|
case "ip":
|
160
188
|
if (action === "create") {
|
161
|
-
await tryAwaitWithRetry(async () => await db.createIpAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
189
|
+
await tryAwaitWithRetry(async () => await db.createIpAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null, finalAttribute.array || false));
|
162
190
|
}
|
163
191
|
else {
|
164
|
-
await tryAwaitWithRetry(async () => await db.updateIpAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
192
|
+
await tryAwaitWithRetry(async () => await db.updateIpAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null));
|
165
193
|
}
|
166
194
|
break;
|
167
195
|
case "url":
|
168
196
|
if (action === "create") {
|
169
|
-
await tryAwaitWithRetry(async () => await db.createUrlAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
197
|
+
await tryAwaitWithRetry(async () => await db.createUrlAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null, finalAttribute.array || false));
|
170
198
|
}
|
171
199
|
else {
|
172
|
-
await tryAwaitWithRetry(async () => await db.updateUrlAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault
|
200
|
+
await tryAwaitWithRetry(async () => await db.updateUrlAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null));
|
173
201
|
}
|
174
202
|
break;
|
175
203
|
case "enum":
|
176
204
|
if (action === "create") {
|
177
|
-
await tryAwaitWithRetry(async () => await db.createEnumAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.elements, finalAttribute.required || false, finalAttribute.xdefault
|
205
|
+
await tryAwaitWithRetry(async () => await db.createEnumAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.elements, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null, finalAttribute.array || false));
|
178
206
|
}
|
179
207
|
else {
|
180
|
-
await tryAwaitWithRetry(async () => await db.updateEnumAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.elements, finalAttribute.required || false, finalAttribute.xdefault
|
208
|
+
await tryAwaitWithRetry(async () => await db.updateEnumAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.elements, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null));
|
181
209
|
}
|
182
210
|
break;
|
183
211
|
case "relationship":
|
package/dist/init.js
CHANGED
File without changes
|
package/dist/main.js
CHANGED
File without changes
|
@@ -83,7 +83,7 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
|
|
83
83
|
console.log(`Deleted attribute: ${attribute.key} to recreate it because they diff (update disabled temporarily)`);
|
84
84
|
return;
|
85
85
|
}
|
86
|
-
|
86
|
+
console.log(`${action}-ing attribute: ${finalAttribute.key}`);
|
87
87
|
// Relationship attribute logic with adjustments
|
88
88
|
let collectionFoundViaRelatedCollection;
|
89
89
|
let relatedCollectionId;
|
@@ -121,6 +121,7 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
|
|
121
121
|
}
|
122
122
|
}
|
123
123
|
finalAttribute = attributeSchema.parse(finalAttribute);
|
124
|
+
console.log(`Final Attribute: ${JSON.stringify(finalAttribute)}`);
|
124
125
|
switch (finalAttribute.type) {
|
125
126
|
case "string":
|
126
127
|
if (action === "create") {
|
@@ -1,8 +1,5 @@
|
|
1
1
|
import { Client, Databases, IndexType, Query, } from "node-appwrite";
|
2
2
|
import { getAppwriteClient, tryAwaitWithRetry, } from "../utils/helperFunctions.js";
|
3
|
-
import { transferDocumentsBetweenDbsLocalToLocal, transferDocumentsBetweenDbsLocalToRemote, } from "./collections.js";
|
4
|
-
import { createOrUpdateAttribute } from "./attributes.js";
|
5
|
-
import { parseAttribute } from "appwrite-utils";
|
6
3
|
export const fetchAllDatabases = async (database) => {
|
7
4
|
const databases = await tryAwaitWithRetry(async () => await database.list([Query.limit(25)]));
|
8
5
|
const allDatabases = databases.databases;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Databases, Query } from "node-appwrite";
|
2
|
-
import { createOrUpdateAttribute } from "
|
2
|
+
import { createOrUpdateAttribute } from "../collections/attributes.js";
|
3
3
|
import { getMigrationCollectionSchemas } from "./backup.js";
|
4
4
|
import { areCollectionNamesSame, delay, toCamelCase, tryAwaitWithRetry, } from "../utils/index.js";
|
5
5
|
import {} from "appwrite-utils";
|
@@ -2,7 +2,7 @@ import { tryAwaitWithRetry } from "appwrite-utils";
|
|
2
2
|
import { Client, Databases, IndexType, Query, Storage, } from "node-appwrite";
|
3
3
|
import { InputFile } from "node-appwrite/file";
|
4
4
|
import { getAppwriteClient } from "../utils/helperFunctions.js";
|
5
|
-
import { createOrUpdateAttribute } from "
|
5
|
+
import { createOrUpdateAttribute } from "../collections/attributes.js";
|
6
6
|
import { parseAttribute } from "appwrite-utils";
|
7
7
|
export const transferStorageLocalToLocal = async (storage, fromBucketId, toBucketId) => {
|
8
8
|
console.log(`Transferring files from ${fromBucketId} to ${toBucketId}`);
|
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.76",
|
5
5
|
"main": "src/main.ts",
|
6
6
|
"type": "module",
|
7
7
|
"repository": {
|
@@ -12,11 +12,61 @@ const attributesSame = (
|
|
12
12
|
databaseAttribute: Attribute,
|
13
13
|
configAttribute: Attribute
|
14
14
|
): boolean => {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
const attributesToCheck = [
|
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'
|
31
|
+
];
|
32
|
+
|
33
|
+
return attributesToCheck.every(attr => {
|
34
|
+
// Check if both objects have the attribute
|
35
|
+
const dbHasAttr = attr in databaseAttribute;
|
36
|
+
const configHasAttr = attr in configAttribute;
|
37
|
+
|
38
|
+
// If both have the attribute, compare values
|
39
|
+
if (dbHasAttr && configHasAttr) {
|
40
|
+
const dbValue = databaseAttribute[attr as keyof typeof databaseAttribute];
|
41
|
+
const configValue = configAttribute[attr as keyof typeof configAttribute];
|
42
|
+
|
43
|
+
// Consider undefined and null as equivalent
|
44
|
+
if ((dbValue === undefined || dbValue === null) && (configValue === undefined || configValue === null)) {
|
45
|
+
return true;
|
46
|
+
}
|
47
|
+
|
48
|
+
return dbValue === configValue;
|
49
|
+
}
|
50
|
+
|
51
|
+
// If neither has the attribute, consider it the same
|
52
|
+
if (!dbHasAttr && !configHasAttr) {
|
53
|
+
return true;
|
54
|
+
}
|
55
|
+
|
56
|
+
// If one has the attribute and the other doesn't, check if it's undefined or null
|
57
|
+
if (dbHasAttr && !configHasAttr) {
|
58
|
+
const dbValue = databaseAttribute[attr as keyof typeof databaseAttribute];
|
59
|
+
return dbValue === undefined || dbValue === null;
|
60
|
+
}
|
61
|
+
|
62
|
+
if (!dbHasAttr && configHasAttr) {
|
63
|
+
const configValue = configAttribute[attr as keyof typeof configAttribute];
|
64
|
+
return configValue === undefined || configValue === null;
|
65
|
+
}
|
66
|
+
|
67
|
+
// If we reach here, the attributes are different
|
68
|
+
return false;
|
69
|
+
});
|
20
70
|
};
|
21
71
|
|
22
72
|
export const createOrUpdateAttribute = async (
|
@@ -27,10 +77,11 @@ export const createOrUpdateAttribute = async (
|
|
27
77
|
): Promise<void> => {
|
28
78
|
let action = "create";
|
29
79
|
let foundAttribute: Attribute | undefined;
|
80
|
+
const updateEnabled = true;
|
30
81
|
let finalAttribute: any = attribute;
|
31
82
|
try {
|
32
83
|
const collectionAttr = collection.attributes.find(
|
33
|
-
// @ts-
|
84
|
+
// @ts-expect-error
|
34
85
|
(attr) => attr.key === attribute.key
|
35
86
|
) as unknown as any;
|
36
87
|
foundAttribute = parseAttribute(collectionAttr);
|
@@ -38,45 +89,23 @@ export const createOrUpdateAttribute = async (
|
|
38
89
|
foundAttribute = undefined;
|
39
90
|
}
|
40
91
|
|
41
|
-
if (foundAttribute) {
|
42
|
-
//
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
foundAttribute.type === "relationship" &&
|
55
|
-
attribute.type === "relationship" &&
|
56
|
-
"onDelete" in foundAttribute &&
|
57
|
-
"onDelete" in attribute
|
58
|
-
? foundAttribute.onDelete !== attribute.onDelete
|
59
|
-
: false;
|
60
|
-
|
61
|
-
if (requiredChanged || xdefaultChanged || onDeleteChanged) {
|
62
|
-
console.log(
|
63
|
-
`Updating attribute: ${attribute.key}\nRequired changed: ${requiredChanged}\nDefault changed: ${xdefaultChanged}\nOnDelete changed: ${onDeleteChanged}`
|
64
|
-
);
|
65
|
-
console.log(
|
66
|
-
`Found attribute: ${JSON.stringify(foundAttribute, null, 2)}`
|
67
|
-
);
|
68
|
-
console.log(`New attribute: ${JSON.stringify(attribute, null, 2)}`);
|
69
|
-
finalAttribute = {
|
70
|
-
...foundAttribute,
|
71
|
-
...attribute,
|
72
|
-
};
|
73
|
-
action = "update";
|
74
|
-
} else {
|
75
|
-
// If no properties have changed, return early
|
76
|
-
return;
|
77
|
-
}
|
92
|
+
if (foundAttribute && attributesSame(foundAttribute, attribute) && updateEnabled) {
|
93
|
+
// No need to do anything, they are the same
|
94
|
+
return;
|
95
|
+
} else if (foundAttribute && !attributesSame(foundAttribute, attribute) && updateEnabled) {
|
96
|
+
console.log(
|
97
|
+
`Updating attribute with same key ${attribute.key} but different values`
|
98
|
+
);
|
99
|
+
finalAttribute = attribute;
|
100
|
+
action = "update";
|
101
|
+
} else if (!updateEnabled && foundAttribute && !attributesSame(foundAttribute, attribute)) {
|
102
|
+
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
103
|
+
console.log(`Deleted attribute: ${attribute.key} to recreate it because they diff (update disabled temporarily)`);
|
104
|
+
return;
|
78
105
|
}
|
79
106
|
|
107
|
+
// console.log(`${action}-ing attribute: ${finalAttribute.key}`);
|
108
|
+
|
80
109
|
// Relationship attribute logic with adjustments
|
81
110
|
let collectionFoundViaRelatedCollection: Models.Collection | undefined;
|
82
111
|
let relatedCollectionId: string | undefined;
|
@@ -122,6 +151,7 @@ export const createOrUpdateAttribute = async (
|
|
122
151
|
}
|
123
152
|
}
|
124
153
|
finalAttribute = attributeSchema.parse(finalAttribute);
|
154
|
+
// console.log(`Final Attribute: ${JSON.stringify(finalAttribute)}`);
|
125
155
|
switch (finalAttribute.type) {
|
126
156
|
case "string":
|
127
157
|
if (action === "create") {
|
@@ -133,9 +163,7 @@ export const createOrUpdateAttribute = async (
|
|
133
163
|
finalAttribute.key,
|
134
164
|
finalAttribute.size,
|
135
165
|
finalAttribute.required || false,
|
136
|
-
finalAttribute.xdefault
|
137
|
-
? `${finalAttribute.xdefault}`
|
138
|
-
: undefined,
|
166
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
139
167
|
finalAttribute.array || false,
|
140
168
|
finalAttribute.encrypted
|
141
169
|
)
|
@@ -148,9 +176,7 @@ export const createOrUpdateAttribute = async (
|
|
148
176
|
collection.$id,
|
149
177
|
finalAttribute.key,
|
150
178
|
finalAttribute.required || false,
|
151
|
-
finalAttribute.xdefault
|
152
|
-
? `${finalAttribute.xdefault}`
|
153
|
-
: undefined,
|
179
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
154
180
|
)
|
155
181
|
);
|
156
182
|
}
|
@@ -176,10 +202,10 @@ export const createOrUpdateAttribute = async (
|
|
176
202
|
collection.$id,
|
177
203
|
finalAttribute.key,
|
178
204
|
finalAttribute.required || false,
|
179
|
-
finalAttribute.min,
|
180
|
-
finalAttribute.max,
|
181
|
-
finalAttribute.xdefault
|
182
|
-
finalAttribute.array
|
205
|
+
finalAttribute.min || -2147483647,
|
206
|
+
finalAttribute.max || 2147483647,
|
207
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
208
|
+
finalAttribute.array || false
|
183
209
|
)
|
184
210
|
);
|
185
211
|
} else {
|
@@ -202,9 +228,9 @@ export const createOrUpdateAttribute = async (
|
|
202
228
|
collection.$id,
|
203
229
|
finalAttribute.key,
|
204
230
|
finalAttribute.required || false,
|
205
|
-
finalAttribute.min ||
|
231
|
+
finalAttribute.min || -2147483647,
|
206
232
|
finalAttribute.max || 2147483647,
|
207
|
-
finalAttribute.xdefault
|
233
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null
|
208
234
|
)
|
209
235
|
);
|
210
236
|
}
|
@@ -218,10 +244,10 @@ export const createOrUpdateAttribute = async (
|
|
218
244
|
collection.$id,
|
219
245
|
finalAttribute.key,
|
220
246
|
finalAttribute.required || false,
|
221
|
-
finalAttribute.min,
|
222
|
-
finalAttribute.max,
|
223
|
-
finalAttribute.xdefault
|
224
|
-
finalAttribute.array
|
247
|
+
finalAttribute.min || -2147483647,
|
248
|
+
finalAttribute.max || 2147483647,
|
249
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
250
|
+
finalAttribute.array || false
|
225
251
|
)
|
226
252
|
);
|
227
253
|
} else {
|
@@ -232,9 +258,9 @@ export const createOrUpdateAttribute = async (
|
|
232
258
|
collection.$id,
|
233
259
|
finalAttribute.key,
|
234
260
|
finalAttribute.required || false,
|
235
|
-
finalAttribute.min ||
|
261
|
+
finalAttribute.min || -2147483647,
|
236
262
|
finalAttribute.max || 2147483647,
|
237
|
-
finalAttribute.xdefault
|
263
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null
|
238
264
|
)
|
239
265
|
);
|
240
266
|
}
|
@@ -248,8 +274,8 @@ export const createOrUpdateAttribute = async (
|
|
248
274
|
collection.$id,
|
249
275
|
finalAttribute.key,
|
250
276
|
finalAttribute.required || false,
|
251
|
-
finalAttribute.xdefault
|
252
|
-
finalAttribute.array
|
277
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
278
|
+
finalAttribute.array || false
|
253
279
|
)
|
254
280
|
);
|
255
281
|
} else {
|
@@ -260,7 +286,7 @@ export const createOrUpdateAttribute = async (
|
|
260
286
|
collection.$id,
|
261
287
|
finalAttribute.key,
|
262
288
|
finalAttribute.required || false,
|
263
|
-
finalAttribute.xdefault
|
289
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null
|
264
290
|
)
|
265
291
|
);
|
266
292
|
}
|
@@ -274,8 +300,8 @@ export const createOrUpdateAttribute = async (
|
|
274
300
|
collection.$id,
|
275
301
|
finalAttribute.key,
|
276
302
|
finalAttribute.required || false,
|
277
|
-
finalAttribute.xdefault
|
278
|
-
finalAttribute.array
|
303
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
304
|
+
finalAttribute.array || false
|
279
305
|
)
|
280
306
|
);
|
281
307
|
} else {
|
@@ -286,7 +312,7 @@ export const createOrUpdateAttribute = async (
|
|
286
312
|
collection.$id,
|
287
313
|
finalAttribute.key,
|
288
314
|
finalAttribute.required || false,
|
289
|
-
finalAttribute.xdefault
|
315
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null
|
290
316
|
)
|
291
317
|
);
|
292
318
|
}
|
@@ -300,8 +326,8 @@ export const createOrUpdateAttribute = async (
|
|
300
326
|
collection.$id,
|
301
327
|
finalAttribute.key,
|
302
328
|
finalAttribute.required || false,
|
303
|
-
finalAttribute.xdefault
|
304
|
-
finalAttribute.array
|
329
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
330
|
+
finalAttribute.array || false
|
305
331
|
)
|
306
332
|
);
|
307
333
|
} else {
|
@@ -312,7 +338,7 @@ export const createOrUpdateAttribute = async (
|
|
312
338
|
collection.$id,
|
313
339
|
finalAttribute.key,
|
314
340
|
finalAttribute.required || false,
|
315
|
-
finalAttribute.xdefault
|
341
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null
|
316
342
|
)
|
317
343
|
);
|
318
344
|
}
|
@@ -326,8 +352,8 @@ export const createOrUpdateAttribute = async (
|
|
326
352
|
collection.$id,
|
327
353
|
finalAttribute.key,
|
328
354
|
finalAttribute.required || false,
|
329
|
-
finalAttribute.xdefault
|
330
|
-
finalAttribute.array
|
355
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
356
|
+
finalAttribute.array || false
|
331
357
|
)
|
332
358
|
);
|
333
359
|
} else {
|
@@ -338,7 +364,7 @@ export const createOrUpdateAttribute = async (
|
|
338
364
|
collection.$id,
|
339
365
|
finalAttribute.key,
|
340
366
|
finalAttribute.required || false,
|
341
|
-
finalAttribute.xdefault
|
367
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null
|
342
368
|
)
|
343
369
|
);
|
344
370
|
}
|
@@ -352,8 +378,8 @@ export const createOrUpdateAttribute = async (
|
|
352
378
|
collection.$id,
|
353
379
|
finalAttribute.key,
|
354
380
|
finalAttribute.required || false,
|
355
|
-
finalAttribute.xdefault
|
356
|
-
finalAttribute.array
|
381
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
382
|
+
finalAttribute.array || false
|
357
383
|
)
|
358
384
|
);
|
359
385
|
} else {
|
@@ -364,7 +390,7 @@ export const createOrUpdateAttribute = async (
|
|
364
390
|
collection.$id,
|
365
391
|
finalAttribute.key,
|
366
392
|
finalAttribute.required || false,
|
367
|
-
finalAttribute.xdefault
|
393
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null
|
368
394
|
)
|
369
395
|
);
|
370
396
|
}
|
@@ -379,8 +405,8 @@ export const createOrUpdateAttribute = async (
|
|
379
405
|
finalAttribute.key,
|
380
406
|
finalAttribute.elements,
|
381
407
|
finalAttribute.required || false,
|
382
|
-
finalAttribute.xdefault
|
383
|
-
finalAttribute.array
|
408
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null,
|
409
|
+
finalAttribute.array || false
|
384
410
|
)
|
385
411
|
);
|
386
412
|
} else {
|
@@ -392,7 +418,7 @@ export const createOrUpdateAttribute = async (
|
|
392
418
|
finalAttribute.key,
|
393
419
|
finalAttribute.elements,
|
394
420
|
finalAttribute.required || false,
|
395
|
-
finalAttribute.xdefault
|
421
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required ? finalAttribute.xdefault : null
|
396
422
|
)
|
397
423
|
);
|
398
424
|
}
|
@@ -107,7 +107,7 @@ export const createOrUpdateAttribute = async (
|
|
107
107
|
return;
|
108
108
|
}
|
109
109
|
|
110
|
-
|
110
|
+
console.log(`${action}-ing attribute: ${finalAttribute.key}`);
|
111
111
|
|
112
112
|
// Relationship attribute logic with adjustments
|
113
113
|
let collectionFoundViaRelatedCollection: Models.Collection | undefined;
|
@@ -154,6 +154,7 @@ export const createOrUpdateAttribute = async (
|
|
154
154
|
}
|
155
155
|
}
|
156
156
|
finalAttribute = attributeSchema.parse(finalAttribute);
|
157
|
+
console.log(`Final Attribute: ${JSON.stringify(finalAttribute)}`);
|
157
158
|
switch (finalAttribute.type) {
|
158
159
|
case "string":
|
159
160
|
if (action === "create") {
|
@@ -9,12 +9,6 @@ import {
|
|
9
9
|
getAppwriteClient,
|
10
10
|
tryAwaitWithRetry,
|
11
11
|
} from "../utils/helperFunctions.js";
|
12
|
-
import {
|
13
|
-
transferDocumentsBetweenDbsLocalToLocal,
|
14
|
-
transferDocumentsBetweenDbsLocalToRemote,
|
15
|
-
} from "./collections.js";
|
16
|
-
import { createOrUpdateAttribute } from "./attributes.js";
|
17
|
-
import { parseAttribute } from "appwrite-utils";
|
18
12
|
|
19
13
|
export const fetchAllDatabases = async (
|
20
14
|
database: Databases
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Databases, Query, type Models } from "node-appwrite";
|
2
|
-
import { createOrUpdateAttribute } from "
|
2
|
+
import { createOrUpdateAttribute } from "../collections/attributes.js";
|
3
3
|
import { getMigrationCollectionSchemas } from "./backup.js";
|
4
4
|
import {
|
5
5
|
areCollectionNamesSame,
|
@@ -9,7 +9,7 @@ import {
|
|
9
9
|
} from "node-appwrite";
|
10
10
|
import { InputFile } from "node-appwrite/file";
|
11
11
|
import { getAppwriteClient } from "../utils/helperFunctions.js";
|
12
|
-
import { createOrUpdateAttribute } from "
|
12
|
+
import { createOrUpdateAttribute } from "../collections/attributes.js";
|
13
13
|
import { parseAttribute } from "appwrite-utils";
|
14
14
|
|
15
15
|
export interface TransferOptions {
|