appwrite-utils-cli 1.3.5 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/AdapterFactory.d.ts +87 -0
- package/dist/adapters/AdapterFactory.js +217 -0
- package/dist/adapters/DatabaseAdapter.d.ts +217 -0
- package/dist/adapters/DatabaseAdapter.js +50 -0
- package/dist/adapters/LegacyAdapter.d.ts +49 -0
- package/dist/adapters/LegacyAdapter.js +382 -0
- package/dist/adapters/TablesDBAdapter.d.ts +55 -0
- package/dist/adapters/TablesDBAdapter.js +302 -0
- package/dist/adapters/index.d.ts +11 -0
- package/dist/adapters/index.js +12 -0
- package/dist/collections/attributes.js +41 -22
- package/dist/collections/methods.d.ts +4 -3
- package/dist/collections/methods.js +34 -14
- package/dist/config/yamlConfig.d.ts +40 -437
- package/dist/config/yamlConfig.js +8 -2
- package/dist/databases/setup.js +2 -2
- package/dist/main.js +0 -0
- package/dist/migrations/appwriteToX.d.ts +26 -37
- package/dist/migrations/comprehensiveTransfer.js +4 -4
- package/dist/migrations/dataLoader.d.ts +124 -1484
- package/dist/migrations/dataLoader.js +2 -1
- package/dist/migrations/relationships.d.ts +2 -3
- package/dist/migrations/relationships.js +1 -1
- package/dist/migrations/services/UserMappingService.js +1 -1
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +24 -279
- package/dist/migrations/yaml/YamlImportConfigLoader.js +7 -2
- package/dist/schemas/authUser.d.ts +7 -47
- package/dist/schemas/authUser.js +1 -1
- package/dist/shared/jsonSchemaGenerator.d.ts +0 -2
- package/dist/shared/jsonSchemaGenerator.js +4 -17
- package/dist/shared/migrationHelpers.d.ts +17 -119
- package/dist/shared/operationQueue.js +16 -7
- package/dist/shared/schemaGenerator.js +2 -17
- package/dist/storage/schemas.d.ts +149 -296
- package/dist/users/methods.d.ts +2 -2
- package/dist/utils/configMigration.js +0 -1
- package/dist/utils/getClientFromConfig.d.ts +26 -0
- package/dist/utils/getClientFromConfig.js +37 -0
- package/dist/utils/loadConfigs.js +0 -2
- package/dist/utils/schemaStrings.js +2 -17
- package/dist/utils/setupFiles.js +2 -0
- package/dist/utils/versionDetection.d.ts +56 -0
- package/dist/utils/versionDetection.js +217 -0
- package/dist/utils/yamlConverter.d.ts +0 -1
- package/dist/utils/yamlConverter.js +0 -2
- package/dist/utilsController.js +2 -0
- package/package.json +3 -2
- package/src/adapters/AdapterFactory.ts +296 -0
- package/src/adapters/DatabaseAdapter.ts +290 -0
- package/src/adapters/LegacyAdapter.ts +667 -0
- package/src/adapters/TablesDBAdapter.ts +429 -0
- package/src/adapters/index.ts +37 -0
- package/src/collections/attributes.ts +347 -153
- package/src/collections/methods.ts +43 -28
- package/src/config/yamlConfig.ts +8 -2
- package/src/databases/setup.ts +2 -2
- package/src/migrations/afterImportActions.ts +2 -2
- package/src/migrations/comprehensiveTransfer.ts +4 -0
- package/src/migrations/dataLoader.ts +2 -1
- package/src/migrations/relationships.ts +1 -1
- package/src/migrations/services/UserMappingService.ts +1 -1
- package/src/migrations/yaml/YamlImportConfigLoader.ts +7 -2
- package/src/schemas/authUser.ts +1 -1
- package/src/shared/jsonSchemaGenerator.ts +4 -19
- package/src/shared/operationQueue.ts +20 -13
- package/src/shared/schemaGenerator.ts +2 -16
- package/src/types/node-appwrite-tablesdb.d.ts +44 -0
- package/src/users/methods.ts +2 -2
- package/src/utils/configMigration.ts +0 -1
- package/src/utils/getClientFromConfig.ts +56 -0
- package/src/utils/loadConfigs.ts +0 -2
- package/src/utils/schemaStrings.ts +2 -16
- package/src/utils/setupFiles.ts +2 -0
- package/src/utils/versionDetection.ts +265 -0
- package/src/utils/yamlConverter.ts +0 -2
- package/src/utilsController.ts +2 -0
- package/dist/functions/openapi.d.ts +0 -4
- package/dist/functions/openapi.js +0 -60
- package/dist/migrations/attributes.d.ts +0 -4
- package/dist/migrations/attributes.js +0 -301
- package/dist/migrations/backup.d.ts +0 -687
- package/dist/migrations/backup.js +0 -175
- package/dist/migrations/collections.d.ts +0 -22
- package/dist/migrations/collections.js +0 -347
- package/dist/migrations/converters.d.ts +0 -46
- package/dist/migrations/converters.js +0 -139
- package/dist/migrations/databases.d.ts +0 -2
- package/dist/migrations/databases.js +0 -28
- package/dist/migrations/dbHelpers.d.ts +0 -5
- package/dist/migrations/dbHelpers.js +0 -57
- package/dist/migrations/helper.d.ts +0 -3
- package/dist/migrations/helper.js +0 -21
- package/dist/migrations/indexes.d.ts +0 -4
- package/dist/migrations/indexes.js +0 -19
- package/dist/migrations/logging.d.ts +0 -10
- package/dist/migrations/logging.js +0 -46
- package/dist/migrations/migrationHelper.d.ts +0 -173
- package/dist/migrations/migrationHelper.js +0 -130
- package/dist/migrations/openapi.d.ts +0 -4
- package/dist/migrations/openapi.js +0 -60
- package/dist/migrations/queue.d.ts +0 -13
- package/dist/migrations/queue.js +0 -79
- package/dist/migrations/schemaStrings.d.ts +0 -14
- package/dist/migrations/schemaStrings.js +0 -478
- package/dist/migrations/setupDatabase.d.ts +0 -6
- package/dist/migrations/setupDatabase.js +0 -115
- package/dist/migrations/storage.d.ts +0 -10
- package/dist/migrations/storage.js +0 -340
- package/dist/migrations/users.d.ts +0 -16
- package/dist/migrations/users.js +0 -276
- package/dist/migrations/validationRules.d.ts +0 -43
- package/dist/migrations/validationRules.js +0 -42
- package/dist/shared/attributeManager.d.ts +0 -17
- package/dist/shared/attributeManager.js +0 -272
- package/src/functions/openapi.ts +0 -83
- package/src/shared/attributeManager.ts +0 -428
@@ -0,0 +1,302 @@
|
|
1
|
+
/**
|
2
|
+
* TablesDBAdapter - Native TablesDB API Implementation
|
3
|
+
*
|
4
|
+
* This adapter provides direct access to the new Appwrite TablesDB API
|
5
|
+
* without any translation layer. It uses object notation parameters
|
6
|
+
* and returns Models.Row instead of Models.Document.
|
7
|
+
*/
|
8
|
+
import { BaseAdapter, AdapterError } from './DatabaseAdapter.js';
|
9
|
+
/**
|
10
|
+
* TablesDBAdapter implementation for native TablesDB API
|
11
|
+
*/
|
12
|
+
export class TablesDBAdapter extends BaseAdapter {
|
13
|
+
tablesDB;
|
14
|
+
constructor(client) {
|
15
|
+
super(client, 'tablesdb');
|
16
|
+
// Assuming TablesDB service is available on the client
|
17
|
+
this.tablesDB = client.tablesDB || client;
|
18
|
+
}
|
19
|
+
// Row (Document) Operations
|
20
|
+
async listRows(params) {
|
21
|
+
try {
|
22
|
+
const result = await this.tablesDB.listRows(params);
|
23
|
+
return {
|
24
|
+
data: result.rows,
|
25
|
+
rows: result.rows,
|
26
|
+
total: result.total
|
27
|
+
};
|
28
|
+
}
|
29
|
+
catch (error) {
|
30
|
+
throw new AdapterError(`Failed to list rows: ${error instanceof Error ? error.message : 'Unknown error'}`, 'LIST_ROWS_FAILED', error instanceof Error ? error : undefined);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
async createRow(params) {
|
34
|
+
try {
|
35
|
+
const result = await this.tablesDB.createRow(params);
|
36
|
+
return {
|
37
|
+
data: result,
|
38
|
+
rows: [result]
|
39
|
+
};
|
40
|
+
}
|
41
|
+
catch (error) {
|
42
|
+
throw new AdapterError(`Failed to create row: ${error instanceof Error ? error.message : 'Unknown error'}`, 'CREATE_ROW_FAILED', error instanceof Error ? error : undefined);
|
43
|
+
}
|
44
|
+
}
|
45
|
+
async updateRow(params) {
|
46
|
+
try {
|
47
|
+
const result = await this.tablesDB.updateRow(params);
|
48
|
+
return {
|
49
|
+
data: result,
|
50
|
+
rows: [result]
|
51
|
+
};
|
52
|
+
}
|
53
|
+
catch (error) {
|
54
|
+
throw new AdapterError(`Failed to update row: ${error instanceof Error ? error.message : 'Unknown error'}`, 'UPDATE_ROW_FAILED', error instanceof Error ? error : undefined);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
async deleteRow(params) {
|
58
|
+
try {
|
59
|
+
const result = await this.tablesDB.deleteRow(params);
|
60
|
+
return { data: result };
|
61
|
+
}
|
62
|
+
catch (error) {
|
63
|
+
throw new AdapterError(`Failed to delete row: ${error instanceof Error ? error.message : 'Unknown error'}`, 'DELETE_ROW_FAILED', error instanceof Error ? error : undefined);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
async getRow(params) {
|
67
|
+
try {
|
68
|
+
const result = await this.tablesDB.getRow(params);
|
69
|
+
return {
|
70
|
+
data: result,
|
71
|
+
rows: [result]
|
72
|
+
};
|
73
|
+
}
|
74
|
+
catch (error) {
|
75
|
+
throw new AdapterError(`Failed to get row: ${error instanceof Error ? error.message : 'Unknown error'}`, 'GET_ROW_FAILED', error instanceof Error ? error : undefined);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
// Table (Collection) Operations
|
79
|
+
async listTables(params) {
|
80
|
+
try {
|
81
|
+
const result = await this.tablesDB.listTables(params);
|
82
|
+
return {
|
83
|
+
data: result.tables,
|
84
|
+
tables: result.tables,
|
85
|
+
total: result.total
|
86
|
+
};
|
87
|
+
}
|
88
|
+
catch (error) {
|
89
|
+
throw new AdapterError(`Failed to list tables: ${error instanceof Error ? error.message : 'Unknown error'}`, 'LIST_TABLES_FAILED', error instanceof Error ? error : undefined);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
async createTable(params) {
|
93
|
+
try {
|
94
|
+
const result = await this.tablesDB.createTable(params);
|
95
|
+
return {
|
96
|
+
data: result,
|
97
|
+
tables: [result]
|
98
|
+
};
|
99
|
+
}
|
100
|
+
catch (error) {
|
101
|
+
throw new AdapterError(`Failed to create table: ${error instanceof Error ? error.message : 'Unknown error'}`, 'CREATE_TABLE_FAILED', error instanceof Error ? error : undefined);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
async updateTable(params) {
|
105
|
+
try {
|
106
|
+
const result = await this.tablesDB.updateTable(params);
|
107
|
+
return {
|
108
|
+
data: result,
|
109
|
+
tables: [result]
|
110
|
+
};
|
111
|
+
}
|
112
|
+
catch (error) {
|
113
|
+
throw new AdapterError(`Failed to update table: ${error instanceof Error ? error.message : 'Unknown error'}`, 'UPDATE_TABLE_FAILED', error instanceof Error ? error : undefined);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
async deleteTable(params) {
|
117
|
+
try {
|
118
|
+
const result = await this.tablesDB.deleteTable(params);
|
119
|
+
return { data: result };
|
120
|
+
}
|
121
|
+
catch (error) {
|
122
|
+
throw new AdapterError(`Failed to delete table: ${error instanceof Error ? error.message : 'Unknown error'}`, 'DELETE_TABLE_FAILED', error instanceof Error ? error : undefined);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
async getTable(params) {
|
126
|
+
try {
|
127
|
+
const result = await this.tablesDB.getTable(params);
|
128
|
+
return {
|
129
|
+
data: result,
|
130
|
+
tables: [result]
|
131
|
+
};
|
132
|
+
}
|
133
|
+
catch (error) {
|
134
|
+
throw new AdapterError(`Failed to get table: ${error instanceof Error ? error.message : 'Unknown error'}`, 'GET_TABLE_FAILED', error instanceof Error ? error : undefined);
|
135
|
+
}
|
136
|
+
}
|
137
|
+
// Index Operations
|
138
|
+
async listIndexes(params) {
|
139
|
+
try {
|
140
|
+
const result = await this.tablesDB.listIndexes(params);
|
141
|
+
return {
|
142
|
+
data: result.indexes,
|
143
|
+
total: result.total
|
144
|
+
};
|
145
|
+
}
|
146
|
+
catch (error) {
|
147
|
+
throw new AdapterError(`Failed to list indexes: ${error instanceof Error ? error.message : 'Unknown error'}`, 'LIST_INDEXES_FAILED', error instanceof Error ? error : undefined);
|
148
|
+
}
|
149
|
+
}
|
150
|
+
async createIndex(params) {
|
151
|
+
try {
|
152
|
+
const result = await this.tablesDB.createIndex(params);
|
153
|
+
return { data: result };
|
154
|
+
}
|
155
|
+
catch (error) {
|
156
|
+
throw new AdapterError(`Failed to create index: ${error instanceof Error ? error.message : 'Unknown error'}`, 'CREATE_INDEX_FAILED', error instanceof Error ? error : undefined);
|
157
|
+
}
|
158
|
+
}
|
159
|
+
async deleteIndex(params) {
|
160
|
+
try {
|
161
|
+
const result = await this.tablesDB.deleteIndex(params);
|
162
|
+
return { data: result };
|
163
|
+
}
|
164
|
+
catch (error) {
|
165
|
+
throw new AdapterError(`Failed to delete index: ${error instanceof Error ? error.message : 'Unknown error'}`, 'DELETE_INDEX_FAILED', error instanceof Error ? error : undefined);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
// Attribute Operations
|
169
|
+
async createAttribute(params) {
|
170
|
+
try {
|
171
|
+
// TablesDB may have different method names for attribute operations
|
172
|
+
const result = await this.tablesDB.createAttribute(params);
|
173
|
+
return { data: result };
|
174
|
+
}
|
175
|
+
catch (error) {
|
176
|
+
throw new AdapterError(`Failed to create attribute: ${error instanceof Error ? error.message : 'Unknown error'}`, 'CREATE_ATTRIBUTE_FAILED', error instanceof Error ? error : undefined);
|
177
|
+
}
|
178
|
+
}
|
179
|
+
async updateAttribute(params) {
|
180
|
+
try {
|
181
|
+
const result = await this.tablesDB.updateAttribute(params);
|
182
|
+
return { data: result };
|
183
|
+
}
|
184
|
+
catch (error) {
|
185
|
+
throw new AdapterError(`Failed to update attribute: ${error instanceof Error ? error.message : 'Unknown error'}`, 'UPDATE_ATTRIBUTE_FAILED', error instanceof Error ? error : undefined);
|
186
|
+
}
|
187
|
+
}
|
188
|
+
async deleteAttribute(params) {
|
189
|
+
try {
|
190
|
+
const result = await this.tablesDB.deleteAttribute(params);
|
191
|
+
return { data: result };
|
192
|
+
}
|
193
|
+
catch (error) {
|
194
|
+
throw new AdapterError(`Failed to delete attribute: ${error instanceof Error ? error.message : 'Unknown error'}`, 'DELETE_ATTRIBUTE_FAILED', error instanceof Error ? error : undefined);
|
195
|
+
}
|
196
|
+
}
|
197
|
+
// Bulk Operations (Native TablesDB Support)
|
198
|
+
async bulkCreateRows(params) {
|
199
|
+
try {
|
200
|
+
const result = await this.tablesDB.bulkCreateRows(params);
|
201
|
+
return {
|
202
|
+
data: result.rows,
|
203
|
+
rows: result.rows,
|
204
|
+
total: result.rows?.length || 0
|
205
|
+
};
|
206
|
+
}
|
207
|
+
catch (error) {
|
208
|
+
throw new AdapterError(`Failed to bulk create rows: ${error instanceof Error ? error.message : 'Unknown error'}`, 'BULK_CREATE_ROWS_FAILED', error instanceof Error ? error : undefined);
|
209
|
+
}
|
210
|
+
}
|
211
|
+
async bulkUpsertRows(params) {
|
212
|
+
try {
|
213
|
+
const result = await this.tablesDB.bulkUpsertRows(params);
|
214
|
+
return {
|
215
|
+
data: result.rows,
|
216
|
+
rows: result.rows,
|
217
|
+
total: result.rows?.length || 0
|
218
|
+
};
|
219
|
+
}
|
220
|
+
catch (error) {
|
221
|
+
throw new AdapterError(`Failed to bulk upsert rows: ${error instanceof Error ? error.message : 'Unknown error'}`, 'BULK_UPSERT_ROWS_FAILED', error instanceof Error ? error : undefined);
|
222
|
+
}
|
223
|
+
}
|
224
|
+
async bulkDeleteRows(params) {
|
225
|
+
try {
|
226
|
+
const result = await this.tablesDB.bulkDeleteRows(params);
|
227
|
+
return {
|
228
|
+
data: result,
|
229
|
+
total: params.rowIds.length
|
230
|
+
};
|
231
|
+
}
|
232
|
+
catch (error) {
|
233
|
+
throw new AdapterError(`Failed to bulk delete rows: ${error instanceof Error ? error.message : 'Unknown error'}`, 'BULK_DELETE_ROWS_FAILED', error instanceof Error ? error : undefined);
|
234
|
+
}
|
235
|
+
}
|
236
|
+
// Metadata and Capabilities
|
237
|
+
getMetadata() {
|
238
|
+
return {
|
239
|
+
apiMode: 'tablesdb',
|
240
|
+
terminology: {
|
241
|
+
container: 'table',
|
242
|
+
item: 'row',
|
243
|
+
service: 'TablesDB'
|
244
|
+
},
|
245
|
+
capabilities: {
|
246
|
+
bulkOperations: true,
|
247
|
+
advancedQueries: true,
|
248
|
+
realtime: true,
|
249
|
+
transactions: true // TablesDB may support transactions
|
250
|
+
}
|
251
|
+
};
|
252
|
+
}
|
253
|
+
supportsBulkOperations() {
|
254
|
+
return true; // TablesDB natively supports bulk operations
|
255
|
+
}
|
256
|
+
// Advanced TablesDB Features
|
257
|
+
/**
|
258
|
+
* Execute a transaction (if supported by TablesDB)
|
259
|
+
*/
|
260
|
+
async executeTransaction(operations) {
|
261
|
+
if (!this.tablesDB.transaction) {
|
262
|
+
throw new AdapterError('Transactions are not supported in this TablesDB version', 'TRANSACTIONS_NOT_SUPPORTED');
|
263
|
+
}
|
264
|
+
try {
|
265
|
+
const result = await this.tablesDB.transaction(operations);
|
266
|
+
return { data: result };
|
267
|
+
}
|
268
|
+
catch (error) {
|
269
|
+
throw new AdapterError(`Transaction failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 'TRANSACTION_FAILED', error instanceof Error ? error : undefined);
|
270
|
+
}
|
271
|
+
}
|
272
|
+
/**
|
273
|
+
* Subscribe to real-time updates (if supported)
|
274
|
+
*/
|
275
|
+
subscribeToTable(params, callback) {
|
276
|
+
if (!this.tablesDB.subscribe) {
|
277
|
+
throw new AdapterError('Real-time subscriptions are not supported', 'REALTIME_NOT_SUPPORTED');
|
278
|
+
}
|
279
|
+
try {
|
280
|
+
return this.tablesDB.subscribe(`databases.${params.databaseId}.tables.${params.tableId}.rows`, callback);
|
281
|
+
}
|
282
|
+
catch (error) {
|
283
|
+
throw new AdapterError(`Failed to subscribe to table: ${error instanceof Error ? error.message : 'Unknown error'}`, 'SUBSCRIPTION_FAILED', error instanceof Error ? error : undefined);
|
284
|
+
}
|
285
|
+
}
|
286
|
+
/**
|
287
|
+
* Get table statistics (if available in TablesDB)
|
288
|
+
*/
|
289
|
+
async getTableStats(params) {
|
290
|
+
try {
|
291
|
+
if (!this.tablesDB.getTableStats) {
|
292
|
+
// Fallback to basic table info
|
293
|
+
return this.getTable(params);
|
294
|
+
}
|
295
|
+
const result = await this.tablesDB.getTableStats(params);
|
296
|
+
return { data: result };
|
297
|
+
}
|
298
|
+
catch (error) {
|
299
|
+
throw new AdapterError(`Failed to get table stats: ${error instanceof Error ? error.message : 'Unknown error'}`, 'GET_TABLE_STATS_FAILED', error instanceof Error ? error : undefined);
|
300
|
+
}
|
301
|
+
}
|
302
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* Adapters Module - Unified Database API for Appwrite
|
3
|
+
*
|
4
|
+
* This module exports all adapter classes and utilities for working with
|
5
|
+
* both legacy Appwrite (collections/documents) and TablesDB (tables/rows) APIs.
|
6
|
+
*/
|
7
|
+
export { AdapterFactory, type AdapterFactoryConfig, type AdapterFactoryResult } from './AdapterFactory.js';
|
8
|
+
export { type DatabaseAdapter, type CreateRowParams, type UpdateRowParams, type ListRowsParams, type DeleteRowParams, type CreateTableParams, type UpdateTableParams, type ListTablesParams, type DeleteTableParams, type GetTableParams, type BulkCreateRowsParams, type BulkUpsertRowsParams, type BulkDeleteRowsParams, type CreateIndexParams, type ListIndexesParams, type DeleteIndexParams, type CreateAttributeParams, type UpdateAttributeParams, type DeleteAttributeParams, type ApiResponse, type AdapterMetadata, BaseAdapter } from './DatabaseAdapter.js';
|
9
|
+
export { TablesDBAdapter } from './TablesDBAdapter.js';
|
10
|
+
export { LegacyAdapter } from './LegacyAdapter.js';
|
11
|
+
export { createDatabaseAdapter, getApiCapabilities } from './AdapterFactory.js';
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/**
|
2
|
+
* Adapters Module - Unified Database API for Appwrite
|
3
|
+
*
|
4
|
+
* This module exports all adapter classes and utilities for working with
|
5
|
+
* both legacy Appwrite (collections/documents) and TablesDB (tables/rows) APIs.
|
6
|
+
*/
|
7
|
+
export { AdapterFactory } from './AdapterFactory.js';
|
8
|
+
export { BaseAdapter } from './DatabaseAdapter.js';
|
9
|
+
export { TablesDBAdapter } from './TablesDBAdapter.js';
|
10
|
+
export { LegacyAdapter } from './LegacyAdapter.js';
|
11
|
+
// Convenience exports
|
12
|
+
export { createDatabaseAdapter, getApiCapabilities } from './AdapterFactory.js';
|
@@ -29,19 +29,19 @@ retryCount = 0, maxRetries = 5) => {
|
|
29
29
|
}
|
30
30
|
console.log(chalk.gray(`Attribute '${attributeKey}' status: ${attribute.status}`));
|
31
31
|
switch (attribute.status) {
|
32
|
-
case
|
32
|
+
case "available":
|
33
33
|
console.log(chalk.green(`✅ Attribute '${attributeKey}' is now available`));
|
34
34
|
return true;
|
35
|
-
case
|
35
|
+
case "failed":
|
36
36
|
console.log(chalk.red(`❌ Attribute '${attributeKey}' failed: ${attribute.error}`));
|
37
37
|
return false;
|
38
|
-
case
|
38
|
+
case "stuck":
|
39
39
|
console.log(chalk.yellow(`⚠️ Attribute '${attributeKey}' is stuck, will retry...`));
|
40
40
|
return false;
|
41
|
-
case
|
41
|
+
case "processing":
|
42
42
|
// Continue waiting
|
43
43
|
break;
|
44
|
-
case
|
44
|
+
case "deleting":
|
45
45
|
console.log(chalk.yellow(`Attribute '${attributeKey}' is being deleted`));
|
46
46
|
break;
|
47
47
|
default:
|
@@ -254,7 +254,8 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
|
|
254
254
|
// Relationship attribute logic with adjustments
|
255
255
|
let collectionFoundViaRelatedCollection;
|
256
256
|
let relatedCollectionId;
|
257
|
-
if (finalAttribute.type === "relationship"
|
257
|
+
if (finalAttribute.type === "relationship" &&
|
258
|
+
finalAttribute.relatedCollection) {
|
258
259
|
if (nameToIdMapping.has(finalAttribute.relatedCollection)) {
|
259
260
|
relatedCollectionId = nameToIdMapping.get(finalAttribute.relatedCollection);
|
260
261
|
try {
|
@@ -277,9 +278,9 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
|
|
277
278
|
nameToIdMapping.set(finalAttribute.relatedCollection, relatedCollectionId);
|
278
279
|
}
|
279
280
|
}
|
280
|
-
//
|
281
|
-
if (
|
282
|
-
|
281
|
+
// ONLY queue relationship attributes that have actual unresolved dependencies
|
282
|
+
if (!(relatedCollectionId && collectionFoundViaRelatedCollection)) {
|
283
|
+
console.log(chalk.yellow(`⏳ Queueing relationship attribute '${finalAttribute.key}' - related collection '${finalAttribute.relatedCollection}' not found yet`));
|
283
284
|
enqueueOperation({
|
284
285
|
type: "attribute",
|
285
286
|
collectionId: collection.$id,
|
@@ -302,35 +303,49 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
|
|
302
303
|
else {
|
303
304
|
await tryAwaitWithRetry(async () => await db.updateStringAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required
|
304
305
|
? finalAttribute.xdefault
|
305
|
-
: null));
|
306
|
+
: null, finalAttribute.size));
|
306
307
|
}
|
307
308
|
break;
|
308
309
|
case "integer":
|
309
310
|
if (action === "create") {
|
310
311
|
if (finalAttribute.min &&
|
311
312
|
BigInt(finalAttribute.min) === BigInt(-9223372036854776000)) {
|
312
|
-
|
313
|
+
finalAttribute.min = undefined;
|
313
314
|
}
|
314
315
|
if (finalAttribute.max &&
|
315
316
|
BigInt(finalAttribute.max) === BigInt(9223372036854776000)) {
|
316
|
-
|
317
|
+
finalAttribute.max = undefined;
|
317
318
|
}
|
318
|
-
|
319
|
+
const minValue = finalAttribute.min !== undefined && finalAttribute.min !== null
|
320
|
+
? parseInt(finalAttribute.min)
|
321
|
+
: -9007199254740991;
|
322
|
+
const maxValue = finalAttribute.max !== undefined && finalAttribute.max !== null
|
323
|
+
? parseInt(finalAttribute.max)
|
324
|
+
: 9007199254740991;
|
325
|
+
console.log(`DEBUG: Creating integer attribute '${finalAttribute.key}' with min=${minValue}, max=${maxValue}, minType=${typeof minValue}, maxType=${typeof maxValue}`);
|
326
|
+
await tryAwaitWithRetry(async () => await db.createIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, minValue, maxValue, finalAttribute.xdefault !== undefined && !finalAttribute.required
|
319
327
|
? finalAttribute.xdefault
|
320
328
|
: null, finalAttribute.array || false));
|
321
329
|
}
|
322
330
|
else {
|
323
331
|
if (finalAttribute.min &&
|
324
332
|
BigInt(finalAttribute.min) === BigInt(-9223372036854776000)) {
|
325
|
-
|
333
|
+
finalAttribute.min = undefined;
|
326
334
|
}
|
327
335
|
if (finalAttribute.max &&
|
328
336
|
BigInt(finalAttribute.max) === BigInt(9223372036854776000)) {
|
329
|
-
|
337
|
+
finalAttribute.max = undefined;
|
330
338
|
}
|
331
|
-
|
339
|
+
const minValue = finalAttribute.min !== undefined && finalAttribute.min !== null
|
340
|
+
? parseInt(finalAttribute.min)
|
341
|
+
: 9007199254740991;
|
342
|
+
const maxValue = finalAttribute.max !== undefined && finalAttribute.max !== null
|
343
|
+
? parseInt(finalAttribute.max)
|
344
|
+
: 9007199254740991;
|
345
|
+
console.log(`DEBUG: Updating integer attribute '${finalAttribute.key}' with min=${minValue}, max=${maxValue}, minType=${typeof minValue}, maxType=${typeof maxValue}`);
|
346
|
+
await tryAwaitWithRetry(async () => await db.updateIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault !== undefined && !finalAttribute.required
|
332
347
|
? finalAttribute.xdefault
|
333
|
-
: null));
|
348
|
+
: null, minValue, maxValue));
|
334
349
|
}
|
335
350
|
break;
|
336
351
|
case "double":
|
@@ -469,15 +484,16 @@ export const createUpdateCollectionAttributesWithStatusCheck = async (db, dbId,
|
|
469
484
|
}
|
470
485
|
const existingAttributesMap = new Map();
|
471
486
|
try {
|
487
|
+
const parsedAttributes = currentCollection.attributes.map((attr) =>
|
472
488
|
// @ts-expect-error
|
473
|
-
|
474
|
-
parsedAttributes.forEach(attr => existingAttributesMap.set(attr.key, attr));
|
489
|
+
parseAttribute(attr));
|
490
|
+
parsedAttributes.forEach((attr) => existingAttributesMap.set(attr.key, attr));
|
475
491
|
}
|
476
492
|
catch (error) {
|
477
493
|
console.log(chalk.yellow(`Warning: Could not parse existing attributes: ${error}`));
|
478
494
|
}
|
479
495
|
// Filter to only attributes that need processing (new or changed)
|
480
|
-
const attributesToProcess = attributes.filter(attribute => {
|
496
|
+
const attributesToProcess = attributes.filter((attribute) => {
|
481
497
|
const existing = existingAttributesMap.get(attribute.key);
|
482
498
|
if (!existing) {
|
483
499
|
console.log(chalk.blue(`➕ New attribute: ${attribute.key}`));
|
@@ -500,7 +516,8 @@ export const createUpdateCollectionAttributesWithStatusCheck = async (db, dbId,
|
|
500
516
|
let remainingAttributes = [...attributesToProcess];
|
501
517
|
let overallRetryCount = 0;
|
502
518
|
const maxOverallRetries = 3;
|
503
|
-
while (remainingAttributes.length > 0 &&
|
519
|
+
while (remainingAttributes.length > 0 &&
|
520
|
+
overallRetryCount < maxOverallRetries) {
|
504
521
|
const attributesToProcessThisRound = [...remainingAttributes];
|
505
522
|
remainingAttributes = []; // Reset for next iteration
|
506
523
|
console.log(chalk.blue(`\n=== Attempt ${overallRetryCount + 1}/${maxOverallRetries} - Processing ${attributesToProcessThisRound.length} attributes ===`));
|
@@ -544,7 +561,9 @@ export const createUpdateCollectionAttributesWithStatusCheck = async (db, dbId,
|
|
544
561
|
}
|
545
562
|
// If we get here, some attributes still failed after all retries
|
546
563
|
if (attributesToProcess.length > 0) {
|
547
|
-
console.log(chalk.red(`\n❌ Failed to create ${attributesToProcess.length} attributes after ${maxOverallRetries} attempts: ${attributesToProcess
|
564
|
+
console.log(chalk.red(`\n❌ Failed to create ${attributesToProcess.length} attributes after ${maxOverallRetries} attempts: ${attributesToProcess
|
565
|
+
.map((a) => a.key)
|
566
|
+
.join(", ")}`));
|
548
567
|
console.log(chalk.red(`This may indicate a fundamental issue with the attribute definitions or Appwrite instance`));
|
549
568
|
return false;
|
550
569
|
}
|
@@ -1,8 +1,9 @@
|
|
1
1
|
import { Databases, type Models } from "node-appwrite";
|
2
2
|
import type { AppwriteConfig, CollectionCreate } from "appwrite-utils";
|
3
|
-
|
4
|
-
export declare const
|
5
|
-
export declare const
|
3
|
+
import type { DatabaseAdapter } from "../adapters/DatabaseAdapter.js";
|
4
|
+
export declare const documentExists: (db: Databases | DatabaseAdapter, dbId: string, targetCollectionId: string, toCreateObject: any) => Promise<Models.Document | null>;
|
5
|
+
export declare const checkForCollection: (db: Databases | DatabaseAdapter, dbId: string, collection: Partial<CollectionCreate>) => Promise<Models.Collection | null>;
|
6
|
+
export declare const fetchAndCacheCollectionByName: (db: Databases | DatabaseAdapter, dbId: string, collectionName: string) => Promise<Models.Collection | undefined>;
|
6
7
|
export declare const wipeDatabase: (database: Databases, databaseId: string) => Promise<{
|
7
8
|
collectionId: string;
|
8
9
|
collectionName: string;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { Client, Databases, ID, Permission, Query, } from "node-appwrite";
|
2
|
-
import {
|
2
|
+
import { getAdapterFromConfig } from "../utils/getClientFromConfig.js";
|
3
|
+
import { nameToIdMapping, processQueue, queuedOperations } from "../shared/operationQueue.js";
|
3
4
|
import { createUpdateCollectionAttributes, createUpdateCollectionAttributesWithStatusCheck } from "./attributes.js";
|
4
5
|
import { createOrUpdateIndexes, createOrUpdateIndexesWithStatusCheck } from "./indexes.js";
|
5
6
|
import { SchemaGenerator } from "../shared/schemaGenerator.js";
|
@@ -9,7 +10,9 @@ import { MessageFormatter } from "../shared/messageFormatter.js";
|
|
9
10
|
import { ProgressManager } from "../shared/progressManager.js";
|
10
11
|
import chalk from "chalk";
|
11
12
|
export const documentExists = async (db, dbId, targetCollectionId, toCreateObject) => {
|
12
|
-
const collection = await db
|
13
|
+
const collection = await (db instanceof Databases ?
|
14
|
+
db.getCollection(dbId, targetCollectionId) :
|
15
|
+
db.getTable({ databaseId: dbId, tableId: targetCollectionId }));
|
13
16
|
const attributes = collection.attributes;
|
14
17
|
let arrayTypeAttributes = attributes
|
15
18
|
.filter((attribute) => attribute.array === true)
|
@@ -46,16 +49,22 @@ export const documentExists = async (db, dbId, targetCollectionId, toCreateObjec
|
|
46
49
|
// Convert to Query parameters
|
47
50
|
const validQueryParams = validMappedEntries.map(([key, value]) => Query.equal(key, value));
|
48
51
|
// Execute the query with the validated and prepared parameters
|
49
|
-
const result = await db
|
50
|
-
|
52
|
+
const result = await (db instanceof Databases ?
|
53
|
+
db.listDocuments(dbId, targetCollectionId, validQueryParams) :
|
54
|
+
db.listRows({ databaseId: dbId, tableId: targetCollectionId, queries: validQueryParams }));
|
55
|
+
const items = db instanceof Databases ? result.documents : (result.rows || result.documents);
|
56
|
+
return items?.[0] || null;
|
51
57
|
};
|
52
58
|
export const checkForCollection = async (db, dbId, collection) => {
|
53
59
|
try {
|
54
60
|
MessageFormatter.progress(`Checking for collection with name: ${collection.name}`, { prefix: "Collections" });
|
55
|
-
const response = await tryAwaitWithRetry(async () =>
|
56
|
-
|
57
|
-
|
58
|
-
|
61
|
+
const response = await tryAwaitWithRetry(async () => db instanceof Databases ?
|
62
|
+
await db.listCollections(dbId, [Query.equal("name", collection.name)]) :
|
63
|
+
await db.listTables({ databaseId: dbId, queries: [Query.equal("name", collection.name)] }));
|
64
|
+
const items = db instanceof Databases ? response.collections : (response.tables || response.collections);
|
65
|
+
if (items && items.length > 0) {
|
66
|
+
MessageFormatter.info(`Collection found: ${items[0].$id}`, { prefix: "Collections" });
|
67
|
+
return { ...collection, ...items[0] };
|
59
68
|
}
|
60
69
|
else {
|
61
70
|
MessageFormatter.info(`No collection found with name: ${collection.name}`, { prefix: "Collections" });
|
@@ -72,13 +81,18 @@ export const fetchAndCacheCollectionByName = async (db, dbId, collectionName) =>
|
|
72
81
|
if (nameToIdMapping.has(collectionName)) {
|
73
82
|
const collectionId = nameToIdMapping.get(collectionName);
|
74
83
|
MessageFormatter.debug(`Collection found in cache: ${collectionId}`, undefined, { prefix: "Collections" });
|
75
|
-
return await tryAwaitWithRetry(async () =>
|
84
|
+
return await tryAwaitWithRetry(async () => db instanceof Databases ?
|
85
|
+
await db.getCollection(dbId, collectionId) :
|
86
|
+
await db.getTable({ databaseId: dbId, tableId: collectionId }));
|
76
87
|
}
|
77
88
|
else {
|
78
89
|
MessageFormatter.progress(`Fetching collection by name: ${collectionName}`, { prefix: "Collections" });
|
79
|
-
const collectionsPulled = await tryAwaitWithRetry(async () =>
|
80
|
-
|
81
|
-
|
90
|
+
const collectionsPulled = await tryAwaitWithRetry(async () => db instanceof Databases ?
|
91
|
+
await db.listCollections(dbId, [Query.equal("name", collectionName)]) :
|
92
|
+
await db.listTables({ databaseId: dbId, queries: [Query.equal("name", collectionName)] }));
|
93
|
+
const items = db instanceof Databases ? collectionsPulled.collections : (collectionsPulled.tables || collectionsPulled.collections);
|
94
|
+
if ((collectionsPulled.total || items?.length) > 0) {
|
95
|
+
const collection = items[0];
|
82
96
|
MessageFormatter.info(`Collection found: ${collection.$id}`, { prefix: "Collections" });
|
83
97
|
nameToIdMapping.set(collectionName, collection.$id);
|
84
98
|
return collection;
|
@@ -281,8 +295,14 @@ export const createOrUpdateCollections = async (database, databaseId, config, de
|
|
281
295
|
// Add delay after creating indexes
|
282
296
|
await delay(250);
|
283
297
|
}
|
284
|
-
// Process any remaining tasks in the queue
|
285
|
-
|
298
|
+
// Process any remaining tasks in the queue (only if there are operations to process)
|
299
|
+
if (queuedOperations.length > 0) {
|
300
|
+
MessageFormatter.info(`Processing ${queuedOperations.length} queued operations (relationship dependencies)`, { prefix: "Collections" });
|
301
|
+
await processQueue(database, databaseId);
|
302
|
+
}
|
303
|
+
else {
|
304
|
+
MessageFormatter.info("No queued operations to process", { prefix: "Collections" });
|
305
|
+
}
|
286
306
|
};
|
287
307
|
export const generateMockData = async (database, databaseId, configCollections) => {
|
288
308
|
for (const { collection, mockFunction } of configCollections) {
|