@njdamstra/appwrite-utils-cli 1.8.9

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 (392) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1133 -0
  3. package/dist/adapters/AdapterFactory.d.ts +94 -0
  4. package/dist/adapters/AdapterFactory.js +405 -0
  5. package/dist/adapters/DatabaseAdapter.d.ts +233 -0
  6. package/dist/adapters/DatabaseAdapter.js +50 -0
  7. package/dist/adapters/LegacyAdapter.d.ts +50 -0
  8. package/dist/adapters/LegacyAdapter.js +612 -0
  9. package/dist/adapters/TablesDBAdapter.d.ts +45 -0
  10. package/dist/adapters/TablesDBAdapter.js +571 -0
  11. package/dist/adapters/index.d.ts +11 -0
  12. package/dist/adapters/index.js +12 -0
  13. package/dist/backups/operations/bucketBackup.d.ts +19 -0
  14. package/dist/backups/operations/bucketBackup.js +197 -0
  15. package/dist/backups/operations/collectionBackup.d.ts +30 -0
  16. package/dist/backups/operations/collectionBackup.js +201 -0
  17. package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
  18. package/dist/backups/operations/comprehensiveBackup.js +238 -0
  19. package/dist/backups/schemas/bucketManifest.d.ts +93 -0
  20. package/dist/backups/schemas/bucketManifest.js +33 -0
  21. package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
  22. package/dist/backups/schemas/comprehensiveManifest.js +32 -0
  23. package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
  24. package/dist/backups/tracking/centralizedTracking.js +274 -0
  25. package/dist/cli/commands/configCommands.d.ts +8 -0
  26. package/dist/cli/commands/configCommands.js +166 -0
  27. package/dist/cli/commands/databaseCommands.d.ts +13 -0
  28. package/dist/cli/commands/databaseCommands.js +554 -0
  29. package/dist/cli/commands/functionCommands.d.ts +7 -0
  30. package/dist/cli/commands/functionCommands.js +330 -0
  31. package/dist/cli/commands/schemaCommands.d.ts +7 -0
  32. package/dist/cli/commands/schemaCommands.js +169 -0
  33. package/dist/cli/commands/storageCommands.d.ts +5 -0
  34. package/dist/cli/commands/storageCommands.js +143 -0
  35. package/dist/cli/commands/transferCommands.d.ts +5 -0
  36. package/dist/cli/commands/transferCommands.js +384 -0
  37. package/dist/collections/attributes.d.ts +13 -0
  38. package/dist/collections/attributes.js +1364 -0
  39. package/dist/collections/indexes.d.ts +12 -0
  40. package/dist/collections/indexes.js +217 -0
  41. package/dist/collections/methods.d.ts +19 -0
  42. package/dist/collections/methods.js +682 -0
  43. package/dist/collections/tableOperations.d.ts +86 -0
  44. package/dist/collections/tableOperations.js +434 -0
  45. package/dist/collections/transferOperations.d.ts +8 -0
  46. package/dist/collections/transferOperations.js +412 -0
  47. package/dist/collections/wipeOperations.d.ts +16 -0
  48. package/dist/collections/wipeOperations.js +233 -0
  49. package/dist/config/ConfigManager.d.ts +445 -0
  50. package/dist/config/ConfigManager.js +625 -0
  51. package/dist/config/configMigration.d.ts +87 -0
  52. package/dist/config/configMigration.js +390 -0
  53. package/dist/config/configValidation.d.ts +66 -0
  54. package/dist/config/configValidation.js +358 -0
  55. package/dist/config/index.d.ts +8 -0
  56. package/dist/config/index.js +7 -0
  57. package/dist/config/services/ConfigDiscoveryService.d.ts +126 -0
  58. package/dist/config/services/ConfigDiscoveryService.js +374 -0
  59. package/dist/config/services/ConfigLoaderService.d.ts +129 -0
  60. package/dist/config/services/ConfigLoaderService.js +540 -0
  61. package/dist/config/services/ConfigMergeService.d.ts +208 -0
  62. package/dist/config/services/ConfigMergeService.js +308 -0
  63. package/dist/config/services/ConfigValidationService.d.ts +214 -0
  64. package/dist/config/services/ConfigValidationService.js +310 -0
  65. package/dist/config/services/SessionAuthService.d.ts +225 -0
  66. package/dist/config/services/SessionAuthService.js +456 -0
  67. package/dist/config/services/__tests__/ConfigMergeService.test.d.ts +1 -0
  68. package/dist/config/services/__tests__/ConfigMergeService.test.js +271 -0
  69. package/dist/config/services/index.d.ts +13 -0
  70. package/dist/config/services/index.js +10 -0
  71. package/dist/config/yamlConfig.d.ts +722 -0
  72. package/dist/config/yamlConfig.js +702 -0
  73. package/dist/databases/methods.d.ts +6 -0
  74. package/dist/databases/methods.js +35 -0
  75. package/dist/databases/setup.d.ts +5 -0
  76. package/dist/databases/setup.js +45 -0
  77. package/dist/examples/yamlTerminologyExample.d.ts +42 -0
  78. package/dist/examples/yamlTerminologyExample.js +272 -0
  79. package/dist/functions/deployments.d.ts +4 -0
  80. package/dist/functions/deployments.js +146 -0
  81. package/dist/functions/fnConfigDiscovery.d.ts +3 -0
  82. package/dist/functions/fnConfigDiscovery.js +108 -0
  83. package/dist/functions/methods.d.ts +16 -0
  84. package/dist/functions/methods.js +162 -0
  85. package/dist/functions/pathResolution.d.ts +37 -0
  86. package/dist/functions/pathResolution.js +185 -0
  87. package/dist/functions/templates/count-docs-in-collection/README.md +54 -0
  88. package/dist/functions/templates/count-docs-in-collection/src/main.ts +159 -0
  89. package/dist/functions/templates/count-docs-in-collection/src/request.ts +9 -0
  90. package/dist/functions/templates/hono-typescript/README.md +286 -0
  91. package/dist/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
  92. package/dist/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
  93. package/dist/functions/templates/hono-typescript/src/app.ts +180 -0
  94. package/dist/functions/templates/hono-typescript/src/context.ts +103 -0
  95. package/dist/functions/templates/hono-typescript/src/index.ts +54 -0
  96. package/dist/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
  97. package/dist/functions/templates/typescript-node/README.md +32 -0
  98. package/dist/functions/templates/typescript-node/src/context.ts +103 -0
  99. package/dist/functions/templates/typescript-node/src/index.ts +29 -0
  100. package/dist/functions/templates/uv/README.md +31 -0
  101. package/dist/functions/templates/uv/pyproject.toml +30 -0
  102. package/dist/functions/templates/uv/src/__init__.py +0 -0
  103. package/dist/functions/templates/uv/src/context.py +125 -0
  104. package/dist/functions/templates/uv/src/index.py +46 -0
  105. package/dist/init.d.ts +2 -0
  106. package/dist/init.js +57 -0
  107. package/dist/interactiveCLI.d.ts +31 -0
  108. package/dist/interactiveCLI.js +898 -0
  109. package/dist/main.d.ts +2 -0
  110. package/dist/main.js +1172 -0
  111. package/dist/migrations/afterImportActions.d.ts +17 -0
  112. package/dist/migrations/afterImportActions.js +306 -0
  113. package/dist/migrations/appwriteToX.d.ts +211 -0
  114. package/dist/migrations/appwriteToX.js +491 -0
  115. package/dist/migrations/comprehensiveTransfer.d.ts +147 -0
  116. package/dist/migrations/comprehensiveTransfer.js +1317 -0
  117. package/dist/migrations/dataLoader.d.ts +753 -0
  118. package/dist/migrations/dataLoader.js +1250 -0
  119. package/dist/migrations/importController.d.ts +23 -0
  120. package/dist/migrations/importController.js +268 -0
  121. package/dist/migrations/importDataActions.d.ts +50 -0
  122. package/dist/migrations/importDataActions.js +230 -0
  123. package/dist/migrations/relationships.d.ts +29 -0
  124. package/dist/migrations/relationships.js +204 -0
  125. package/dist/migrations/services/DataTransformationService.d.ts +55 -0
  126. package/dist/migrations/services/DataTransformationService.js +158 -0
  127. package/dist/migrations/services/FileHandlerService.d.ts +75 -0
  128. package/dist/migrations/services/FileHandlerService.js +236 -0
  129. package/dist/migrations/services/ImportOrchestrator.d.ts +97 -0
  130. package/dist/migrations/services/ImportOrchestrator.js +485 -0
  131. package/dist/migrations/services/RateLimitManager.d.ts +138 -0
  132. package/dist/migrations/services/RateLimitManager.js +279 -0
  133. package/dist/migrations/services/RelationshipResolver.d.ts +120 -0
  134. package/dist/migrations/services/RelationshipResolver.js +332 -0
  135. package/dist/migrations/services/UserMappingService.d.ts +109 -0
  136. package/dist/migrations/services/UserMappingService.js +277 -0
  137. package/dist/migrations/services/ValidationService.d.ts +74 -0
  138. package/dist/migrations/services/ValidationService.js +260 -0
  139. package/dist/migrations/transfer.d.ts +26 -0
  140. package/dist/migrations/transfer.js +608 -0
  141. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +131 -0
  142. package/dist/migrations/yaml/YamlImportConfigLoader.js +383 -0
  143. package/dist/migrations/yaml/YamlImportIntegration.d.ts +93 -0
  144. package/dist/migrations/yaml/YamlImportIntegration.js +341 -0
  145. package/dist/migrations/yaml/generateImportSchemas.d.ts +30 -0
  146. package/dist/migrations/yaml/generateImportSchemas.js +1327 -0
  147. package/dist/schemas/authUser.d.ts +24 -0
  148. package/dist/schemas/authUser.js +17 -0
  149. package/dist/setup.d.ts +2 -0
  150. package/dist/setup.js +5 -0
  151. package/dist/setupCommands.d.ts +58 -0
  152. package/dist/setupCommands.js +490 -0
  153. package/dist/setupController.d.ts +9 -0
  154. package/dist/setupController.js +34 -0
  155. package/dist/shared/attributeMapper.d.ts +20 -0
  156. package/dist/shared/attributeMapper.js +203 -0
  157. package/dist/shared/backupMetadataSchema.d.ts +94 -0
  158. package/dist/shared/backupMetadataSchema.js +38 -0
  159. package/dist/shared/backupTracking.d.ts +18 -0
  160. package/dist/shared/backupTracking.js +176 -0
  161. package/dist/shared/confirmationDialogs.d.ts +75 -0
  162. package/dist/shared/confirmationDialogs.js +236 -0
  163. package/dist/shared/errorUtils.d.ts +54 -0
  164. package/dist/shared/errorUtils.js +95 -0
  165. package/dist/shared/functionManager.d.ts +48 -0
  166. package/dist/shared/functionManager.js +336 -0
  167. package/dist/shared/indexManager.d.ts +24 -0
  168. package/dist/shared/indexManager.js +151 -0
  169. package/dist/shared/jsonSchemaGenerator.d.ts +50 -0
  170. package/dist/shared/jsonSchemaGenerator.js +290 -0
  171. package/dist/shared/logging.d.ts +61 -0
  172. package/dist/shared/logging.js +116 -0
  173. package/dist/shared/messageFormatter.d.ts +39 -0
  174. package/dist/shared/messageFormatter.js +162 -0
  175. package/dist/shared/migrationHelpers.d.ts +61 -0
  176. package/dist/shared/migrationHelpers.js +145 -0
  177. package/dist/shared/operationLogger.d.ts +10 -0
  178. package/dist/shared/operationLogger.js +12 -0
  179. package/dist/shared/operationQueue.d.ts +40 -0
  180. package/dist/shared/operationQueue.js +311 -0
  181. package/dist/shared/operationsTable.d.ts +26 -0
  182. package/dist/shared/operationsTable.js +286 -0
  183. package/dist/shared/operationsTableSchema.d.ts +48 -0
  184. package/dist/shared/operationsTableSchema.js +35 -0
  185. package/dist/shared/progressManager.d.ts +62 -0
  186. package/dist/shared/progressManager.js +215 -0
  187. package/dist/shared/pydanticModelGenerator.d.ts +17 -0
  188. package/dist/shared/pydanticModelGenerator.js +615 -0
  189. package/dist/shared/relationshipExtractor.d.ts +56 -0
  190. package/dist/shared/relationshipExtractor.js +138 -0
  191. package/dist/shared/schemaGenerator.d.ts +40 -0
  192. package/dist/shared/schemaGenerator.js +556 -0
  193. package/dist/shared/selectionDialogs.d.ts +214 -0
  194. package/dist/shared/selectionDialogs.js +544 -0
  195. package/dist/storage/backupCompression.d.ts +20 -0
  196. package/dist/storage/backupCompression.js +67 -0
  197. package/dist/storage/methods.d.ts +32 -0
  198. package/dist/storage/methods.js +472 -0
  199. package/dist/storage/schemas.d.ts +842 -0
  200. package/dist/storage/schemas.js +175 -0
  201. package/dist/types.d.ts +4 -0
  202. package/dist/types.js +3 -0
  203. package/dist/users/methods.d.ts +16 -0
  204. package/dist/users/methods.js +277 -0
  205. package/dist/utils/ClientFactory.d.ts +87 -0
  206. package/dist/utils/ClientFactory.js +212 -0
  207. package/dist/utils/configDiscovery.d.ts +78 -0
  208. package/dist/utils/configDiscovery.js +472 -0
  209. package/dist/utils/configMigration.d.ts +1 -0
  210. package/dist/utils/configMigration.js +261 -0
  211. package/dist/utils/constantsGenerator.d.ts +31 -0
  212. package/dist/utils/constantsGenerator.js +321 -0
  213. package/dist/utils/dataConverters.d.ts +46 -0
  214. package/dist/utils/dataConverters.js +139 -0
  215. package/dist/utils/directoryUtils.d.ts +22 -0
  216. package/dist/utils/directoryUtils.js +59 -0
  217. package/dist/utils/getClientFromConfig.d.ts +39 -0
  218. package/dist/utils/getClientFromConfig.js +199 -0
  219. package/dist/utils/helperFunctions.d.ts +63 -0
  220. package/dist/utils/helperFunctions.js +156 -0
  221. package/dist/utils/index.d.ts +2 -0
  222. package/dist/utils/index.js +2 -0
  223. package/dist/utils/loadConfigs.d.ts +50 -0
  224. package/dist/utils/loadConfigs.js +358 -0
  225. package/dist/utils/pathResolvers.d.ts +53 -0
  226. package/dist/utils/pathResolvers.js +72 -0
  227. package/dist/utils/projectConfig.d.ts +119 -0
  228. package/dist/utils/projectConfig.js +171 -0
  229. package/dist/utils/retryFailedPromises.d.ts +2 -0
  230. package/dist/utils/retryFailedPromises.js +23 -0
  231. package/dist/utils/sessionAuth.d.ts +48 -0
  232. package/dist/utils/sessionAuth.js +164 -0
  233. package/dist/utils/setupFiles.d.ts +4 -0
  234. package/dist/utils/setupFiles.js +1192 -0
  235. package/dist/utils/typeGuards.d.ts +35 -0
  236. package/dist/utils/typeGuards.js +57 -0
  237. package/dist/utils/validationRules.d.ts +43 -0
  238. package/dist/utils/validationRules.js +42 -0
  239. package/dist/utils/versionDetection.d.ts +58 -0
  240. package/dist/utils/versionDetection.js +251 -0
  241. package/dist/utils/yamlConverter.d.ts +100 -0
  242. package/dist/utils/yamlConverter.js +428 -0
  243. package/dist/utils/yamlLoader.d.ts +70 -0
  244. package/dist/utils/yamlLoader.js +267 -0
  245. package/dist/utilsController.d.ts +106 -0
  246. package/dist/utilsController.js +863 -0
  247. package/package.json +75 -0
  248. package/scripts/copy-templates.ts +23 -0
  249. package/src/adapters/AdapterFactory.ts +510 -0
  250. package/src/adapters/DatabaseAdapter.ts +306 -0
  251. package/src/adapters/LegacyAdapter.ts +841 -0
  252. package/src/adapters/TablesDBAdapter.ts +773 -0
  253. package/src/adapters/index.ts +37 -0
  254. package/src/backups/operations/bucketBackup.ts +277 -0
  255. package/src/backups/operations/collectionBackup.ts +310 -0
  256. package/src/backups/operations/comprehensiveBackup.ts +342 -0
  257. package/src/backups/schemas/bucketManifest.ts +78 -0
  258. package/src/backups/schemas/comprehensiveManifest.ts +76 -0
  259. package/src/backups/tracking/centralizedTracking.ts +352 -0
  260. package/src/cli/commands/configCommands.ts +201 -0
  261. package/src/cli/commands/databaseCommands.ts +749 -0
  262. package/src/cli/commands/functionCommands.ts +418 -0
  263. package/src/cli/commands/schemaCommands.ts +200 -0
  264. package/src/cli/commands/storageCommands.ts +152 -0
  265. package/src/cli/commands/transferCommands.ts +457 -0
  266. package/src/collections/attributes.ts +2054 -0
  267. package/src/collections/attributes.ts.backup +1555 -0
  268. package/src/collections/indexes.ts +352 -0
  269. package/src/collections/methods.ts +745 -0
  270. package/src/collections/tableOperations.ts +506 -0
  271. package/src/collections/transferOperations.ts +590 -0
  272. package/src/collections/wipeOperations.ts +346 -0
  273. package/src/config/ConfigManager.ts +808 -0
  274. package/src/config/README.md +274 -0
  275. package/src/config/configMigration.ts +575 -0
  276. package/src/config/configValidation.ts +445 -0
  277. package/src/config/index.ts +10 -0
  278. package/src/config/services/ConfigDiscoveryService.ts +463 -0
  279. package/src/config/services/ConfigLoaderService.ts +740 -0
  280. package/src/config/services/ConfigMergeService.ts +388 -0
  281. package/src/config/services/ConfigValidationService.ts +394 -0
  282. package/src/config/services/SessionAuthService.ts +565 -0
  283. package/src/config/services/__tests__/ConfigMergeService.test.ts +351 -0
  284. package/src/config/services/index.ts +29 -0
  285. package/src/config/yamlConfig.ts +761 -0
  286. package/src/databases/methods.ts +49 -0
  287. package/src/databases/setup.ts +77 -0
  288. package/src/examples/yamlTerminologyExample.ts +346 -0
  289. package/src/functions/deployments.ts +220 -0
  290. package/src/functions/fnConfigDiscovery.ts +103 -0
  291. package/src/functions/methods.ts +271 -0
  292. package/src/functions/pathResolution.ts +227 -0
  293. package/src/functions/templates/count-docs-in-collection/README.md +54 -0
  294. package/src/functions/templates/count-docs-in-collection/src/main.ts +159 -0
  295. package/src/functions/templates/count-docs-in-collection/src/request.ts +9 -0
  296. package/src/functions/templates/hono-typescript/README.md +286 -0
  297. package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
  298. package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
  299. package/src/functions/templates/hono-typescript/src/app.ts +180 -0
  300. package/src/functions/templates/hono-typescript/src/context.ts +103 -0
  301. package/src/functions/templates/hono-typescript/src/index.ts +54 -0
  302. package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
  303. package/src/functions/templates/typescript-node/README.md +32 -0
  304. package/src/functions/templates/typescript-node/src/context.ts +103 -0
  305. package/src/functions/templates/typescript-node/src/index.ts +29 -0
  306. package/src/functions/templates/uv/README.md +31 -0
  307. package/src/functions/templates/uv/pyproject.toml +30 -0
  308. package/src/functions/templates/uv/src/__init__.py +0 -0
  309. package/src/functions/templates/uv/src/context.py +125 -0
  310. package/src/functions/templates/uv/src/index.py +46 -0
  311. package/src/init.ts +62 -0
  312. package/src/interactiveCLI.ts +1136 -0
  313. package/src/main.ts +1661 -0
  314. package/src/migrations/afterImportActions.ts +580 -0
  315. package/src/migrations/appwriteToX.ts +664 -0
  316. package/src/migrations/comprehensiveTransfer.ts +2285 -0
  317. package/src/migrations/dataLoader.ts +1702 -0
  318. package/src/migrations/importController.ts +428 -0
  319. package/src/migrations/importDataActions.ts +315 -0
  320. package/src/migrations/relationships.ts +334 -0
  321. package/src/migrations/services/DataTransformationService.ts +196 -0
  322. package/src/migrations/services/FileHandlerService.ts +311 -0
  323. package/src/migrations/services/ImportOrchestrator.ts +666 -0
  324. package/src/migrations/services/RateLimitManager.ts +363 -0
  325. package/src/migrations/services/RelationshipResolver.ts +461 -0
  326. package/src/migrations/services/UserMappingService.ts +345 -0
  327. package/src/migrations/services/ValidationService.ts +349 -0
  328. package/src/migrations/transfer.ts +1068 -0
  329. package/src/migrations/yaml/YamlImportConfigLoader.ts +439 -0
  330. package/src/migrations/yaml/YamlImportIntegration.ts +446 -0
  331. package/src/migrations/yaml/generateImportSchemas.ts +1354 -0
  332. package/src/schemas/authUser.ts +23 -0
  333. package/src/setup.ts +8 -0
  334. package/src/setupCommands.ts +603 -0
  335. package/src/setupController.ts +43 -0
  336. package/src/shared/attributeMapper.ts +229 -0
  337. package/src/shared/backupMetadataSchema.ts +93 -0
  338. package/src/shared/backupTracking.ts +211 -0
  339. package/src/shared/confirmationDialogs.ts +327 -0
  340. package/src/shared/errorUtils.ts +110 -0
  341. package/src/shared/functionManager.ts +525 -0
  342. package/src/shared/indexManager.ts +254 -0
  343. package/src/shared/jsonSchemaGenerator.ts +383 -0
  344. package/src/shared/logging.ts +149 -0
  345. package/src/shared/messageFormatter.ts +208 -0
  346. package/src/shared/migrationHelpers.ts +232 -0
  347. package/src/shared/operationLogger.ts +20 -0
  348. package/src/shared/operationQueue.ts +377 -0
  349. package/src/shared/operationsTable.ts +338 -0
  350. package/src/shared/operationsTableSchema.ts +60 -0
  351. package/src/shared/progressManager.ts +278 -0
  352. package/src/shared/pydanticModelGenerator.ts +618 -0
  353. package/src/shared/relationshipExtractor.ts +214 -0
  354. package/src/shared/schemaGenerator.ts +644 -0
  355. package/src/shared/selectionDialogs.ts +749 -0
  356. package/src/storage/backupCompression.ts +88 -0
  357. package/src/storage/methods.ts +698 -0
  358. package/src/storage/schemas.ts +205 -0
  359. package/src/types/node-appwrite-tablesdb.d.ts +44 -0
  360. package/src/types.ts +9 -0
  361. package/src/users/methods.ts +359 -0
  362. package/src/utils/ClientFactory.ts +240 -0
  363. package/src/utils/configDiscovery.ts +557 -0
  364. package/src/utils/configMigration.ts +348 -0
  365. package/src/utils/constantsGenerator.ts +369 -0
  366. package/src/utils/dataConverters.ts +159 -0
  367. package/src/utils/directoryUtils.ts +61 -0
  368. package/src/utils/getClientFromConfig.ts +257 -0
  369. package/src/utils/helperFunctions.ts +228 -0
  370. package/src/utils/index.ts +2 -0
  371. package/src/utils/loadConfigs.ts +449 -0
  372. package/src/utils/pathResolvers.ts +81 -0
  373. package/src/utils/projectConfig.ts +299 -0
  374. package/src/utils/retryFailedPromises.ts +29 -0
  375. package/src/utils/sessionAuth.ts +230 -0
  376. package/src/utils/setupFiles.ts +1238 -0
  377. package/src/utils/typeGuards.ts +65 -0
  378. package/src/utils/validationRules.ts +88 -0
  379. package/src/utils/versionDetection.ts +292 -0
  380. package/src/utils/yamlConverter.ts +542 -0
  381. package/src/utils/yamlLoader.ts +371 -0
  382. package/src/utilsController.ts +1203 -0
  383. package/tests/README.md +497 -0
  384. package/tests/adapters/AdapterFactory.test.ts +277 -0
  385. package/tests/integration/syncOperations.test.ts +463 -0
  386. package/tests/jest.config.js +25 -0
  387. package/tests/migration/configMigration.test.ts +546 -0
  388. package/tests/setup.ts +62 -0
  389. package/tests/testUtils.ts +340 -0
  390. package/tests/utils/loadConfigs.test.ts +350 -0
  391. package/tests/validation/configValidation.test.ts +412 -0
  392. package/tsconfig.json +44 -0
