@deterministic-code/datasources 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/package.json +16 -4
  2. package/src/ArrayReader.ts +32 -0
  3. package/src/BatchCommandIBulkWriteStrategy.ts +228 -0
  4. package/src/BuiltRepository.ts +17 -0
  5. package/src/BulkCRUDRepository.ts +84 -0
  6. package/src/BulkCommand.ts +6 -0
  7. package/src/BulkWriteEnrichment.ts +19 -0
  8. package/src/CRUDRepository.ts +264 -0
  9. package/src/CRUDRepositoryBuilder.ts +53 -0
  10. package/src/CRUDRepositoryOptions.ts +8 -0
  11. package/src/CRUDRepositoryStatements.ts +43 -0
  12. package/src/CascadeDeleteEnrichmentStrategy.ts +51 -0
  13. package/src/CascadeDeleteUpdateEnrichmentStrategy.ts +28 -0
  14. package/src/CommandMiddlewareHost.ts +113 -0
  15. package/src/ConsoleCommandMiddleware.ts +64 -0
  16. package/src/CreateEnrichmentStrategy.ts +82 -0
  17. package/src/Datasource.ts +152 -0
  18. package/src/DatasourceError.ts +6 -0
  19. package/src/DatasourceFactory.ts +86 -0
  20. package/src/DatasourceOptions.ts +1 -0
  21. package/src/DatasourceUrl.ts +37 -0
  22. package/src/DatasourceUrlParser.ts +188 -0
  23. package/src/DefaultCreateEnrichmentStrategy.ts +21 -0
  24. package/src/DefaultReadonlyEnrichmentStrategy.ts +164 -0
  25. package/src/DefaultUpdateEnrichmentStrategy.ts +40 -0
  26. package/src/DefaultWriteEnrichmentStrategy.ts +151 -0
  27. package/src/DeleteEnrichmentStrategy.ts +56 -0
  28. package/src/DriverLoader.ts +97 -0
  29. package/src/Enrichment.ts +15 -0
  30. package/src/EnrichmentPropertyType.ts +9 -0
  31. package/src/ExpectConsoleMiddleware.ts +47 -0
  32. package/src/FirstResultReader.ts +49 -0
  33. package/src/HashsetOptimizedReadonlyEnrichmentStrategy.ts +80 -0
  34. package/src/IBulkWriteStrategy.ts +13 -0
  35. package/src/ICRUDRepository.ts +13 -0
  36. package/src/ICRUDRepositoryFactory.ts +8 -0
  37. package/src/ICommand.ts +45 -0
  38. package/src/ICommandMiddleware.ts +20 -0
  39. package/src/IConnection.ts +13 -0
  40. package/src/IDatasource.ts +27 -0
  41. package/src/IDatasourceFactory.ts +6 -0
  42. package/src/IDriver.ts +24 -0
  43. package/src/IEnriched.ts +11 -0
  44. package/src/IReader.ts +8 -0
  45. package/src/IReadonlyEnrichmentStrategy.ts +19 -0
  46. package/src/IReadonlyRepository.ts +21 -0
  47. package/src/IRepository.ts +5 -0
  48. package/src/IRepositoryFactory.ts +8 -0
  49. package/src/IRepositoryTree.ts +5 -0
  50. package/src/IRepositoryTreeNode.ts +8 -0
  51. package/src/ITransaction.ts +9 -0
  52. package/src/IUnitOfWork.ts +5 -0
  53. package/src/IWriteEnrichmentStrategy.ts +8 -0
  54. package/src/Information.ts +5 -0
  55. package/src/IsolationLevel.ts +8 -0
  56. package/src/LazyWriteEnrichmentStrategy.ts +5 -0
  57. package/src/NestedToObjectEnrichmentStrategy.ts +33 -0
  58. package/src/Parameter.ts +8 -0
  59. package/src/ParameterDirection.ts +9 -0
  60. package/src/ProviderCatalog.ts +21 -0
  61. package/src/ProviderNotImplementedError.ts +9 -0
  62. package/src/ProviderNotInstalledError.ts +9 -0
  63. package/src/ReadonlyRepository.ts +276 -0
  64. package/src/ReadonlyRepositoryBuilder.ts +53 -0
  65. package/src/ReadonlyRepositoryMappingOptions.ts +15 -0
  66. package/src/ReadonlyRepositoryStatements.ts +13 -0
  67. package/src/RepositoryAccess.ts +14 -0
  68. package/src/RepositoryFactory.ts +115 -0
  69. package/src/RepositoryNotRegisteredError.ts +9 -0
  70. package/src/RepositoryTree.ts +6 -0
  71. package/src/RepositoryTreeNode.ts +11 -0
  72. package/src/Response.ts +15 -0
  73. package/src/Row.ts +3 -0
  74. package/src/SingleCommandIBulkWriteStrategy.ts +35 -0
  75. package/src/StatementMappers.ts +110 -0
  76. package/src/StoredEnrichment.ts +25 -0
  77. package/src/StoredProcedureBulkWriteStrategy.ts +164 -0
  78. package/src/StreamingReader.ts +64 -0
  79. package/src/UnitOfWorkTransaction.ts +50 -0
  80. package/src/UpdateEnrichmentStrategy.ts +97 -0
  81. package/src/WriteMode.ts +1 -0
  82. package/src/builders/Field.ts +6 -0
  83. package/src/builders/Scalar.ts +1 -0
  84. package/src/builders/index.ts +2 -0
  85. package/src/collectAsync.ts +7 -0
  86. package/src/converters/Cell.ts +10 -0
  87. package/src/converters/ChangeCasingConverter.ts +59 -0
  88. package/src/converters/Constructable.ts +1 -0
  89. package/src/converters/MetaDataRowTypeConverter.ts +80 -0
  90. package/src/converters/PluralizerConverter.ts +67 -0
  91. package/src/converters/RegexConverter.ts +14 -0
  92. package/src/converters/ReplaceConverter.ts +6 -0
  93. package/src/converters/RowTypeConverter.ts +33 -0
  94. package/src/converters/ToLowerCaseConverter.ts +4 -0
  95. package/src/converters/ToUpperCaseConverter.ts +4 -0
  96. package/src/converters/TypeConverter.ts +6 -0
  97. package/src/createCRUDRepositoryOptions.ts +21 -0
  98. package/src/createReadonlyRepositoryMappingOptions.ts +26 -0
  99. package/src/dotEnv.ts +16 -0
  100. package/src/index.ts +222 -0
  101. package/src/mappers/ChangeCasingMapper.ts +15 -0
  102. package/src/mappers/DictionaryMapper.ts +16 -0
  103. package/src/mappers/FlatToNestedMapper.ts +127 -0
  104. package/src/mappers/IFlatToNestedMapper.ts +7 -0
  105. package/src/mappers/IMapper.ts +4 -0
  106. package/src/mappers/IdentityMapper.ts +6 -0
  107. package/src/mappers/PluralizerMapper.ts +9 -0
  108. package/src/mappers/RowTypeMapper.ts +13 -0
  109. package/src/mappers/TransformConverterMapper.ts +11 -0
  110. package/src/mappers/TransformMapper.ts +8 -0
  111. package/src/mappers/TypeMap.ts +10 -0
  112. package/src/mappers/TypeMapGroup.ts +6 -0
  113. package/src/mocks/index.ts +9 -0
  114. package/src/mocks/mock-command.ts +66 -0
  115. package/src/mocks/mock-connection.ts +57 -0
  116. package/src/mocks/mock-datasource.ts +65 -0
  117. package/src/mocks/mock-driver.ts +27 -0
  118. package/src/mocks/mock-reader.ts +38 -0
  119. package/src/mocks/mock-repository.ts +91 -0
  120. package/src/mocks/mock-select-statement.ts +17 -0
  121. package/src/mocks/mock-transaction.ts +31 -0
  122. package/src/mocks/mock-where.ts +13 -0
  123. package/src/parametersToRecord.ts +11 -0
  124. package/src/readerToAsyncIterable.ts +11 -0
  125. package/src/splitStatements.ts +99 -0
  126. package/src/statementParameters.ts +22 -0
  127. package/src/statementUsesParameter.ts +4 -0
  128. package/src/statements/Aggregate.ts +9 -0
  129. package/src/statements/ArrayExpression.ts +5 -0
  130. package/src/statements/BulkDeleteStatement.ts +18 -0
  131. package/src/statements/BulkDeleteStatementTextRenderer.ts +16 -0
  132. package/src/statements/BulkInsertStatement.ts +37 -0
  133. package/src/statements/BulkInsertStatementTextRenderer.ts +10 -0
  134. package/src/statements/BulkUpdateStatement.ts +24 -0
  135. package/src/statements/BulkUpdateStatementTextRenderer.ts +29 -0
  136. package/src/statements/CheckConstraint.ts +9 -0
  137. package/src/statements/Cmp.ts +12 -0
  138. package/src/statements/Column.ts +10 -0
  139. package/src/statements/ColumnDefault.ts +6 -0
  140. package/src/statements/Condition.ts +3 -0
  141. package/src/statements/ConditionRenderer.ts +17 -0
  142. package/src/statements/CreateIndexStatement.ts +18 -0
  143. package/src/statements/CreateIndexStatementTextRenderer.ts +11 -0
  144. package/src/statements/CreateTableStatement.ts +18 -0
  145. package/src/statements/CreateTableStatementTextRenderer.ts +92 -0
  146. package/src/statements/DefaultStatementTextRenderer.ts +9 -0
  147. package/src/statements/DeleteStatement.ts +15 -0
  148. package/src/statements/DeleteStatementTextRenderer.ts +12 -0
  149. package/src/statements/ExecuteStoredProcedureStatement.ts +15 -0
  150. package/src/statements/ExecuteStoredProcedureStatementTextRenderer.ts +15 -0
  151. package/src/statements/ExpressionEvaluator.ts +166 -0
  152. package/src/statements/ExpressionRenderer.ts +161 -0
  153. package/src/statements/ForeignKey.ts +23 -0
  154. package/src/statements/IBulkDeleteStatement.ts +3 -0
  155. package/src/statements/IBulkInsertStatement.ts +3 -0
  156. package/src/statements/IBulkUpdateStatement.ts +3 -0
  157. package/src/statements/ICondition.ts +5 -0
  158. package/src/statements/IConditionVisitor.ts +7 -0
  159. package/src/statements/ICreateIndexStatement.ts +3 -0
  160. package/src/statements/ICreateTableStatement.ts +3 -0
  161. package/src/statements/IDeleteStatement.ts +6 -0
  162. package/src/statements/IExecuteStoredProcedureStatement.ts +3 -0
  163. package/src/statements/IExpression.ts +1 -0
  164. package/src/statements/IInsertStatement.ts +3 -0
  165. package/src/statements/IReturnStatement.ts +3 -0
  166. package/src/statements/ISelectStatement.ts +6 -0
  167. package/src/statements/IStatement.ts +5 -0
  168. package/src/statements/IStatementVisitor.ts +27 -0
  169. package/src/statements/ITableConstraint.ts +6 -0
  170. package/src/statements/IUpdateStatement.ts +6 -0
  171. package/src/statements/IWhere.ts +7 -0
  172. package/src/statements/Identifier.ts +5 -0
  173. package/src/statements/InsertStatement.ts +15 -0
  174. package/src/statements/InsertStatementTextRenderer.ts +7 -0
  175. package/src/statements/Join.ts +26 -0
  176. package/src/statements/Literal.ts +6 -0
  177. package/src/statements/Native.ts +5 -0
  178. package/src/statements/NotNull.ts +3 -0
  179. package/src/statements/Operator.ts +234 -0
  180. package/src/statements/OrderBy.ts +19 -0
  181. package/src/statements/PrimaryKey.ts +9 -0
  182. package/src/statements/ReturnStatement.ts +15 -0
  183. package/src/statements/ReturnStatementTextRenderer.ts +15 -0
  184. package/src/statements/SelectInsertedIdStatement.ts +11 -0
  185. package/src/statements/SelectInsertedIdStatementTextRenderer.ts +7 -0
  186. package/src/statements/SelectStatement.ts +34 -0
  187. package/src/statements/SelectStatementOptions.ts +16 -0
  188. package/src/statements/SelectStatementTextRenderer.ts +71 -0
  189. package/src/statements/StatementEvaluator.ts +5 -0
  190. package/src/statements/StatementParser.ts +461 -0
  191. package/src/statements/StatementRenderer.ts +120 -0
  192. package/src/statements/StatementTextRenderer.ts +60 -0
  193. package/src/statements/Subquery.ts +6 -0
  194. package/src/statements/UniqueConstraint.ts +9 -0
  195. package/src/statements/UpdateStatement.ts +34 -0
  196. package/src/statements/UpdateStatementTextRenderer.ts +63 -0
  197. package/src/statements/Where.ts +250 -0
  198. package/src/statements/WhereText.ts +10 -0
  199. package/src/statements/index.ts +75 -0
  200. package/src/stubs/StubCommand.ts +30 -0
  201. package/src/stubs/StubConnection.ts +21 -0
  202. package/src/stubs/StubDatasource.ts +60 -0
  203. package/src/stubs/StubReader.ts +25 -0
  204. package/src/stubs/StubRepository.ts +42 -0
  205. package/src/stubs/StubTransaction.ts +17 -0
  206. package/src/stubs/createStubDatasource.ts +4 -0
  207. package/src/stubs/index.ts +7 -0
  208. package/src/stubs/notImplemented.ts +5 -0
  209. package/README.md +0 -3
