appwrite-utils-cli 1.3.5 → 1.4.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.
Files changed (116) hide show
  1. package/dist/adapters/AdapterFactory.d.ts +87 -0
  2. package/dist/adapters/AdapterFactory.js +217 -0
  3. package/dist/adapters/DatabaseAdapter.d.ts +217 -0
  4. package/dist/adapters/DatabaseAdapter.js +50 -0
  5. package/dist/adapters/LegacyAdapter.d.ts +49 -0
  6. package/dist/adapters/LegacyAdapter.js +382 -0
  7. package/dist/adapters/TablesDBAdapter.d.ts +55 -0
  8. package/dist/adapters/TablesDBAdapter.js +302 -0
  9. package/dist/adapters/index.d.ts +11 -0
  10. package/dist/adapters/index.js +12 -0
  11. package/dist/collections/attributes.js +41 -22
  12. package/dist/collections/methods.d.ts +4 -3
  13. package/dist/collections/methods.js +34 -14
  14. package/dist/config/yamlConfig.d.ts +40 -437
  15. package/dist/config/yamlConfig.js +8 -2
  16. package/dist/databases/setup.js +2 -2
  17. package/dist/main.js +0 -0
  18. package/dist/migrations/appwriteToX.d.ts +26 -37
  19. package/dist/migrations/comprehensiveTransfer.js +4 -4
  20. package/dist/migrations/dataLoader.d.ts +124 -1484
  21. package/dist/migrations/dataLoader.js +2 -1
  22. package/dist/migrations/relationships.d.ts +2 -3
  23. package/dist/migrations/relationships.js +1 -1
  24. package/dist/migrations/services/UserMappingService.js +1 -1
  25. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +24 -279
  26. package/dist/migrations/yaml/YamlImportConfigLoader.js +7 -2
  27. package/dist/schemas/authUser.d.ts +7 -47
  28. package/dist/schemas/authUser.js +1 -1
  29. package/dist/shared/jsonSchemaGenerator.d.ts +0 -2
  30. package/dist/shared/jsonSchemaGenerator.js +4 -17
  31. package/dist/shared/migrationHelpers.d.ts +17 -119
  32. package/dist/shared/operationQueue.js +16 -7
  33. package/dist/shared/schemaGenerator.js +2 -17
  34. package/dist/storage/schemas.d.ts +149 -296
  35. package/dist/users/methods.d.ts +2 -2
  36. package/dist/utils/configMigration.js +0 -1
  37. package/dist/utils/getClientFromConfig.d.ts +26 -0
  38. package/dist/utils/getClientFromConfig.js +37 -0
  39. package/dist/utils/loadConfigs.js +0 -2
  40. package/dist/utils/schemaStrings.js +2 -17
  41. package/dist/utils/setupFiles.js +2 -0
  42. package/dist/utils/versionDetection.d.ts +56 -0
  43. package/dist/utils/versionDetection.js +217 -0
  44. package/dist/utils/yamlConverter.d.ts +0 -1
  45. package/dist/utils/yamlConverter.js +0 -2
  46. package/dist/utilsController.js +2 -0
  47. package/package.json +3 -2
  48. package/src/adapters/AdapterFactory.ts +296 -0
  49. package/src/adapters/DatabaseAdapter.ts +290 -0
  50. package/src/adapters/LegacyAdapter.ts +667 -0
  51. package/src/adapters/TablesDBAdapter.ts +429 -0
  52. package/src/adapters/index.ts +37 -0
  53. package/src/collections/attributes.ts +347 -153
  54. package/src/collections/methods.ts +43 -28
  55. package/src/config/yamlConfig.ts +8 -2
  56. package/src/databases/setup.ts +2 -2
  57. package/src/migrations/afterImportActions.ts +2 -2
  58. package/src/migrations/comprehensiveTransfer.ts +4 -0
  59. package/src/migrations/dataLoader.ts +2 -1
  60. package/src/migrations/relationships.ts +1 -1
  61. package/src/migrations/services/UserMappingService.ts +1 -1
  62. package/src/migrations/yaml/YamlImportConfigLoader.ts +7 -2
  63. package/src/schemas/authUser.ts +1 -1
  64. package/src/shared/jsonSchemaGenerator.ts +4 -19
  65. package/src/shared/operationQueue.ts +20 -13
  66. package/src/shared/schemaGenerator.ts +2 -16
  67. package/src/types/node-appwrite-tablesdb.d.ts +44 -0
  68. package/src/users/methods.ts +2 -2
  69. package/src/utils/configMigration.ts +0 -1
  70. package/src/utils/getClientFromConfig.ts +56 -0
  71. package/src/utils/loadConfigs.ts +0 -2
  72. package/src/utils/schemaStrings.ts +2 -16
  73. package/src/utils/setupFiles.ts +2 -0
  74. package/src/utils/versionDetection.ts +265 -0
  75. package/src/utils/yamlConverter.ts +0 -2
  76. package/src/utilsController.ts +2 -0
  77. package/dist/functions/openapi.d.ts +0 -4
  78. package/dist/functions/openapi.js +0 -60
  79. package/dist/migrations/attributes.d.ts +0 -4
  80. package/dist/migrations/attributes.js +0 -301
  81. package/dist/migrations/backup.d.ts +0 -687
  82. package/dist/migrations/backup.js +0 -175
  83. package/dist/migrations/collections.d.ts +0 -22
  84. package/dist/migrations/collections.js +0 -347
  85. package/dist/migrations/converters.d.ts +0 -46
  86. package/dist/migrations/converters.js +0 -139
  87. package/dist/migrations/databases.d.ts +0 -2
  88. package/dist/migrations/databases.js +0 -28
  89. package/dist/migrations/dbHelpers.d.ts +0 -5
  90. package/dist/migrations/dbHelpers.js +0 -57
  91. package/dist/migrations/helper.d.ts +0 -3
  92. package/dist/migrations/helper.js +0 -21
  93. package/dist/migrations/indexes.d.ts +0 -4
  94. package/dist/migrations/indexes.js +0 -19
  95. package/dist/migrations/logging.d.ts +0 -10
  96. package/dist/migrations/logging.js +0 -46
  97. package/dist/migrations/migrationHelper.d.ts +0 -173
  98. package/dist/migrations/migrationHelper.js +0 -130
  99. package/dist/migrations/openapi.d.ts +0 -4
  100. package/dist/migrations/openapi.js +0 -60
  101. package/dist/migrations/queue.d.ts +0 -13
  102. package/dist/migrations/queue.js +0 -79
  103. package/dist/migrations/schemaStrings.d.ts +0 -14
  104. package/dist/migrations/schemaStrings.js +0 -478
  105. package/dist/migrations/setupDatabase.d.ts +0 -6
  106. package/dist/migrations/setupDatabase.js +0 -115
  107. package/dist/migrations/storage.d.ts +0 -10
  108. package/dist/migrations/storage.js +0 -340
  109. package/dist/migrations/users.d.ts +0 -16
  110. package/dist/migrations/users.js +0 -276
  111. package/dist/migrations/validationRules.d.ts +0 -43
  112. package/dist/migrations/validationRules.js +0 -42
  113. package/dist/shared/attributeManager.d.ts +0 -17
  114. package/dist/shared/attributeManager.js +0 -272
  115. package/src/functions/openapi.ts +0 -83
  116. package/src/shared/attributeManager.ts +0 -428
