@deterministic-code/datasources 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (508) hide show
  1. package/dist/ArrayReader.d.ts +12 -0
  2. package/dist/BatchCommandIBulkWriteStrategy.d.ts +33 -0
  3. package/dist/BuiltRepository.d.ts +16 -0
  4. package/dist/BulkCRUDRepository.d.ts +17 -0
  5. package/dist/BulkCommand.d.ts +5 -0
  6. package/dist/BulkWriteEnrichment.d.ts +4 -0
  7. package/dist/CRUDRepository.d.ts +40 -0
  8. package/dist/CRUDRepositoryBuilder.d.ts +19 -0
  9. package/dist/CRUDRepositoryOptions.d.ts +7 -0
  10. package/dist/CRUDRepositoryStatements.d.ts +17 -0
  11. package/dist/CascadeDeleteEnrichmentStrategy.d.ts +7 -0
  12. package/dist/CascadeDeleteUpdateEnrichmentStrategy.d.ts +8 -0
  13. package/dist/CommandMiddlewareHost.d.ts +22 -0
  14. package/dist/ConsoleCommandMiddleware.d.ts +14 -0
  15. package/dist/CreateEnrichmentStrategy.d.ts +14 -0
  16. package/dist/Datasource.d.ts +30 -0
  17. package/dist/DatasourceError.d.ts +3 -0
  18. package/dist/DatasourceFactory.d.ts +12 -0
  19. package/dist/DatasourceOptions.d.ts +1 -0
  20. package/dist/DatasourceUrl.d.ts +12 -0
  21. package/dist/DatasourceUrlParser.d.ts +4 -0
  22. package/dist/DefaultCreateEnrichmentStrategy.d.ts +7 -0
  23. package/dist/DefaultReadonlyEnrichmentStrategy.d.ts +19 -0
  24. package/dist/DefaultUpdateEnrichmentStrategy.d.ts +7 -0
  25. package/dist/DefaultWriteEnrichmentStrategy.d.ts +21 -0
  26. package/dist/DeleteEnrichmentStrategy.d.ts +11 -0
  27. package/dist/DriverLoader.d.ts +5 -0
  28. package/dist/Enrichment.d.ts +13 -0
  29. package/dist/EnrichmentPropertyType.d.ts +7 -0
  30. package/dist/ExpectConsoleMiddleware.d.ts +15 -0
  31. package/dist/FirstResultReader.d.ts +19 -0
  32. package/dist/HashsetOptimizedReadonlyEnrichmentStrategy.d.ts +9 -0
  33. package/dist/IBulkWriteStrategy.d.ts +12 -0
  34. package/dist/ICRUDRepository.d.ts +12 -0
  35. package/dist/ICRUDRepositoryFactory.d.ts +7 -0
  36. package/dist/ICommand.d.ts +20 -0
  37. package/dist/ICommandMiddleware.d.ts +12 -0
  38. package/dist/IConnection.d.ts +12 -0
  39. package/dist/IDatasource.d.ts +18 -0
  40. package/dist/IDatasourceFactory.d.ts +5 -0
  41. package/dist/IDriver.d.ts +19 -0
  42. package/dist/IEnriched.d.ts +6 -0
  43. package/dist/IReader.d.ts +8 -0
  44. package/dist/IReadonlyEnrichmentStrategy.d.ts +7 -0
  45. package/dist/IReadonlyRepository.d.ts +11 -0
  46. package/dist/IRepository.d.ts +4 -0
  47. package/dist/IRepositoryFactory.d.ts +7 -0
  48. package/dist/IRepositoryTree.d.ts +4 -0
  49. package/dist/IRepositoryTreeNode.d.ts +7 -0
  50. package/dist/ITransaction.d.ts +8 -0
  51. package/dist/IUnitOfWork.d.ts +5 -0
  52. package/dist/IWriteEnrichmentStrategy.d.ts +7 -0
  53. package/dist/Information.d.ts +5 -0
  54. package/dist/IsolationLevel.d.ts +7 -0
  55. package/dist/LazyWriteEnrichmentStrategy.d.ts +4 -0
  56. package/dist/NestedToObjectEnrichmentStrategy.d.ts +10 -0
  57. package/dist/Parameter.d.ts +7 -0
  58. package/dist/ParameterDirection.d.ts +7 -0
  59. package/dist/ProviderCatalog.d.ts +7 -0
  60. package/dist/ProviderNotImplementedError.d.ts +4 -0
  61. package/dist/ProviderNotInstalledError.d.ts +4 -0
  62. package/dist/ReadonlyRepository.d.ts +59 -0
  63. package/dist/ReadonlyRepositoryBuilder.d.ts +12 -0
  64. package/dist/ReadonlyRepositoryMappingOptions.d.ts +14 -0
  65. package/dist/ReadonlyRepositoryStatements.d.ts +8 -0
  66. package/dist/RepositoryAccess.d.ts +11 -0
  67. package/dist/RepositoryFactory.d.ts +23 -0
  68. package/dist/RepositoryNotRegisteredError.d.ts +4 -0
  69. package/dist/RepositoryTree.d.ts +6 -0
  70. package/dist/RepositoryTreeNode.d.ts +9 -0
  71. package/dist/Response.d.ts +7 -0
  72. package/dist/Row.d.ts +2 -0
  73. package/dist/SingleCommandIBulkWriteStrategy.d.ts +11 -0
  74. package/dist/StatementMappers.d.ts +16 -0
  75. package/dist/StoredEnrichment.d.ts +11 -0
  76. package/dist/StoredProcedureBulkWriteStrategy.d.ts +27 -0
  77. package/dist/StreamingReader.d.ts +16 -0
  78. package/dist/UnitOfWorkTransaction.d.ts +12 -0
  79. package/dist/UpdateEnrichmentStrategy.d.ts +18 -0
  80. package/dist/WriteMode.d.ts +1 -0
  81. package/dist/builders/Field.d.ts +5 -0
  82. package/dist/builders/Scalar.d.ts +1 -0
  83. package/dist/builders/index.d.ts +2 -0
  84. package/dist/collectAsync.d.ts +1 -0
  85. package/dist/converters/Cell.d.ts +2 -0
  86. package/dist/converters/ChangeCasingConverter.d.ts +7 -0
  87. package/dist/converters/Constructable.d.ts +1 -0
  88. package/dist/converters/MetaDataRowTypeConverter.d.ts +14 -0
  89. package/dist/converters/PluralizerConverter.d.ts +4 -0
  90. package/dist/converters/RegexConverter.d.ts +7 -0
  91. package/dist/converters/ReplaceConverter.d.ts +7 -0
  92. package/dist/converters/RowTypeConverter.d.ts +10 -0
  93. package/dist/converters/ToLowerCaseConverter.d.ts +4 -0
  94. package/dist/converters/ToUpperCaseConverter.d.ts +4 -0
  95. package/dist/converters/TypeConverter.d.ts +5 -0
  96. package/dist/createCRUDRepositoryOptions.d.ts +7 -0
  97. package/dist/createReadonlyRepositoryMappingOptions.d.ts +6 -0
  98. package/dist/dotEnv.d.ts +5 -0
  99. package/dist/index.d.ts +119 -0
  100. package/dist/mappers/ChangeCasingMapper.d.ts +9 -0
  101. package/dist/mappers/DictionaryMapper.d.ts +8 -0
  102. package/dist/mappers/FlatToNestedMapper.d.ts +20 -0
  103. package/dist/mappers/IFlatToNestedMapper.d.ts +6 -0
  104. package/dist/mappers/IMapper.d.ts +4 -0
  105. package/dist/mappers/IdentityMapper.d.ts +5 -0
  106. package/dist/mappers/PluralizerMapper.d.ts +6 -0
  107. package/dist/mappers/RowTypeMapper.d.ts +6 -0
  108. package/dist/mappers/TransformConverterMapper.d.ts +5 -0
  109. package/dist/mappers/TransformMapper.d.ts +6 -0
  110. package/dist/mappers/TypeMap.d.ts +8 -0
  111. package/dist/mappers/TypeMapGroup.d.ts +5 -0
  112. package/dist/mocks/index.d.ts +9 -0
  113. package/dist/mocks/mock-command.d.ts +28 -0
  114. package/dist/mocks/mock-connection.d.ts +22 -0
  115. package/dist/mocks/mock-datasource.d.ts +24 -0
  116. package/dist/mocks/mock-driver.d.ts +15 -0
  117. package/dist/mocks/mock-reader.d.ts +14 -0
  118. package/dist/mocks/mock-repository.d.ts +42 -0
  119. package/dist/mocks/mock-select-statement.d.ts +10 -0
  120. package/dist/mocks/mock-transaction.d.ts +16 -0
  121. package/dist/mocks/mock-where.d.ts +8 -0
  122. package/dist/parametersToRecord.d.ts +2 -0
  123. package/dist/readerToAsyncIterable.d.ts +2 -0
  124. package/dist/splitStatements.d.ts +1 -0
  125. package/dist/statementParameters.d.ts +1 -0
  126. package/dist/statementUsesParameter.d.ts +1 -0
  127. package/dist/statements/Aggregate.d.ts +6 -0
  128. package/dist/statements/ArrayExpression.d.ts +5 -0
  129. package/dist/statements/BulkDeleteStatement.d.ts +11 -0
  130. package/dist/statements/BulkDeleteStatementTextRenderer.d.ts +4 -0
  131. package/dist/statements/BulkInsertStatement.d.ts +12 -0
  132. package/dist/statements/BulkInsertStatementTextRenderer.d.ts +4 -0
  133. package/dist/statements/BulkUpdateStatement.d.ts +16 -0
  134. package/dist/statements/BulkUpdateStatementTextRenderer.d.ts +8 -0
  135. package/dist/statements/CheckConstraint.d.ts +7 -0
  136. package/dist/statements/Cmp.d.ts +9 -0
  137. package/dist/statements/Column.d.ts +9 -0
  138. package/dist/statements/ColumnDefault.d.ts +5 -0
  139. package/dist/statements/Condition.d.ts +3 -0
  140. package/dist/statements/ConditionRenderer.d.ts +12 -0
  141. package/dist/statements/CreateIndexStatement.d.ts +10 -0
  142. package/dist/statements/CreateIndexStatementTextRenderer.d.ts +5 -0
  143. package/dist/statements/CreateTableStatement.d.ts +11 -0
  144. package/dist/statements/CreateTableStatementTextRenderer.d.ts +18 -0
  145. package/dist/statements/DefaultStatementTextRenderer.d.ts +5 -0
  146. package/dist/statements/DeleteStatement.d.ts +9 -0
  147. package/dist/statements/DeleteStatementTextRenderer.d.ts +7 -0
  148. package/dist/statements/ExecuteStoredProcedureStatement.d.ts +9 -0
  149. package/dist/statements/ExecuteStoredProcedureStatementTextRenderer.d.ts +4 -0
  150. package/dist/statements/ExpressionEvaluator.d.ts +5 -0
  151. package/dist/statements/ExpressionRenderer.d.ts +8 -0
  152. package/dist/statements/ForeignKey.d.ts +19 -0
  153. package/dist/statements/IBulkDeleteStatement.d.ts +3 -0
  154. package/dist/statements/IBulkInsertStatement.d.ts +3 -0
  155. package/dist/statements/IBulkUpdateStatement.d.ts +3 -0
  156. package/dist/statements/ICondition.d.ts +4 -0
  157. package/dist/statements/IConditionVisitor.d.ts +6 -0
  158. package/dist/statements/ICreateIndexStatement.d.ts +3 -0
  159. package/dist/statements/ICreateTableStatement.d.ts +3 -0
  160. package/dist/statements/IDeleteStatement.d.ts +5 -0
  161. package/dist/statements/IExecuteStoredProcedureStatement.d.ts +3 -0
  162. package/dist/statements/IExpression.d.ts +2 -0
  163. package/dist/statements/IInsertStatement.d.ts +3 -0
  164. package/dist/statements/IReturnStatement.d.ts +3 -0
  165. package/dist/statements/ISelectStatement.d.ts +5 -0
  166. package/dist/statements/IStatement.d.ts +4 -0
  167. package/dist/statements/IStatementVisitor.d.ts +26 -0
  168. package/dist/statements/ITableConstraint.d.ts +5 -0
  169. package/dist/statements/IUpdateStatement.d.ts +5 -0
  170. package/dist/statements/IWhere.d.ts +6 -0
  171. package/dist/statements/Identifier.d.ts +5 -0
  172. package/dist/statements/InsertStatement.d.ts +9 -0
  173. package/dist/statements/InsertStatementTextRenderer.d.ts +4 -0
  174. package/dist/statements/Join.d.ts +14 -0
  175. package/dist/statements/Literal.d.ts +6 -0
  176. package/dist/statements/Native.d.ts +5 -0
  177. package/dist/statements/NotNull.d.ts +4 -0
  178. package/dist/statements/Operator.d.ts +107 -0
  179. package/dist/statements/OrderBy.d.ts +10 -0
  180. package/dist/statements/PrimaryKey.d.ts +7 -0
  181. package/dist/statements/ReturnStatement.d.ts +9 -0
  182. package/dist/statements/ReturnStatementTextRenderer.d.ts +4 -0
  183. package/dist/statements/SelectInsertedIdStatement.d.ts +8 -0
  184. package/dist/statements/SelectInsertedIdStatementTextRenderer.d.ts +4 -0
  185. package/dist/statements/SelectStatement.d.ts +20 -0
  186. package/dist/statements/SelectStatementOptions.d.ts +15 -0
  187. package/dist/statements/SelectStatementTextRenderer.d.ts +19 -0
  188. package/dist/statements/StatementEvaluator.d.ts +4 -0
  189. package/dist/statements/StatementParser.d.ts +4 -0
  190. package/dist/statements/StatementRenderer.d.ts +42 -0
  191. package/dist/statements/StatementTextRenderer.d.ts +14 -0
  192. package/dist/statements/Subquery.d.ts +6 -0
  193. package/dist/statements/UniqueConstraint.d.ts +7 -0
  194. package/dist/statements/UpdateStatement.d.ts +14 -0
  195. package/dist/statements/UpdateStatementTextRenderer.d.ts +14 -0
  196. package/dist/statements/Where.d.ts +16 -0
  197. package/dist/statements/WhereText.d.ts +8 -0
  198. package/dist/statements/index.d.ts +75 -0
  199. package/dist/stubs/StubCommand.d.ts +15 -0
  200. package/dist/stubs/StubConnection.d.ts +13 -0
  201. package/dist/stubs/StubDatasource.d.ts +20 -0
  202. package/dist/stubs/StubReader.d.ts +11 -0
  203. package/dist/stubs/StubRepository.d.ts +22 -0
  204. package/dist/stubs/StubTransaction.d.ts +10 -0
  205. package/dist/stubs/createStubDatasource.d.ts +2 -0
  206. package/dist/stubs/index.d.ts +7 -0
  207. package/dist/stubs/notImplemented.d.ts +1 -0
  208. package/package.json +24 -4
  209. package/src/ArrayReader.test.ts +23 -0
  210. package/src/ArrayReader.ts +32 -0
  211. package/src/BatchCommandIBulkWriteStrategy.ts +228 -0
  212. package/src/BuiltRepository.ts +17 -0
  213. package/src/BulkCRUDRepository.test.ts +183 -0
  214. package/src/BulkCRUDRepository.ts +84 -0
  215. package/src/BulkCommand.ts +6 -0
  216. package/src/BulkWriteEnrichment.ts +19 -0
  217. package/src/BulkWriteStrategy.test.ts +293 -0
  218. package/src/CRUDRepository.test.ts +420 -0
  219. package/src/CRUDRepository.ts +264 -0
  220. package/src/CRUDRepositoryBuilder.ts +53 -0
  221. package/src/CRUDRepositoryOptions.test.ts +76 -0
  222. package/src/CRUDRepositoryOptions.ts +8 -0
  223. package/src/CRUDRepositoryStatements.ts +43 -0
  224. package/src/CascadeDeleteEnrichmentStrategy.ts +51 -0
  225. package/src/CascadeDeleteUpdateEnrichmentStrategy.ts +28 -0
  226. package/src/Command.test.ts +105 -0
  227. package/src/CommandMiddlewareHost.test.ts +98 -0
  228. package/src/CommandMiddlewareHost.ts +113 -0
  229. package/src/Connection.test.ts +34 -0
  230. package/src/ConsoleCommandMiddleware.test.ts +149 -0
  231. package/src/ConsoleCommandMiddleware.ts +64 -0
  232. package/src/CreateEnrichmentStrategy.ts +82 -0
  233. package/src/Datasource.test.ts +63 -0
  234. package/src/Datasource.ts +152 -0
  235. package/src/DatasourceError.test.ts +10 -0
  236. package/src/DatasourceError.ts +6 -0
  237. package/src/DatasourceFactory.test.ts +159 -0
  238. package/src/DatasourceFactory.ts +86 -0
  239. package/src/DatasourceOptions.ts +1 -0
  240. package/src/DatasourceUrl.ts +37 -0
  241. package/src/DatasourceUrlParser.test.ts +173 -0
  242. package/src/DatasourceUrlParser.ts +188 -0
  243. package/src/DefaultCreateEnrichmentStrategy.ts +21 -0
  244. package/src/DefaultReadonlyEnrichmentStrategy.ts +164 -0
  245. package/src/DefaultUpdateEnrichmentStrategy.ts +40 -0
  246. package/src/DefaultWriteEnrichmentStrategy.ts +151 -0
  247. package/src/DeleteEnrichmentStrategy.ts +56 -0
  248. package/src/DriverLoader.ts +97 -0
  249. package/src/Enrichment.ts +15 -0
  250. package/src/EnrichmentPropertyType.ts +9 -0
  251. package/src/ExpectConsoleMiddleware.test.ts +79 -0
  252. package/src/ExpectConsoleMiddleware.ts +47 -0
  253. package/src/FirstResultReader.test.ts +43 -0
  254. package/src/FirstResultReader.ts +49 -0
  255. package/src/HashsetOptimizedReadonlyEnrichmentStrategy.ts +80 -0
  256. package/src/IBulkWriteStrategy.ts +13 -0
  257. package/src/ICRUDRepository.ts +13 -0
  258. package/src/ICRUDRepositoryFactory.ts +8 -0
  259. package/src/ICommand.ts +45 -0
  260. package/src/ICommandMiddleware.ts +20 -0
  261. package/src/IConnection.ts +13 -0
  262. package/src/IDatasource.ts +27 -0
  263. package/src/IDatasourceFactory.ts +6 -0
  264. package/src/IDriver.ts +24 -0
  265. package/src/IEnriched.ts +11 -0
  266. package/src/IReader.ts +8 -0
  267. package/src/IReadonlyEnrichmentStrategy.ts +19 -0
  268. package/src/IReadonlyRepository.ts +21 -0
  269. package/src/IRepository.ts +5 -0
  270. package/src/IRepositoryFactory.ts +8 -0
  271. package/src/IRepositoryTree.ts +5 -0
  272. package/src/IRepositoryTreeNode.ts +8 -0
  273. package/src/ITransaction.ts +9 -0
  274. package/src/IUnitOfWork.ts +5 -0
  275. package/src/IWriteEnrichmentStrategy.ts +8 -0
  276. package/src/Information.ts +5 -0
  277. package/src/IsolationLevel.test.ts +13 -0
  278. package/src/IsolationLevel.ts +8 -0
  279. package/src/LazyWriteEnrichmentStrategy.ts +5 -0
  280. package/src/NestedToObjectEnrichmentStrategy.ts +33 -0
  281. package/src/Parameter.ts +8 -0
  282. package/src/ParameterDirection.ts +9 -0
  283. package/src/ProviderCatalog.test.ts +110 -0
  284. package/src/ProviderCatalog.ts +21 -0
  285. package/src/ProviderNotImplementedError.test.ts +11 -0
  286. package/src/ProviderNotImplementedError.ts +9 -0
  287. package/src/ProviderNotInstalledError.test.ts +11 -0
  288. package/src/ProviderNotInstalledError.ts +9 -0
  289. package/src/ReadonlyRepository.test.ts +406 -0
  290. package/src/ReadonlyRepository.ts +276 -0
  291. package/src/ReadonlyRepositoryBuilder.ts +53 -0
  292. package/src/ReadonlyRepositoryMappingOptions.ts +15 -0
  293. package/src/ReadonlyRepositoryStatements.ts +13 -0
  294. package/src/RepositoryAccess.ts +14 -0
  295. package/src/RepositoryFactory.test.ts +94 -0
  296. package/src/RepositoryFactory.ts +115 -0
  297. package/src/RepositoryNotRegisteredError.ts +9 -0
  298. package/src/RepositoryTree.ts +6 -0
  299. package/src/RepositoryTreeNode.ts +11 -0
  300. package/src/Response.ts +15 -0
  301. package/src/Row.ts +3 -0
  302. package/src/SingleCommandIBulkWriteStrategy.ts +35 -0
  303. package/src/StatementMappers.test.ts +221 -0
  304. package/src/StatementMappers.ts +110 -0
  305. package/src/StoredEnrichment.ts +25 -0
  306. package/src/StoredProcedureBulkWriteStrategy.ts +164 -0
  307. package/src/StreamingReader.test.ts +126 -0
  308. package/src/StreamingReader.ts +64 -0
  309. package/src/Transaction.test.ts +37 -0
  310. package/src/UnitOfWorkTransaction.test.ts +43 -0
  311. package/src/UnitOfWorkTransaction.ts +50 -0
  312. package/src/UpdateEnrichmentStrategy.ts +97 -0
  313. package/src/UserViewCRUDRepository.test.ts +323 -0
  314. package/src/WriteMode.ts +1 -0
  315. package/src/builders/Field.ts +6 -0
  316. package/src/builders/Scalar.ts +1 -0
  317. package/src/builders/builders.test.ts +404 -0
  318. package/src/builders/index.ts +2 -0
  319. package/src/collectAsync.ts +7 -0
  320. package/src/converters/Cell.ts +10 -0
  321. package/src/converters/ChangeCasingConverter.test.ts +34 -0
  322. package/src/converters/ChangeCasingConverter.ts +59 -0
  323. package/src/converters/Constructable.ts +1 -0
  324. package/src/converters/MetaDataRowTypeConverter.ts +80 -0
  325. package/src/converters/PluralizerConverter.test.ts +43 -0
  326. package/src/converters/PluralizerConverter.ts +67 -0
  327. package/src/converters/RegexConverter.test.ts +11 -0
  328. package/src/converters/RegexConverter.ts +14 -0
  329. package/src/converters/ReplaceConverter.test.ts +9 -0
  330. package/src/converters/ReplaceConverter.ts +6 -0
  331. package/src/converters/RowTypeConverter.test.ts +79 -0
  332. package/src/converters/RowTypeConverter.ts +33 -0
  333. package/src/converters/ToLowerCaseConverter.test.ts +9 -0
  334. package/src/converters/ToLowerCaseConverter.ts +4 -0
  335. package/src/converters/ToUpperCaseConverter.test.ts +9 -0
  336. package/src/converters/ToUpperCaseConverter.ts +4 -0
  337. package/src/converters/TypeConverter.ts +6 -0
  338. package/src/createCRUDRepositoryOptions.ts +21 -0
  339. package/src/createReadonlyRepositoryMappingOptions.ts +26 -0
  340. package/src/dotEnv.test.ts +21 -0
  341. package/src/dotEnv.ts +16 -0
  342. package/src/edgeCases.test.ts +485 -0
  343. package/src/index.ts +222 -0
  344. package/src/mappers/ChangeCasingMapper.test.ts +32 -0
  345. package/src/mappers/ChangeCasingMapper.ts +15 -0
  346. package/src/mappers/DictionaryMapper.test.ts +69 -0
  347. package/src/mappers/DictionaryMapper.ts +16 -0
  348. package/src/mappers/FlatToNestedMapper.test.ts +269 -0
  349. package/src/mappers/FlatToNestedMapper.ts +127 -0
  350. package/src/mappers/IFlatToNestedMapper.ts +7 -0
  351. package/src/mappers/IMapper.ts +4 -0
  352. package/src/mappers/IdentityMapper.test.ts +12 -0
  353. package/src/mappers/IdentityMapper.ts +6 -0
  354. package/src/mappers/PluralizerMapper.test.ts +40 -0
  355. package/src/mappers/PluralizerMapper.ts +9 -0
  356. package/src/mappers/RowTypeMapper.test.ts +12 -0
  357. package/src/mappers/RowTypeMapper.ts +13 -0
  358. package/src/mappers/TransformConverterMapper.test.ts +181 -0
  359. package/src/mappers/TransformConverterMapper.ts +11 -0
  360. package/src/mappers/TransformMapper.ts +8 -0
  361. package/src/mappers/TypeMap.ts +10 -0
  362. package/src/mappers/TypeMapGroup.ts +6 -0
  363. package/src/mappers/transformMapper.test.ts +66 -0
  364. package/src/mocks/MockCommand.test.ts +75 -0
  365. package/src/mocks/MockConnection.test.ts +34 -0
  366. package/src/mocks/MockDatasource.test.ts +40 -0
  367. package/src/mocks/MockReader.test.ts +17 -0
  368. package/src/mocks/MockRepository.test.ts +32 -0
  369. package/src/mocks/MockSelectStatement.test.ts +11 -0
  370. package/src/mocks/MockTransaction.test.ts +17 -0
  371. package/src/mocks/MockWhere.test.ts +11 -0
  372. package/src/mocks/index.ts +9 -0
  373. package/src/mocks/mock-command.ts +66 -0
  374. package/src/mocks/mock-connection.ts +57 -0
  375. package/src/mocks/mock-datasource.ts +65 -0
  376. package/src/mocks/mock-driver.ts +27 -0
  377. package/src/mocks/mock-reader.ts +38 -0
  378. package/src/mocks/mock-repository.ts +91 -0
  379. package/src/mocks/mock-select-statement.ts +17 -0
  380. package/src/mocks/mock-transaction.ts +31 -0
  381. package/src/mocks/mock-where.ts +13 -0
  382. package/src/parametersToRecord.test.ts +19 -0
  383. package/src/parametersToRecord.ts +11 -0
  384. package/src/public-surface.test.ts +23 -0
  385. package/src/readWithWhereClauseAndCustomFlatToNestedObjectMappingOptions.test.ts +126 -0
  386. package/src/readerToAsyncIterable.test.ts +39 -0
  387. package/src/readerToAsyncIterable.ts +11 -0
  388. package/src/repository.test.ts +410 -0
  389. package/src/repository.type.test.ts +29 -0
  390. package/src/splitStatements.ts +99 -0
  391. package/src/statementParameters.ts +22 -0
  392. package/src/statementUsesParameter.ts +4 -0
  393. package/src/statements/Aggregate.ts +9 -0
  394. package/src/statements/ArrayExpression.ts +5 -0
  395. package/src/statements/BulkDeleteStatement.ts +18 -0
  396. package/src/statements/BulkDeleteStatementTextRenderer.ts +16 -0
  397. package/src/statements/BulkInsertStatement.ts +37 -0
  398. package/src/statements/BulkInsertStatementTextRenderer.ts +10 -0
  399. package/src/statements/BulkUpdateStatement.ts +24 -0
  400. package/src/statements/BulkUpdateStatementTextRenderer.ts +29 -0
  401. package/src/statements/CheckConstraint.ts +9 -0
  402. package/src/statements/Cmp.ts +12 -0
  403. package/src/statements/Column.ts +10 -0
  404. package/src/statements/ColumnDefault.ts +6 -0
  405. package/src/statements/Condition.ts +3 -0
  406. package/src/statements/ConditionRenderer.ts +17 -0
  407. package/src/statements/CreateIndexStatement.ts +18 -0
  408. package/src/statements/CreateIndexStatementTextRenderer.ts +11 -0
  409. package/src/statements/CreateTableStatement.ts +18 -0
  410. package/src/statements/CreateTableStatementTextRenderer.ts +92 -0
  411. package/src/statements/DefaultStatementTextRenderer.ts +9 -0
  412. package/src/statements/DeleteStatement.ts +15 -0
  413. package/src/statements/DeleteStatementTextRenderer.ts +12 -0
  414. package/src/statements/ExecuteStoredProcedureStatement.ts +15 -0
  415. package/src/statements/ExecuteStoredProcedureStatementTextRenderer.ts +15 -0
  416. package/src/statements/ExpressionEvaluator.ts +166 -0
  417. package/src/statements/ExpressionRenderer.ts +161 -0
  418. package/src/statements/ForeignKey.ts +23 -0
  419. package/src/statements/IBulkDeleteStatement.ts +3 -0
  420. package/src/statements/IBulkInsertStatement.ts +3 -0
  421. package/src/statements/IBulkUpdateStatement.ts +3 -0
  422. package/src/statements/ICondition.ts +5 -0
  423. package/src/statements/IConditionVisitor.ts +7 -0
  424. package/src/statements/ICreateIndexStatement.ts +3 -0
  425. package/src/statements/ICreateTableStatement.ts +3 -0
  426. package/src/statements/IDeleteStatement.ts +6 -0
  427. package/src/statements/IExecuteStoredProcedureStatement.ts +3 -0
  428. package/src/statements/IExpression.ts +1 -0
  429. package/src/statements/IInsertStatement.ts +3 -0
  430. package/src/statements/IReturnStatement.ts +3 -0
  431. package/src/statements/ISelectStatement.ts +6 -0
  432. package/src/statements/IStatement.ts +5 -0
  433. package/src/statements/IStatementVisitor.ts +27 -0
  434. package/src/statements/ITableConstraint.ts +6 -0
  435. package/src/statements/IUpdateStatement.ts +6 -0
  436. package/src/statements/IWhere.ts +7 -0
  437. package/src/statements/Identifier.ts +5 -0
  438. package/src/statements/InsertStatement.ts +15 -0
  439. package/src/statements/InsertStatementTextRenderer.ts +7 -0
  440. package/src/statements/Join.ts +26 -0
  441. package/src/statements/Literal.ts +6 -0
  442. package/src/statements/Native.ts +5 -0
  443. package/src/statements/NotNull.ts +3 -0
  444. package/src/statements/Operator.ts +234 -0
  445. package/src/statements/OrderBy.ts +19 -0
  446. package/src/statements/PrimaryKey.ts +9 -0
  447. package/src/statements/ReturnStatement.ts +15 -0
  448. package/src/statements/ReturnStatementTextRenderer.ts +15 -0
  449. package/src/statements/SelectInsertedIdStatement.test.ts +11 -0
  450. package/src/statements/SelectInsertedIdStatement.ts +11 -0
  451. package/src/statements/SelectInsertedIdStatementTextRenderer.ts +7 -0
  452. package/src/statements/SelectStatement.ts +34 -0
  453. package/src/statements/SelectStatementOptions.ts +16 -0
  454. package/src/statements/SelectStatementTextRenderer.ts +71 -0
  455. package/src/statements/StatementCompile.test.ts +231 -0
  456. package/src/statements/StatementEvaluator.ts +5 -0
  457. package/src/statements/StatementParser.test.ts +304 -0
  458. package/src/statements/StatementParser.ts +461 -0
  459. package/src/statements/StatementRenderer.ts +120 -0
  460. package/src/statements/StatementTextRenderer.ts +60 -0
  461. package/src/statements/Subquery.ts +6 -0
  462. package/src/statements/UniqueConstraint.ts +9 -0
  463. package/src/statements/UpdateStatement.ts +34 -0
  464. package/src/statements/UpdateStatementTextRenderer.ts +63 -0
  465. package/src/statements/Where.ts +250 -0
  466. package/src/statements/WhereText.ts +10 -0
  467. package/src/statements/index.ts +75 -0
  468. package/src/stubs/StubCommand.ts +30 -0
  469. package/src/stubs/StubConnection.ts +21 -0
  470. package/src/stubs/StubDatasource.test.ts +99 -0
  471. package/src/stubs/StubDatasource.ts +60 -0
  472. package/src/stubs/StubReader.ts +25 -0
  473. package/src/stubs/StubRepository.ts +42 -0
  474. package/src/stubs/StubTransaction.ts +17 -0
  475. package/src/stubs/createStubDatasource.ts +4 -0
  476. package/src/stubs/index.ts +7 -0
  477. package/src/stubs/notImplemented.ts +5 -0
  478. package/src/tests/contact/Address.ts +14 -0
  479. package/src/tests/contact/AddressType.ts +6 -0
  480. package/src/tests/contact/Base.ts +7 -0
  481. package/src/tests/contact/Contact.ts +12 -0
  482. package/src/tests/contact/ContactBase.ts +8 -0
  483. package/src/tests/contact/ContactChangeLog.ts +8 -0
  484. package/src/tests/contact/ContactGroup.ts +6 -0
  485. package/src/tests/contact/ContactGroupBase.ts +6 -0
  486. package/src/tests/contact/ContactGroupMember.ts +6 -0
  487. package/src/tests/contact/ContactSource.ts +6 -0
  488. package/src/tests/contact/ContactType.ts +6 -0
  489. package/src/tests/contact/ContactsService.test.ts +118 -0
  490. package/src/tests/contact/ContactsService.ts +32 -0
  491. package/src/tests/contact/ImportContactRequest.ts +4 -0
  492. package/src/tests/contact/ImportContactResult.ts +5 -0
  493. package/src/tests/contact/LegacyContact.ts +7 -0
  494. package/src/tests/contact/LegacyMigrationResult.ts +5 -0
  495. package/src/tests/contact/Phone.ts +9 -0
  496. package/src/tests/contact/PhoneType.ts +6 -0
  497. package/src/tests/contact/asContactsView.ts +63 -0
  498. package/src/tests/contact/contactColumns.ts +40 -0
  499. package/src/tests/contact/contactLookupIds.ts +32 -0
  500. package/src/tests/contact/contactLookups.ts +6 -0
  501. package/src/tests/contact/contactsParity.ts +63 -0
  502. package/src/tests/contact/contactsServiceOf.ts +38 -0
  503. package/src/tests/contact/contactsView.ts +31 -0
  504. package/src/tests/contact/expectContactsView.ts +23 -0
  505. package/src/tests/contact/extraContact.ts +61 -0
  506. package/src/tests/contact/logMapped.ts +5 -0
  507. package/src/tests/contact/seedContacts.ts +31 -0
  508. package/README.md +0 -3