package/src/IDriver.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { ICommand } from "./ICommand.ts";
2
+ import type { IConnection } from "./IConnection.ts";
3
+ import type { ITransaction } from "./ITransaction.ts";
4
+ import type { IsolationLevel } from "./IsolationLevel.ts";
5
+ import type { DatasourceOptions } from "./DatasourceOptions.ts";
6
+ import type { Cell } from "./converters/Cell.ts";
7
+ import type { TypeConverter } from "./converters/TypeConverter.ts";
8
+ import type { Information } from "./Information.ts";
9
+ import type { StatementTextRenderer } from "./statements/StatementTextRenderer.ts";
10
+
11
+ export const columnType = (name: string): string => name;
12
+
13
+ export interface IDriver {
14
+ connection(options?: DatasourceOptions): IConnection;
15
+ command(connection: IConnection): ICommand;
16
+ transaction(
17
+ connection: IConnection,
18
+ isolation?: IsolationLevel,
19
+ ): ITransaction;
20
+ rowTypeConverters: Record<string, TypeConverter<Cell, Cell>>;
21
+ columnType(name: string): string;
22
+ statementRenderer?: StatementTextRenderer | null;
23
+ information?: Information | null;
24
+ }
@@ -0,0 +1,11 @@
1
+ import type { Enrichment } from "./Enrichment.ts";
2
+ import type { IReadonlyEnrichmentStrategy } from "./IReadonlyEnrichmentStrategy.ts";
3
+ import type { IReadonlyRepository } from "./IReadonlyRepository.ts";
4
+
5
+ export interface IEnriched<T> {
6
+ addEnriched<TRelated extends object>(
7
+ enrichment: Enrichment,
8
+ via: IReadonlyRepository<TRelated>,
9
+ strategy?: IReadonlyEnrichmentStrategy<T & object>,
10
+ ): this;
11
+ }
package/src/IReader.ts ADDED
@@ -0,0 +1,8 @@
1
+ export interface IReader<T = unknown> {
2
+ readonly current: T | undefined;
3
+ next(): Promise<boolean>;
4
+ nextResult(): Promise<boolean>;
5
+ read(): AsyncIterable<T>;
6
+ dispose(): Promise<void>;
7
+ [Symbol.asyncDispose](): Promise<void>;
8
+ }
@@ -0,0 +1,19 @@
1
+ import type { Enrichment } from "./Enrichment.ts";
2
+ import type { IReadonlyRepository } from "./IReadonlyRepository.ts";
3
+ import type { Row } from "./Row.ts";
4
+
5
+ export interface IReadonlyEnrichmentStrategy<T extends object> {
6
+ apply<TRelated extends object>(
7
+ via: IReadonlyRepository<TRelated>,
8
+ enrichment: Enrichment,
9
+ parents: T[],
10
+ sources?: (Row | undefined)[],
11
+ ): Promise<void>;
12
+ applyLinked<TRelated extends object, TLink extends object>(
13
+ via: IReadonlyRepository<TRelated>,
14
+ link: IReadonlyRepository<TLink>,
15
+ enrichment: Enrichment,
16
+ parents: T[],
17
+ sources?: (Row | undefined)[],
18
+ ): Promise<void>;
19
+ }
@@ -0,0 +1,21 @@
1
+ import type { Parameter } from "./Parameter.ts";
2
+ import type { IExecuteStoredProcedureStatement } from "./statements/IExecuteStoredProcedureStatement.ts";
3
+ import type { ISelectStatement } from "./statements/ISelectStatement.ts";
4
+ import type { IRepository } from "./IRepository.ts";
5
+ import type { IWhere } from "./statements/IWhere.ts";
6
+ import type { ReadonlyRepositoryMappingOptions } from "./ReadonlyRepositoryMappingOptions.ts";
7
+
8
+ export type ReadQuery = ISelectStatement | IWhere | IExecuteStoredProcedureStatement;
9
+
10
+ export interface IReadonlyRepository<T = unknown> extends IRepository<T> {
11
+ readSingle(
12
+ query?: ReadQuery,
13
+ parameters?: Parameter[],
14
+ options?: ReadonlyRepositoryMappingOptions<T>,
15
+ ): Promise<T | undefined>;
16
+ read(
17
+ query?: ReadQuery,
18
+ parameters?: Parameter[],
19
+ options?: ReadonlyRepositoryMappingOptions<T>,
20
+ ): AsyncIterable<T>;
21
+ }
@@ -0,0 +1,5 @@
1
+ import type { Constructable } from "./converters/Constructable.ts";
2
+
3
+ export interface IRepository<T = unknown> {
4
+ readonly type: Constructable<T>;
5
+ }
@@ -0,0 +1,8 @@
1
+ import type { Constructable } from "./converters/Constructable.ts";
2
+ import type { IReadonlyRepository } from "./IReadonlyRepository.ts";
3
+ import type { IRepository } from "./IRepository.ts";
4
+
5
+ export interface IRepositoryFactory {
6
+ register(repository: IRepository): void;
7
+ create<T>(type: Constructable<T>): IReadonlyRepository<T>;
8
+ }
@@ -0,0 +1,5 @@
1
+ import type { IRepositoryTreeNode } from "./IRepositoryTreeNode.ts";
2
+
3
+ export interface IRepositoryTree {
4
+ readonly parent: IRepositoryTreeNode;
5
+ }
@@ -0,0 +1,8 @@
1
+ import type { Enrichment } from "./Enrichment.ts";
2
+
3
+ export interface IRepositoryTreeNode {
4
+ readonly value: object;
5
+ readonly propertyName: string;
6
+ readonly parent?: IRepositoryTreeNode;
7
+ readonly enrichment?: Enrichment;
8
+ }
@@ -0,0 +1,9 @@
1
+ import type { IConnection } from "./IConnection.ts";
2
+ import type { IsolationLevel } from "./IsolationLevel.ts";
3
+
4
+ export interface ITransaction {
5
+ readonly connection: IConnection;
6
+ readonly isolation: IsolationLevel;
7
+ commit(): Promise<void>;
8
+ abort(): Promise<void>;
9
+ }
@@ -0,0 +1,5 @@
1
+ export interface IUnitOfWork {
2
+ begin(): Promise<void>;
3
+ commit(): Promise<void>;
4
+ abort(): Promise<void>;
5
+ }
@@ -0,0 +1,8 @@
1
+ import type { IRepositoryTree } from "./IRepositoryTree.ts";
2
+ import type { WriteMode } from "./WriteMode.ts";
3
+
4
+ export interface IWriteEnrichmentStrategy<T> {
5
+ readonly useTransaction: boolean;
6
+ persist(tree: IRepositoryTree, items: T[], mode: WriteMode): Promise<void>;
7
+ persistBulk?(tree: IRepositoryTree, items: T[], mode: WriteMode): Promise<void>;
8
+ }
@@ -0,0 +1,5 @@
1
+ export type Information = {
2
+ descriptions: readonly string[];
3
+ overrides: readonly string[];
4
+ changeLogs: readonly string[];
5
+ };
@@ -0,0 +1,8 @@
1
+ export const IsolationLevel = {
2
+ ReadUncommitted: "readUncommitted",
3
+ ReadCommitted: "readCommitted",
4
+ RepeatableRead: "repeatableRead",
5
+ Serializable: "serializable",
6
+ } as const;
7
+
8
+ export type IsolationLevel = (typeof IsolationLevel)[keyof typeof IsolationLevel];
@@ -0,0 +1,5 @@
1
+ import { DefaultWriteEnrichmentStrategy } from "./DefaultWriteEnrichmentStrategy.ts";
2
+
3
+ export class LazyWriteEnrichmentStrategy<T> extends DefaultWriteEnrichmentStrategy<T> {
4
+ protected override skipUnloaded = true;
5
+ }
@@ -0,0 +1,33 @@
1
+ import type { Cells } from "./converters/Cell.ts";
2
+ import type { Enrichment } from "./Enrichment.ts";
3
+ import type { IReadonlyRepository } from "./IReadonlyRepository.ts";
4
+ import { FlatToNestedMapper } from "./mappers/FlatToNestedMapper.ts";
5
+ import type { TypeMap } from "./mappers/TypeMap.ts";
6
+ import type { Row } from "./Row.ts";
7
+ import { DefaultReadonlyEnrichmentStrategy } from "./DefaultReadonlyEnrichmentStrategy.ts";
8
+
9
+ export class NestedToObjectEnrichmentStrategy<T extends object>
10
+ extends DefaultReadonlyEnrichmentStrategy<T>
11
+ {
12
+ private readonly nested: FlatToNestedMapper<T>;
13
+
14
+ constructor(typeMap: TypeMap<T>) {
15
+ super();
16
+ this.nested = new FlatToNestedMapper(typeMap);
17
+ }
18
+
19
+ override apply<TRelated extends object>(
20
+ _via: IReadonlyRepository<TRelated>,
21
+ _enrichment: Enrichment,
22
+ parents: T[],
23
+ sources?: (Row | undefined)[],
24
+ ): Promise<void> {
25
+ parents.length = 0;
26
+ for (const item of this.nested.map(rows(sources))) parents.push(item);
27
+ return Promise.resolve();
28
+ }
29
+ }
30
+
31
+ function* rows(sources?: (Row | undefined)[]): Iterable<Cells> {
32
+ for (const source of sources ?? []) if (source) yield source;
33
+ }
@@ -0,0 +1,8 @@
1
+ import type { Scalar } from "./builders/Scalar.ts";
2
+ import type { ParameterDirection } from "./ParameterDirection.ts";
3
+
4
+ export interface Parameter<T = Scalar> {
5
+ name: string;
6
+ value?: T;
7
+ direction?: ParameterDirection;
8
+ }
@@ -0,0 +1,9 @@
1
+ export const ParameterDirection = {
2
+ Input: "input",
3
+ Output: "output",
4
+ InputOutput: "inputOutput",
5
+ ReturnValue: "returnValue",
6
+ } as const;
7
+
8
+ export type ParameterDirection =
9
+ (typeof ParameterDirection)[keyof typeof ParameterDirection];
@@ -0,0 +1,21 @@
1
+ export class ProviderCatalog {
2
+ constructor(
3
+ readonly name: string,
4
+ readonly location: string,
5
+ readonly module: string,
6
+ ) {}
7
+
8
+ static readonly default: Readonly<Record<string, ProviderCatalog>> = {
9
+ json: new ProviderCatalog("json", "@datasources/json", "JsonDriver"),
10
+ memory: new ProviderCatalog("memory", "@datasources/memory", "MemoryDriver"),
11
+ sqlite: new ProviderCatalog("sqlite", "@datasources/sqlite", "SqliteDriver"),
12
+ xml: new ProviderCatalog("xml", "@datasources/xml", "XmlDriver"),
13
+ yaml: new ProviderCatalog("yaml", "@datasources/yaml", "YamlDriver"),
14
+ mysql: new ProviderCatalog("mysql", "@datasources/mysql", "MysqlDriver"),
15
+ sqlserver: new ProviderCatalog("sqlserver", "@datasources/sqlserver", "SqlServerDriver"),
16
+ postgres: new ProviderCatalog("postgres", "@datasources/postgres", "PostgresDriver"),
17
+ oracle: new ProviderCatalog("oracle", "@datasources/oracle", "OracleDriver"),
18
+ mongodb: new ProviderCatalog("mongodb", "@datasources/mongodb", "MongoDbDriver"),
19
+ dynamodb: new ProviderCatalog("dynamodb", "@datasources/dynamodb", "DynamoDbDriver"),
20
+ };
21
+ }
@@ -0,0 +1,9 @@
1
+ export class ProviderNotImplementedError extends Error {
2
+ readonly provider: string;
3
+
4
+ constructor(provider: string) {
5
+ super(`Provider "${provider}" is not implemented`);
6
+ this.name = "ProviderNotImplementedError";
7
+ this.provider = provider;
8
+ }
9
+ }
@@ -0,0 +1,9 @@
1
+ export class ProviderNotInstalledError extends Error {
2
+ readonly provider: string;
3
+
4
+ constructor(provider: string) {
5
+ super(`Provider "${provider}" is not installed`);
6
+ this.name = "ProviderNotInstalledError";
7
+ this.provider = provider;
8
+ }
9
+ }
@@ -0,0 +1,276 @@
1
+ import type { ICommand } from "./ICommand.ts";
2
+ import { executeReader } from "./ICommand.ts";
3
+ import type { ICommandMiddleware } from "./ICommandMiddleware.ts";
4
+ import type { IConnection } from "./IConnection.ts";
5
+ import { ExecuteStoredProcedureStatement } from "./statements/ExecuteStoredProcedureStatement.ts";
6
+ import type { Parameter } from "./Parameter.ts";
7
+ import type { ISelectStatement } from "./statements/ISelectStatement.ts";
8
+ import type { IStatement } from "./statements/IStatement.ts";
9
+ import type { IReadonlyRepository, ReadQuery } from "./IReadonlyRepository.ts";
10
+ import type { Row } from "./Row.ts";
11
+ import type { IWhere } from "./statements/IWhere.ts";
12
+ import { DatasourceError } from "./DatasourceError.ts";
13
+ import type { Cell, Cells } from "./converters/Cell.ts";
14
+ import type { Constructable } from "./converters/Constructable.ts";
15
+ import { MetaDataRowTypeConverter } from "./converters/MetaDataRowTypeConverter.ts";
16
+ import { SelectStatement } from "./statements/SelectStatement.ts";
17
+ import { createReadonlyRepositoryMappingOptions } from "./createReadonlyRepositoryMappingOptions.ts";
18
+ import type { ReadonlyRepositoryMappingOptions } from "./ReadonlyRepositoryMappingOptions.ts";
19
+ import type { BuiltRepository } from "./BuiltRepository.ts";
20
+ import { ReadonlyRepositoryBuilder } from "./ReadonlyRepositoryBuilder.ts";
21
+ import type { TypeConverter } from "./converters/TypeConverter.ts";
22
+ import type { IMapper } from "./mappers/IMapper.ts";
23
+ import { IdentityMapper } from "./mappers/IdentityMapper.ts";
24
+ import type { ReadonlyRepositoryStatements } from "./ReadonlyRepositoryStatements.ts";
25
+ import { StatementMappers } from "./StatementMappers.ts";
26
+ import { DefaultReadonlyEnrichmentStrategy } from "./DefaultReadonlyEnrichmentStrategy.ts";
27
+ import type { Enrichment } from "./Enrichment.ts";
28
+ import type { IEnriched } from "./IEnriched.ts";
29
+ import type { IReadonlyEnrichmentStrategy } from "./IReadonlyEnrichmentStrategy.ts";
30
+ import { StoredEnrichment } from "./StoredEnrichment.ts";
31
+
32
+ export const untyped = <T>(): Constructable<T> => Object as never as Constructable<T>;
33
+
34
+ export type Sourced<T> = { item: T; source?: Row };
35
+
36
+ const storedEnrichments = new WeakMap<object, StoredEnrichment[]>();
37
+
38
+ export const enrichmentsOf = (host: object): readonly StoredEnrichment[] | undefined =>
39
+ storedEnrichments.get(host);
40
+
41
+ export const isBuilt = <T>(
42
+ value: IConnection | BuiltRepository<T>,
43
+ ): value is BuiltRepository<T> =>
44
+ "statements" in value && "objectConverter" in value && "propertyMappings" in value;
45
+
46
+ export const builtOf = <T>(
47
+ typeOrConnectionOrBuilt: Constructable<T> | IConnection | BuiltRepository<T>,
48
+ connectionOrOptions?: IConnection | ReadonlyRepositoryMappingOptions<T>,
49
+ ): BuiltRepository<T> | undefined =>
50
+ typeof typeOrConnectionOrBuilt === "function"
51
+ ? connectionOrOptions === undefined
52
+ ? undefined
53
+ : new ReadonlyRepositoryBuilder<T>().parts(
54
+ connectionOrOptions as IConnection,
55
+ createReadonlyRepositoryMappingOptions(typeOrConnectionOrBuilt),
56
+ )
57
+ : isBuilt(typeOrConnectionOrBuilt)
58
+ ? typeOrConnectionOrBuilt
59
+ : new ReadonlyRepositoryBuilder<T>().parts(
60
+ typeOrConnectionOrBuilt,
61
+ connectionOrOptions as ReadonlyRepositoryMappingOptions<T>,
62
+ );
63
+
64
+ export class ReadonlyRepository<T> implements IReadonlyRepository<T>, IEnriched<T> {
65
+ readonly type: Constructable<T>;
66
+ private connection?: IConnection;
67
+ protected rowConverter?: TypeConverter<Cells, Cells>;
68
+ protected objectConverter?: TypeConverter<T, Cells>;
69
+ private entityMappers: IMapper<string, string> = new IdentityMapper();
70
+ private propertyMappers: IMapper<string, string> = new IdentityMapper();
71
+ private statementMappers = new StatementMappers(new IdentityMapper(), new IdentityMapper());
72
+ private readonlyStatements?: ReadonlyRepositoryStatements;
73
+ private readonly middlewares: ICommandMiddleware[] = [];
74
+
75
+ constructor(type: Constructable<T>);
76
+ constructor(type: Constructable<T>, connection: IConnection);
77
+ constructor(connection: IConnection, options: ReadonlyRepositoryMappingOptions<T>);
78
+ constructor(built: BuiltRepository<T>);
79
+ constructor();
80
+ constructor(
81
+ typeOrConnectionOrBuilt?: Constructable<T> | IConnection | BuiltRepository<T>,
82
+ connectionOrOptions?: IConnection | ReadonlyRepositoryMappingOptions<T>,
83
+ ) {
84
+ storedEnrichments.set(this, []);
85
+ if (typeOrConnectionOrBuilt === undefined) {
86
+ this.type = untyped();
87
+ return;
88
+ }
89
+ const built = builtOf(typeOrConnectionOrBuilt, connectionOrOptions);
90
+ if (!built) {
91
+ this.type = typeOrConnectionOrBuilt as Constructable<T>;
92
+ return;
93
+ }
94
+ this.type = built.type;
95
+ this.connection = built.connection;
96
+ this.rowConverter = built.rowConverter;
97
+ this.objectConverter = built.objectConverter;
98
+ this.entityMappers = built.entityMapper;
99
+ this.propertyMappers = built.propertyMappings;
100
+ this.statementMappers = new StatementMappers(built.entityMapper, built.propertyMappings);
101
+ this.readonlyStatements = built.statements;
102
+ }
103
+
104
+ addMiddleware = (middleware: ICommandMiddleware): this => {
105
+ this.middlewares.push(middleware);
106
+ return this;
107
+ };
108
+
109
+ addEnriched<TRelated extends object>(
110
+ enrichment: Enrichment,
111
+ via: IReadonlyRepository<TRelated>,
112
+ strategy?: IReadonlyEnrichmentStrategy<T & object>,
113
+ ): this {
114
+ const chosen = strategy ?? new DefaultReadonlyEnrichmentStrategy<T & object>();
115
+ this.entries().push(
116
+ new StoredEnrichment<T & object>(
117
+ enrichment,
118
+ (parents, sources) => chosen.apply(via, enrichment, parents, sources),
119
+ ),
120
+ );
121
+ return this;
122
+ }
123
+
124
+ async *read(
125
+ query?: ReadQuery,
126
+ parameters?: Parameter[],
127
+ options?: ReadonlyRepositoryMappingOptions<T>,
128
+ ): AsyncIterable<T> {
129
+ for await (const sourced of this.readTracked(query, parameters, options)) yield sourced.item;
130
+ }
131
+
132
+ async readSingle(
133
+ query?: ReadQuery,
134
+ parameters?: Parameter[],
135
+ options?: ReadonlyRepositoryMappingOptions<T>,
136
+ ): Promise<T | undefined> {
137
+ for await (const item of this.read(query, parameters, options)) return item;
138
+ return undefined;
139
+ }
140
+
141
+ protected get enriched(): boolean {
142
+ return this.entries().length > 0;
143
+ }
144
+
145
+ protected command = (): ICommand =>
146
+ this.middlewares.reduce(
147
+ (command, middleware) => command.addMiddleware(middleware),
148
+ this.connection!.createCommand(),
149
+ );
150
+
151
+ protected column = (property: string): string => this.statementMappers.column(property);
152
+
153
+ protected cell = (
154
+ property: string,
155
+ value: Cell,
156
+ fieldsApplied: boolean,
157
+ options?: ReadonlyRepositoryMappingOptions<T>,
158
+ ): Cell => {
159
+ const objects = options?.objectConverter ?? this.objectConverter;
160
+ const field =
161
+ objects instanceof MetaDataRowTypeConverter ? objects.fields[property] : undefined;
162
+ return field && !fieldsApplied ? field.reverseConvert(value) : value;
163
+ };
164
+
165
+ private entries = (): StoredEnrichment<T & object>[] =>
166
+ storedEnrichments.get(this) as StoredEnrichment<T & object>[];
167
+
168
+ private mappers = (options?: ReadonlyRepositoryMappingOptions<T>): StatementMappers =>
169
+ options?.entityMapper === undefined && options?.propertyMappings === undefined
170
+ ? this.statementMappers
171
+ : new StatementMappers(
172
+ options?.entityMapper ?? this.entityMappers,
173
+ options?.propertyMappings ?? this.propertyMappers,
174
+ );
175
+
176
+ private rowConverterOf = (options?: ReadonlyRepositoryMappingOptions<T>): TypeConverter<Cells, Cells> | undefined =>
177
+ options?.rowConverter ?? this.rowConverter;
178
+
179
+ private objects = (options?: ReadonlyRepositoryMappingOptions<T>): TypeConverter<T, Cells> =>
180
+ options?.objectConverter ??
181
+ this.objectConverter ??
182
+ (() => {
183
+ throw new DatasourceError("Object converter required");
184
+ })();
185
+
186
+ private async *readTracked(
187
+ query?: ReadQuery,
188
+ parameters?: Parameter[],
189
+ options?: ReadonlyRepositoryMappingOptions<T>,
190
+ ): AsyncIterable<Sourced<T>> {
191
+ const mappers = this.mappers(options);
192
+ const statement = mappers.apply(
193
+ query instanceof ExecuteStoredProcedureStatement ? query : this.readQuery(query, mappers, options),
194
+ (name, value) => this.cell(name, value, false, options),
195
+ );
196
+ const listed =
197
+ parameters ??
198
+ (statement instanceof SelectStatement ? statement.where?.parameters : undefined);
199
+ yield* this.apply(this.readItems(statement, listed, mappers, this.rowConverterOf(options), this.objects(options)));
200
+ }
201
+
202
+ private async *apply(pairs: AsyncIterable<Sourced<T>>): AsyncIterable<Sourced<T>> {
203
+ if (!this.enriched) {
204
+ yield* pairs;
205
+ return;
206
+ }
207
+ yield* this.sourced(pairs);
208
+ }
209
+
210
+ private convertObject = (row: Cells, objects: TypeConverter<T, Cells>): T =>
211
+ objects instanceof MetaDataRowTypeConverter
212
+ ? objects.convert(row, this.type)
213
+ : objects.convert(row);
214
+
215
+ private async *readItems(
216
+ query: IStatement | undefined,
217
+ parameters: Parameter[] | undefined,
218
+ mappers: StatementMappers,
219
+ rows: TypeConverter<Cells, Cells> | undefined,
220
+ objects: TypeConverter<T, Cells>,
221
+ ): AsyncIterable<Sourced<T>> {
222
+ const statement = query ?? this.readonlyStatements!.select();
223
+ const reader = await executeReader(this.command(), statement, parameters);
224
+ try {
225
+ while (await reader.next()) {
226
+ const renamed = this.columnToPropertyName(
227
+ reader.current ??
228
+ (() => {
229
+ throw new DatasourceError("Reader current must be a row");
230
+ })(),
231
+ mappers,
232
+ );
233
+ yield {
234
+ item: this.convertObject(rows ? rows.convert(renamed) : renamed, objects),
235
+ source: renamed,
236
+ };
237
+ }
238
+ } finally {
239
+ await reader.dispose();
240
+ }
241
+ }
242
+
243
+ private async *sourced(pairs: AsyncIterable<Sourced<T>>): AsyncIterable<Sourced<T>> {
244
+ const items: T[] = [];
245
+ const sources: (Row | undefined)[] = [];
246
+ for await (const sourced of pairs) {
247
+ items.push(sourced.item);
248
+ sources.push(sourced.source);
249
+ }
250
+ await this.fill(items as (T & object)[], sources);
251
+ for (let index = 0; index < items.length; index++)
252
+ yield { item: items[index]!, source: sources[index] };
253
+ }
254
+
255
+ private fill = async (parents: (T & object)[], sources?: (Row | undefined)[]): Promise<void> => {
256
+ for (const entry of this.entries()) await entry.apply(parents, sources);
257
+ };
258
+
259
+ private columnToPropertyName = (row: Cells, mappers: StatementMappers): Cells =>
260
+ Object.fromEntries(Object.entries(row).map(([key, value]) => [mappers.property(key), value]));
261
+
262
+ private readQuery = (
263
+ query: ISelectStatement | IWhere | undefined,
264
+ mappers: StatementMappers,
265
+ options?: ReadonlyRepositoryMappingOptions<T>,
266
+ ): ISelectStatement | undefined =>
267
+ !query
268
+ ? this.readonlyStatements?.select()
269
+ : "where" in query
270
+ ? query
271
+ : this.readonlyStatements
272
+ ? this.readonlyStatements.select(
273
+ mappers.applyWhere(query, (name, cell) => this.cell(name, cell, false, options))!,
274
+ )
275
+ : new SelectStatement({ where: query });
276
+ }
@@ -0,0 +1,53 @@
1
+ import type { IConnection } from "./IConnection.ts";
2
+ import type { Constructable } from "./converters/Constructable.ts";
3
+ import { MetaDataRowTypeConverter } from "./converters/MetaDataRowTypeConverter.ts";
4
+ import { fieldNamesOf } from "./createReadonlyRepositoryMappingOptions.ts";
5
+ import type { BuiltRepository } from "./BuiltRepository.ts";
6
+ import type { IMapper } from "./mappers/IMapper.ts";
7
+ import type { ReadonlyRepositoryMappingOptions } from "./ReadonlyRepositoryMappingOptions.ts";
8
+ import { ReadonlyRepositoryStatements } from "./ReadonlyRepositoryStatements.ts";
9
+ import { IdentityMapper } from "./mappers/IdentityMapper.ts";
10
+
11
+ export class ReadonlyRepositoryBuilder<T = object> {
12
+ protected entityMapper: IMapper<string, string> = new IdentityMapper();
13
+ protected propertyMapper: IMapper<string, string> = new IdentityMapper();
14
+
15
+ parts = (connection: IConnection, options: ReadonlyRepositoryMappingOptions<T>): BuiltRepository<T> => {
16
+ const rowConverter = options.rowConverter;
17
+ const objectConverter = options.objectConverter ?? new MetaDataRowTypeConverter<T>();
18
+ const entityMapper = options.entityMapper ?? new IdentityMapper<string>();
19
+ const propertyMappings = options.propertyMappings ?? new IdentityMapper<string>();
20
+ this.entityMapper = entityMapper;
21
+ this.propertyMapper = propertyMappings;
22
+ const entity = entityMapper.map(options.entity ?? options.type?.name ?? "");
23
+ const names = options.readProperties ?? (options.type ? fieldNamesOf(options.type) : []);
24
+ if (objectConverter instanceof MetaDataRowTypeConverter && options.type) {
25
+ const instance = new options.type() as Record<string, string | number | boolean | bigint | null | object>;
26
+ objectConverter.references.clear();
27
+ objectConverter.referenceColumns = propertyMappings;
28
+ for (const name of names) {
29
+ const value = instance[name];
30
+ if (value !== null && typeof value === "object" && !Array.isArray(value))
31
+ objectConverter.references.add(name);
32
+ }
33
+ }
34
+ const columns = [...names]
35
+ .map((name) => propertyMappings.map(name))
36
+ .sort((left, right) => left.localeCompare(right));
37
+ return {
38
+ connection,
39
+ rowConverter,
40
+ objectConverter,
41
+ propertyMappings,
42
+ entityMapper,
43
+ statements: this.statements(entity, columns),
44
+ ids: this.ids(options),
45
+ type: options.type ?? (Object as never as Constructable<T>),
46
+ };
47
+ };
48
+
49
+ protected ids = (_options: ReadonlyRepositoryMappingOptions<T>): string[] => [];
50
+
51
+ protected statements = (table: string, columns: string[]): ReadonlyRepositoryStatements =>
52
+ new ReadonlyRepositoryStatements(table, columns);
53
+ }
@@ -0,0 +1,15 @@
1
+ import type { Cell, Cells } from "./converters/Cell.ts";
2
+ import type { Constructable } from "./converters/Constructable.ts";
3
+ import type { TypeConverter } from "./converters/TypeConverter.ts";
4
+ import type { IMapper } from "./mappers/IMapper.ts";
5
+
6
+ export type ReadonlyRepositoryMappingOptions<T = Cells> = {
7
+ entity?: string;
8
+ entityMapper?: IMapper<string, string>;
9
+ propertyMappings?: IMapper<string, string>;
10
+ rowConverter?: TypeConverter<Cells, Cells>;
11
+ objectConverter?: TypeConverter<T, Cells>;
12
+ type?: Constructable<T>;
13
+ rowTypeConverters?: Record<string, TypeConverter<Cell, Cell>>;
14
+ readProperties?: string[];
15
+ };
@@ -0,0 +1,13 @@
1
+ import type { ISelectStatement } from "./statements/ISelectStatement.ts";
2
+ import type { IWhere } from "./statements/IWhere.ts";
3
+ import { SelectStatement } from "./statements/SelectStatement.ts";
4
+
5
+ export class ReadonlyRepositoryStatements {
6
+ constructor(
7
+ protected readonly table: string,
8
+ readonly readColumns: readonly string[],
9
+ ) {}
10
+
11
+ select = (where?: IWhere): ISelectStatement =>
12
+ new SelectStatement({ table: this.table, fields: [...this.readColumns], where });
13
+ }
@@ -0,0 +1,14 @@
1
+ import type { IConnection } from "./IConnection.ts";
2
+ import type { ICRUDRepository } from "./ICRUDRepository.ts";
3
+ import type { IReadonlyRepository } from "./IReadonlyRepository.ts";
4
+
5
+ export class RepositoryAccess {
6
+ constructor(
7
+ private readonly createRepo: (connection: IConnection) => ICRUDRepository,
8
+ private readonly createReadonlyRepo: (connection: IConnection) => IReadonlyRepository,
9
+ private readonly connection: IConnection,
10
+ ) {}
11
+
12
+ create = (): ICRUDRepository => this.createRepo(this.connection);
13
+ createReadonly = (): IReadonlyRepository => this.createReadonlyRepo(this.connection);
14
+ }