@@ -1,60 +0,0 @@
1
- import { OpenAPIRegistry, OpenApiGeneratorV3, OpenApiGeneratorV31, } from "@asteasolutions/zod-to-openapi";
2
- import { attributeSchema, CollectionSchema, } from "appwrite-utils";
3
- import { z } from "zod";
4
- import { writeFileSync } from "fs";
5
- const registry = new OpenAPIRegistry();
6
- export const generateOpenApi = async (config) => {
7
- if (!config.collections) {
8
- return;
9
- }
10
- for (const collection of config.collections) {
11
- // Transform and register each attribute schema
12
- const attributeSchemas = collection.attributes.map((attribute) => {
13
- return transformTypeToOpenApi(attributeSchema, attribute.description);
14
- });
15
- // Create and register the collection schema with descriptions
16
- const updatedCollectionSchema = CollectionSchema.extend({
17
- // @ts-ignore
18
- attributes: attributeSchemas,
19
- }).openapi(collection.description ?? "No description");
20
- // Register the updated collection schema under the collection name
21
- registry.register(collection.name, updatedCollectionSchema);
22
- }
23
- // Convert the registry to OpenAPI JSON
24
- const generator = new OpenApiGeneratorV31(registry.definitions);
25
- const openApiSpec = generator.generateComponents();
26
- // Output the OpenAPI spec to a file
27
- writeFileSync("./appwrite/openapi/openapi.json", JSON.stringify(openApiSpec, null, 2));
28
- };
29
- export function transformTypeToOpenApi(schema, description) {
30
- // Check if description is an object (OpenAPI properties) or a string
31
- let updatedSchema;
32
- if (!description) {
33
- return schema;
34
- }
35
- if (typeof description === "string") {
36
- updatedSchema = schema.openapi(description);
37
- }
38
- else if (typeof description === "object") {
39
- updatedSchema = schema.openapi(description);
40
- }
41
- else {
42
- updatedSchema = schema;
43
- }
44
- // Check and transform attributes if they exist
45
- if (schema._def && schema._def.shape) {
46
- const shape = schema._def.shape();
47
- for (const key in shape) {
48
- const attributeDesc = shape[key].description;
49
- if (attributeDesc) {
50
- if (typeof attributeDesc === "string") {
51
- shape[key] = shape[key].openapi(attributeDesc);
52
- }
53
- else if (typeof attributeDesc === "object") {
54
- shape[key] = shape[key].openapi(attributeDesc);
55
- }
56
- }
57
- }
58
- }
59
- return updatedSchema;
60
- }
@@ -1,13 +0,0 @@
1
- import { type Databases, type Models } from "node-appwrite";
2
- import type { Attribute } from "appwrite-utils";
3
- export interface QueuedOperation {
4
- type: "attribute";
5
- collectionId?: string;
6
- attribute?: Attribute;
7
- collection?: Models.Collection;
8
- dependencies?: string[];
9
- }
10
- export declare const queuedOperations: QueuedOperation[];
11
- export declare const nameToIdMapping: Map<string, string>;
12
- export declare const enqueueOperation: (operation: QueuedOperation) => void;
13
- export declare const processQueue: (db: Databases, dbId: string) => Promise<void>;
@@ -1,79 +0,0 @@
1
- import { Query } from "node-appwrite";
2
- import { createOrUpdateAttribute } from "./attributes.js";
3
- import { fetchAndCacheCollectionByName } from "../collections/methods.js";
4
- import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
5
- export const queuedOperations = [];
6
- export const nameToIdMapping = new Map();
7
- export const enqueueOperation = (operation) => {
8
- queuedOperations.push(operation);
9
- };
10
- export const processQueue = async (db, dbId) => {
11
- console.log("---------------------------------");
12
- console.log(`Starting Queue processing of ${dbId}`);
13
- console.log("---------------------------------");
14
- let progress = true;
15
- while (progress) {
16
- progress = false;
17
- console.log("Processing queued operations:");
18
- for (let i = 0; i < queuedOperations.length; i++) {
19
- const operation = queuedOperations[i];
20
- let collectionFound;
21
- // Handle relationship attribute operations
22
- if (operation.attribute?.type === "relationship") {
23
- // Attempt to resolve the collection directly if collectionId is specified
24
- if (operation.collectionId) {
25
- console.log(`\tFetching collection by ID: ${operation.collectionId}`);
26
- try {
27
- collectionFound = await tryAwaitWithRetry(async () => await db.getCollection(dbId, operation.collectionId));
28
- }
29
- catch (e) {
30
- console.log(`\tCollection not found by ID: ${operation.collectionId}`);
31
- }
32
- }
33
- // Attempt to resolve related collection if specified and not already found
34
- if (!collectionFound && operation.attribute?.relatedCollection) {
35
- collectionFound = await fetchAndCacheCollectionByName(db, dbId, operation.attribute.relatedCollection);
36
- }
37
- // Handle dependencies if collection still not found
38
- if (!collectionFound) {
39
- for (const dep of operation.dependencies || []) {
40
- collectionFound = await fetchAndCacheCollectionByName(db, dbId, dep);
41
- if (collectionFound)
42
- break; // Break early if collection is found
43
- }
44
- }
45
- }
46
- else if (operation.collectionId) {
47
- // Handle non-relationship operations with a specified collectionId
48
- console.log(`\tFetching collection by ID: ${operation.collectionId}`);
49
- try {
50
- collectionFound = await tryAwaitWithRetry(async () => await db.getCollection(dbId, operation.collectionId));
51
- }
52
- catch (e) {
53
- console.log(`\tCollection not found by ID: ${operation.collectionId}`);
54
- }
55
- }
56
- // Process the operation if the collection is found
57
- if (collectionFound && operation.attribute) {
58
- console.log(`\tProcessing attribute: ${operation.attribute.key} for collection ID: ${collectionFound.$id}`);
59
- await createOrUpdateAttribute(db, dbId, collectionFound, operation.attribute);
60
- queuedOperations.splice(i, 1);
61
- i--; // Adjust index since we're modifying the array
62
- progress = true;
63
- }
64
- else {
65
- console.error(`\tCollection not found for operation, removing from queue: ${JSON.stringify(operation)}`);
66
- queuedOperations.splice(i, 1);
67
- i--; // Adjust index since we're modifying the array
68
- }
69
- }
70
- console.log(`\tFinished processing queued operations`);
71
- }
72
- if (queuedOperations.length > 0) {
73
- console.error("Unresolved operations remain due to unmet dependencies.");
74
- console.log(queuedOperations);
75
- }
76
- console.log("---------------------------------");
77
- console.log(`Queue processing complete for ${dbId}`);
78
- console.log("---------------------------------");
79
- };
@@ -1,14 +0,0 @@
1
- import type { AppwriteConfig, Attribute } from "appwrite-utils";
2
- export declare class SchemaGenerator {
3
- private relationshipMap;
4
- private config;
5
- private appwriteFolderPath;
6
- constructor(config: AppwriteConfig, appwriteFolderPath: string);
7
- updateTsSchemas(): void;
8
- updateConfig(config: AppwriteConfig): void;
9
- private extractRelationships;
10
- private addRelationship;
11
- generateSchemas(): void;
12
- createSchemaString: (name: string, attributes: Attribute[]) => string;
13
- typeToZod: (attribute: Attribute) => string;
14
- }
@@ -1,478 +0,0 @@
1
- import { toCamelCase, toPascalCase } from "../utils/index.js";
2
- import { z } from "zod";
3
- import fs from "fs";
4
- import path from "path";
5
- import { dump } from "js-yaml";
6
- import { getDatabaseFromConfig } from "./afterImportActions.js";
7
- import { ulid } from "ulidx";
8
- export class SchemaGenerator {
9
- relationshipMap = new Map();
10
- config;
11
- appwriteFolderPath;
12
- constructor(config, appwriteFolderPath) {
13
- this.config = config;
14
- this.appwriteFolderPath = appwriteFolderPath;
15
- this.extractRelationships();
16
- }
17
- updateTsSchemas() {
18
- const collections = this.config.collections;
19
- const functions = this.config.functions || [];
20
- delete this.config.collections;
21
- delete this.config.functions;
22
- const configPath = path.join(this.appwriteFolderPath, "appwriteConfig.ts");
23
- const configContent = `import { type AppwriteConfig } from "appwrite-utils";
24
-
25
- const appwriteConfig: AppwriteConfig = {
26
- appwriteEndpoint: "${this.config.appwriteEndpoint}",
27
- appwriteProject: "${this.config.appwriteProject}",
28
- appwriteKey: "${this.config.appwriteKey}",
29
- enableBackups: ${this.config.enableBackups},
30
- backupInterval: ${this.config.backupInterval},
31
- backupRetention: ${this.config.backupRetention},
32
- enableBackupCleanup: ${this.config.enableBackupCleanup},
33
- enableMockData: ${this.config.enableMockData},
34
- documentBucketId: "${this.config.documentBucketId}",
35
- usersCollectionName: "${this.config.usersCollectionName}",
36
- databases: ${JSON.stringify(this.config.databases, null, 4)},
37
- buckets: ${JSON.stringify(this.config.buckets, null, 4)},
38
- functions: ${JSON.stringify(functions.map((func) => ({
39
- functionId: func.$id || ulid(),
40
- name: func.name,
41
- runtime: func.runtime,
42
- path: func.dirPath || `functions/${func.name}`,
43
- entrypoint: func.entrypoint || "src/index.ts",
44
- execute: func.execute,
45
- events: func.events || [],
46
- schedule: func.schedule || "",
47
- timeout: func.timeout || 15,
48
- enabled: func.enabled !== false,
49
- logging: func.logging !== false,
50
- commands: func.commands || "npm install",
51
- scopes: func.scopes || [],
52
- installationId: func.installationId,
53
- providerRepositoryId: func.providerRepositoryId,
54
- providerBranch: func.providerBranch,
55
- providerSilentMode: func.providerSilentMode,
56
- providerRootDirectory: func.providerRootDirectory,
57
- specification: func.specification,
58
- ...(func.predeployCommands
59
- ? { predeployCommands: func.predeployCommands }
60
- : {}),
61
- ...(func.deployDir ? { deployDir: func.deployDir } : {}),
62
- })), null, 4)}
63
- };
64
-
65
- export default appwriteConfig;
66
- `;
67
- fs.writeFileSync(configPath, configContent, { encoding: "utf-8" });
68
- const collectionsFolderPath = path.join(this.appwriteFolderPath, "collections");
69
- if (!fs.existsSync(collectionsFolderPath)) {
70
- fs.mkdirSync(collectionsFolderPath, { recursive: true });
71
- }
72
- collections?.forEach((collection) => {
73
- const { databaseId, ...collectionWithoutDbId } = collection; // Destructure to exclude databaseId
74
- const collectionFilePath = path.join(collectionsFolderPath, `${collection.name}.ts`);
75
- const collectionContent = `import { type CollectionCreate } from "appwrite-utils";
76
-
77
- const ${collection.name}Config: Partial<CollectionCreate> = {
78
- name: "${collection.name}",
79
- $id: "${collection.$id}",
80
- enabled: ${collection.enabled},
81
- documentSecurity: ${collection.documentSecurity},
82
- $permissions: [
83
- ${collection.$permissions
84
- .map((permission) => `{ permission: "${permission.permission}", target: "${permission.target}" }`)
85
- .join(",\n ")}
86
- ],
87
- attributes: [
88
- ${collection.attributes
89
- .map((attr) => {
90
- return `{ ${Object.entries(attr)
91
- .map(([key, value]) => {
92
- // Check the type of the value and format it accordingly
93
- if (typeof value === "string") {
94
- // If the value is a string, wrap it in quotes
95
- return `${key}: "${value.replace(/"/g, '\\"')}"`; // Escape existing quotes in the string
96
- }
97
- else if (Array.isArray(value)) {
98
- // If the value is an array, join it with commas
99
- if (value.length > 0) {
100
- return `${key}: [${value
101
- .map((item) => `"${item}"`)
102
- .join(", ")}]`;
103
- }
104
- else {
105
- return `${key}: []`;
106
- }
107
- }
108
- else {
109
- // If the value is not a string (e.g., boolean or number), output it directly
110
- return `${key}: ${value}`;
111
- }
112
- })
113
- .join(", ")} }`;
114
- })
115
- .join(",\n ")}
116
- ],
117
- indexes: [
118
- ${(collection.indexes?.map((index) => {
119
- // Map each attribute to ensure it is properly quoted
120
- const formattedAttributes = index.attributes.map((attr) => `"${attr}"`).join(", ") ?? "";
121
- return `{ key: "${index.key}", type: "${index.type}", attributes: [${formattedAttributes}], orders: [${index.orders
122
- ?.filter((order) => order !== null)
123
- .map((order) => `"${order}"`)
124
- .join(", ") ?? ""}] }`;
125
- }) ?? []).join(",\n ")}
126
- ]
127
- };
128
-
129
- export default ${collection.name}Config;
130
- `;
131
- fs.writeFileSync(collectionFilePath, collectionContent, {
132
- encoding: "utf-8",
133
- });
134
- console.log(`Collection schema written to ${collectionFilePath}`);
135
- });
136
- }
137
- updateConfig(config) {
138
- const configPath = path.join(this.appwriteFolderPath, "appwriteConfig.ts");
139
- const configContent = `import { type AppwriteConfig } from "appwrite-utils";
140
-
141
- const appwriteConfig: AppwriteConfig = {
142
- appwriteEndpoint: "${config.appwriteEndpoint}",
143
- appwriteProject: "${config.appwriteProject}",
144
- appwriteKey: "${config.appwriteKey}",
145
- enableBackups: ${config.enableBackups},
146
- backupInterval: ${config.backupInterval},
147
- backupRetention: ${config.backupRetention},
148
- enableBackupCleanup: ${config.enableBackupCleanup},
149
- enableMockData: ${config.enableMockData},
150
- documentBucketId: "${config.documentBucketId}",
151
- usersCollectionName: "${config.usersCollectionName}",
152
- databases: ${JSON.stringify(config.databases, null, 4)},
153
- buckets: ${JSON.stringify(config.buckets, null, 4)},
154
- functions: ${JSON.stringify(config.functions?.map((func) => ({
155
- $id: func.$id || ulid(),
156
- name: func.name,
157
- runtime: func.runtime,
158
- dirPath: func.dirPath || `functions/${func.name}`,
159
- entrypoint: func.entrypoint || "src/index.ts",
160
- execute: func.execute || [],
161
- events: func.events || [],
162
- schedule: func.schedule || "",
163
- timeout: func.timeout || 15,
164
- enabled: func.enabled !== false,
165
- logging: func.logging !== false,
166
- commands: func.commands || "npm install",
167
- scopes: func.scopes || [],
168
- installationId: func.installationId,
169
- providerRepositoryId: func.providerRepositoryId,
170
- providerBranch: func.providerBranch,
171
- providerSilentMode: func.providerSilentMode,
172
- providerRootDirectory: func.providerRootDirectory,
173
- specification: func.specification,
174
- })), null, 4)}
175
- };
176
-
177
- export default appwriteConfig;
178
- `;
179
- fs.writeFileSync(configPath, configContent, { encoding: "utf-8" });
180
- }
181
- extractRelationships() {
182
- if (!this.config.collections) {
183
- return;
184
- }
185
- this.config.collections.forEach((collection) => {
186
- if (!collection.attributes) {
187
- return;
188
- }
189
- collection.attributes.forEach((attr) => {
190
- if (attr.type === "relationship" && attr.twoWay && attr.twoWayKey) {
191
- const relationshipAttr = attr;
192
- let isArrayParent = false;
193
- let isArrayChild = false;
194
- switch (relationshipAttr.relationType) {
195
- case "oneToMany":
196
- isArrayParent = true;
197
- isArrayChild = false;
198
- break;
199
- case "manyToMany":
200
- isArrayParent = true;
201
- isArrayChild = true;
202
- break;
203
- case "oneToOne":
204
- isArrayParent = false;
205
- isArrayChild = false;
206
- break;
207
- case "manyToOne":
208
- isArrayParent = false;
209
- isArrayChild = true;
210
- break;
211
- default:
212
- break;
213
- }
214
- this.addRelationship(collection.name, relationshipAttr.relatedCollection, attr.key, relationshipAttr.twoWayKey, isArrayParent, isArrayChild);
215
- console.log(`Extracted relationship: ${attr.key}\n\t${collection.name} -> ${relationshipAttr.relatedCollection}, databaseId: ${collection.databaseId}`);
216
- }
217
- });
218
- });
219
- }
220
- addRelationship(parentCollection, childCollection, parentKey, childKey, isArrayParent, isArrayChild) {
221
- const relationshipsChild = this.relationshipMap.get(childCollection) || [];
222
- const relationshipsParent = this.relationshipMap.get(parentCollection) || [];
223
- relationshipsParent.push({
224
- parentCollection,
225
- childCollection,
226
- parentKey,
227
- childKey,
228
- isArray: isArrayParent,
229
- isChild: false,
230
- });
231
- relationshipsChild.push({
232
- parentCollection,
233
- childCollection,
234
- parentKey,
235
- childKey,
236
- isArray: isArrayChild,
237
- isChild: true,
238
- });
239
- this.relationshipMap.set(childCollection, relationshipsChild);
240
- this.relationshipMap.set(parentCollection, relationshipsParent);
241
- }
242
- generateSchemas() {
243
- if (!this.config.collections) {
244
- return;
245
- }
246
- this.config.collections.forEach((collection) => {
247
- const schemaString = this.createSchemaString(collection.name, collection.attributes || []);
248
- const camelCaseName = toCamelCase(collection.name);
249
- const schemaPath = path.join(this.appwriteFolderPath, "schemas", `${camelCaseName}.ts`);
250
- fs.writeFileSync(schemaPath, schemaString, { encoding: "utf-8" });
251
- console.log(`Schema written to ${schemaPath}`);
252
- });
253
- }
254
- createSchemaString = (name, attributes) => {
255
- const pascalName = toPascalCase(name);
256
- let imports = `import { z } from "zod";\n`;
257
- const hasDescription = attributes.some((attr) => attr.description);
258
- if (hasDescription) {
259
- imports += `import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";\n`;
260
- imports += `extendZodWithOpenApi(z);\n`;
261
- }
262
- // Use the relationshipMap to find related collections
263
- const relationshipDetails = this.relationshipMap.get(name) || [];
264
- const relatedCollections = relationshipDetails
265
- .filter((detail, index, self) => {
266
- const uniqueKey = `${detail.parentCollection}-${detail.childCollection}-${detail.parentKey}-${detail.childKey}`;
267
- return (index ===
268
- self.findIndex((obj) => `${obj.parentCollection}-${obj.childCollection}-${obj.parentKey}-${obj.childKey}` ===
269
- uniqueKey));
270
- })
271
- .map((detail) => {
272
- const relatedCollectionName = detail.isChild
273
- ? detail.parentCollection
274
- : detail.childCollection;
275
- const key = detail.isChild ? detail.childKey : detail.parentKey;
276
- const isArray = detail.isArray ? "array" : "";
277
- return [relatedCollectionName, key, isArray];
278
- });
279
- let relatedTypes = "";
280
- let relatedTypesLazy = "";
281
- let curNum = 0;
282
- let maxNum = relatedCollections.length;
283
- relatedCollections.forEach((relatedCollection) => {
284
- console.log(relatedCollection);
285
- let relatedPascalName = toPascalCase(relatedCollection[0]);
286
- let relatedCamelName = toCamelCase(relatedCollection[0]);
287
- curNum++;
288
- let endNameTypes = relatedPascalName;
289
- let endNameLazy = `${relatedPascalName}Schema`;
290
- if (relatedCollection[2] === "array") {
291
- endNameTypes += "[]";
292
- endNameLazy += ".array().default([])";
293
- }
294
- else if (!(relatedCollection[2] === "array")) {
295
- endNameTypes += " | null";
296
- endNameLazy += ".nullish()";
297
- }
298
- imports += `import { ${relatedPascalName}Schema, type ${relatedPascalName} } from "./${relatedCamelName}";\n`;
299
- relatedTypes += `${relatedCollection[1]}?: ${endNameTypes};\n`;
300
- if (relatedTypes.length > 0 && curNum !== maxNum) {
301
- relatedTypes += " ";
302
- }
303
- relatedTypesLazy += `${relatedCollection[1]}: z.lazy(() => ${endNameLazy}),\n`;
304
- if (relatedTypesLazy.length > 0 && curNum !== maxNum) {
305
- relatedTypesLazy += " ";
306
- }
307
- });
308
- let schemaString = `${imports}\n\n`;
309
- schemaString += `export const ${pascalName}SchemaBase = z.object({\n`;
310
- schemaString += ` $id: z.string().optional(),\n`;
311
- schemaString += ` $createdAt: z.string().optional(),\n`;
312
- schemaString += ` $updatedAt: z.string().optional(),\n`;
313
- for (const attribute of attributes) {
314
- if (attribute.type === "relationship") {
315
- continue;
316
- }
317
- schemaString += ` ${attribute.key}: ${this.typeToZod(attribute)},\n`;
318
- }
319
- schemaString += `});\n\n`;
320
- schemaString += `export type ${pascalName}Base = z.infer<typeof ${pascalName}SchemaBase>`;
321
- if (relatedTypes.length > 0) {
322
- schemaString += ` & {\n ${relatedTypes}};\n\n`;
323
- }
324
- else {
325
- schemaString += `;\n\n`;
326
- }
327
- schemaString += `export const ${pascalName}Schema: z.ZodType<${pascalName}Base> = ${pascalName}SchemaBase`;
328
- if (relatedTypes.length > 0) {
329
- schemaString += `.extend({\n ${relatedTypesLazy}});\n\n`;
330
- }
331
- else {
332
- schemaString += `;\n`;
333
- }
334
- schemaString += `export type ${pascalName} = z.infer<typeof ${pascalName}Schema>;\n\n`;
335
- return schemaString;
336
- };
337
- typeToZod = (attribute) => {
338
- let baseSchemaCode = "";
339
- const finalAttribute = (attribute.type === "string" &&
340
- attribute.format &&
341
- attribute.format === "enum" &&
342
- attribute.type === "string"
343
- ? { ...attribute, type: attribute.format }
344
- : attribute);
345
- switch (finalAttribute.type) {
346
- case "string":
347
- baseSchemaCode = "z.string()";
348
- if (finalAttribute.size) {
349
- baseSchemaCode += `.max(${finalAttribute.size}, "Maximum length of ${finalAttribute.size} characters exceeded")`;
350
- }
351
- if (finalAttribute.xdefault !== undefined) {
352
- baseSchemaCode += `.default("${finalAttribute.xdefault}")`;
353
- }
354
- if (!attribute.required && !attribute.array) {
355
- baseSchemaCode += ".nullish()";
356
- }
357
- break;
358
- case "integer":
359
- baseSchemaCode = "z.number().int()";
360
- if (finalAttribute.min !== undefined) {
361
- if (BigInt(finalAttribute.min) === BigInt(-9223372036854776000)) {
362
- delete finalAttribute.min;
363
- }
364
- else {
365
- baseSchemaCode += `.min(${finalAttribute.min}, "Minimum value of ${finalAttribute.min} not met")`;
366
- }
367
- }
368
- if (finalAttribute.max !== undefined) {
369
- if (BigInt(finalAttribute.max) === BigInt(9223372036854776000)) {
370
- delete finalAttribute.max;
371
- }
372
- else {
373
- baseSchemaCode += `.max(${finalAttribute.max}, "Maximum value of ${finalAttribute.max} exceeded")`;
374
- }
375
- }
376
- if (finalAttribute.xdefault !== undefined) {
377
- baseSchemaCode += `.default(${finalAttribute.xdefault})`;
378
- }
379
- if (!finalAttribute.required && !finalAttribute.array) {
380
- baseSchemaCode += ".nullish()";
381
- }
382
- break;
383
- case "float":
384
- baseSchemaCode = "z.number()";
385
- if (finalAttribute.min !== undefined) {
386
- baseSchemaCode += `.min(${finalAttribute.min}, "Minimum value of ${finalAttribute.min} not met")`;
387
- }
388
- if (finalAttribute.max !== undefined) {
389
- baseSchemaCode += `.max(${finalAttribute.max}, "Maximum value of ${finalAttribute.max} exceeded")`;
390
- }
391
- if (finalAttribute.xdefault !== undefined) {
392
- baseSchemaCode += `.default(${finalAttribute.xdefault})`;
393
- }
394
- if (!finalAttribute.required && !finalAttribute.array) {
395
- baseSchemaCode += ".nullish()";
396
- }
397
- break;
398
- case "boolean":
399
- baseSchemaCode = "z.boolean()";
400
- if (finalAttribute.xdefault !== undefined) {
401
- baseSchemaCode += `.default(${finalAttribute.xdefault})`;
402
- }
403
- if (!finalAttribute.required && !finalAttribute.array) {
404
- baseSchemaCode += ".nullish()";
405
- }
406
- break;
407
- case "datetime":
408
- baseSchemaCode = "z.date()";
409
- if (finalAttribute.xdefault !== undefined) {
410
- baseSchemaCode += `.default(new Date("${finalAttribute.xdefault}"))`;
411
- }
412
- if (!finalAttribute.required && !finalAttribute.array) {
413
- baseSchemaCode += ".nullish()";
414
- }
415
- break;
416
- case "email":
417
- baseSchemaCode = "z.string().email()";
418
- if (finalAttribute.xdefault !== undefined) {
419
- baseSchemaCode += `.default("${finalAttribute.xdefault}")`;
420
- }
421
- if (!finalAttribute.required && !finalAttribute.array) {
422
- baseSchemaCode += ".nullish()";
423
- }
424
- break;
425
- case "ip":
426
- baseSchemaCode = "z.string()"; // Add custom validation as needed
427
- if (finalAttribute.xdefault !== undefined) {
428
- baseSchemaCode += `.default("${finalAttribute.xdefault}")`;
429
- }
430
- if (!finalAttribute.required && !finalAttribute.array) {
431
- baseSchemaCode += ".nullish()";
432
- }
433
- break;
434
- case "url":
435
- baseSchemaCode = "z.string().url()";
436
- if (finalAttribute.xdefault !== undefined) {
437
- baseSchemaCode += `.default("${finalAttribute.xdefault}")`;
438
- }
439
- if (!finalAttribute.required && !finalAttribute.array) {
440
- baseSchemaCode += ".nullish()";
441
- }
442
- break;
443
- case "enum":
444
- baseSchemaCode = `z.enum([${finalAttribute.elements
445
- .map((element) => `"${element}"`)
446
- .join(", ")}])`;
447
- if (finalAttribute.xdefault !== undefined) {
448
- baseSchemaCode += `.default("${finalAttribute.xdefault}")`;
449
- }
450
- if (!attribute.required && !attribute.array) {
451
- baseSchemaCode += ".nullish()";
452
- }
453
- break;
454
- case "relationship":
455
- break;
456
- default:
457
- baseSchemaCode = "z.any()";
458
- }
459
- // Handle arrays
460
- if (attribute.array) {
461
- baseSchemaCode = `z.array(${baseSchemaCode})`;
462
- }
463
- if (attribute.array && !attribute.required) {
464
- baseSchemaCode += ".nullish()";
465
- }
466
- if (attribute.description) {
467
- if (typeof attribute.description === "string") {
468
- baseSchemaCode += `.openapi({ description: "${attribute.description}" })`;
469
- }
470
- else {
471
- baseSchemaCode += `.openapi(${Object.entries(attribute.description)
472
- .map(([key, value]) => `"${key}": ${value}`)
473
- .join(", ")})`;
474
- }
475
- }
476
- return baseSchemaCode;
477
- };
478
- }
@@ -1,6 +0,0 @@
1
- import { Databases, type Models } from "node-appwrite";
2
- import { type AppwriteConfig } from "appwrite-utils";
3
- export declare const setupMigrationDatabase: (config: AppwriteConfig) => Promise<void>;
4
- export declare const ensureDatabasesExist: (config: AppwriteConfig, databasesToEnsure?: Models.Database[]) => Promise<void>;
5
- export declare const wipeOtherDatabases: (database: Databases, databasesToKeep: Models.Database[]) => Promise<void>;
6
- export declare const ensureCollectionsExist: (config: AppwriteConfig, database: Models.Database, collectionsToEnsure?: Models.Collection[]) => Promise<void>;