@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,221 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { DictionaryMapper } from "./mappers/DictionaryMapper.ts";
3
+ import { StatementMappers } from "./StatementMappers.ts";
4
+ import { DefaultStatementTextRenderer } from "./statements/DefaultStatementTextRenderer.ts";
5
+ import { DeleteStatement } from "./statements/DeleteStatement.ts";
6
+ import { ExecuteStoredProcedureStatement } from "./statements/ExecuteStoredProcedureStatement.ts";
7
+ import { Identifier } from "./statements/Identifier.ts";
8
+ import { InsertStatement } from "./statements/InsertStatement.ts";
9
+ import { Join } from "./statements/Join.ts";
10
+ import { Operator } from "./statements/Operator.ts";
11
+ import { OrderBy } from "./statements/OrderBy.ts";
12
+ import { SelectInsertedIdStatement } from "./statements/SelectInsertedIdStatement.ts";
13
+ import { SelectStatement } from "./statements/SelectStatement.ts";
14
+ import { UpdateStatement } from "./statements/UpdateStatement.ts";
15
+ import { Where } from "./statements/Where.ts";
16
+ import { WhereText } from "./statements/WhereText.ts";
17
+ import type { Cell } from "./converters/Cell.ts";
18
+
19
+ const mapper = (name: string, value: Cell): Cell =>
20
+ typeof value === "string" ? `${name}:${value.toUpperCase()}` : value;
21
+
22
+ describe("StatementMappers", () => {
23
+ it("maps a select", () => {
24
+ const mappings = new StatementMappers(
25
+ new DictionaryMapper([
26
+ ["User", "people"],
27
+ ["Role", "roles"],
28
+ ]),
29
+ new DictionaryMapper([
30
+ ["Name", "full_name"],
31
+ ["title", "book.title"],
32
+ ["id", "user_id"],
33
+ ]),
34
+ );
35
+ const select = new SelectStatement({
36
+ distinct: true,
37
+ table: "User",
38
+ fields: ["Name", "title", "scope.title", "alias.other", '"schema.name".id'],
39
+ where: new Where(new Operator.Equals("Name", "Bea")),
40
+ joins: [Join.inner("Role", "User.id", "Role.user_id"), Join.cross("logs")],
41
+ groupBy: ["Name"],
42
+ having: new Where(new Operator.Equals("Name", "Bea")),
43
+ orderBy: [OrderBy.desc("Name")],
44
+ limit: 5,
45
+ offset: 1,
46
+ });
47
+ const mapped = mappings.apply(select, mapper) as SelectStatement;
48
+ expect(mapped.table).toBe("people");
49
+ expect(mapped.fields).toEqual([
50
+ "full_name",
51
+ "book.title",
52
+ "book.title",
53
+ "alias.other",
54
+ '"schema.name".user_id',
55
+ ]);
56
+ expect(mapped.distinct).toBe(true);
57
+ expect(mapped.limit).toBe(5);
58
+ expect(mapped.offset).toBe(1);
59
+ expect(mapped.groupBy).toEqual(["full_name"]);
60
+ expect(mapped.orderBy).toEqual([{ column: "full_name", direction: "desc" }]);
61
+ expect((mapped.joins[0]?.on as Operator.Equals).left).toBeInstanceOf(Identifier);
62
+ expect(((mapped.joins[0]?.on as Operator.Equals).left as Identifier).name).toBe("people.user_id");
63
+ expect(mapped.joins[1]).toEqual({ kind: "cross", table: "logs" });
64
+ expect(DefaultStatementTextRenderer.instance.render(mapped)).toContain("full_name = $full_name");
65
+ expect(mapped.where?.parameters?.[0]?.value).toBe("Name:BEA");
66
+ expect(mappings.property("full_name")).toBe("Name");
67
+ expect(mappings.property("people.full_name")).toBe("Name");
68
+ expect(mappings.property("other")).toBe("other");
69
+ expect(mappings.property("people.missing")).toBe("people.missing");
70
+ });
71
+
72
+ it("maps writes", () => {
73
+ const mappings = new StatementMappers(
74
+ new DictionaryMapper([
75
+ ["User", "people"],
76
+ ["Role", "roles"],
77
+ ]),
78
+ new DictionaryMapper([
79
+ ["Name", "full_name"],
80
+ ["title", "book.title"],
81
+ ["id", "user_id"],
82
+ ]),
83
+ );
84
+ const insert = mappings.apply(new InsertStatement("User", [{ name: "Name", value: "Ada" }]), mapper) as InsertStatement;
85
+ expect(DefaultStatementTextRenderer.instance.render(insert)).toBe("INSERT INTO people (full_name) VALUES ($full_name)");
86
+ expect(insert.fields[0]?.value).toBe("Ada");
87
+
88
+ const update = mappings.apply(
89
+ new UpdateStatement("User", [{ name: "Name", value: "Ada" }], new Where(new Operator.Equals("Name", "Bea"))),
90
+ mapper,
91
+ ) as UpdateStatement;
92
+ expect(DefaultStatementTextRenderer.instance.render(update)).toBe(
93
+ "UPDATE people SET full_name = $full_name WHERE full_name = $full_name__where",
94
+ );
95
+ expect(update.parameters[0]?.value).toBe("Ada");
96
+ expect(update.parameters[1]).toEqual({ name: "full_name__where", value: "Name:BEA" });
97
+
98
+ const deleted = mappings.apply(
99
+ new DeleteStatement("User", new Where(new Operator.Equals("Name", "Bea"))),
100
+ mapper,
101
+ ) as DeleteStatement;
102
+ expect(DefaultStatementTextRenderer.instance.render(deleted)).toBe("DELETE FROM people WHERE full_name = $full_name");
103
+
104
+ const inserted = mappings.apply(new SelectInsertedIdStatement("User", "id"), mapper) as SelectInsertedIdStatement;
105
+ expect(inserted.table).toBe("people");
106
+ expect(inserted.column).toBe("user_id");
107
+ });
108
+
109
+ it("leaves raw and other statements", () => {
110
+ const mappings = new StatementMappers(
111
+ new DictionaryMapper([
112
+ ["User", "people"],
113
+ ["Role", "roles"],
114
+ ]),
115
+ new DictionaryMapper([
116
+ ["Name", "full_name"],
117
+ ["title", "book.title"],
118
+ ["id", "user_id"],
119
+ ]),
120
+ );
121
+ const call = new ExecuteStoredProcedureStatement("save_user", []);
122
+ expect(mappings.apply(call, mapper)).toBe(call);
123
+ expect(mappings.apply(undefined, mapper)).toBeUndefined();
124
+ const text = new WhereText("name = $name");
125
+ expect(mappings.applyWhere(text, mapper)).toBe(text);
126
+ const kept = mappings.apply(new DeleteStatement("User", text), mapper) as DeleteStatement;
127
+ expect(kept.where).toBe(text);
128
+ expect(DefaultStatementTextRenderer.instance.render(kept)).toBe("DELETE FROM people WHERE name = $name");
129
+ });
130
+
131
+ it("maps a select field alias", () => {
132
+ const mappings = new StatementMappers(
133
+ new DictionaryMapper([
134
+ ["Contact", "contacts_base"],
135
+ ["Address", "address"],
136
+ ]),
137
+ new DictionaryMapper([
138
+ ["Id", "id"],
139
+ ["FirstName", "first_name"],
140
+ ["ContactId", "contact_id"],
141
+ ]),
142
+ );
143
+ const select = new SelectStatement({
144
+ table: "Contact",
145
+ fields: ["Contact.Id AS Id", "Contact.FirstName AS FirstName", "Address.Id AS AddressId"],
146
+ joins: [Join.left("Address", "Contact.Id", "Address.ContactId")],
147
+ });
148
+ const mapped = mappings.apply(select, mapper) as SelectStatement;
149
+ expect(DefaultStatementTextRenderer.instance.render(mapped)).toBe(
150
+ "SELECT contacts_base.id AS Id, contacts_base.first_name AS FirstName, address.id AS AddressId FROM contacts_base LEFT JOIN address ON contacts_base.id = address.contact_id",
151
+ );
152
+ });
153
+
154
+ it("maps a contacts select", () => {
155
+ const mappings = new StatementMappers(
156
+ new DictionaryMapper([
157
+ ["Contact", "contacts_base"],
158
+ ["ContactSource", "contact_source"],
159
+ ["ContactType", "contact_type"],
160
+ ["Address", "address"],
161
+ ["AddressType", "address_type"],
162
+ ["Phone", "phone"],
163
+ ["PhoneType", "phone_type"],
164
+ ]),
165
+ new DictionaryMapper([
166
+ ["Id", "id"],
167
+ ["FirstName", "first_name"],
168
+ ["LastName", "last_name"],
169
+ ["Email", "email"],
170
+ ["Name", "name"],
171
+ ["Line1", "line1"],
172
+ ["City", "city"],
173
+ ["Number", "number"],
174
+ ["ContactId", "contact_id"],
175
+ ["ContactSourceId", "contact_source_id"],
176
+ ["ContactTypeId", "contact_type_id"],
177
+ ["AddressTypeId", "address_type_id"],
178
+ ["PhoneTypeId", "phone_type_id"],
179
+ ]),
180
+ );
181
+ const select = new SelectStatement({
182
+ distinct: true,
183
+ table: "Contact",
184
+ fields: [
185
+ "Contact.FirstName",
186
+ "Contact.LastName",
187
+ "Contact.Email",
188
+ "ContactSource.Name",
189
+ "Address.Line1",
190
+ "Address.City",
191
+ "Phone.Number",
192
+ ],
193
+ where: new Where(
194
+ new Operator.And(
195
+ new Operator.Equals("Contact.Email", "ada@ex.com"),
196
+ new Operator.GreaterThan("Address.City", "A"),
197
+ ),
198
+ ),
199
+ joins: [
200
+ Join.inner("ContactSource", "Contact.ContactSourceId", "ContactSource.Id"),
201
+ Join.inner("ContactType", "Contact.ContactTypeId", "ContactType.Id"),
202
+ Join.left("Address", "Contact.Id", "Address.ContactId"),
203
+ Join.left("AddressType", "Address.AddressTypeId", "AddressType.Id"),
204
+ Join.left("Phone", "Contact.Id", "Phone.ContactId"),
205
+ Join.left("PhoneType", "Phone.PhoneTypeId", "PhoneType.Id"),
206
+ ],
207
+ groupBy: ["Contact.LastName"],
208
+ having: new Where(new Operator.Equals("ContactType.Name", "person")),
209
+ orderBy: [OrderBy.asc("Contact.LastName"), OrderBy.desc("Contact.FirstName")],
210
+ limit: 20,
211
+ offset: 1,
212
+ });
213
+ const mapped = mappings.apply(select, mapper) as SelectStatement;
214
+ expect(DefaultStatementTextRenderer.instance.render(mapped)).toBe(
215
+ "SELECT DISTINCT contacts_base.first_name, contacts_base.last_name, contacts_base.email, contact_source.name, address.line1, address.city, phone.number FROM contacts_base INNER JOIN contact_source ON contacts_base.contact_source_id = contact_source.id INNER JOIN contact_type ON contacts_base.contact_type_id = contact_type.id LEFT JOIN address ON contacts_base.id = address.contact_id LEFT JOIN address_type ON address.address_type_id = address_type.id LEFT JOIN phone ON contacts_base.id = phone.contact_id LEFT JOIN phone_type ON phone.phone_type_id = phone_type.id WHERE contacts_base.email = $contacts_base.email AND address.city > $address.city GROUP BY contacts_base.last_name HAVING contact_type.name = $contact_type.name ORDER BY contacts_base.last_name ASC, contacts_base.first_name DESC LIMIT 20 OFFSET 1",
216
+ );
217
+ expect(mapped.where?.parameters[0]?.value).toBe("Contact.Email:ADA@EX.COM");
218
+ expect(mapped.where?.parameters[1]?.value).toBe("Address.City:A");
219
+ expect((mapped.having as Where).parameters[0]?.value).toBe("ContactType.Name:PERSON");
220
+ });
221
+ });
@@ -0,0 +1,110 @@
1
+ import type { Cell } from "./converters/Cell.ts";
2
+ import type { IMapper } from "./mappers/IMapper.ts";
3
+ import { DeleteStatement } from "./statements/DeleteStatement.ts";
4
+ import type { IStatement } from "./statements/IStatement.ts";
5
+ import type { IWhere } from "./statements/IWhere.ts";
6
+ import { InsertStatement } from "./statements/InsertStatement.ts";
7
+ import { SelectInsertedIdStatement } from "./statements/SelectInsertedIdStatement.ts";
8
+ import { SelectStatement } from "./statements/SelectStatement.ts";
9
+ import { UpdateStatement } from "./statements/UpdateStatement.ts";
10
+ import { Where } from "./statements/Where.ts";
11
+
12
+ export class StatementMappers implements IMapper<string, string> {
13
+ constructor(
14
+ private readonly entityMappers: IMapper<string, string>,
15
+ private readonly propertyMappers: IMapper<string, string>,
16
+ ) {}
17
+
18
+ map = (property: string): string => {
19
+ const dot = lastDot(property);
20
+ if (dot < 0) return this.propertyMappers.map(property);
21
+ const qualifier = property.slice(0, dot);
22
+ const name = property.slice(dot + 1);
23
+ const mapped = this.propertyMappers.map(name);
24
+ if (mapped !== name && mapped.includes(".")) return mapped;
25
+ const table = this.entityMappers.map(qualifier);
26
+ return table === qualifier && mapped === name ? property : `${table}.${mapped}`;
27
+ };
28
+
29
+ reverseMap = (key: string): string => {
30
+ const reversed = this.propertyMappers.reverseMap(key);
31
+ if (reversed !== key && this.propertyMappers.map(reversed) === key) return reversed;
32
+ const dot = lastDot(key);
33
+ if (dot < 0) return reversed;
34
+ const column = key.slice(dot + 1);
35
+ const name = this.propertyMappers.reverseMap(column);
36
+ return name !== column && this.propertyMappers.map(name) === column ? name : reversed;
37
+ };
38
+
39
+ column = (property: string): string => this.map(property);
40
+
41
+ property = (key: string): string => this.reverseMap(key);
42
+
43
+ apply = (
44
+ query: IStatement | undefined,
45
+ cell: (property: string, value: Cell) => Cell,
46
+ ): IStatement | undefined => {
47
+ if (query instanceof SelectStatement && query.table)
48
+ return new SelectStatement({
49
+ distinct: query.distinct,
50
+ table: this.entityMappers.map(query.table),
51
+ fields: query.fields.map(this.mapSelectField),
52
+ where: query.where instanceof Where ? this.applyWhere(query.where, cell) : query.where,
53
+ joins: query.joins.map((join) => ({
54
+ kind: join.kind,
55
+ table: this.entityMappers.map(join.table),
56
+ on: join.on ? new Where(join.on).map(this.column, cell).condition : undefined,
57
+ })),
58
+ groupBy: query.groupBy.map(this.column),
59
+ having: query.having instanceof Where ? this.applyWhere(query.having, cell) : query.having,
60
+ orderBy: query.orderBy.map((order) => ({ column: this.column(order.column), direction: order.direction })),
61
+ limit: query.limit,
62
+ offset: query.offset,
63
+ });
64
+ if (query instanceof InsertStatement && query.table !== undefined)
65
+ return new InsertStatement(
66
+ this.entityMappers.map(query.table),
67
+ query.fields.map((field) => ({ name: this.column(field.name), value: field.value })),
68
+ );
69
+ if (query instanceof UpdateStatement && query.table !== undefined)
70
+ return new UpdateStatement(
71
+ this.entityMappers.map(query.table),
72
+ query.fields.map((field) => ({ name: this.column(field.name), value: field.value })),
73
+ query.where instanceof Where ? this.applyWhere(query.where, cell) : query.where,
74
+ );
75
+ if (query instanceof DeleteStatement && query.table !== undefined)
76
+ return new DeleteStatement(
77
+ this.entityMappers.map(query.table),
78
+ query.where instanceof Where ? this.applyWhere(query.where, cell) : query.where,
79
+ );
80
+ if (query instanceof SelectInsertedIdStatement)
81
+ return new SelectInsertedIdStatement(this.entityMappers.map(query.table), this.column(query.column));
82
+ return query;
83
+ };
84
+
85
+ applyWhere = (
86
+ where: IWhere | undefined,
87
+ cell: (property: string, value: Cell) => Cell,
88
+ ): IWhere | undefined =>
89
+ where instanceof Where ? where.map(this.column, cell) : where;
90
+
91
+ private mapSelectField = (field: string): string => {
92
+ const asIndex = field.toUpperCase().indexOf(" AS ");
93
+ if (asIndex >= 0) {
94
+ const expression = field.slice(0, asIndex).trim();
95
+ const alias = field.slice(asIndex + 4).trim();
96
+ return `${this.map(expression)} AS ${alias}`;
97
+ }
98
+ return this.map(field);
99
+ };
100
+ }
101
+
102
+ const lastDot = (name: string): number => {
103
+ let quoted = false;
104
+ let dot = -1;
105
+ for (let i = 0; i < name.length; i++) {
106
+ if (name[i] === '"') quoted = !quoted;
107
+ if (name[i] === "." && !quoted) dot = i;
108
+ }
109
+ return dot;
110
+ };
@@ -0,0 +1,25 @@
1
+ import type { Enrichment } from "./Enrichment.ts";
2
+ import type { ICRUDRepository } from "./ICRUDRepository.ts";
3
+ import type { Row } from "./Row.ts";
4
+
5
+ export type ApplyEnrichment<T extends object = object> = (
6
+ parents: T[],
7
+ sources?: (Row | undefined)[],
8
+ ) => Promise<void>;
9
+
10
+ export class StoredEnrichment<T extends object = object> {
11
+ apply: ApplyEnrichment<T>;
12
+ persist?: ICRUDRepository<object>;
13
+ link?: ICRUDRepository<object>;
14
+
15
+ constructor(
16
+ readonly enrichment: Enrichment,
17
+ apply: ApplyEnrichment<T>,
18
+ persist?: ICRUDRepository<object>,
19
+ link?: ICRUDRepository<object>,
20
+ ) {
21
+ this.apply = apply;
22
+ this.persist = persist;
23
+ this.link = link;
24
+ }
25
+ }
@@ -0,0 +1,164 @@
1
+ import type { Cell, Cells } from "./converters/Cell.ts";
2
+ import { DatasourceError } from "./DatasourceError.ts";
3
+ import type { Response } from "./Response.ts";
4
+ import type { IWhere } from "./statements/IWhere.ts";
5
+ import { ExecuteStoredProcedureStatement } from "./statements/ExecuteStoredProcedureStatement.ts";
6
+ import type { CRUDRepository } from "./CRUDRepository.ts";
7
+ import type { CRUDRepositoryOptions } from "./CRUDRepositoryOptions.ts";
8
+ import type { ICommand } from "./ICommand.ts";
9
+ import { execute } from "./ICommand.ts";
10
+ import type { IBulkWriteStrategy } from "./IBulkWriteStrategy.ts";
11
+ import { repositoryParts } from "./CRUDRepositoryBuilder.ts";
12
+ import { MetaDataRowTypeConverter } from "./converters/MetaDataRowTypeConverter.ts";
13
+ import { afterBulkWrite } from "./BulkWriteEnrichment.ts";
14
+ import { ParameterDirection } from "./ParameterDirection.ts";
15
+ import type { Parameter } from "./Parameter.ts";
16
+
17
+ const empty = (): Response => ({ result: null, rowsAffected: 0 });
18
+
19
+ const json = (rows: Cells[]): string => `[${rows.map(object).join(",")}]`;
20
+
21
+ const object = (row: Cells): string =>
22
+ `{${Object.entries(row)
23
+ .sort(([left], [right]) => left.localeCompare(right))
24
+ .map(([key, value]) => `${quote(key)}:${scalar(value)}`)
25
+ .join(",")}}`;
26
+
27
+ const scalar = (value: Cell): string => {
28
+ if (value === null || value === undefined) return "null";
29
+ if (typeof value === "boolean") return value ? "true" : "false";
30
+ if (typeof value === "number") return Number.isFinite(value) ? JSON.stringify(value) : fail();
31
+ if (typeof value === "bigint") return value.toString();
32
+ if (typeof value === "string") return quote(value);
33
+ if (value instanceof Date) return quote(roundTrip(value));
34
+ if (value instanceof Uint8Array) return quote(base64(value));
35
+ return fail();
36
+ };
37
+
38
+ const fail = (): string => {
39
+ throw new DatasourceError("Unsupported bulk payload value");
40
+ };
41
+
42
+ const roundTrip = (date: Date): string =>
43
+ date.toISOString().replace(/\.(\d{3})Z$/, (_, fraction: string) => `.${fraction}0000Z`);
44
+
45
+ const base64 = (bytes: Uint8Array): string =>
46
+ btoa(Array.from(bytes, (byte) => String.fromCharCode(byte)).join(""));
47
+
48
+ const quote = (text: string): string => {
49
+ let result = "\"";
50
+ for (const ch of text) {
51
+ result += ({
52
+ "\\": "\\\\",
53
+ "\"": "\\\"",
54
+ "\b": "\\b",
55
+ "\f": "\\f",
56
+ "\n": "\\n",
57
+ "\r": "\\r",
58
+ "\t": "\\t",
59
+ }[ch] ?? (ch < " " ? `\\u${ch.charCodeAt(0).toString(16).padStart(4, "0")}` : ch));
60
+ }
61
+ return `${result}"`;
62
+ };
63
+
64
+ export class StoredProcedureBulkWriteStrategy<T extends object> implements IBulkWriteStrategy<T> {
65
+ repo!: CRUDRepository<T>;
66
+ command!: ICommand;
67
+ options!: CRUDRepositoryOptions<T>;
68
+
69
+ attach = (command: ICommand, options: CRUDRepositoryOptions<T>): void => {
70
+ this.command = command;
71
+ this.options = options;
72
+ };
73
+
74
+ constructor(
75
+ private readonly createName: string,
76
+ private readonly updateName: string,
77
+ private readonly deleteName: string,
78
+ ) {}
79
+
80
+ create = (items: T[]): Promise<Response> => this.then(this.call(this.createName, items, true), items, "create");
81
+
82
+ update = (items: T[], _byWhere: IWhere | undefined): Promise<Response> =>
83
+ this.then(this.call(this.updateName, items), items, "update");
84
+
85
+ delete = (items: T[], _byWhere: IWhere | undefined): Promise<Response> =>
86
+ this.then(this.call(this.deleteName, items), items, "delete");
87
+
88
+ private then = async (write: Promise<Response>, items: T[], mode: "create" | "update" | "delete"): Promise<Response> => {
89
+ const response = await write;
90
+ await afterBulkWrite(this.repo, this.options, items, mode);
91
+ return response;
92
+ };
93
+
94
+ private call = async (name: string, items: T[], generated = false): Promise<Response> => {
95
+ if (items.length === 0) return empty();
96
+ const payload = { name: "payload", value: json(items.map((item) => this.rowOf(item, generated))) };
97
+ const parameters: Parameter[] = generated && this.ids().length === 1
98
+ ? [payload, { name: "ids", value: null, direction: ParameterDirection.InputOutput }]
99
+ : [payload];
100
+ const response = await execute(this.command, new ExecuteStoredProcedureStatement(name, parameters), parameters);
101
+ if (generated) this.applyIds(items, response.parameters);
102
+ return response;
103
+ };
104
+
105
+ private ids = (): readonly string[] => this.options.ids ?? this.repo.ids ?? ["id"];
106
+
107
+ private rowOf = (item: T, create = false): Cells => {
108
+ const stored = this.reverse(item);
109
+ const statements = repositoryParts(this.command.connection, this.options).statements;
110
+ const row: Cells = {};
111
+ for (const name of statements.readColumns) {
112
+ if (create && this.identity(name) && !assigned(stored[name] ?? stored[this.ids()[0]!])) continue;
113
+ const match = Object.entries(stored).find(([key]) => this.column(key) === name);
114
+ row[name] = match?.[1] ?? null;
115
+ }
116
+ return row;
117
+ };
118
+
119
+ private identity = (column: string): boolean => this.ids().length === 1 && this.ids()[0] === column;
120
+
121
+ private applyIds = (items: T[], parameters?: Parameter[]): void => {
122
+ if (this.ids().length !== 1) return;
123
+ const found = parameters?.find((parameter) => parameter.name === "ids");
124
+ const list = parseIds(found?.value);
125
+ const column = this.ids()[0]!;
126
+ for (let index = 0; index < items.length && index < list.length; index++)
127
+ stamp(items[index], column, list[index]!);
128
+ };
129
+
130
+ private column = (property: string): string => this.options.propertyMappings?.map(property) ?? property;
131
+
132
+ private reverse = (item: T): Cells => {
133
+ const objects = this.options.objectConverter ?? new MetaDataRowTypeConverter<T>();
134
+ const row = objects.reverseConvert(item);
135
+ return this.options.rowConverter ? this.options.rowConverter.reverseConvert(row) : row;
136
+ };
137
+ }
138
+
139
+ const assigned = (value: Cell | undefined): boolean => {
140
+ if (value === null || value === undefined) return false;
141
+ if (value === 0 || value === 0n) return false;
142
+ if (typeof value === "string") return value.length > 0;
143
+ return true;
144
+ };
145
+
146
+ const parseIds = (value: Cell | undefined): number[] => {
147
+ const text =
148
+ typeof value === "string" ? value.trim()
149
+ : typeof value === "number" || typeof value === "bigint" ? String(value)
150
+ : "";
151
+ if (text === "" || text === "[]" || text === "null") return [];
152
+ return text
153
+ .replace(/^\[/, "")
154
+ .replace(/\]$/, "")
155
+ .split(",")
156
+ .map((part) => part.trim())
157
+ .filter(Boolean)
158
+ .map((part) => Number(part));
159
+ };
160
+
161
+ const stamp = <T extends object>(item: T, column: string, id: number): void => {
162
+ const key = column in item ? column : "id" in item ? "id" : "Id" in item ? "Id" : column;
163
+ (item as Record<string, Cell>)[key] = id;
164
+ };
@@ -0,0 +1,126 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { splitStatements, statementParameters, statementUsesParameter, statementReader, StreamingReader } from "./index.ts";
3
+
4
+ describe("splitStatements", () => {
5
+ it("splits on semicolons outside quotes and comments", () => {
6
+ expect(splitStatements("")).toEqual([]);
7
+ expect(splitStatements("SELECT 1")).toEqual(["SELECT 1"]);
8
+ expect(splitStatements("SELECT 1;")).toEqual(["SELECT 1"]);
9
+ expect(splitStatements("SELECT 1 AS id; SELECT 2 AS id")).toEqual([
10
+ "SELECT 1 AS id",
11
+ "SELECT 2 AS id",
12
+ ]);
13
+ expect(splitStatements("SELECT ';' AS id; SELECT 2 AS id")).toEqual([
14
+ "SELECT ';' AS id",
15
+ "SELECT 2 AS id",
16
+ ]);
17
+ expect(splitStatements('SELECT "a""b" AS id; SELECT `c`')).toEqual([
18
+ 'SELECT "a""b" AS id',
19
+ "SELECT `c`",
20
+ ]);
21
+ expect(splitStatements("SELECT 1; -- tail\nSELECT 2")).toEqual([
22
+ "SELECT 1",
23
+ "-- tail\nSELECT 2",
24
+ ]);
25
+ expect(splitStatements("SELECT 1; /* ; */ SELECT 2")).toEqual([
26
+ "SELECT 1",
27
+ "/* ; */ SELECT 2",
28
+ ]);
29
+ const mysql = "CREATE PROCEDURE add_user()\nBEGIN\n INSERT INTO t VALUES (1);\nEND";
30
+ expect(splitStatements(mysql)).toEqual([mysql]);
31
+ const postgres =
32
+ "CREATE PROCEDURE bulk_create_user(payload jsonb)\nLANGUAGE plpgsql\nAS $$\nBEGIN\n INSERT INTO t VALUES (1);\nEND;\n$$";
33
+ expect(splitStatements(postgres)).toEqual([postgres]);
34
+ });
35
+
36
+ it("matches a parameter token at a word boundary", () => {
37
+ expect(statementUsesParameter("INSERT INTO t (is_enabled) VALUES ($is_enabled__10)", "is_enabled__10")).toBe(true);
38
+ expect(statementUsesParameter("INSERT INTO t (is_enabled) VALUES ($is_enabled__10)", "is_enabled__1")).toBe(false);
39
+ expect(statementUsesParameter("$is_enabled__1", "is_enabled__1")).toBe(true);
40
+ expect(statementParameters("INSERT INTO t (a, b) VALUES ($a__0, $b__0), ($a__1, $b__1)")).toEqual([
41
+ "a__0",
42
+ "b__0",
43
+ "a__1",
44
+ "b__1",
45
+ ]);
46
+ });
47
+ });
48
+
49
+ describe("StreamingReader", () => {
50
+ it("reads the current set and advances on nextResult", async () => {
51
+ const sets = [[{ id: 1 }], [{ id: 2 }]];
52
+ let set = 0;
53
+ let row = 0;
54
+ let reads = 0;
55
+ let closed = false;
56
+ const reader = new StreamingReader(
57
+ async () => {
58
+ reads += 1;
59
+ const rows = sets[set] ?? [];
60
+ if (row >= rows.length) return undefined;
61
+ const current = rows[row];
62
+ row += 1;
63
+ return current;
64
+ },
65
+ async () => {
66
+ set += 1;
67
+ row = 0;
68
+ return set < sets.length;
69
+ },
70
+ async () => {
71
+ closed = true;
72
+ },
73
+ );
74
+ expect(reads).toBe(0);
75
+ expect(await reader.next()).toBe(true);
76
+ expect(reader.current).toEqual({ id: 1 });
77
+ expect(await reader.next()).toBe(false);
78
+ expect(reader.current).toBeUndefined();
79
+ expect(await reader.nextResult()).toBe(true);
80
+ expect(reader.current).toBeUndefined();
81
+ expect(await reader.next()).toBe(true);
82
+ expect(reader.current).toEqual({ id: 2 });
83
+ expect(await reader.nextResult()).toBe(false);
84
+ await reader.dispose();
85
+ await reader.dispose();
86
+ expect(closed).toBe(true);
87
+ const plain = new StreamingReader(
88
+ async () => undefined,
89
+ async () => false,
90
+ );
91
+ expect(await Array.fromAsync(plain.read())).toEqual([]);
92
+ await plain.dispose();
93
+ await plain[Symbol.asyncDispose]();
94
+ await plain.dispose();
95
+ });
96
+
97
+ it("loads one statement at a time", async () => {
98
+ const loaded: string[] = [];
99
+ const reader = statementReader(["SELECT 1 AS id", "SELECT 2 AS id"], async function* (sql) {
100
+ loaded.push(sql);
101
+ yield sql.endsWith("1 AS id") ? { id: 1 } : { id: 2 };
102
+ });
103
+ expect(loaded).toEqual([]);
104
+ expect(await reader.next()).toBe(true);
105
+ expect(reader.current).toEqual({ id: 1 });
106
+ expect(await reader.next()).toBe(false);
107
+ expect(loaded).toEqual(["SELECT 1 AS id"]);
108
+ expect(await reader.nextResult()).toBe(true);
109
+ expect(await reader.next()).toBe(true);
110
+ expect(reader.current).toEqual({ id: 2 });
111
+ expect(await reader.nextResult()).toBe(false);
112
+ expect(await reader.next()).toBe(false);
113
+ expect(loaded).toEqual(["SELECT 1 AS id", "SELECT 2 AS id"]);
114
+ await reader.dispose();
115
+ });
116
+
117
+ it("returns false when a statement reader has no statements", async () => {
118
+ const reader = statementReader([], async function* () {});
119
+ expect(await reader.next()).toBe(false);
120
+ expect(await reader.nextResult()).toBe(false);
121
+ const blank = statementReader([""], async function* () {
122
+ yield { id: 1 };
123
+ });
124
+ expect(await blank.next()).toBe(false);
125
+ });
126
+ });