appwrite-utils-cli 1.5.1 → 1.6.0
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/CHANGELOG.md +199 -0
- package/README.md +251 -29
- package/dist/adapters/AdapterFactory.d.ts +10 -3
- package/dist/adapters/AdapterFactory.js +213 -17
- package/dist/adapters/TablesDBAdapter.js +60 -17
- package/dist/backups/operations/bucketBackup.d.ts +19 -0
- package/dist/backups/operations/bucketBackup.js +197 -0
- package/dist/backups/operations/collectionBackup.d.ts +30 -0
- package/dist/backups/operations/collectionBackup.js +201 -0
- package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
- package/dist/backups/operations/comprehensiveBackup.js +238 -0
- package/dist/backups/schemas/bucketManifest.d.ts +93 -0
- package/dist/backups/schemas/bucketManifest.js +33 -0
- package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
- package/dist/backups/schemas/comprehensiveManifest.js +32 -0
- package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
- package/dist/backups/tracking/centralizedTracking.js +274 -0
- package/dist/cli/commands/configCommands.d.ts +8 -0
- package/dist/cli/commands/configCommands.js +160 -0
- package/dist/cli/commands/databaseCommands.d.ts +13 -0
- package/dist/cli/commands/databaseCommands.js +478 -0
- package/dist/cli/commands/functionCommands.d.ts +7 -0
- package/dist/cli/commands/functionCommands.js +289 -0
- package/dist/cli/commands/schemaCommands.d.ts +7 -0
- package/dist/cli/commands/schemaCommands.js +134 -0
- package/dist/cli/commands/transferCommands.d.ts +5 -0
- package/dist/cli/commands/transferCommands.js +384 -0
- package/dist/collections/attributes.d.ts +5 -4
- package/dist/collections/attributes.js +539 -246
- package/dist/collections/indexes.js +39 -37
- package/dist/collections/methods.d.ts +2 -16
- package/dist/collections/methods.js +90 -538
- package/dist/collections/transferOperations.d.ts +7 -0
- package/dist/collections/transferOperations.js +331 -0
- package/dist/collections/wipeOperations.d.ts +16 -0
- package/dist/collections/wipeOperations.js +328 -0
- package/dist/config/configMigration.d.ts +87 -0
- package/dist/config/configMigration.js +390 -0
- package/dist/config/configValidation.d.ts +66 -0
- package/dist/config/configValidation.js +358 -0
- package/dist/config/yamlConfig.d.ts +455 -1
- package/dist/config/yamlConfig.js +145 -52
- package/dist/databases/methods.js +3 -2
- package/dist/databases/setup.d.ts +1 -2
- package/dist/databases/setup.js +9 -87
- package/dist/examples/yamlTerminologyExample.d.ts +42 -0
- package/dist/examples/yamlTerminologyExample.js +269 -0
- package/dist/functions/deployments.js +11 -10
- package/dist/functions/methods.d.ts +1 -1
- package/dist/functions/methods.js +5 -4
- package/dist/init.js +9 -9
- package/dist/interactiveCLI.d.ts +8 -17
- package/dist/interactiveCLI.js +186 -1171
- package/dist/main.js +364 -21
- package/dist/migrations/afterImportActions.js +22 -30
- package/dist/migrations/appwriteToX.js +71 -25
- package/dist/migrations/dataLoader.js +35 -26
- package/dist/migrations/importController.js +29 -30
- package/dist/migrations/relationships.js +13 -12
- package/dist/migrations/services/ImportOrchestrator.js +16 -19
- package/dist/migrations/transfer.js +46 -46
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +3 -1
- package/dist/migrations/yaml/YamlImportConfigLoader.js +6 -3
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +9 -3
- package/dist/migrations/yaml/YamlImportIntegration.js +22 -11
- package/dist/migrations/yaml/generateImportSchemas.d.ts +14 -1
- package/dist/migrations/yaml/generateImportSchemas.js +736 -7
- package/dist/schemas/authUser.d.ts +1 -1
- package/dist/setupController.js +3 -2
- package/dist/shared/backupMetadataSchema.d.ts +94 -0
- package/dist/shared/backupMetadataSchema.js +38 -0
- package/dist/shared/backupTracking.d.ts +18 -0
- package/dist/shared/backupTracking.js +176 -0
- package/dist/shared/confirmationDialogs.js +15 -15
- package/dist/shared/errorUtils.d.ts +54 -0
- package/dist/shared/errorUtils.js +95 -0
- package/dist/shared/functionManager.js +20 -19
- package/dist/shared/indexManager.js +12 -11
- package/dist/shared/jsonSchemaGenerator.js +10 -26
- package/dist/shared/logging.d.ts +51 -0
- package/dist/shared/logging.js +70 -0
- package/dist/shared/messageFormatter.d.ts +2 -0
- package/dist/shared/messageFormatter.js +10 -0
- package/dist/shared/migrationHelpers.d.ts +6 -16
- package/dist/shared/migrationHelpers.js +24 -21
- package/dist/shared/operationLogger.d.ts +8 -1
- package/dist/shared/operationLogger.js +11 -24
- package/dist/shared/operationQueue.d.ts +28 -1
- package/dist/shared/operationQueue.js +268 -66
- package/dist/shared/operationsTable.d.ts +26 -0
- package/dist/shared/operationsTable.js +286 -0
- package/dist/shared/operationsTableSchema.d.ts +48 -0
- package/dist/shared/operationsTableSchema.js +35 -0
- package/dist/shared/relationshipExtractor.d.ts +56 -0
- package/dist/shared/relationshipExtractor.js +138 -0
- package/dist/shared/schemaGenerator.d.ts +19 -1
- package/dist/shared/schemaGenerator.js +56 -75
- package/dist/storage/backupCompression.d.ts +20 -0
- package/dist/storage/backupCompression.js +67 -0
- package/dist/storage/methods.d.ts +16 -2
- package/dist/storage/methods.js +98 -14
- package/dist/users/methods.js +9 -8
- package/dist/utils/configDiscovery.d.ts +78 -0
- package/dist/utils/configDiscovery.js +430 -0
- package/dist/utils/directoryUtils.d.ts +22 -0
- package/dist/utils/directoryUtils.js +59 -0
- package/dist/utils/getClientFromConfig.d.ts +17 -8
- package/dist/utils/getClientFromConfig.js +162 -17
- package/dist/utils/helperFunctions.d.ts +16 -2
- package/dist/utils/helperFunctions.js +19 -5
- package/dist/utils/loadConfigs.d.ts +34 -9
- package/dist/utils/loadConfigs.js +236 -316
- package/dist/utils/pathResolvers.d.ts +53 -0
- package/dist/utils/pathResolvers.js +72 -0
- package/dist/utils/projectConfig.d.ts +119 -0
- package/dist/utils/projectConfig.js +171 -0
- package/dist/utils/retryFailedPromises.js +4 -2
- package/dist/utils/sessionAuth.d.ts +48 -0
- package/dist/utils/sessionAuth.js +164 -0
- package/dist/utils/sessionPreservationExample.d.ts +1666 -0
- package/dist/utils/sessionPreservationExample.js +101 -0
- package/dist/utils/setupFiles.js +301 -41
- package/dist/utils/typeGuards.d.ts +35 -0
- package/dist/utils/typeGuards.js +57 -0
- package/dist/utils/versionDetection.js +145 -9
- package/dist/utils/yamlConverter.d.ts +53 -3
- package/dist/utils/yamlConverter.js +232 -13
- package/dist/utils/yamlLoader.d.ts +70 -0
- package/dist/utils/yamlLoader.js +263 -0
- package/dist/utilsController.d.ts +36 -3
- package/dist/utilsController.js +186 -56
- package/package.json +12 -2
- package/src/adapters/AdapterFactory.ts +263 -35
- package/src/adapters/TablesDBAdapter.ts +225 -36
- package/src/backups/operations/bucketBackup.ts +277 -0
- package/src/backups/operations/collectionBackup.ts +310 -0
- package/src/backups/operations/comprehensiveBackup.ts +342 -0
- package/src/backups/schemas/bucketManifest.ts +78 -0
- package/src/backups/schemas/comprehensiveManifest.ts +76 -0
- package/src/backups/tracking/centralizedTracking.ts +352 -0
- package/src/cli/commands/configCommands.ts +194 -0
- package/src/cli/commands/databaseCommands.ts +635 -0
- package/src/cli/commands/functionCommands.ts +379 -0
- package/src/cli/commands/schemaCommands.ts +163 -0
- package/src/cli/commands/transferCommands.ts +457 -0
- package/src/collections/attributes.ts +900 -621
- package/src/collections/attributes.ts.backup +1555 -0
- package/src/collections/indexes.ts +116 -114
- package/src/collections/methods.ts +295 -968
- package/src/collections/transferOperations.ts +516 -0
- package/src/collections/wipeOperations.ts +501 -0
- package/src/config/README.md +274 -0
- package/src/config/configMigration.ts +575 -0
- package/src/config/configValidation.ts +445 -0
- package/src/config/yamlConfig.ts +168 -55
- package/src/databases/methods.ts +3 -2
- package/src/databases/setup.ts +11 -138
- package/src/examples/yamlTerminologyExample.ts +341 -0
- package/src/functions/deployments.ts +14 -12
- package/src/functions/methods.ts +11 -11
- package/src/functions/templates/hono-typescript/README.md +286 -0
- package/src/functions/templates/hono-typescript/package.json +26 -0
- package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
- package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
- package/src/functions/templates/hono-typescript/src/app.ts +180 -0
- package/src/functions/templates/hono-typescript/src/context.ts +103 -0
- package/src/functions/templates/hono-typescript/src/index.ts +54 -0
- package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
- package/src/functions/templates/hono-typescript/tsconfig.json +20 -0
- package/src/functions/templates/typescript-node/package.json +2 -1
- package/src/functions/templates/typescript-node/src/context.ts +103 -0
- package/src/functions/templates/typescript-node/src/index.ts +18 -12
- package/src/functions/templates/uv/pyproject.toml +1 -0
- package/src/functions/templates/uv/src/context.py +125 -0
- package/src/functions/templates/uv/src/index.py +35 -5
- package/src/init.ts +9 -11
- package/src/interactiveCLI.ts +276 -1591
- package/src/main.ts +418 -24
- package/src/migrations/afterImportActions.ts +71 -44
- package/src/migrations/appwriteToX.ts +100 -34
- package/src/migrations/dataLoader.ts +48 -34
- package/src/migrations/importController.ts +44 -39
- package/src/migrations/relationships.ts +28 -18
- package/src/migrations/services/ImportOrchestrator.ts +24 -27
- package/src/migrations/transfer.ts +159 -121
- package/src/migrations/yaml/YamlImportConfigLoader.ts +11 -4
- package/src/migrations/yaml/YamlImportIntegration.ts +47 -20
- package/src/migrations/yaml/generateImportSchemas.ts +751 -12
- package/src/setupController.ts +3 -2
- package/src/shared/backupMetadataSchema.ts +93 -0
- package/src/shared/backupTracking.ts +211 -0
- package/src/shared/confirmationDialogs.ts +19 -19
- package/src/shared/errorUtils.ts +110 -0
- package/src/shared/functionManager.ts +21 -20
- package/src/shared/indexManager.ts +12 -11
- package/src/shared/jsonSchemaGenerator.ts +38 -52
- package/src/shared/logging.ts +75 -0
- package/src/shared/messageFormatter.ts +14 -1
- package/src/shared/migrationHelpers.ts +45 -38
- package/src/shared/operationLogger.ts +11 -36
- package/src/shared/operationQueue.ts +322 -93
- package/src/shared/operationsTable.ts +338 -0
- package/src/shared/operationsTableSchema.ts +60 -0
- package/src/shared/relationshipExtractor.ts +214 -0
- package/src/shared/schemaGenerator.ts +179 -219
- package/src/storage/backupCompression.ts +88 -0
- package/src/storage/methods.ts +131 -34
- package/src/users/methods.ts +11 -9
- package/src/utils/configDiscovery.ts +502 -0
- package/src/utils/directoryUtils.ts +61 -0
- package/src/utils/getClientFromConfig.ts +205 -22
- package/src/utils/helperFunctions.ts +23 -5
- package/src/utils/loadConfigs.ts +313 -345
- package/src/utils/pathResolvers.ts +81 -0
- package/src/utils/projectConfig.ts +299 -0
- package/src/utils/retryFailedPromises.ts +4 -2
- package/src/utils/sessionAuth.ts +230 -0
- package/src/utils/setupFiles.ts +322 -54
- package/src/utils/typeGuards.ts +65 -0
- package/src/utils/versionDetection.ts +218 -64
- package/src/utils/yamlConverter.ts +296 -13
- package/src/utils/yamlLoader.ts +364 -0
- package/src/utilsController.ts +314 -110
- package/tests/README.md +497 -0
- package/tests/adapters/AdapterFactory.test.ts +277 -0
- package/tests/integration/syncOperations.test.ts +463 -0
- package/tests/jest.config.js +25 -0
- package/tests/migration/configMigration.test.ts +546 -0
- package/tests/setup.ts +62 -0
- package/tests/testUtils.ts +340 -0
- package/tests/utils/loadConfigs.test.ts +350 -0
- package/tests/validation/configValidation.test.ts +412 -0
- package/src/utils/schemaStrings.ts +0 -517
@@ -0,0 +1,390 @@
|
|
1
|
+
import { TableCreateSchema } from "appwrite-utils";
|
2
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
3
|
+
import { validateCollectionsTablesConfig } from "./configValidation.js";
|
4
|
+
import path from "path";
|
5
|
+
import fs from "fs";
|
6
|
+
import chalk from "chalk";
|
7
|
+
/**
|
8
|
+
* Creates a migration plan for converting collections to tables
|
9
|
+
*/
|
10
|
+
export function createMigrationPlan(config, strategy = "full_migration", specificCollections) {
|
11
|
+
const collections = config.collections || [];
|
12
|
+
const existingTables = config.tables || [];
|
13
|
+
const collectionsToMigrate = [];
|
14
|
+
const collectionsToKeep = [];
|
15
|
+
const tablesToCreate = [];
|
16
|
+
const expectedChanges = [];
|
17
|
+
const warnings = [];
|
18
|
+
const recommendations = [];
|
19
|
+
// Determine which collections to migrate based on strategy
|
20
|
+
collections.forEach((collection, index) => {
|
21
|
+
const shouldMigrate = determineShouldMigrate(collection, strategy, specificCollections);
|
22
|
+
if (shouldMigrate) {
|
23
|
+
const migrationItem = createCollectionMigrationItem(collection, index);
|
24
|
+
collectionsToMigrate.push(migrationItem);
|
25
|
+
tablesToCreate.push(migrationItem.newTable);
|
26
|
+
// Check for potential issues
|
27
|
+
if (migrationItem.warnings.length > 0) {
|
28
|
+
warnings.push(...migrationItem.warnings);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
else {
|
32
|
+
collectionsToKeep.push(collection);
|
33
|
+
}
|
34
|
+
});
|
35
|
+
// Create expected changes
|
36
|
+
expectedChanges.push(...createExpectedChanges(strategy, collectionsToMigrate, collectionsToKeep));
|
37
|
+
// Assess complexity
|
38
|
+
const estimatedComplexity = assessMigrationComplexity(collectionsToMigrate, strategy);
|
39
|
+
// Generate recommendations
|
40
|
+
recommendations.push(...generateMigrationRecommendations(config, strategy, collectionsToMigrate));
|
41
|
+
// Add strategy-specific warnings
|
42
|
+
if (strategy === "dual_format") {
|
43
|
+
warnings.push("Dual format increases configuration file size and maintenance overhead");
|
44
|
+
recommendations.push("Consider migrating to tables_only after testing dual format");
|
45
|
+
}
|
46
|
+
if (strategy === "full_migration" && collections.length > 10) {
|
47
|
+
warnings.push("Large migration may require careful testing and staged deployment");
|
48
|
+
recommendations.push("Consider incremental migration for large projects");
|
49
|
+
}
|
50
|
+
return {
|
51
|
+
strategy,
|
52
|
+
collectionsToMigrate,
|
53
|
+
collectionsToKeep,
|
54
|
+
tablesToCreate,
|
55
|
+
expectedChanges,
|
56
|
+
estimatedComplexity,
|
57
|
+
warnings,
|
58
|
+
recommendations
|
59
|
+
};
|
60
|
+
}
|
61
|
+
/**
|
62
|
+
* Executes a migration plan
|
63
|
+
*/
|
64
|
+
export function executeMigrationPlan(config, plan, options = {}) {
|
65
|
+
const { validateResult = true, dryRun = false, preserveOriginal = false } = options;
|
66
|
+
try {
|
67
|
+
// Create new configuration based on strategy
|
68
|
+
const newConfig = applyMigrationPlan(config, plan, preserveOriginal);
|
69
|
+
// Validate the result if requested
|
70
|
+
let validation = { isValid: true, errors: [], warnings: [], suggestions: [] };
|
71
|
+
if (validateResult) {
|
72
|
+
validation = validateCollectionsTablesConfig(newConfig);
|
73
|
+
}
|
74
|
+
const changes = plan.expectedChanges;
|
75
|
+
const warnings = [...plan.warnings];
|
76
|
+
const errors = [];
|
77
|
+
// Add validation errors to the result
|
78
|
+
if (validation.errors.length > 0) {
|
79
|
+
errors.push(...validation.errors.map(e => e.message));
|
80
|
+
}
|
81
|
+
if (validation.warnings.length > 0) {
|
82
|
+
warnings.push(...validation.warnings.map(w => w.message));
|
83
|
+
}
|
84
|
+
const success = errors.length === 0;
|
85
|
+
if (dryRun) {
|
86
|
+
MessageFormatter.info("Dry run completed - no changes were made", { prefix: "Migration" });
|
87
|
+
}
|
88
|
+
return {
|
89
|
+
success,
|
90
|
+
newConfig,
|
91
|
+
changes,
|
92
|
+
validation,
|
93
|
+
warnings,
|
94
|
+
errors
|
95
|
+
};
|
96
|
+
}
|
97
|
+
catch (error) {
|
98
|
+
return {
|
99
|
+
success: false,
|
100
|
+
newConfig: config,
|
101
|
+
changes: [],
|
102
|
+
validation: { isValid: false, errors: [], warnings: [], suggestions: [] },
|
103
|
+
warnings: [],
|
104
|
+
errors: [error instanceof Error ? error.message : "Unknown migration error"]
|
105
|
+
};
|
106
|
+
}
|
107
|
+
}
|
108
|
+
/**
|
109
|
+
* Converts a single collection to table format
|
110
|
+
*/
|
111
|
+
export function convertCollectionToTable(collection) {
|
112
|
+
const table = {
|
113
|
+
name: collection.name,
|
114
|
+
tableId: collection.$id || collection.name.toLowerCase().replace(/\s+/g, '_'),
|
115
|
+
enabled: collection.enabled,
|
116
|
+
documentSecurity: collection.documentSecurity,
|
117
|
+
$permissions: collection.$permissions,
|
118
|
+
attributes: collection.attributes,
|
119
|
+
indexes: collection.indexes,
|
120
|
+
importDefs: collection.importDefs,
|
121
|
+
databaseId: collection.databaseId
|
122
|
+
};
|
123
|
+
// Add $id for backward compatibility if it exists
|
124
|
+
if (collection.$id) {
|
125
|
+
table.$id = collection.$id;
|
126
|
+
}
|
127
|
+
return table;
|
128
|
+
}
|
129
|
+
/**
|
130
|
+
* Creates a migration item for a single collection
|
131
|
+
*/
|
132
|
+
function createCollectionMigrationItem(collection, index) {
|
133
|
+
const tableInput = convertCollectionToTable(collection);
|
134
|
+
const newTable = TableCreateSchema.parse(tableInput);
|
135
|
+
const changes = [];
|
136
|
+
const warnings = [];
|
137
|
+
// Document changes
|
138
|
+
changes.push(`Convert collection '${collection.name}' to table format`);
|
139
|
+
if (collection.$id && collection.$id !== newTable.tableId) {
|
140
|
+
changes.push(`Change ID from '$id: ${collection.$id}' to 'tableId: ${newTable.tableId}'`);
|
141
|
+
}
|
142
|
+
// Check for potential issues
|
143
|
+
if (collection.attributes.some(attr => attr.type === 'relationship')) {
|
144
|
+
warnings.push(`Collection '${collection.name}' has relationship attributes that may need manual review`);
|
145
|
+
}
|
146
|
+
if (collection.indexes && collection.indexes.length > 5) {
|
147
|
+
warnings.push(`Collection '${collection.name}' has many indexes (${collection.indexes.length}) - verify compatibility`);
|
148
|
+
}
|
149
|
+
return {
|
150
|
+
collection,
|
151
|
+
index,
|
152
|
+
newTable,
|
153
|
+
changes,
|
154
|
+
warnings
|
155
|
+
};
|
156
|
+
}
|
157
|
+
/**
|
158
|
+
* Determines if a collection should be migrated based on strategy
|
159
|
+
*/
|
160
|
+
function determineShouldMigrate(collection, strategy, specificCollections) {
|
161
|
+
switch (strategy) {
|
162
|
+
case "full_migration":
|
163
|
+
case "tables_only":
|
164
|
+
return true;
|
165
|
+
case "dual_format":
|
166
|
+
return true;
|
167
|
+
case "incremental":
|
168
|
+
if (!specificCollections || specificCollections.length === 0) {
|
169
|
+
return false;
|
170
|
+
}
|
171
|
+
return specificCollections.includes(collection.name) ||
|
172
|
+
specificCollections.includes(collection.$id || "");
|
173
|
+
default:
|
174
|
+
return false;
|
175
|
+
}
|
176
|
+
}
|
177
|
+
/**
|
178
|
+
* Creates expected changes list based on migration plan
|
179
|
+
*/
|
180
|
+
function createExpectedChanges(strategy, collectionsToMigrate, collectionsToKeep) {
|
181
|
+
const changes = [];
|
182
|
+
// Add table creation changes
|
183
|
+
collectionsToMigrate.forEach(item => {
|
184
|
+
changes.push({
|
185
|
+
type: "add",
|
186
|
+
description: `Add table '${item.newTable.name}' converted from collection`,
|
187
|
+
impact: "medium",
|
188
|
+
location: `tables[${item.newTable.name}]`
|
189
|
+
});
|
190
|
+
});
|
191
|
+
// Add collection removal changes (if not preserving)
|
192
|
+
if (strategy === "full_migration" || strategy === "tables_only") {
|
193
|
+
collectionsToMigrate.forEach(item => {
|
194
|
+
changes.push({
|
195
|
+
type: "remove",
|
196
|
+
description: `Remove collection '${item.collection.name}' (converted to table)`,
|
197
|
+
impact: "high",
|
198
|
+
location: `collections[${item.index}]`
|
199
|
+
});
|
200
|
+
});
|
201
|
+
}
|
202
|
+
// Add array structure changes
|
203
|
+
if (collectionsToMigrate.length > 0) {
|
204
|
+
changes.push({
|
205
|
+
type: "modify",
|
206
|
+
description: `${strategy === "dual_format" ? "Add" : "Create"} tables array with ${collectionsToMigrate.length} items`,
|
207
|
+
impact: "medium",
|
208
|
+
location: "config.tables"
|
209
|
+
});
|
210
|
+
}
|
211
|
+
if (strategy === "tables_only" && collectionsToKeep.length === 0) {
|
212
|
+
changes.push({
|
213
|
+
type: "remove",
|
214
|
+
description: "Remove collections array (fully migrated to tables)",
|
215
|
+
impact: "high",
|
216
|
+
location: "config.collections"
|
217
|
+
});
|
218
|
+
}
|
219
|
+
return changes;
|
220
|
+
}
|
221
|
+
/**
|
222
|
+
* Assesses migration complexity
|
223
|
+
*/
|
224
|
+
function assessMigrationComplexity(collectionsToMigrate, strategy) {
|
225
|
+
const collectionCount = collectionsToMigrate.length;
|
226
|
+
const hasRelationships = collectionsToMigrate.some(item => item.collection.attributes.some(attr => attr.type === 'relationship'));
|
227
|
+
const hasComplexIndexes = collectionsToMigrate.some(item => (item.collection.indexes?.length || 0) > 5);
|
228
|
+
if (collectionCount === 0)
|
229
|
+
return "low";
|
230
|
+
if (collectionCount <= 3 && !hasRelationships && !hasComplexIndexes)
|
231
|
+
return "low";
|
232
|
+
if (collectionCount <= 10 && !hasComplexIndexes && strategy !== "full_migration")
|
233
|
+
return "medium";
|
234
|
+
return "high";
|
235
|
+
}
|
236
|
+
/**
|
237
|
+
* Generates migration recommendations
|
238
|
+
*/
|
239
|
+
function generateMigrationRecommendations(config, strategy, collectionsToMigrate) {
|
240
|
+
const recommendations = [];
|
241
|
+
if (collectionsToMigrate.length > 5) {
|
242
|
+
recommendations.push("Consider migrating in smaller batches for easier rollback");
|
243
|
+
}
|
244
|
+
if (collectionsToMigrate.some(item => item.warnings.length > 0)) {
|
245
|
+
recommendations.push("Review relationship attributes and complex indexes after migration");
|
246
|
+
}
|
247
|
+
if (!config.apiMode || config.apiMode === "auto") {
|
248
|
+
recommendations.push("Set apiMode to 'tablesdb' after migration for explicit API selection");
|
249
|
+
}
|
250
|
+
if (strategy === "dual_format") {
|
251
|
+
recommendations.push("Test with dual format before removing collections array");
|
252
|
+
recommendations.push("Monitor for any breaking changes with both APIs");
|
253
|
+
}
|
254
|
+
return recommendations;
|
255
|
+
}
|
256
|
+
/**
|
257
|
+
* Applies migration plan to create new configuration
|
258
|
+
*/
|
259
|
+
function applyMigrationPlan(config, plan, preserveOriginal) {
|
260
|
+
const newConfig = { ...config };
|
261
|
+
// Initialize tables array if it doesn't exist
|
262
|
+
if (!newConfig.tables) {
|
263
|
+
newConfig.tables = [];
|
264
|
+
}
|
265
|
+
// Add migrated tables
|
266
|
+
newConfig.tables.push(...plan.tablesToCreate);
|
267
|
+
// Handle collections based on strategy
|
268
|
+
if (plan.strategy === "full_migration" || plan.strategy === "tables_only") {
|
269
|
+
if (preserveOriginal) {
|
270
|
+
// Keep original collections but mark them as migrated
|
271
|
+
newConfig.collections = (newConfig.collections || []).map(collection => ({
|
272
|
+
...collection,
|
273
|
+
// Add a comment or marker to indicate it's been migrated
|
274
|
+
_migrated: true
|
275
|
+
}));
|
276
|
+
}
|
277
|
+
else {
|
278
|
+
// Remove migrated collections
|
279
|
+
const migratedNames = new Set(plan.collectionsToMigrate.map(item => item.collection.name));
|
280
|
+
newConfig.collections = (newConfig.collections || []).filter(collection => !migratedNames.has(collection.name));
|
281
|
+
// If no collections remain, remove the array for tables_only strategy
|
282
|
+
if (newConfig.collections.length === 0 && plan.strategy === "tables_only") {
|
283
|
+
delete newConfig.collections;
|
284
|
+
}
|
285
|
+
}
|
286
|
+
}
|
287
|
+
// For dual_format and incremental, keep existing collections unchanged
|
288
|
+
return newConfig;
|
289
|
+
}
|
290
|
+
/**
|
291
|
+
* Utility function to migrate collections to tables with simple interface
|
292
|
+
*/
|
293
|
+
export function migrateCollectionsToTables(config, options = {}) {
|
294
|
+
const { strategy = "full_migration", specificCollections, validateResult = true, dryRun = false } = options;
|
295
|
+
// Create migration plan
|
296
|
+
const plan = createMigrationPlan(config, strategy, specificCollections);
|
297
|
+
// Execute migration
|
298
|
+
const result = executeMigrationPlan(config, plan, {
|
299
|
+
validateResult,
|
300
|
+
dryRun
|
301
|
+
});
|
302
|
+
return result;
|
303
|
+
}
|
304
|
+
/**
|
305
|
+
* Saves migration results to files
|
306
|
+
*/
|
307
|
+
export async function saveMigrationResult(result, outputPath, options = {}) {
|
308
|
+
const { createBackup = true, originalConfigPath } = options;
|
309
|
+
try {
|
310
|
+
// Create backup if requested
|
311
|
+
if (createBackup && originalConfigPath && fs.existsSync(originalConfigPath)) {
|
312
|
+
const backupPath = `${originalConfigPath}.backup.${Date.now()}`;
|
313
|
+
fs.copyFileSync(originalConfigPath, backupPath);
|
314
|
+
MessageFormatter.success(`Backup created: ${backupPath}`, { prefix: "Migration" });
|
315
|
+
}
|
316
|
+
// Write new configuration
|
317
|
+
const configContent = `import { type AppwriteConfig } from "appwrite-utils";
|
318
|
+
|
319
|
+
const appwriteConfig: AppwriteConfig = ${JSON.stringify(result.newConfig, null, 2)};
|
320
|
+
|
321
|
+
export default appwriteConfig;
|
322
|
+
`;
|
323
|
+
fs.writeFileSync(outputPath, configContent, 'utf8');
|
324
|
+
MessageFormatter.success(`Migration result saved: ${outputPath}`, { prefix: "Migration" });
|
325
|
+
// Create migration report
|
326
|
+
const reportPath = outputPath.replace(/\.(ts|js)$/, '.migration-report.md');
|
327
|
+
const report = generateMigrationReport(result);
|
328
|
+
fs.writeFileSync(reportPath, report, 'utf8');
|
329
|
+
MessageFormatter.info(`Migration report saved: ${reportPath}`, { prefix: "Migration" });
|
330
|
+
}
|
331
|
+
catch (error) {
|
332
|
+
throw new Error(`Failed to save migration result: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
333
|
+
}
|
334
|
+
}
|
335
|
+
/**
|
336
|
+
* Generates a detailed migration report
|
337
|
+
*/
|
338
|
+
function generateMigrationReport(result) {
|
339
|
+
const timestamp = new Date().toISOString();
|
340
|
+
return `# Migration Report
|
341
|
+
|
342
|
+
**Generated:** ${timestamp}
|
343
|
+
**Status:** ${result.success ? "✅ Success" : "❌ Failed"}
|
344
|
+
|
345
|
+
## Changes Applied
|
346
|
+
|
347
|
+
${result.changes.map(change => `- **${change.type.toUpperCase()}**: ${change.description} (Impact: ${change.impact})`).join('\n')}
|
348
|
+
|
349
|
+
## Validation Results
|
350
|
+
|
351
|
+
**Valid Configuration:** ${result.validation.isValid ? "✅ Yes" : "❌ No"}
|
352
|
+
|
353
|
+
${result.validation.errors.length > 0 ? `
|
354
|
+
### Errors
|
355
|
+
${result.validation.errors.map(error => `- ${error.message}`).join('\n')}
|
356
|
+
` : ''}
|
357
|
+
|
358
|
+
${result.validation.warnings.length > 0 ? `
|
359
|
+
### Warnings
|
360
|
+
${result.validation.warnings.map(warning => `- ${warning.message}`).join('\n')}
|
361
|
+
` : ''}
|
362
|
+
|
363
|
+
${result.validation.suggestions.length > 0 ? `
|
364
|
+
### Suggestions
|
365
|
+
${result.validation.suggestions.map(suggestion => `- ${suggestion.message}`).join('\n')}
|
366
|
+
` : ''}
|
367
|
+
|
368
|
+
${result.warnings.length > 0 ? `
|
369
|
+
## Migration Warnings
|
370
|
+
|
371
|
+
${result.warnings.map(warning => `- ${warning}`).join('\n')}
|
372
|
+
` : ''}
|
373
|
+
|
374
|
+
${result.errors.length > 0 ? `
|
375
|
+
## Migration Errors
|
376
|
+
|
377
|
+
${result.errors.map(error => `- ${error}`).join('\n')}
|
378
|
+
` : ''}
|
379
|
+
|
380
|
+
## Next Steps
|
381
|
+
|
382
|
+
1. Review the migrated configuration
|
383
|
+
2. Test with your Appwrite instance
|
384
|
+
3. Update your deployment scripts if necessary
|
385
|
+
4. Consider setting \`apiMode\` to 'tablesdb' for explicit API selection
|
386
|
+
|
387
|
+
---
|
388
|
+
*Generated by appwrite-utils-cli migration tools*
|
389
|
+
`;
|
390
|
+
}
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import { type AppwriteConfig } from "appwrite-utils";
|
2
|
+
/**
|
3
|
+
* Validation error types for different categories of issues
|
4
|
+
*/
|
5
|
+
export type ValidationErrorType = "naming_conflict" | "invalid_database_reference" | "missing_required_field" | "schema_inconsistency" | "duplicate_definition" | "cross_array_conflict";
|
6
|
+
/**
|
7
|
+
* Detailed validation error information
|
8
|
+
*/
|
9
|
+
export interface ValidationError {
|
10
|
+
type: ValidationErrorType;
|
11
|
+
message: string;
|
12
|
+
details?: string;
|
13
|
+
suggestion?: string;
|
14
|
+
affectedItems?: string[];
|
15
|
+
severity: "error" | "warning" | "info";
|
16
|
+
}
|
17
|
+
/**
|
18
|
+
* Configuration validation result
|
19
|
+
*/
|
20
|
+
export interface ValidationResult {
|
21
|
+
isValid: boolean;
|
22
|
+
errors: ValidationError[];
|
23
|
+
warnings: ValidationError[];
|
24
|
+
suggestions: ValidationError[];
|
25
|
+
}
|
26
|
+
/**
|
27
|
+
* Conflict information between collections and tables
|
28
|
+
*/
|
29
|
+
export interface ConfigConflict {
|
30
|
+
name: string;
|
31
|
+
collectionsIndex?: number;
|
32
|
+
tablesIndex?: number;
|
33
|
+
type: "name" | "id" | "database_reference";
|
34
|
+
message: string;
|
35
|
+
}
|
36
|
+
/**
|
37
|
+
* Main configuration validation function
|
38
|
+
* Validates the dual collections/tables configuration schema
|
39
|
+
*/
|
40
|
+
export declare function validateCollectionsTablesConfig(config: AppwriteConfig): ValidationResult;
|
41
|
+
/**
|
42
|
+
* Detects naming conflicts between collections and tables
|
43
|
+
*/
|
44
|
+
export declare function detectNamingConflicts(config: AppwriteConfig): ValidationError[];
|
45
|
+
/**
|
46
|
+
* Find naming conflicts between collections and tables
|
47
|
+
*/
|
48
|
+
export declare function findNamingConflicts(config: AppwriteConfig): ConfigConflict[];
|
49
|
+
/**
|
50
|
+
* Validates database ID references in collections and tables
|
51
|
+
*/
|
52
|
+
export declare function validateDatabaseReferences(config: AppwriteConfig): ValidationError[];
|
53
|
+
/**
|
54
|
+
* Validates schema consistency between collections and tables
|
55
|
+
*/
|
56
|
+
export declare function validateSchemaConsistency(config: AppwriteConfig): ValidationError[];
|
57
|
+
/**
|
58
|
+
* Reports validation results with formatted output
|
59
|
+
*/
|
60
|
+
export declare function reportValidationResults(result: ValidationResult, options?: {
|
61
|
+
verbose?: boolean;
|
62
|
+
}): void;
|
63
|
+
/**
|
64
|
+
* Validation with strict mode for enhanced checking
|
65
|
+
*/
|
66
|
+
export declare function validateWithStrictMode(config: AppwriteConfig, strictMode?: boolean): ValidationResult;
|