@@ -0,0 +1,23 @@
1
+ import { type Databases, type Models, type Storage } from "node-appwrite";
2
+ import type { AppwriteConfig, ConfigDatabase } from "@njdamstra/appwrite-utils";
3
+ import type { ImportDataActions } from "./importDataActions.js";
4
+ import type { SetupOptions } from "../utilsController.js";
5
+ import { DataLoader } from "./dataLoader.js";
6
+ export declare class ImportController {
7
+ private config;
8
+ private database;
9
+ private storage;
10
+ private appwriteFolderPath;
11
+ private importDataActions;
12
+ private setupOptions;
13
+ private documentCache;
14
+ private batchLimit;
15
+ private hasImportedUsers;
16
+ private postImportActionsQueue;
17
+ private databasesToRun;
18
+ constructor(config: AppwriteConfig, database: Databases, storage: Storage, appwriteFolderPath: string, importDataActions: ImportDataActions, setupOptions: SetupOptions, databasesToRun?: Models.Database[]);
19
+ run(specificCollections?: string[]): Promise<void>;
20
+ updateOthersToFinalData(updatedDb: Models.Database, targetDb: Models.Database): Promise<void>;
21
+ importCollections(db: ConfigDatabase, dataLoader: DataLoader, specificCollections?: string[]): Promise<void>;
22
+ executePostImportActions(dbId: string, dataLoader: DataLoader, specificCollections?: string[]): Promise<void>;
23
+ }
@@ -0,0 +1,268 @@
1
+ import { AppwriteException, ID, Query, } from "node-appwrite";
2
+ import { areCollectionNamesSame, tryAwaitWithRetry } from "../utils/index.js";
3
+ import { resolveAndUpdateRelationships } from "./relationships.js";
4
+ import { UsersController } from "../users/methods.js";
5
+ import { logger } from "../shared/logging.js";
6
+ import { updateOperation } from "../shared/migrationHelpers.js";
7
+ import { LegacyAdapter } from "../adapters/LegacyAdapter.js";
8
+ import { BatchSchema, OperationCreateSchema, OperationSchema, } from "../storage/schemas.js";
9
+ import { DataLoader } from "./dataLoader.js";
10
+ import { transferDatabaseLocalToLocal, transferStorageLocalToLocal, } from "./transfer.js";
11
+ import { MessageFormatter } from "../shared/messageFormatter.js";
12
+ import { ProgressManager } from "../shared/progressManager.js";
13
+ export class ImportController {
14
+ config;
15
+ database;
16
+ storage;
17
+ appwriteFolderPath;
18
+ importDataActions;
19
+ setupOptions;
20
+ documentCache;
21
+ batchLimit = 25; // Define batch size limit
22
+ hasImportedUsers = false;
23
+ postImportActionsQueue = [];
24
+ databasesToRun;
25
+ constructor(config, database, storage, appwriteFolderPath, importDataActions, setupOptions, databasesToRun) {
26
+ this.config = config;
27
+ this.database = database;
28
+ this.storage = storage;
29
+ this.appwriteFolderPath = appwriteFolderPath;
30
+ this.importDataActions = importDataActions;
31
+ this.setupOptions = setupOptions;
32
+ this.documentCache = new Map();
33
+ this.databasesToRun = databasesToRun || [];
34
+ }
35
+ async run(specificCollections) {
36
+ let databasesToProcess;
37
+ if (this.databasesToRun.length > 0) {
38
+ // Use the provided databases
39
+ databasesToProcess = this.databasesToRun;
40
+ }
41
+ else {
42
+ // If no databases are specified, fetch all databases
43
+ const allDatabases = await this.database.list();
44
+ databasesToProcess = allDatabases.databases;
45
+ }
46
+ let dataLoader;
47
+ let databaseRan;
48
+ for (let db of databasesToProcess) {
49
+ MessageFormatter.banner(`Starting import data for database: ${db.name}`, "Database Import");
50
+ if (!databaseRan) {
51
+ databaseRan = db;
52
+ dataLoader = new DataLoader(this.appwriteFolderPath, this.importDataActions, this.database, this.config, this.setupOptions.shouldWriteFile);
53
+ await dataLoader.setupMaps(db.$id);
54
+ await dataLoader.start(db.$id);
55
+ await this.importCollections(db, dataLoader, specificCollections);
56
+ await resolveAndUpdateRelationships(db.$id, this.database, this.config);
57
+ await this.executePostImportActions(db.$id, dataLoader, specificCollections);
58
+ }
59
+ else if (databaseRan.$id !== db.$id) {
60
+ await this.updateOthersToFinalData(databaseRan, db);
61
+ }
62
+ MessageFormatter.divider();
63
+ MessageFormatter.success(`Finished import data for database: ${db.name}`, { prefix: "Import" });
64
+ MessageFormatter.divider();
65
+ }
66
+ }
67
+ async updateOthersToFinalData(updatedDb, targetDb) {
68
+ if (this.database) {
69
+ await transferDatabaseLocalToLocal(this.database, updatedDb.$id, targetDb.$id);
70
+ }
71
+ if (this.storage) {
72
+ // Find the corresponding database configs
73
+ const updatedDbConfig = this.config.databases.find((db) => db.$id === updatedDb.$id);
74
+ const targetDbConfig = this.config.databases.find((db) => db.$id === targetDb.$id);
75
+ const allBuckets = await this.storage.listBuckets([Query.limit(1000)]);
76
+ const bucketsWithDbIdInThem = allBuckets.buckets.filter((bucket) => bucket.name.toLowerCase().includes(updatedDb.$id.toLowerCase()));
77
+ const configuredUpdatedBucketId = `${this.config.documentBucketId}_${updatedDb.$id.toLowerCase().trim().replace(" ", "")}`;
78
+ const configuredTargetBucketId = `${this.config.documentBucketId}_${targetDb.$id.toLowerCase().trim().replace(" ", "")}`;
79
+ let sourceBucketId;
80
+ let targetBucketId;
81
+ if (bucketsWithDbIdInThem.find((bucket) => bucket.$id === configuredUpdatedBucketId)) {
82
+ sourceBucketId = configuredUpdatedBucketId;
83
+ }
84
+ else if (bucketsWithDbIdInThem.find((bucket) => bucket.$id === configuredTargetBucketId)) {
85
+ targetBucketId = configuredTargetBucketId;
86
+ }
87
+ if (!sourceBucketId) {
88
+ sourceBucketId =
89
+ updatedDbConfig?.bucket?.$id || bucketsWithDbIdInThem[0]?.$id;
90
+ }
91
+ if (!targetBucketId) {
92
+ targetBucketId =
93
+ targetDbConfig?.bucket?.$id || bucketsWithDbIdInThem[0]?.$id;
94
+ }
95
+ if (sourceBucketId && targetBucketId) {
96
+ await transferStorageLocalToLocal(this.storage, sourceBucketId, targetBucketId);
97
+ }
98
+ }
99
+ }
100
+ async importCollections(db, dataLoader, specificCollections) {
101
+ const collectionsToImport = specificCollections ||
102
+ (this.config.collections
103
+ ? this.config.collections.map((c) => c.name)
104
+ : []);
105
+ for (const collection of this.config.collections || []) {
106
+ if (collectionsToImport.includes(collection.name)) {
107
+ let isUsersCollection = this.config.usersCollectionName &&
108
+ dataLoader.getCollectionKey(this.config.usersCollectionName) ===
109
+ dataLoader.getCollectionKey(collection.name);
110
+ const importOperationId = dataLoader.collectionImportOperations.get(dataLoader.getCollectionKey(collection.name));
111
+ const createBatches = (finalData) => {
112
+ let maxBatchLength = 50;
113
+ const finalBatches = [];
114
+ for (let i = 0; i < finalData.length; i++) {
115
+ if (i % maxBatchLength === 0) {
116
+ finalBatches.push([]);
117
+ }
118
+ finalBatches[finalBatches.length - 1].push(finalData[i]);
119
+ }
120
+ return finalBatches;
121
+ };
122
+ if (isUsersCollection && !this.hasImportedUsers) {
123
+ const usersDataMap = dataLoader.importMap.get(dataLoader.getCollectionKey("users"));
124
+ const usersData = usersDataMap?.data;
125
+ const usersController = new UsersController(this.config, this.database);
126
+ if (usersData) {
127
+ console.log("Found users data", usersData.length);
128
+ const userDataBatches = createBatches(usersData);
129
+ for (const batch of userDataBatches) {
130
+ console.log("Importing users batch", batch.length);
131
+ const userBatchPromises = batch
132
+ .filter((item) => {
133
+ let itemId;
134
+ if (item.finalData.userId) {
135
+ itemId = item.finalData.userId;
136
+ }
137
+ else if (item.finalData.docId) {
138
+ itemId = item.finalData.docId;
139
+ }
140
+ if (!itemId) {
141
+ return false;
142
+ }
143
+ return (item &&
144
+ item.finalData &&
145
+ !dataLoader.userExistsMap.has(itemId));
146
+ })
147
+ .map((item) => {
148
+ dataLoader.userExistsMap.set(item.finalData.userId ||
149
+ item.finalData.docId ||
150
+ item.context.userId ||
151
+ item.context.docId, true);
152
+ return usersController.createUserAndReturn(item.finalData);
153
+ });
154
+ const promiseResults = await Promise.allSettled(userBatchPromises);
155
+ for (const item of batch) {
156
+ if (item && item.finalData) {
157
+ dataLoader.userExistsMap.set(item.finalData.userId ||
158
+ item.finalData.docId ||
159
+ item.context.userId ||
160
+ item.context.docId, true);
161
+ }
162
+ }
163
+ MessageFormatter.success("Finished importing users batch", { prefix: "Import" });
164
+ }
165
+ this.hasImportedUsers = true;
166
+ MessageFormatter.success("Finished importing users", { prefix: "Import" });
167
+ }
168
+ }
169
+ if (!importOperationId) {
170
+ // Skip further processing if no import operation is found
171
+ continue;
172
+ }
173
+ let importOperation = null;
174
+ importOperation = await this.database.getDocument("migrations", "currentOperations", importOperationId);
175
+ const adapter = new LegacyAdapter(this.database.client);
176
+ await updateOperation(adapter, db.$id, importOperation.$id, {
177
+ status: "in_progress",
178
+ });
179
+ const collectionData = dataLoader.importMap.get(dataLoader.getCollectionKey(collection.name));
180
+ MessageFormatter.processing(`Processing collection: ${collection.name}...`, { prefix: "Import" });
181
+ if (!collectionData) {
182
+ MessageFormatter.warning(`No collection data for ${collection.name}`, { prefix: "Import" });
183
+ continue;
184
+ }
185
+ const dataSplit = createBatches(collectionData.data);
186
+ let processedItems = 0;
187
+ for (let i = 0; i < dataSplit.length; i++) {
188
+ const batches = dataSplit[i];
189
+ MessageFormatter.progress(`Processing batch ${i + 1} of ${dataSplit.length}`, { prefix: "Import" });
190
+ const batchPromises = batches.map((item, index) => {
191
+ try {
192
+ const id = item.finalData.docId ||
193
+ item.finalData.userId ||
194
+ item.context.docId ||
195
+ item.context.userId;
196
+ if (item.finalData.hasOwnProperty("userId")) {
197
+ delete item.finalData.userId;
198
+ }
199
+ if (item.finalData.hasOwnProperty("docId")) {
200
+ delete item.finalData.docId;
201
+ }
202
+ if (!item.finalData) {
203
+ return Promise.resolve();
204
+ }
205
+ return tryAwaitWithRetry(async () => await this.database.createDocument(db.$id, collection.$id, id, item.finalData));
206
+ }
207
+ catch (error) {
208
+ MessageFormatter.error("Error creating document", error instanceof Error ? error : new Error(String(error)), { prefix: "Import" });
209
+ return Promise.resolve();
210
+ }
211
+ });
212
+ // Wait for all promises in the current batch to resolve
213
+ await Promise.all(batchPromises);
214
+ MessageFormatter.success(`Completed batch ${i + 1} of ${dataSplit.length}`, { prefix: "Import" });
215
+ if (importOperation) {
216
+ const adapter = new LegacyAdapter(this.database.client);
217
+ await updateOperation(adapter, db.$id, importOperation.$id, {
218
+ progress: processedItems,
219
+ });
220
+ }
221
+ }
222
+ // After all batches are processed, update the operation status to completed
223
+ if (importOperation) {
224
+ const adapter = new LegacyAdapter(this.database.client);
225
+ await updateOperation(adapter, db.$id, importOperation.$id, {
226
+ status: "completed",
227
+ });
228
+ }
229
+ }
230
+ }
231
+ }
232
+ async executePostImportActions(dbId, dataLoader, specificCollections) {
233
+ MessageFormatter.info("Executing post-import actions...", { prefix: "Import" });
234
+ const collectionsToProcess = specificCollections && specificCollections.length > 0
235
+ ? specificCollections
236
+ : this.config.collections
237
+ ? this.config.collections.map((c) => c.name)
238
+ : Array.from(dataLoader.importMap.keys());
239
+ MessageFormatter.info(`Collections to process: ${collectionsToProcess.join(", ")}`, { prefix: "Import" });
240
+ // Iterate over each collection in the importMap
241
+ for (const [collectionKey, collectionData,] of dataLoader.importMap.entries()) {
242
+ const allCollectionKeys = collectionsToProcess.map((c) => dataLoader.getCollectionKey(c));
243
+ if (allCollectionKeys.includes(collectionKey)) {
244
+ MessageFormatter.processing(`Processing post-import actions for collection: ${collectionKey}`, { prefix: "Import" });
245
+ // Iterate over each item in the collectionData.data
246
+ for (const item of collectionData.data) {
247
+ // Assuming each item has attributeMappings that contain actions to be executed
248
+ if (item.importDef && item.importDef.attributeMappings) {
249
+ // Use item.context as the context for action execution
250
+ const context = item.context; // Directly use item.context as the context for action execution
251
+ // Iterate through attributeMappings to execute actions
252
+ try {
253
+ // Execute post-import actions for the current attributeMapping
254
+ // Pass item.finalData as the data to be processed along with the context
255
+ await this.importDataActions.executeAfterImportActions(item.finalData, item.importDef.attributeMappings, context);
256
+ }
257
+ catch (error) {
258
+ MessageFormatter.error(`Failed to execute post-import actions for item in collection ${collectionKey}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Import" });
259
+ }
260
+ }
261
+ }
262
+ }
263
+ else {
264
+ MessageFormatter.info(`Skipping collection: ${collectionKey} because it's not valid for post-import actions`, { prefix: "Import" });
265
+ }
266
+ }
267
+ }
268
+ }
@@ -0,0 +1,50 @@
1
+ import { type Databases, type Storage } from "node-appwrite";
2
+ import type { AppwriteConfig } from "@njdamstra/appwrite-utils";
3
+ import { type ValidationRules, type AttributeMappings } from "@njdamstra/appwrite-utils";
4
+ import { type ConverterFunctions } from "@njdamstra/appwrite-utils";
5
+ import { type AfterImportActions } from "@njdamstra/appwrite-utils";
6
+ export declare class ImportDataActions {
7
+ private db;
8
+ private storage;
9
+ private config;
10
+ private converterDefinitions;
11
+ private validityRuleDefinitions;
12
+ private afterImportActionsDefinitions;
13
+ constructor(db: Databases, storage: Storage, config: AppwriteConfig, converterDefinitions: ConverterFunctions, validityRuleDefinitions: ValidationRules, afterImportActionsDefinitions: AfterImportActions);
14
+ /**
15
+ * Runs converter functions on the item based on the provided attribute mappings.
16
+ *
17
+ * @param item - The item to be transformed.
18
+ * @param attributeMappings - The mappings that define how each attribute should be transformed.
19
+ * @returns The transformed item.
20
+ */
21
+ runConverterFunctions(item: any, attributeMappings: AttributeMappings): any;
22
+ /**
23
+ * Validates a single data item based on defined validation rules.
24
+ * @param item The data item to validate.
25
+ * @param attributeMap The attribute mappings for the data item.
26
+ * @param context The context for resolving templated parameters in validation rules.
27
+ * @returns A promise that resolves to true if the item is valid, false otherwise.
28
+ */
29
+ validateItem(item: any, attributeMap: AttributeMappings, context: {
30
+ [key: string]: any;
31
+ }): boolean;
32
+ executeAfterImportActions(item: any, attributeMap: AttributeMappings, context: {
33
+ [key: string]: any;
34
+ }): Promise<void>;
35
+ executeAction(actionName: string, params: any[], // Accepts any type, including objects
36
+ context: {
37
+ [key: string]: any;
38
+ }, item: any): Promise<void>;
39
+ /**
40
+ * Resolves a templated string or object using the provided context and current data item.
41
+ * If the template is a string that starts and ends with "{}", it replaces it with the corresponding value from item or context.
42
+ * If the template is an object, it recursively resolves its properties.
43
+ * @param template The templated string or object.
44
+ * @param context The context for resolving the template.
45
+ * @param item The current data item being processed.
46
+ */
47
+ resolveTemplate(template: any, context: {
48
+ [key: string]: any;
49
+ }, item: any): any;
50
+ }
@@ -0,0 +1,230 @@
1
+ import {} from "node-appwrite";
2
+ import { validationRules, } from "@njdamstra/appwrite-utils";
3
+ import { converterFunctions } from "@njdamstra/appwrite-utils";
4
+ import { convertObjectBySchema } from "../utils/dataConverters.js";
5
+ import {} from "@njdamstra/appwrite-utils";
6
+ import { afterImportActions } from "./afterImportActions.js";
7
+ import { logger } from "../shared/logging.js";
8
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
9
+ export class ImportDataActions {
10
+ db;
11
+ storage;
12
+ config;
13
+ converterDefinitions;
14
+ validityRuleDefinitions;
15
+ afterImportActionsDefinitions;
16
+ constructor(db, storage, config, converterDefinitions, validityRuleDefinitions, afterImportActionsDefinitions) {
17
+ this.db = db;
18
+ this.storage = storage;
19
+ this.config = config;
20
+ this.converterDefinitions = converterDefinitions;
21
+ this.validityRuleDefinitions = validityRuleDefinitions;
22
+ this.afterImportActionsDefinitions = afterImportActionsDefinitions;
23
+ }
24
+ /**
25
+ * Runs converter functions on the item based on the provided attribute mappings.
26
+ *
27
+ * @param item - The item to be transformed.
28
+ * @param attributeMappings - The mappings that define how each attribute should be transformed.
29
+ * @returns The transformed item.
30
+ */
31
+ runConverterFunctions(item, attributeMappings) {
32
+ const conversionSchema = attributeMappings.reduce((schema, mapping) => {
33
+ schema[mapping.targetKey] = (originalValue) => {
34
+ if (!mapping.converters) {
35
+ return originalValue;
36
+ }
37
+ return mapping.converters?.reduce((value, converterName) => {
38
+ let shouldProcessAsArray = false;
39
+ if ((converterName.includes("[Arr]") ||
40
+ converterName.includes("[arr]")) &&
41
+ Array.isArray(value)) {
42
+ shouldProcessAsArray = true;
43
+ converterName = converterName
44
+ .replace("[Arr]", "")
45
+ .replace("[arr]", "");
46
+ }
47
+ else if ((!Array.isArray(value) && converterName.includes("[Arr]")) ||
48
+ converterName.includes("[arr]")) {
49
+ converterName = converterName
50
+ .replace("[Arr]", "")
51
+ .replace("[arr]", "");
52
+ }
53
+ const converterFunction = converterFunctions[converterName];
54
+ if (converterFunction) {
55
+ if (Array.isArray(value) && !shouldProcessAsArray) {
56
+ return value.map((item) => converterFunction(item));
57
+ }
58
+ else {
59
+ return converterFunction(value);
60
+ }
61
+ }
62
+ else {
63
+ logger.warn(`Converter function '${converterName}' is not defined.`);
64
+ return value;
65
+ }
66
+ }, originalValue);
67
+ };
68
+ return schema;
69
+ }, {});
70
+ // Convert the item using the constructed schema
71
+ const convertedItem = convertObjectBySchema(item, conversionSchema);
72
+ // Merge the converted item back into the original item object
73
+ Object.assign(item, convertedItem);
74
+ return item;
75
+ }
76
+ /**
77
+ * Validates a single data item based on defined validation rules.
78
+ * @param item The data item to validate.
79
+ * @param attributeMap The attribute mappings for the data item.
80
+ * @param context The context for resolving templated parameters in validation rules.
81
+ * @returns A promise that resolves to true if the item is valid, false otherwise.
82
+ */
83
+ validateItem(item, attributeMap, context) {
84
+ for (const mapping of attributeMap) {
85
+ const { validationActions } = mapping;
86
+ if (!validationActions ||
87
+ !Array.isArray(validationActions) ||
88
+ !validationActions.length) {
89
+ return true; // Assume items without validation actions as valid.
90
+ }
91
+ for (const ruleDef of validationActions) {
92
+ const { action, params } = ruleDef;
93
+ const validationRule = validationRules[action];
94
+ if (!validationRule) {
95
+ logger.warn(`Validation rule '${action}' is not defined.`);
96
+ continue; // Optionally, consider undefined rules as a validation failure.
97
+ }
98
+ // Resolve templated parameters
99
+ const resolvedParams = params.map((param) => this.resolveTemplate(param, context, item));
100
+ // Apply the validation rule
101
+ let isValid = false;
102
+ if (Array.isArray(item)) {
103
+ isValid = item.every((item) => validationRule(item, ...resolvedParams));
104
+ }
105
+ else {
106
+ isValid = validationRule(item, ...resolvedParams);
107
+ }
108
+ if (!isValid) {
109
+ logger.error(`Validation failed for rule '${action}' with params ${params.join(", ")}`);
110
+ return false; // Stop validation on first failure
111
+ }
112
+ }
113
+ }
114
+ return true; // The item passed all validations
115
+ }
116
+ async executeAfterImportActions(item, attributeMap, context) {
117
+ for (const mapping of attributeMap) {
118
+ const { postImportActions } = mapping;
119
+ if (!postImportActions || !Array.isArray(postImportActions)) {
120
+ continue; // Skip to the next attribute if no actions are defined
121
+ }
122
+ for (const actionDef of postImportActions) {
123
+ const { action, params } = actionDef;
124
+ console.log(`Executing post-import action '${action}' for attribute '${mapping.targetKey}' with params ${params.join(", ")}...`);
125
+ try {
126
+ await tryAwaitWithRetry(async () => await this.executeAction(action, params, context, item));
127
+ }
128
+ catch (error) {
129
+ logger.error(`Failed to execute post-import action '${action}' for attribute '${mapping.targetKey}':`, error);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ async executeAction(actionName, params, // Accepts any type, including objects
135
+ context, item) {
136
+ const actionMethod = afterImportActions[actionName];
137
+ if (typeof actionMethod === "function") {
138
+ try {
139
+ // Resolve parameters, handling both strings and objects
140
+ const resolvedParams = params.map((param) => {
141
+ // Directly resolve each param, whether it's an object or a string
142
+ return this.resolveTemplate(param, context, item);
143
+ });
144
+ // Execute the action with resolved parameters
145
+ // Parameters are passed as-is, with objects treated as single parameters
146
+ console.log(`Executing action '${actionName}' from context with params:`, resolvedParams);
147
+ logger.info(`Executing action '${actionName}' from context: ${JSON.stringify(context, null, 2)} with params:`, resolvedParams);
148
+ await actionMethod(this.config, ...resolvedParams);
149
+ }
150
+ catch (error) {
151
+ logger.error(`Error executing action '${actionName}' with context:`, context, error);
152
+ throw new Error(`Execution failed for action '${actionName}': ${error.message}`);
153
+ }
154
+ }
155
+ else {
156
+ logger.warn(`Action '${actionName}' is not defined.`);
157
+ throw new Error(`Action '${actionName}' is not defined.`);
158
+ }
159
+ }
160
+ /**
161
+ * Resolves a templated string or object using the provided context and current data item.
162
+ * If the template is a string that starts and ends with "{}", it replaces it with the corresponding value from item or context.
163
+ * If the template is an object, it recursively resolves its properties.
164
+ * @param template The templated string or object.
165
+ * @param context The context for resolving the template.
166
+ * @param item The current data item being processed.
167
+ */
168
+ resolveTemplate(template, context, item) {
169
+ // Function to recursively resolve paths, including handling [any] notation
170
+ const resolvePath = (path, currentContext) => {
171
+ const anyKeyRegex = /\[any\]/g;
172
+ let pathParts = path.split(".").filter(Boolean);
173
+ return pathParts.reduce((acc, part, index) => {
174
+ // Handle [any] part by iterating over all elements if it's an object or an array
175
+ if (part === "[any]") {
176
+ if (Array.isArray(acc)) {
177
+ return acc
178
+ .map((item) => item[pathParts[index + 1]])
179
+ .filter((item) => item !== undefined);
180
+ }
181
+ else if (typeof acc === "object") {
182
+ return Object.values(acc)
183
+ .map((item) => item[pathParts[index + 1]])
184
+ .filter((item) => item !== undefined);
185
+ }
186
+ }
187
+ else {
188
+ return acc?.[part];
189
+ }
190
+ }, currentContext);
191
+ };
192
+ if (typeof template === "string") {
193
+ // Matches placeholders in the template
194
+ const regex = /\{([^}]+)\}/g;
195
+ let match;
196
+ let resolvedString = template;
197
+ while ((match = regex.exec(template)) !== null) {
198
+ const path = match[1];
199
+ // Resolve the path, handling [any] notation and arrays/objects
200
+ const resolvedValue = resolvePath(path, { ...context, ...item });
201
+ if (resolvedValue !== undefined) {
202
+ // If it's an array (from [any] notation), join the values; adjust as needed
203
+ const value = Array.isArray(resolvedValue)
204
+ ? resolvedValue.join(", ")
205
+ : resolvedValue;
206
+ resolvedString = resolvedString.replace(match[0], value);
207
+ }
208
+ else {
209
+ logger.warn(`Failed to resolve ${template} in context: `, JSON.stringify({ ...context, ...item }, null, 2));
210
+ }
211
+ }
212
+ // console.log(`Resolved string: ${resolvedString}`);
213
+ return resolvedString;
214
+ }
215
+ else if (typeof template === "object" && template !== null) {
216
+ // Recursively resolve templates for each property in the object
217
+ const resolvedObject = Array.isArray(template) ? [] : {};
218
+ for (const key in template) {
219
+ const resolvedValue = this.resolveTemplate(template[key], context, item);
220
+ if (resolvedValue !== undefined) {
221
+ // Only assign if resolvedValue is not undefined
222
+ resolvedObject[key] = resolvedValue;
223
+ }
224
+ }
225
+ return resolvedObject;
226
+ }
227
+ // console.log(`Template is not a string or object: ${template}`);
228
+ return template;
229
+ }
230
+ }
@@ -0,0 +1,29 @@
1
+ import { Databases } from "node-appwrite";
2
+ import type { AppwriteConfig } from "@njdamstra/appwrite-utils";
3
+ /**
4
+ * Finds collections that have defined relationship attributes.
5
+ */
6
+ export declare const findCollectionsWithRelationships: (config: AppwriteConfig) => Map<string, {
7
+ key: string;
8
+ required: boolean;
9
+ type: "relationship";
10
+ relatedCollection: string;
11
+ relationType: "oneToMany" | "manyToOne" | "oneToOne" | "manyToMany";
12
+ twoWay: boolean;
13
+ onDelete: "setNull" | "cascade" | "restrict";
14
+ array?: boolean | undefined;
15
+ format?: string | undefined;
16
+ status?: string | undefined;
17
+ attributes?: string[] | undefined;
18
+ orders?: string[] | undefined;
19
+ $createdAt?: string | undefined;
20
+ $updatedAt?: string | undefined;
21
+ error?: string | undefined;
22
+ twoWayKey?: string | undefined;
23
+ side?: "parent" | "child" | undefined;
24
+ importMapping?: {
25
+ originalIdField: string;
26
+ targetField?: string | undefined;
27
+ } | undefined;
28
+ }[]>;
29
+ export declare function resolveAndUpdateRelationships(dbId: string, database: Databases, config: AppwriteConfig): Promise<void>;