@@ -0,0 +1,164 @@
1
+ import type { Scalar } from "./builders/Scalar.ts";
2
+ import { DatasourceError } from "./DatasourceError.ts";
3
+ import type { Enrichment } from "./Enrichment.ts";
4
+ import { EnrichmentPropertyType } from "./EnrichmentPropertyType.ts";
5
+ import type { IReadonlyEnrichmentStrategy } from "./IReadonlyEnrichmentStrategy.ts";
6
+ import type { IReadonlyRepository } from "./IReadonlyRepository.ts";
7
+ import type { Row } from "./Row.ts";
8
+ import { Operator, Where } from "./statements/index.ts";
9
+
10
+ type Props = Record<string, Scalar | object>;
11
+
12
+ export class DefaultReadonlyEnrichmentStrategy<T extends object>
13
+ implements IReadonlyEnrichmentStrategy<T>
14
+ {
15
+ apply<TRelated extends object>(
16
+ via: IReadonlyRepository<TRelated>,
17
+ enrichment: Enrichment,
18
+ parents: T[],
19
+ sources?: (Row | undefined)[],
20
+ ): Promise<void> {
21
+ const type = enrichment.type ?? EnrichmentPropertyType.Object;
22
+ const run = {
23
+ [EnrichmentPropertyType.List]: () => this.applyList(via, enrichment, parents, sources),
24
+ [EnrichmentPropertyType.Object]: () => this.applyObject(via, enrichment, parents, sources),
25
+ [EnrichmentPropertyType.Dictionary]: () => this.applyDictionary(via, enrichment, parents, sources),
26
+ }[type];
27
+ return run ? run() : Promise.reject(new DatasourceError(`Unsupported enrichment type "${type}"`));
28
+ }
29
+
30
+ async applyLinked<TRelated extends object, TLink extends object>(
31
+ via: IReadonlyRepository<TRelated>,
32
+ link: IReadonlyRepository<TLink>,
33
+ enrichment: Enrichment,
34
+ parents: T[],
35
+ sources?: (Row | undefined)[],
36
+ ): Promise<void> {
37
+ const association = enrichment.association ?? (() => {
38
+ throw new DatasourceError("Missing association");
39
+ })();
40
+ for (const [index, parent] of parents.entries()) {
41
+ const key = this.sourceKey(parent, enrichment.sourceProperty, sources, index);
42
+ if (key === undefined || key === null) continue;
43
+ const related: TRelated[] = [];
44
+ for await (const row of link.read(
45
+ new Where(new Operator.Equals(association.parent, this.scalar(key))),
46
+ )) {
47
+ const id = this.props(row)[association.related];
48
+ if (id === undefined || id === null || typeof id === "object") continue;
49
+ const entity = await via.readSingle(new Where(new Operator.Equals(enrichment.relatedKey, id)));
50
+ if (entity) related.push(entity);
51
+ }
52
+ Object.assign(parent, { [enrichment.destinationProperty]: related });
53
+ }
54
+ }
55
+
56
+ protected async applyObject<TRelated extends object>(
57
+ via: IReadonlyRepository<TRelated>,
58
+ enrichment: Enrichment,
59
+ parents: T[],
60
+ sources?: (Row | undefined)[],
61
+ ): Promise<void> {
62
+ const cache = new Map<string, TRelated | undefined>();
63
+ for (const [index, parent] of parents.entries()) {
64
+ const key = this.sourceKey(parent, enrichment.sourceProperty, sources, index);
65
+ if (key === undefined || key === null) continue;
66
+ const cacheKey = this.keyOf(key);
67
+ if (!cache.has(cacheKey))
68
+ cache.set(
69
+ cacheKey,
70
+ await via.readSingle(new Where(new Operator.Equals(enrichment.relatedKey, this.scalar(key)))),
71
+ );
72
+ const related = cache.get(cacheKey);
73
+ if (!related) continue;
74
+ Object.assign(parent, {
75
+ [enrichment.destinationProperty]: enrichment.relatedProperty ? this.props(related)[enrichment.relatedProperty] : related,
76
+ });
77
+ }
78
+ }
79
+
80
+ protected async applyList<TRelated extends object>(
81
+ via: IReadonlyRepository<TRelated>,
82
+ enrichment: Enrichment,
83
+ parents: T[],
84
+ sources?: (Row | undefined)[],
85
+ ): Promise<void> {
86
+ for (const [index, parent] of parents.entries()) {
87
+ const key = this.sourceKey(parent, enrichment.sourceProperty, sources, index);
88
+ if (key === undefined || key === null) continue;
89
+ const related: TRelated[] = [];
90
+ for await (const item of via.read(
91
+ new Where(new Operator.Equals(enrichment.relatedKey, this.scalar(key))),
92
+ ))
93
+ related.push(item);
94
+ Object.assign(parent, { [enrichment.destinationProperty]: related });
95
+ }
96
+ }
97
+
98
+ protected async applyDictionary<TRelated extends object>(
99
+ via: IReadonlyRepository<TRelated>,
100
+ enrichment: Enrichment,
101
+ parents: T[],
102
+ sources?: (Row | undefined)[],
103
+ ): Promise<void> {
104
+ const mapKey = mapKeyName(enrichment.relatedKey);
105
+ for (const [index, parent] of parents.entries()) {
106
+ const key = this.sourceKey(parent, enrichment.sourceProperty, sources, index);
107
+ if (key === undefined || key === null) continue;
108
+ const map: Record<string, Scalar | object> = {};
109
+ for await (const item of via.read(
110
+ new Where(new Operator.Equals(enrichment.relatedKey, this.scalar(key))),
111
+ )) {
112
+ const row = this.props(item);
113
+ const entry = row[mapKey];
114
+ if (entry === undefined || entry === null || typeof entry === "object") continue;
115
+ map[String(entry)] = enrichment.relatedProperty
116
+ ? (row[enrichment.relatedProperty] ?? null)
117
+ : Object.fromEntries(
118
+ Object.entries(row).filter(
119
+ ([name]) => name !== mapKey && name !== enrichment.relatedKey && name !== "Id" && name !== "id",
120
+ ),
121
+ );
122
+ }
123
+ Object.assign(parent, { [enrichment.destinationProperty]: map });
124
+ }
125
+ }
126
+
127
+ protected sourceKey(
128
+ parent: T,
129
+ name: string,
130
+ sources: (Row | undefined)[] | undefined,
131
+ index: number,
132
+ ): Scalar | object | undefined {
133
+ const cell = sources?.[index]?.[name];
134
+ const raw = cell !== undefined && cell !== null ? cell : this.props(parent)[name];
135
+ return this.lookupKey(raw);
136
+ }
137
+
138
+ protected props = <TItem>(item: TItem): Props => item as never as Props;
139
+
140
+ protected keyOf = (key: Scalar | object): string => String(this.lookupKey(key));
141
+
142
+ protected lookupKey = (value: Scalar | object | undefined): Scalar | object | undefined => {
143
+ if (value === undefined || value === null || typeof value !== "object") return value;
144
+ const id = this.props(value).Id ?? this.props(value).id;
145
+ return id !== undefined && id !== null && typeof id !== "object" ? id : value;
146
+ };
147
+
148
+ protected scalar = (value: Scalar | object): Scalar => {
149
+ const key = this.lookupKey(value);
150
+ return key === null ||
151
+ typeof key === "string" ||
152
+ typeof key === "number" ||
153
+ typeof key === "boolean" ||
154
+ typeof key === "bigint"
155
+ ? key
156
+ : (() => {
157
+ throw new DatasourceError("Enrichment key must be a scalar");
158
+ })();
159
+ };
160
+ }
161
+
162
+ const mapKeyName = (relatedKey: string): string =>
163
+ relatedKey.includes("_") || relatedKey[0] !== relatedKey[0]?.toUpperCase() ? "key" : "Key";
164
+
@@ -0,0 +1,40 @@
1
+ import { DatasourceError } from "./DatasourceError.ts";
2
+ import { DeleteEnrichmentStrategy } from "./DeleteEnrichmentStrategy.ts";
3
+ import type { Enrichment } from "./Enrichment.ts";
4
+ import type { ICRUDRepository } from "./ICRUDRepository.ts";
5
+ import { UpdateEnrichmentStrategy } from "./UpdateEnrichmentStrategy.ts";
6
+
7
+ export class DefaultUpdateEnrichmentStrategy<T> extends UpdateEnrichmentStrategy<T> {
8
+ async updateChildren<TChild extends object>(writer: ICRUDRepository<TChild>, enrichment: Enrichment, parent: T): Promise<void> {
9
+ const existing = await DeleteEnrichmentStrategy.load(writer, enrichment, parent);
10
+ const rows = this.payloadOf<TChild, T>(parent, enrichment.destinationProperty, enrichment);
11
+ for (const related of rows) this.stampCell(related, enrichment.relatedKey, this.getCell(parent, enrichment.sourceProperty));
12
+ const keys = this.namesOf(writer, rows[0] ?? existing[0] ?? {} as TChild);
13
+ const keep = new Set(rows.filter((row) => this.hasKey(row, keys)).map((row) => this.keyOf(row, keys)));
14
+ for (const row of existing.filter((row) => !keep.has(this.keyOf(row, keys))))
15
+ await writer.delete(row, DeleteEnrichmentStrategy.childrenWhere(writer, enrichment, parent));
16
+ for (const related of rows)
17
+ this.hasKey(related, keys) && existing.some((row) => this.keyOf(row, keys) === this.keyOf(related, keys))
18
+ ? await writer.update(related)
19
+ : await writer.create(related);
20
+ }
21
+
22
+ async updateLinked<TChild extends object>(writer: ICRUDRepository<TChild>, enrichment: Enrichment, parent: T): Promise<void> {
23
+ const association = enrichment.association;
24
+ if (!association) throw new DatasourceError("Missing association");
25
+ const parentKey = this.requiredKey(parent, enrichment);
26
+ const existing = await DeleteEnrichmentStrategy.loadLinks(writer, association.parent, parentKey);
27
+ const wanted = this.relatedIds(parent, enrichment);
28
+ const keep = new Set(wanted.map((id) => String(id)));
29
+ for (const row of existing) {
30
+ const id = this.getCell(row, association.related);
31
+ if (this.presentCell(id) && keep.has(String(id))) continue;
32
+ if (!this.presentCell(id)) continue;
33
+ await writer.delete(row, this.linkWhere(association, parentKey, id));
34
+ }
35
+ for (const id of wanted) {
36
+ if (existing.some((row) => String(this.getCell(row, association.related) ?? "") === String(id))) continue;
37
+ await writer.create({ [association.parent]: parentKey, [association.related]: id } as TChild);
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,151 @@
1
+ import { CascadeDeleteEnrichmentStrategy } from "./CascadeDeleteEnrichmentStrategy.ts";
2
+ import type { CreateEnrichmentStrategy } from "./CreateEnrichmentStrategy.ts";
3
+ import { DatasourceError } from "./DatasourceError.ts";
4
+ import { DefaultCreateEnrichmentStrategy } from "./DefaultCreateEnrichmentStrategy.ts";
5
+ import { EnrichmentPropertyType } from "./EnrichmentPropertyType.ts";
6
+ import { DefaultUpdateEnrichmentStrategy } from "./DefaultUpdateEnrichmentStrategy.ts";
7
+ import type { ICRUDRepository } from "./ICRUDRepository.ts";
8
+ import { enrichmentsOf } from "./ReadonlyRepository.ts";
9
+ import type { IRepositoryTree } from "./IRepositoryTree.ts";
10
+ import type { IWriteEnrichmentStrategy } from "./IWriteEnrichmentStrategy.ts";
11
+ import type { StoredEnrichment } from "./StoredEnrichment.ts";
12
+ import type { Scalar } from "./builders/Scalar.ts";
13
+ import type { DeleteEnrichmentStrategy } from "./DeleteEnrichmentStrategy.ts";
14
+ import type { UpdateEnrichmentStrategy } from "./UpdateEnrichmentStrategy.ts";
15
+ import type { WriteMode } from "./WriteMode.ts";
16
+
17
+ const unloaded = <TParent>(parent: TParent, into: string): boolean => {
18
+ const value = (parent as never as Record<string, Scalar | object>)[into];
19
+ return value === undefined || value === null;
20
+ };
21
+
22
+ const childWriter = (entry: StoredEnrichment, into: string): ICRUDRepository<object> => {
23
+ if (entry.persist) return entry.persist;
24
+ throw new DatasourceError(`Deep write requires a CRUD repository for "${into}"`);
25
+ };
26
+
27
+ const linkWriter = (entry: StoredEnrichment, into: string): ICRUDRepository<object> => {
28
+ if (entry.link) return entry.link;
29
+ throw new DatasourceError(`Deep write requires a CRUD repository for "${into}"`);
30
+ };
31
+
32
+ const dispatch = (mode: string, runs: Record<WriteMode, () => Promise<void>>): Promise<void> =>
33
+ (runs[mode as WriteMode] ??
34
+ (() => {
35
+ throw new DatasourceError("Unknown persist mode");
36
+ }))();
37
+
38
+ export class DefaultWriteEnrichmentStrategy<T> implements IWriteEnrichmentStrategy<T> {
39
+ protected skipUnloaded = false;
40
+ readonly useTransaction: boolean;
41
+ private readonly createStrategy: CreateEnrichmentStrategy<T>;
42
+ private readonly deleteStrategy: DeleteEnrichmentStrategy<T>;
43
+ private readonly updateStrategy: UpdateEnrichmentStrategy<T>;
44
+
45
+ constructor(
46
+ deleteStrategy: DeleteEnrichmentStrategy<T> = new CascadeDeleteEnrichmentStrategy<T>(),
47
+ updateStrategy: UpdateEnrichmentStrategy<T> = new DefaultUpdateEnrichmentStrategy<T>(),
48
+ createStrategy: CreateEnrichmentStrategy<T> = new DefaultCreateEnrichmentStrategy<T>(),
49
+ useTransaction = false,
50
+ ) {
51
+ this.deleteStrategy = deleteStrategy;
52
+ this.updateStrategy = updateStrategy;
53
+ this.createStrategy = createStrategy;
54
+ this.useTransaction = useTransaction;
55
+ }
56
+
57
+ persist = async (tree: IRepositoryTree, items: T[], mode: WriteMode): Promise<void> => {
58
+ await this.walk(tree.parent.value, items, mode);
59
+ };
60
+
61
+ persistBulk = async (tree: IRepositoryTree, items: T[], mode: WriteMode): Promise<void> => {
62
+ if (mode === "delete") return this.persist(tree, items, mode);
63
+ await this.walkBulk(tree.parent.value, items, mode);
64
+ };
65
+
66
+ private walk = async (host: object, parents: T[], mode: WriteMode): Promise<void> => {
67
+ const entries = enrichmentsOf(host);
68
+ if (!entries) return;
69
+ for (const entry of entries) await this.persistEntry(entry, parents, mode);
70
+ };
71
+
72
+ private walkBulk = async (host: object, parents: T[], mode: WriteMode): Promise<void> => {
73
+ const entries = enrichmentsOf(host);
74
+ if (!entries) return;
75
+ for (const entry of entries) await this.persistEntryBulk(entry, parents, mode);
76
+ };
77
+
78
+ private persistEntryBulk = async (
79
+ entry: StoredEnrichment,
80
+ parents: T[],
81
+ mode: WriteMode,
82
+ ): Promise<void> => {
83
+ const enrichment = entry.enrichment;
84
+ const type = enrichment.type ?? EnrichmentPropertyType.Object;
85
+ if (type === EnrichmentPropertyType.Custom)
86
+ throw new DatasourceError(`Unsupported enrichment type "${type}"`);
87
+ if (enrichment.association) {
88
+ const writer = linkWriter(entry, enrichment.destinationProperty);
89
+ for (const parent of parents) {
90
+ if (this.skip(parent, enrichment.destinationProperty, mode)) continue;
91
+ await dispatch(mode, {
92
+ create: () => this.createStrategy.createLinked(writer, enrichment, parent),
93
+ update: () => this.updateStrategy.updateLinked(writer, enrichment, parent),
94
+ delete: () => this.deleteStrategy.deleteLinked(writer, enrichment, parent),
95
+ });
96
+ }
97
+ return;
98
+ }
99
+ if (type === EnrichmentPropertyType.List && enrichment.relatedProperty) return;
100
+ if (type !== EnrichmentPropertyType.List && type !== EnrichmentPropertyType.Dictionary) return;
101
+ const writer = childWriter(entry, enrichment.destinationProperty);
102
+ const ready = parents.filter((parent) => !this.skip(parent, enrichment.destinationProperty, mode));
103
+ const children = ready.flatMap((parent) => this.createStrategy.collectChildren(writer, enrichment, parent));
104
+ if (children.length === 0) return;
105
+ const bulk = writer as ICRUDRepository<object> & { createBulk?: (items: object[]) => Promise<object[]>; updateBulk?: (items: object[]) => Promise<unknown> };
106
+ if (mode === "create") {
107
+ if (bulk.createBulk) await bulk.createBulk(children);
108
+ else for (const child of children) await writer.create(child);
109
+ return;
110
+ }
111
+ if (bulk.updateBulk) await bulk.updateBulk(children);
112
+ else for (const child of children) await writer.update(child);
113
+ };
114
+
115
+ private persistEntry = async (
116
+ entry: StoredEnrichment,
117
+ parents: T[],
118
+ mode: WriteMode,
119
+ ): Promise<void> => {
120
+ const enrichment = entry.enrichment;
121
+ const type = enrichment.type ?? EnrichmentPropertyType.Object;
122
+ if (type === EnrichmentPropertyType.Custom)
123
+ throw new DatasourceError(`Unsupported enrichment type "${type}"`);
124
+ if (enrichment.association) {
125
+ const writer = linkWriter(entry, enrichment.destinationProperty);
126
+ for (const parent of parents) {
127
+ if (this.skip(parent, enrichment.destinationProperty, mode)) continue;
128
+ await dispatch(mode, {
129
+ create: () => this.createStrategy.createLinked(writer, enrichment, parent),
130
+ update: () => this.updateStrategy.updateLinked(writer, enrichment, parent),
131
+ delete: () => this.deleteStrategy.deleteLinked(writer, enrichment, parent),
132
+ });
133
+ }
134
+ return;
135
+ }
136
+ if (type === EnrichmentPropertyType.List && enrichment.relatedProperty) return;
137
+ if (type !== EnrichmentPropertyType.List && type !== EnrichmentPropertyType.Dictionary) return;
138
+ const writer = childWriter(entry, enrichment.destinationProperty);
139
+ for (const parent of parents) {
140
+ if (this.skip(parent, enrichment.destinationProperty, mode)) continue;
141
+ await dispatch(mode, {
142
+ create: () => this.createStrategy.createChildren(writer, enrichment, parent),
143
+ update: () => this.updateStrategy.updateChildren(writer, enrichment, parent),
144
+ delete: () => this.deleteStrategy.deleteChildren(writer, enrichment, parent, async () => {}),
145
+ });
146
+ }
147
+ };
148
+
149
+ private skip = (parent: T, into: string, mode: string): boolean =>
150
+ this.skipUnloaded && mode !== "delete" && unloaded(parent, into);
151
+ }
@@ -0,0 +1,56 @@
1
+ import type { Enrichment } from "./Enrichment.ts";
2
+ import type { ICRUDRepository } from "./ICRUDRepository.ts";
3
+ import type { Scalar } from "./builders/Scalar.ts";
4
+ import { Operator, Where } from "./statements/index.ts";
5
+
6
+ type Props = Record<string, Scalar | object>;
7
+
8
+ const get = <TItem>(item: TItem, name: string): Scalar | object | undefined =>
9
+ (item as never as Props)[name];
10
+
11
+ export abstract class DeleteEnrichmentStrategy<T> {
12
+ abstract deleteChildren<TChild extends object>(
13
+ writer: ICRUDRepository<TChild>,
14
+ enrichment: Enrichment,
15
+ parent: T,
16
+ deleteNested: (rows: TChild[]) => Promise<void>,
17
+ ): Promise<void>;
18
+
19
+ abstract deleteLinked<TChild extends object>(writer: ICRUDRepository<TChild>, enrichment: Enrichment, parent: T): Promise<void>;
20
+
21
+ static load = async <TParent, TChild extends object>(
22
+ writer: ICRUDRepository<TChild>,
23
+ enrichment: Enrichment,
24
+ parent: TParent,
25
+ ): Promise<TChild[]> => {
26
+ const key = get(parent, enrichment.sourceProperty);
27
+ if (key === undefined || key === null || typeof key === "object") return [];
28
+ const items: TChild[] = [];
29
+ for await (const item of writer.read(new Where(new Operator.Equals(enrichment.relatedKey, key))))
30
+ items.push(item);
31
+ return items;
32
+ };
33
+
34
+ static childrenWhere = <TParent, TChild extends object>(
35
+ writer: ICRUDRepository<TChild>,
36
+ enrichment: Enrichment,
37
+ parent: TParent,
38
+ ): Where | undefined => {
39
+ if (writer.ids.length > 0) return undefined;
40
+ const key = get(parent, enrichment.sourceProperty);
41
+ return key === undefined || key === null || typeof key === "object"
42
+ ? undefined
43
+ : new Where(new Operator.Equals(enrichment.relatedKey, key));
44
+ };
45
+
46
+ static loadLinks = async <TChild extends object>(
47
+ writer: ICRUDRepository<TChild>,
48
+ column: string,
49
+ key: Scalar,
50
+ ): Promise<TChild[]> => {
51
+ const items: TChild[] = [];
52
+ for await (const item of writer.read(new Where(new Operator.Equals(column, key))))
53
+ items.push(item);
54
+ return items;
55
+ };
56
+ };
@@ -0,0 +1,97 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { createRequire, registerHooks } from "node:module";
3
+ import { tmpdir } from "node:os";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+ import type { IDriver } from "./IDriver.ts";
6
+ import type { ProviderCatalog } from "./ProviderCatalog.ts";
7
+ import { ProviderNotInstalledError } from "./ProviderNotInstalledError.ts";
8
+
9
+ type DriverCtor = new () => IDriver;
10
+ type DriverModule = Record<string, DriverCtor>;
11
+ type TypeScript = {
12
+ transpileModule: (
13
+ source: string,
14
+ options: {
15
+ compilerOptions: { module: number; target: number };
16
+ fileName: string;
17
+ },
18
+ ) => { outputText: string };
19
+ ModuleKind: { ESNext: number };
20
+ ScriptTarget: { ES2022: number };
21
+ };
22
+
23
+ const require = createRequire(import.meta.url);
24
+ const virtual = new Map<string, string>();
25
+ const virtualBySource = new Map<string, string>();
26
+ let typeScriptHook = false;
27
+ let compiling = false;
28
+ let nextVirtual = 0;
29
+
30
+ const installTypeScriptHook = (): void => {
31
+ if (typeScriptHook) return;
32
+ const typescript = require("typescript") as TypeScript;
33
+ /* v8 ignore start */
34
+ registerHooks({
35
+ resolve: (specifier, context, nextResolve) => {
36
+ const parentURL = context.parentURL ? virtual.get(context.parentURL) ?? context.parentURL : undefined;
37
+ const resolved = nextResolve(specifier, parentURL ? { ...context, parentURL } : context);
38
+ /* v8 ignore next */
39
+ if (!compiling || !resolved.url.endsWith(".ts")) return resolved;
40
+ const existing = virtualBySource.get(resolved.url);
41
+ /* v8 ignore next */
42
+ if (existing) return { url: existing, shortCircuit: true };
43
+ const url = pathToFileURL(`${tmpdir()}/datasources-plugin-${nextVirtual++}.mjs`).href;
44
+ virtual.set(url, resolved.url);
45
+ virtualBySource.set(resolved.url, url);
46
+ return { url, shortCircuit: true };
47
+ },
48
+ load: (url, context, nextLoad) => {
49
+ const original = virtual.get(url) ?? (compiling && url.endsWith(".ts") ? url : undefined);
50
+ /* v8 ignore next */
51
+ if (!original) return nextLoad(url, context);
52
+ const filename = fileURLToPath(original);
53
+ const source = typescript.transpileModule(readFileSync(filename, "utf8"), {
54
+ compilerOptions: {
55
+ module: typescript.ModuleKind.ESNext,
56
+ target: typescript.ScriptTarget.ES2022,
57
+ },
58
+ fileName: filename,
59
+ }).outputText;
60
+ return { format: "module", source, shortCircuit: true };
61
+ },
62
+ });
63
+ /* v8 ignore stop */
64
+ typeScriptHook = true;
65
+ };
66
+
67
+ const instantiate = (catalog: ProviderCatalog): IDriver => {
68
+ compiling = true;
69
+ try {
70
+ return instantiateLoaded(catalog);
71
+ } finally {
72
+ compiling = false;
73
+ }
74
+ };
75
+
76
+ const instantiateLoaded = (catalog: ProviderCatalog): IDriver => {
77
+ const loaded = require(catalog.location) as DriverModule;
78
+ const Type = loaded[catalog.module];
79
+ if (typeof Type !== "function") throw new ProviderNotInstalledError(catalog.name);
80
+ return new Type();
81
+ };
82
+
83
+ export class DriverLoader {
84
+ static load = (catalog: ProviderCatalog): IDriver => {
85
+ try {
86
+ return instantiate(catalog);
87
+ } catch (error) {
88
+ if (error instanceof ProviderNotInstalledError) throw error;
89
+ try {
90
+ installTypeScriptHook();
91
+ return instantiate(catalog);
92
+ } catch {
93
+ throw new ProviderNotInstalledError(catalog.name);
94
+ }
95
+ }
96
+ };
97
+ }
@@ -0,0 +1,15 @@
1
+ import type { EnrichmentPropertyType } from "./EnrichmentPropertyType.ts";
2
+
3
+ export type Association = {
4
+ parent: string;
5
+ related: string;
6
+ };
7
+
8
+ export type Enrichment = {
9
+ destinationProperty: string;
10
+ sourceProperty: string;
11
+ relatedKey: string;
12
+ relatedProperty?: string;
13
+ type?: EnrichmentPropertyType;
14
+ association?: Association;
15
+ };
@@ -0,0 +1,9 @@
1
+ export const EnrichmentPropertyType = {
2
+ Object: "object",
3
+ List: "list",
4
+ Dictionary: "dictionary",
5
+ Custom: "custom",
6
+ } as const;
7
+
8
+ export type EnrichmentPropertyType =
9
+ (typeof EnrichmentPropertyType)[keyof typeof EnrichmentPropertyType];
@@ -0,0 +1,79 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { CommandMiddlewareHost } from "./CommandMiddlewareHost.ts";
3
+ import { ExpectConsoleMiddleware, consoleSignature } from "./ExpectConsoleMiddleware.ts";
4
+
5
+ const now = () => new Date("2026-08-28T01:54:12.101Z");
6
+
7
+ describe("ExpectConsoleMiddleware", () => {
8
+ it("matches the transcript and drops the finish duration", async () => {
9
+ const middleware = new ExpectConsoleMiddleware(
10
+ [
11
+ "[2026-08-28T01:54:12.101Z]-[datasource][Start]-[SELECT 1]",
12
+ "[2026-08-28T01:54:12.101Z]-[datasource][Request]-[{id: 1}]",
13
+ "[2026-08-28T01:54:12.101Z]-[datasource][Finish]-[SELECT 1]",
14
+ "[2026-08-28T01:54:12.101Z]-[datasource][AfterCommand]-[{id: 1}]",
15
+ ],
16
+ now,
17
+ );
18
+ const host = new CommandMiddlewareHost();
19
+ host.addMiddleware(middleware);
20
+ await host.run("SELECT 1", [{ name: "id", value: 1 }], async () => ({
21
+ value: 1,
22
+ rows: [{ id: 1 }],
23
+ }));
24
+ middleware.complete();
25
+ expect(consoleSignature("[2026-08-28T01:54:12.101Z]-[datasource][Finish]-[SELECT 1] 2ms")).toBe(
26
+ "[2026-08-28T01:54:12.101Z]-[datasource][Finish]-[SELECT 1]",
27
+ );
28
+ expect(consoleSignature("[2026-08-28T01:54:12.101Z]-[datasource][Start]-[SELECT 1]")).toBe(
29
+ "[2026-08-28T01:54:12.101Z]-[datasource][Start]-[SELECT 1]",
30
+ );
31
+ expect(consoleSignature("[2026-08-28T01:54:12.101Z]-[datasource][Finish]-[SELECT 1] 3μs")).toBe(
32
+ "[2026-08-28T01:54:12.101Z]-[datasource][Finish]-[SELECT 1]",
33
+ );
34
+ });
35
+
36
+ it("applies a custom line check", async () => {
37
+ const normalize = (line: string) => consoleSignature(line).replaceAll("2026-08-28T01:54:12.101Z", "<date>");
38
+ const middleware = new ExpectConsoleMiddleware(
39
+ [
40
+ "[<date>]-[datasource][Start]-[SELECT 1]",
41
+ "[<date>]-[datasource][Request]-[{id: 1}]",
42
+ "[<date>]-[datasource][Finish]-[SELECT 1]",
43
+ "[<date>]-[datasource][AfterCommand]-[{id: 1}]",
44
+ ],
45
+ now,
46
+ normalize,
47
+ );
48
+ const host = new CommandMiddlewareHost();
49
+ host.addMiddleware(middleware);
50
+ await host.run("SELECT 1", [{ name: "id", value: 1 }], async () => ({
51
+ value: 1,
52
+ rows: [{ id: 1 }],
53
+ }));
54
+ middleware.complete();
55
+ });
56
+
57
+ it("rejects a different line and a short transcript", async () => {
58
+ const host = new CommandMiddlewareHost();
59
+ const mismatch = new ExpectConsoleMiddleware(["[nope]"], now);
60
+ host.addMiddleware(mismatch);
61
+ await expect(
62
+ host.run("SELECT 1", [{ name: "id", value: 1 }], async () => ({
63
+ value: 1,
64
+ rows: [{ id: 1 }],
65
+ })),
66
+ ).rejects.toThrow(/console mismatch at 0/);
67
+ expect(() => new ExpectConsoleMiddleware(["[missing]"], now).complete()).toThrow(
68
+ /actual: <missing>/,
69
+ );
70
+ const extraHost = new CommandMiddlewareHost();
71
+ extraHost.addMiddleware(new ExpectConsoleMiddleware(
72
+ ["[2026-08-28T01:54:12.101Z]-[datasource][Start]-[SELECT 1]"],
73
+ now,
74
+ ));
75
+ await expect(
76
+ extraHost.run("SELECT 1", undefined, async () => ({ value: null, rows: [] })),
77
+ ).rejects.toThrow(/<missing>/);
78
+ });
79
+ });
@@ -0,0 +1,47 @@
1
+ import { ConsoleCommandMiddleware } from "./ConsoleCommandMiddleware.ts";
2
+ import type { ICommandMiddleware } from "./ICommandMiddleware.ts";
3
+ import type { Parameter } from "./Parameter.ts";
4
+ import type { Row } from "./Row.ts";
5
+
6
+ export const consoleSignature = (line: string): string => {
7
+ const duration = line.lastIndexOf("] ");
8
+ return duration >= 0 && (line.endsWith("ms") || line.endsWith("μs"))
9
+ ? line.slice(0, duration + 1)
10
+ : line;
11
+ };
12
+
13
+ export class ExpectConsoleMiddleware implements ICommandMiddleware {
14
+ private readonly inner: ConsoleCommandMiddleware;
15
+ private index = 0;
16
+
17
+ constructor(
18
+ private readonly expected: readonly string[],
19
+ now: () => Date,
20
+ private readonly normalize: (line: string) => string = consoleSignature,
21
+ ) {
22
+ this.inner = new ConsoleCommandMiddleware((line) => this.check(line), now, { isVerbose: "true" });
23
+ }
24
+
25
+ beforeCommand = (text: string, params?: ReadonlyArray<Parameter>) =>
26
+ this.inner.beforeCommand(text, params);
27
+
28
+ afterCommand = (
29
+ text: string,
30
+ params: ReadonlyArray<Parameter> | undefined,
31
+ results: ReadonlyArray<Row>,
32
+ elapsedMs: number,
33
+ error?: Error,
34
+ ) => this.inner.afterCommand(text, params, results, elapsedMs, error);
35
+
36
+ complete = (): void => {
37
+ if (this.index !== this.expected.length)
38
+ throw new Error(`console mismatch at ${this.index}\nexpected: ${this.expected[this.index]}\nactual: <missing>`);
39
+ };
40
+
41
+ private check = (line: string): void => {
42
+ const actual = this.normalize(line);
43
+ if (this.index >= this.expected.length || actual !== this.expected[this.index])
44
+ throw new Error(`console mismatch at ${this.index}\nexpected: ${this.index < this.expected.length ? this.expected[this.index] : "<missing>"}\nactual: ${actual}`);
45
+ this.index++;
46
+ };
47
+ }