@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.
- package/dist/ArrayReader.d.ts +12 -0
- package/dist/BatchCommandIBulkWriteStrategy.d.ts +33 -0
- package/dist/BuiltRepository.d.ts +16 -0
- package/dist/BulkCRUDRepository.d.ts +17 -0
- package/dist/BulkCommand.d.ts +5 -0
- package/dist/BulkWriteEnrichment.d.ts +4 -0
- package/dist/CRUDRepository.d.ts +40 -0
- package/dist/CRUDRepositoryBuilder.d.ts +19 -0
- package/dist/CRUDRepositoryOptions.d.ts +7 -0
- package/dist/CRUDRepositoryStatements.d.ts +17 -0
- package/dist/CascadeDeleteEnrichmentStrategy.d.ts +7 -0
- package/dist/CascadeDeleteUpdateEnrichmentStrategy.d.ts +8 -0
- package/dist/CommandMiddlewareHost.d.ts +22 -0
- package/dist/ConsoleCommandMiddleware.d.ts +14 -0
- package/dist/CreateEnrichmentStrategy.d.ts +14 -0
- package/dist/Datasource.d.ts +30 -0
- package/dist/DatasourceError.d.ts +3 -0
- package/dist/DatasourceFactory.d.ts +12 -0
- package/dist/DatasourceOptions.d.ts +1 -0
- package/dist/DatasourceUrl.d.ts +12 -0
- package/dist/DatasourceUrlParser.d.ts +4 -0
- package/dist/DefaultCreateEnrichmentStrategy.d.ts +7 -0
- package/dist/DefaultReadonlyEnrichmentStrategy.d.ts +19 -0
- package/dist/DefaultUpdateEnrichmentStrategy.d.ts +7 -0
- package/dist/DefaultWriteEnrichmentStrategy.d.ts +21 -0
- package/dist/DeleteEnrichmentStrategy.d.ts +11 -0
- package/dist/DriverLoader.d.ts +5 -0
- package/dist/Enrichment.d.ts +13 -0
- package/dist/EnrichmentPropertyType.d.ts +7 -0
- package/dist/ExpectConsoleMiddleware.d.ts +15 -0
- package/dist/FirstResultReader.d.ts +19 -0
- package/dist/HashsetOptimizedReadonlyEnrichmentStrategy.d.ts +9 -0
- package/dist/IBulkWriteStrategy.d.ts +12 -0
- package/dist/ICRUDRepository.d.ts +12 -0
- package/dist/ICRUDRepositoryFactory.d.ts +7 -0
- package/dist/ICommand.d.ts +20 -0
- package/dist/ICommandMiddleware.d.ts +12 -0
- package/dist/IConnection.d.ts +12 -0
- package/dist/IDatasource.d.ts +18 -0
- package/dist/IDatasourceFactory.d.ts +5 -0
- package/dist/IDriver.d.ts +19 -0
- package/dist/IEnriched.d.ts +6 -0
- package/dist/IReader.d.ts +8 -0
- package/dist/IReadonlyEnrichmentStrategy.d.ts +7 -0
- package/dist/IReadonlyRepository.d.ts +11 -0
- package/dist/IRepository.d.ts +4 -0
- package/dist/IRepositoryFactory.d.ts +7 -0
- package/dist/IRepositoryTree.d.ts +4 -0
- package/dist/IRepositoryTreeNode.d.ts +7 -0
- package/dist/ITransaction.d.ts +8 -0
- package/dist/IUnitOfWork.d.ts +5 -0
- package/dist/IWriteEnrichmentStrategy.d.ts +7 -0
- package/dist/Information.d.ts +5 -0
- package/dist/IsolationLevel.d.ts +7 -0
- package/dist/LazyWriteEnrichmentStrategy.d.ts +4 -0
- package/dist/NestedToObjectEnrichmentStrategy.d.ts +10 -0
- package/dist/Parameter.d.ts +7 -0
- package/dist/ParameterDirection.d.ts +7 -0
- package/dist/ProviderCatalog.d.ts +7 -0
- package/dist/ProviderNotImplementedError.d.ts +4 -0
- package/dist/ProviderNotInstalledError.d.ts +4 -0
- package/dist/ReadonlyRepository.d.ts +59 -0
- package/dist/ReadonlyRepositoryBuilder.d.ts +12 -0
- package/dist/ReadonlyRepositoryMappingOptions.d.ts +14 -0
- package/dist/ReadonlyRepositoryStatements.d.ts +8 -0
- package/dist/RepositoryAccess.d.ts +11 -0
- package/dist/RepositoryFactory.d.ts +23 -0
- package/dist/RepositoryNotRegisteredError.d.ts +4 -0
- package/dist/RepositoryTree.d.ts +6 -0
- package/dist/RepositoryTreeNode.d.ts +9 -0
- package/dist/Response.d.ts +7 -0
- package/dist/Row.d.ts +2 -0
- package/dist/SingleCommandIBulkWriteStrategy.d.ts +11 -0
- package/dist/StatementMappers.d.ts +16 -0
- package/dist/StoredEnrichment.d.ts +11 -0
- package/dist/StoredProcedureBulkWriteStrategy.d.ts +27 -0
- package/dist/StreamingReader.d.ts +16 -0
- package/dist/UnitOfWorkTransaction.d.ts +12 -0
- package/dist/UpdateEnrichmentStrategy.d.ts +18 -0
- package/dist/WriteMode.d.ts +1 -0
- package/dist/builders/Field.d.ts +5 -0
- package/dist/builders/Scalar.d.ts +1 -0
- package/dist/builders/index.d.ts +2 -0
- package/dist/collectAsync.d.ts +1 -0
- package/dist/converters/Cell.d.ts +2 -0
- package/dist/converters/ChangeCasingConverter.d.ts +7 -0
- package/dist/converters/Constructable.d.ts +1 -0
- package/dist/converters/MetaDataRowTypeConverter.d.ts +14 -0
- package/dist/converters/PluralizerConverter.d.ts +4 -0
- package/dist/converters/RegexConverter.d.ts +7 -0
- package/dist/converters/ReplaceConverter.d.ts +7 -0
- package/dist/converters/RowTypeConverter.d.ts +10 -0
- package/dist/converters/ToLowerCaseConverter.d.ts +4 -0
- package/dist/converters/ToUpperCaseConverter.d.ts +4 -0
- package/dist/converters/TypeConverter.d.ts +5 -0
- package/dist/createCRUDRepositoryOptions.d.ts +7 -0
- package/dist/createReadonlyRepositoryMappingOptions.d.ts +6 -0
- package/dist/dotEnv.d.ts +5 -0
- package/dist/index.d.ts +119 -0
- package/dist/mappers/ChangeCasingMapper.d.ts +9 -0
- package/dist/mappers/DictionaryMapper.d.ts +8 -0
- package/dist/mappers/FlatToNestedMapper.d.ts +20 -0
- package/dist/mappers/IFlatToNestedMapper.d.ts +6 -0
- package/dist/mappers/IMapper.d.ts +4 -0
- package/dist/mappers/IdentityMapper.d.ts +5 -0
- package/dist/mappers/PluralizerMapper.d.ts +6 -0
- package/dist/mappers/RowTypeMapper.d.ts +6 -0
- package/dist/mappers/TransformConverterMapper.d.ts +5 -0
- package/dist/mappers/TransformMapper.d.ts +6 -0
- package/dist/mappers/TypeMap.d.ts +8 -0
- package/dist/mappers/TypeMapGroup.d.ts +5 -0
- package/dist/mocks/index.d.ts +9 -0
- package/dist/mocks/mock-command.d.ts +28 -0
- package/dist/mocks/mock-connection.d.ts +22 -0
- package/dist/mocks/mock-datasource.d.ts +24 -0
- package/dist/mocks/mock-driver.d.ts +15 -0
- package/dist/mocks/mock-reader.d.ts +14 -0
- package/dist/mocks/mock-repository.d.ts +42 -0
- package/dist/mocks/mock-select-statement.d.ts +10 -0
- package/dist/mocks/mock-transaction.d.ts +16 -0
- package/dist/mocks/mock-where.d.ts +8 -0
- package/dist/parametersToRecord.d.ts +2 -0
- package/dist/readerToAsyncIterable.d.ts +2 -0
- package/dist/splitStatements.d.ts +1 -0
- package/dist/statementParameters.d.ts +1 -0
- package/dist/statementUsesParameter.d.ts +1 -0
- package/dist/statements/Aggregate.d.ts +6 -0
- package/dist/statements/ArrayExpression.d.ts +5 -0
- package/dist/statements/BulkDeleteStatement.d.ts +11 -0
- package/dist/statements/BulkDeleteStatementTextRenderer.d.ts +4 -0
- package/dist/statements/BulkInsertStatement.d.ts +12 -0
- package/dist/statements/BulkInsertStatementTextRenderer.d.ts +4 -0
- package/dist/statements/BulkUpdateStatement.d.ts +16 -0
- package/dist/statements/BulkUpdateStatementTextRenderer.d.ts +8 -0
- package/dist/statements/CheckConstraint.d.ts +7 -0
- package/dist/statements/Cmp.d.ts +9 -0
- package/dist/statements/Column.d.ts +9 -0
- package/dist/statements/ColumnDefault.d.ts +5 -0
- package/dist/statements/Condition.d.ts +3 -0
- package/dist/statements/ConditionRenderer.d.ts +12 -0
- package/dist/statements/CreateIndexStatement.d.ts +10 -0
- package/dist/statements/CreateIndexStatementTextRenderer.d.ts +5 -0
- package/dist/statements/CreateTableStatement.d.ts +11 -0
- package/dist/statements/CreateTableStatementTextRenderer.d.ts +18 -0
- package/dist/statements/DefaultStatementTextRenderer.d.ts +5 -0
- package/dist/statements/DeleteStatement.d.ts +9 -0
- package/dist/statements/DeleteStatementTextRenderer.d.ts +7 -0
- package/dist/statements/ExecuteStoredProcedureStatement.d.ts +9 -0
- package/dist/statements/ExecuteStoredProcedureStatementTextRenderer.d.ts +4 -0
- package/dist/statements/ExpressionEvaluator.d.ts +5 -0
- package/dist/statements/ExpressionRenderer.d.ts +8 -0
- package/dist/statements/ForeignKey.d.ts +19 -0
- package/dist/statements/IBulkDeleteStatement.d.ts +3 -0
- package/dist/statements/IBulkInsertStatement.d.ts +3 -0
- package/dist/statements/IBulkUpdateStatement.d.ts +3 -0
- package/dist/statements/ICondition.d.ts +4 -0
- package/dist/statements/IConditionVisitor.d.ts +6 -0
- package/dist/statements/ICreateIndexStatement.d.ts +3 -0
- package/dist/statements/ICreateTableStatement.d.ts +3 -0
- package/dist/statements/IDeleteStatement.d.ts +5 -0
- package/dist/statements/IExecuteStoredProcedureStatement.d.ts +3 -0
- package/dist/statements/IExpression.d.ts +2 -0
- package/dist/statements/IInsertStatement.d.ts +3 -0
- package/dist/statements/IReturnStatement.d.ts +3 -0
- package/dist/statements/ISelectStatement.d.ts +5 -0
- package/dist/statements/IStatement.d.ts +4 -0
- package/dist/statements/IStatementVisitor.d.ts +26 -0
- package/dist/statements/ITableConstraint.d.ts +5 -0
- package/dist/statements/IUpdateStatement.d.ts +5 -0
- package/dist/statements/IWhere.d.ts +6 -0
- package/dist/statements/Identifier.d.ts +5 -0
- package/dist/statements/InsertStatement.d.ts +9 -0
- package/dist/statements/InsertStatementTextRenderer.d.ts +4 -0
- package/dist/statements/Join.d.ts +14 -0
- package/dist/statements/Literal.d.ts +6 -0
- package/dist/statements/Native.d.ts +5 -0
- package/dist/statements/NotNull.d.ts +4 -0
- package/dist/statements/Operator.d.ts +107 -0
- package/dist/statements/OrderBy.d.ts +10 -0
- package/dist/statements/PrimaryKey.d.ts +7 -0
- package/dist/statements/ReturnStatement.d.ts +9 -0
- package/dist/statements/ReturnStatementTextRenderer.d.ts +4 -0
- package/dist/statements/SelectInsertedIdStatement.d.ts +8 -0
- package/dist/statements/SelectInsertedIdStatementTextRenderer.d.ts +4 -0
- package/dist/statements/SelectStatement.d.ts +20 -0
- package/dist/statements/SelectStatementOptions.d.ts +15 -0
- package/dist/statements/SelectStatementTextRenderer.d.ts +19 -0
- package/dist/statements/StatementEvaluator.d.ts +4 -0
- package/dist/statements/StatementParser.d.ts +4 -0
- package/dist/statements/StatementRenderer.d.ts +42 -0
- package/dist/statements/StatementTextRenderer.d.ts +14 -0
- package/dist/statements/Subquery.d.ts +6 -0
- package/dist/statements/UniqueConstraint.d.ts +7 -0
- package/dist/statements/UpdateStatement.d.ts +14 -0
- package/dist/statements/UpdateStatementTextRenderer.d.ts +14 -0
- package/dist/statements/Where.d.ts +16 -0
- package/dist/statements/WhereText.d.ts +8 -0
- package/dist/statements/index.d.ts +75 -0
- package/dist/stubs/StubCommand.d.ts +15 -0
- package/dist/stubs/StubConnection.d.ts +13 -0
- package/dist/stubs/StubDatasource.d.ts +20 -0
- package/dist/stubs/StubReader.d.ts +11 -0
- package/dist/stubs/StubRepository.d.ts +22 -0
- package/dist/stubs/StubTransaction.d.ts +10 -0
- package/dist/stubs/createStubDatasource.d.ts +2 -0
- package/dist/stubs/index.d.ts +7 -0
- package/dist/stubs/notImplemented.d.ts +1 -0
- package/package.json +24 -4
- package/src/ArrayReader.test.ts +23 -0
- package/src/ArrayReader.ts +32 -0
- package/src/BatchCommandIBulkWriteStrategy.ts +228 -0
- package/src/BuiltRepository.ts +17 -0
- package/src/BulkCRUDRepository.test.ts +183 -0
- package/src/BulkCRUDRepository.ts +84 -0
- package/src/BulkCommand.ts +6 -0
- package/src/BulkWriteEnrichment.ts +19 -0
- package/src/BulkWriteStrategy.test.ts +293 -0
- package/src/CRUDRepository.test.ts +420 -0
- package/src/CRUDRepository.ts +264 -0
- package/src/CRUDRepositoryBuilder.ts +53 -0
- package/src/CRUDRepositoryOptions.test.ts +76 -0
- package/src/CRUDRepositoryOptions.ts +8 -0
- package/src/CRUDRepositoryStatements.ts +43 -0
- package/src/CascadeDeleteEnrichmentStrategy.ts +51 -0
- package/src/CascadeDeleteUpdateEnrichmentStrategy.ts +28 -0
- package/src/Command.test.ts +105 -0
- package/src/CommandMiddlewareHost.test.ts +98 -0
- package/src/CommandMiddlewareHost.ts +113 -0
- package/src/Connection.test.ts +34 -0
- package/src/ConsoleCommandMiddleware.test.ts +149 -0
- package/src/ConsoleCommandMiddleware.ts +64 -0
- package/src/CreateEnrichmentStrategy.ts +82 -0
- package/src/Datasource.test.ts +63 -0
- package/src/Datasource.ts +152 -0
- package/src/DatasourceError.test.ts +10 -0
- package/src/DatasourceError.ts +6 -0
- package/src/DatasourceFactory.test.ts +159 -0
- package/src/DatasourceFactory.ts +86 -0
- package/src/DatasourceOptions.ts +1 -0
- package/src/DatasourceUrl.ts +37 -0
- package/src/DatasourceUrlParser.test.ts +173 -0
- package/src/DatasourceUrlParser.ts +188 -0
- package/src/DefaultCreateEnrichmentStrategy.ts +21 -0
- package/src/DefaultReadonlyEnrichmentStrategy.ts +164 -0
- package/src/DefaultUpdateEnrichmentStrategy.ts +40 -0
- package/src/DefaultWriteEnrichmentStrategy.ts +151 -0
- package/src/DeleteEnrichmentStrategy.ts +56 -0
- package/src/DriverLoader.ts +97 -0
- package/src/Enrichment.ts +15 -0
- package/src/EnrichmentPropertyType.ts +9 -0
- package/src/ExpectConsoleMiddleware.test.ts +79 -0
- package/src/ExpectConsoleMiddleware.ts +47 -0
- package/src/FirstResultReader.test.ts +43 -0
- package/src/FirstResultReader.ts +49 -0
- package/src/HashsetOptimizedReadonlyEnrichmentStrategy.ts +80 -0
- package/src/IBulkWriteStrategy.ts +13 -0
- package/src/ICRUDRepository.ts +13 -0
- package/src/ICRUDRepositoryFactory.ts +8 -0
- package/src/ICommand.ts +45 -0
- package/src/ICommandMiddleware.ts +20 -0
- package/src/IConnection.ts +13 -0
- package/src/IDatasource.ts +27 -0
- package/src/IDatasourceFactory.ts +6 -0
- package/src/IDriver.ts +24 -0
- package/src/IEnriched.ts +11 -0
- package/src/IReader.ts +8 -0
- package/src/IReadonlyEnrichmentStrategy.ts +19 -0
- package/src/IReadonlyRepository.ts +21 -0
- package/src/IRepository.ts +5 -0
- package/src/IRepositoryFactory.ts +8 -0
- package/src/IRepositoryTree.ts +5 -0
- package/src/IRepositoryTreeNode.ts +8 -0
- package/src/ITransaction.ts +9 -0
- package/src/IUnitOfWork.ts +5 -0
- package/src/IWriteEnrichmentStrategy.ts +8 -0
- package/src/Information.ts +5 -0
- package/src/IsolationLevel.test.ts +13 -0
- package/src/IsolationLevel.ts +8 -0
- package/src/LazyWriteEnrichmentStrategy.ts +5 -0
- package/src/NestedToObjectEnrichmentStrategy.ts +33 -0
- package/src/Parameter.ts +8 -0
- package/src/ParameterDirection.ts +9 -0
- package/src/ProviderCatalog.test.ts +110 -0
- package/src/ProviderCatalog.ts +21 -0
- package/src/ProviderNotImplementedError.test.ts +11 -0
- package/src/ProviderNotImplementedError.ts +9 -0
- package/src/ProviderNotInstalledError.test.ts +11 -0
- package/src/ProviderNotInstalledError.ts +9 -0
- package/src/ReadonlyRepository.test.ts +406 -0
- package/src/ReadonlyRepository.ts +276 -0
- package/src/ReadonlyRepositoryBuilder.ts +53 -0
- package/src/ReadonlyRepositoryMappingOptions.ts +15 -0
- package/src/ReadonlyRepositoryStatements.ts +13 -0
- package/src/RepositoryAccess.ts +14 -0
- package/src/RepositoryFactory.test.ts +94 -0
- package/src/RepositoryFactory.ts +115 -0
- package/src/RepositoryNotRegisteredError.ts +9 -0
- package/src/RepositoryTree.ts +6 -0
- package/src/RepositoryTreeNode.ts +11 -0
- package/src/Response.ts +15 -0
- package/src/Row.ts +3 -0
- package/src/SingleCommandIBulkWriteStrategy.ts +35 -0
- package/src/StatementMappers.test.ts +221 -0
- package/src/StatementMappers.ts +110 -0
- package/src/StoredEnrichment.ts +25 -0
- package/src/StoredProcedureBulkWriteStrategy.ts +164 -0
- package/src/StreamingReader.test.ts +126 -0
- package/src/StreamingReader.ts +64 -0
- package/src/Transaction.test.ts +37 -0
- package/src/UnitOfWorkTransaction.test.ts +43 -0
- package/src/UnitOfWorkTransaction.ts +50 -0
- package/src/UpdateEnrichmentStrategy.ts +97 -0
- package/src/UserViewCRUDRepository.test.ts +323 -0
- package/src/WriteMode.ts +1 -0
- package/src/builders/Field.ts +6 -0
- package/src/builders/Scalar.ts +1 -0
- package/src/builders/builders.test.ts +404 -0
- package/src/builders/index.ts +2 -0
- package/src/collectAsync.ts +7 -0
- package/src/converters/Cell.ts +10 -0
- package/src/converters/ChangeCasingConverter.test.ts +34 -0
- package/src/converters/ChangeCasingConverter.ts +59 -0
- package/src/converters/Constructable.ts +1 -0
- package/src/converters/MetaDataRowTypeConverter.ts +80 -0
- package/src/converters/PluralizerConverter.test.ts +43 -0
- package/src/converters/PluralizerConverter.ts +67 -0
- package/src/converters/RegexConverter.test.ts +11 -0
- package/src/converters/RegexConverter.ts +14 -0
- package/src/converters/ReplaceConverter.test.ts +9 -0
- package/src/converters/ReplaceConverter.ts +6 -0
- package/src/converters/RowTypeConverter.test.ts +79 -0
- package/src/converters/RowTypeConverter.ts +33 -0
- package/src/converters/ToLowerCaseConverter.test.ts +9 -0
- package/src/converters/ToLowerCaseConverter.ts +4 -0
- package/src/converters/ToUpperCaseConverter.test.ts +9 -0
- package/src/converters/ToUpperCaseConverter.ts +4 -0
- package/src/converters/TypeConverter.ts +6 -0
- package/src/createCRUDRepositoryOptions.ts +21 -0
- package/src/createReadonlyRepositoryMappingOptions.ts +26 -0
- package/src/dotEnv.test.ts +21 -0
- package/src/dotEnv.ts +16 -0
- package/src/edgeCases.test.ts +485 -0
- package/src/index.ts +222 -0
- package/src/mappers/ChangeCasingMapper.test.ts +32 -0
- package/src/mappers/ChangeCasingMapper.ts +15 -0
- package/src/mappers/DictionaryMapper.test.ts +69 -0
- package/src/mappers/DictionaryMapper.ts +16 -0
- package/src/mappers/FlatToNestedMapper.test.ts +269 -0
- package/src/mappers/FlatToNestedMapper.ts +127 -0
- package/src/mappers/IFlatToNestedMapper.ts +7 -0
- package/src/mappers/IMapper.ts +4 -0
- package/src/mappers/IdentityMapper.test.ts +12 -0
- package/src/mappers/IdentityMapper.ts +6 -0
- package/src/mappers/PluralizerMapper.test.ts +40 -0
- package/src/mappers/PluralizerMapper.ts +9 -0
- package/src/mappers/RowTypeMapper.test.ts +12 -0
- package/src/mappers/RowTypeMapper.ts +13 -0
- package/src/mappers/TransformConverterMapper.test.ts +181 -0
- package/src/mappers/TransformConverterMapper.ts +11 -0
- package/src/mappers/TransformMapper.ts +8 -0
- package/src/mappers/TypeMap.ts +10 -0
- package/src/mappers/TypeMapGroup.ts +6 -0
- package/src/mappers/transformMapper.test.ts +66 -0
- package/src/mocks/MockCommand.test.ts +75 -0
- package/src/mocks/MockConnection.test.ts +34 -0
- package/src/mocks/MockDatasource.test.ts +40 -0
- package/src/mocks/MockReader.test.ts +17 -0
- package/src/mocks/MockRepository.test.ts +32 -0
- package/src/mocks/MockSelectStatement.test.ts +11 -0
- package/src/mocks/MockTransaction.test.ts +17 -0
- package/src/mocks/MockWhere.test.ts +11 -0
- package/src/mocks/index.ts +9 -0
- package/src/mocks/mock-command.ts +66 -0
- package/src/mocks/mock-connection.ts +57 -0
- package/src/mocks/mock-datasource.ts +65 -0
- package/src/mocks/mock-driver.ts +27 -0
- package/src/mocks/mock-reader.ts +38 -0
- package/src/mocks/mock-repository.ts +91 -0
- package/src/mocks/mock-select-statement.ts +17 -0
- package/src/mocks/mock-transaction.ts +31 -0
- package/src/mocks/mock-where.ts +13 -0
- package/src/parametersToRecord.test.ts +19 -0
- package/src/parametersToRecord.ts +11 -0
- package/src/public-surface.test.ts +23 -0
- package/src/readWithWhereClauseAndCustomFlatToNestedObjectMappingOptions.test.ts +126 -0
- package/src/readerToAsyncIterable.test.ts +39 -0
- package/src/readerToAsyncIterable.ts +11 -0
- package/src/repository.test.ts +410 -0
- package/src/repository.type.test.ts +29 -0
- package/src/splitStatements.ts +99 -0
- package/src/statementParameters.ts +22 -0
- package/src/statementUsesParameter.ts +4 -0
- package/src/statements/Aggregate.ts +9 -0
- package/src/statements/ArrayExpression.ts +5 -0
- package/src/statements/BulkDeleteStatement.ts +18 -0
- package/src/statements/BulkDeleteStatementTextRenderer.ts +16 -0
- package/src/statements/BulkInsertStatement.ts +37 -0
- package/src/statements/BulkInsertStatementTextRenderer.ts +10 -0
- package/src/statements/BulkUpdateStatement.ts +24 -0
- package/src/statements/BulkUpdateStatementTextRenderer.ts +29 -0
- package/src/statements/CheckConstraint.ts +9 -0
- package/src/statements/Cmp.ts +12 -0
- package/src/statements/Column.ts +10 -0
- package/src/statements/ColumnDefault.ts +6 -0
- package/src/statements/Condition.ts +3 -0
- package/src/statements/ConditionRenderer.ts +17 -0
- package/src/statements/CreateIndexStatement.ts +18 -0
- package/src/statements/CreateIndexStatementTextRenderer.ts +11 -0
- package/src/statements/CreateTableStatement.ts +18 -0
- package/src/statements/CreateTableStatementTextRenderer.ts +92 -0
- package/src/statements/DefaultStatementTextRenderer.ts +9 -0
- package/src/statements/DeleteStatement.ts +15 -0
- package/src/statements/DeleteStatementTextRenderer.ts +12 -0
- package/src/statements/ExecuteStoredProcedureStatement.ts +15 -0
- package/src/statements/ExecuteStoredProcedureStatementTextRenderer.ts +15 -0
- package/src/statements/ExpressionEvaluator.ts +166 -0
- package/src/statements/ExpressionRenderer.ts +161 -0
- package/src/statements/ForeignKey.ts +23 -0
- package/src/statements/IBulkDeleteStatement.ts +3 -0
- package/src/statements/IBulkInsertStatement.ts +3 -0
- package/src/statements/IBulkUpdateStatement.ts +3 -0
- package/src/statements/ICondition.ts +5 -0
- package/src/statements/IConditionVisitor.ts +7 -0
- package/src/statements/ICreateIndexStatement.ts +3 -0
- package/src/statements/ICreateTableStatement.ts +3 -0
- package/src/statements/IDeleteStatement.ts +6 -0
- package/src/statements/IExecuteStoredProcedureStatement.ts +3 -0
- package/src/statements/IExpression.ts +1 -0
- package/src/statements/IInsertStatement.ts +3 -0
- package/src/statements/IReturnStatement.ts +3 -0
- package/src/statements/ISelectStatement.ts +6 -0
- package/src/statements/IStatement.ts +5 -0
- package/src/statements/IStatementVisitor.ts +27 -0
- package/src/statements/ITableConstraint.ts +6 -0
- package/src/statements/IUpdateStatement.ts +6 -0
- package/src/statements/IWhere.ts +7 -0
- package/src/statements/Identifier.ts +5 -0
- package/src/statements/InsertStatement.ts +15 -0
- package/src/statements/InsertStatementTextRenderer.ts +7 -0
- package/src/statements/Join.ts +26 -0
- package/src/statements/Literal.ts +6 -0
- package/src/statements/Native.ts +5 -0
- package/src/statements/NotNull.ts +3 -0
- package/src/statements/Operator.ts +234 -0
- package/src/statements/OrderBy.ts +19 -0
- package/src/statements/PrimaryKey.ts +9 -0
- package/src/statements/ReturnStatement.ts +15 -0
- package/src/statements/ReturnStatementTextRenderer.ts +15 -0
- package/src/statements/SelectInsertedIdStatement.test.ts +11 -0
- package/src/statements/SelectInsertedIdStatement.ts +11 -0
- package/src/statements/SelectInsertedIdStatementTextRenderer.ts +7 -0
- package/src/statements/SelectStatement.ts +34 -0
- package/src/statements/SelectStatementOptions.ts +16 -0
- package/src/statements/SelectStatementTextRenderer.ts +71 -0
- package/src/statements/StatementCompile.test.ts +231 -0
- package/src/statements/StatementEvaluator.ts +5 -0
- package/src/statements/StatementParser.test.ts +304 -0
- package/src/statements/StatementParser.ts +461 -0
- package/src/statements/StatementRenderer.ts +120 -0
- package/src/statements/StatementTextRenderer.ts +60 -0
- package/src/statements/Subquery.ts +6 -0
- package/src/statements/UniqueConstraint.ts +9 -0
- package/src/statements/UpdateStatement.ts +34 -0
- package/src/statements/UpdateStatementTextRenderer.ts +63 -0
- package/src/statements/Where.ts +250 -0
- package/src/statements/WhereText.ts +10 -0
- package/src/statements/index.ts +75 -0
- package/src/stubs/StubCommand.ts +30 -0
- package/src/stubs/StubConnection.ts +21 -0
- package/src/stubs/StubDatasource.test.ts +99 -0
- package/src/stubs/StubDatasource.ts +60 -0
- package/src/stubs/StubReader.ts +25 -0
- package/src/stubs/StubRepository.ts +42 -0
- package/src/stubs/StubTransaction.ts +17 -0
- package/src/stubs/createStubDatasource.ts +4 -0
- package/src/stubs/index.ts +7 -0
- package/src/stubs/notImplemented.ts +5 -0
- package/src/tests/contact/Address.ts +14 -0
- package/src/tests/contact/AddressType.ts +6 -0
- package/src/tests/contact/Base.ts +7 -0
- package/src/tests/contact/Contact.ts +12 -0
- package/src/tests/contact/ContactBase.ts +8 -0
- package/src/tests/contact/ContactChangeLog.ts +8 -0
- package/src/tests/contact/ContactGroup.ts +6 -0
- package/src/tests/contact/ContactGroupBase.ts +6 -0
- package/src/tests/contact/ContactGroupMember.ts +6 -0
- package/src/tests/contact/ContactSource.ts +6 -0
- package/src/tests/contact/ContactType.ts +6 -0
- package/src/tests/contact/ContactsService.test.ts +118 -0
- package/src/tests/contact/ContactsService.ts +32 -0
- package/src/tests/contact/ImportContactRequest.ts +4 -0
- package/src/tests/contact/ImportContactResult.ts +5 -0
- package/src/tests/contact/LegacyContact.ts +7 -0
- package/src/tests/contact/LegacyMigrationResult.ts +5 -0
- package/src/tests/contact/Phone.ts +9 -0
- package/src/tests/contact/PhoneType.ts +6 -0
- package/src/tests/contact/asContactsView.ts +63 -0
- package/src/tests/contact/contactColumns.ts +40 -0
- package/src/tests/contact/contactLookupIds.ts +32 -0
- package/src/tests/contact/contactLookups.ts +6 -0
- package/src/tests/contact/contactsParity.ts +63 -0
- package/src/tests/contact/contactsServiceOf.ts +38 -0
- package/src/tests/contact/contactsView.ts +31 -0
- package/src/tests/contact/expectContactsView.ts +23 -0
- package/src/tests/contact/extraContact.ts +61 -0
- package/src/tests/contact/logMapped.ts +5 -0
- package/src/tests/contact/seedContacts.ts +31 -0
- package/README.md +0 -3
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { IConnection } from "./IConnection.ts";
|
|
2
|
+
import { defaultId, fieldNamesOf, createCRUDRepositoryOptions } from "./createCRUDRepositoryOptions.ts";
|
|
3
|
+
import type { CRUDRepositoryOptions } from "./CRUDRepositoryOptions.ts";
|
|
4
|
+
import { CRUDRepository } from "./CRUDRepository.ts";
|
|
5
|
+
import { CRUDRepositoryStatements } from "./CRUDRepositoryStatements.ts";
|
|
6
|
+
import type { BuiltRepository } from "./BuiltRepository.ts";
|
|
7
|
+
import type { Constructable } from "./converters/Constructable.ts";
|
|
8
|
+
import { ReadonlyRepositoryBuilder } from "./ReadonlyRepositoryBuilder.ts";
|
|
9
|
+
import { ReadonlyRepositoryStatements } from "./ReadonlyRepositoryStatements.ts";
|
|
10
|
+
import type { ReadonlyRepositoryMappingOptions } from "./ReadonlyRepositoryMappingOptions.ts";
|
|
11
|
+
|
|
12
|
+
const isCrud = <T>(options: ReadonlyRepositoryMappingOptions<T>): options is CRUDRepositoryOptions<T> =>
|
|
13
|
+
"ids" in options || "write" in options;
|
|
14
|
+
|
|
15
|
+
const withIds = <T>(options: CRUDRepositoryOptions<T>): CRUDRepositoryOptions<T> =>
|
|
16
|
+
"ids" in options
|
|
17
|
+
? options
|
|
18
|
+
: {
|
|
19
|
+
...options,
|
|
20
|
+
ids: options.type ? defaultId(fieldNamesOf(options.type)) : ["id"],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const repositoryParts = <T>(
|
|
24
|
+
typeOrConnection: Constructable<T> | IConnection,
|
|
25
|
+
connectionOrOptions?: IConnection | CRUDRepositoryOptions<T>,
|
|
26
|
+
): { built: BuiltRepository<T>; statements: CRUDRepositoryStatements } => {
|
|
27
|
+
const builder = new CRUDRepositoryBuilder<T>();
|
|
28
|
+
const built =
|
|
29
|
+
typeof typeOrConnection === "function"
|
|
30
|
+
? builder.parts(
|
|
31
|
+
connectionOrOptions as IConnection,
|
|
32
|
+
createCRUDRepositoryOptions(typeOrConnection),
|
|
33
|
+
)
|
|
34
|
+
: builder.parts(typeOrConnection, withIds(connectionOrOptions as CRUDRepositoryOptions<T>));
|
|
35
|
+
return { built, statements: builder.crudStatements! };
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export class CRUDRepositoryBuilder<T = object> extends ReadonlyRepositoryBuilder<T> {
|
|
39
|
+
crudStatements?: CRUDRepositoryStatements;
|
|
40
|
+
|
|
41
|
+
protected override ids = (options: ReadonlyRepositoryMappingOptions<T>): string[] =>
|
|
42
|
+
isCrud(options)
|
|
43
|
+
? (options.ids ?? (options.type ? defaultId(fieldNamesOf(options.type)) : ["id"]))
|
|
44
|
+
: [];
|
|
45
|
+
|
|
46
|
+
protected override statements = (table: string, columns: string[]): ReadonlyRepositoryStatements => {
|
|
47
|
+
this.crudStatements = new CRUDRepositoryStatements(table, columns, this.entityMapper, this.propertyMapper);
|
|
48
|
+
return new ReadonlyRepositoryStatements(table, columns);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
build = (connection: IConnection, options: CRUDRepositoryOptions<T>): CRUDRepository<T> =>
|
|
52
|
+
new CRUDRepository(connection, options);
|
|
53
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { DefaultStatementTextRenderer, Operator, UpdateStatement, Where } from "./statements/index.ts";
|
|
3
|
+
import { CRUDRepositoryStatements } from "./CRUDRepositoryStatements.ts";
|
|
4
|
+
import { CRUDRepository } from "./CRUDRepository.ts";
|
|
5
|
+
import { DefaultWriteEnrichmentStrategy } from "./DefaultWriteEnrichmentStrategy.ts";
|
|
6
|
+
import { CRUDRepositoryBuilder } from "./CRUDRepositoryBuilder.ts";
|
|
7
|
+
import { ReadonlyRepositoryBuilder } from "./ReadonlyRepositoryBuilder.ts";
|
|
8
|
+
import { MockConnection } from "./mocks/mock-connection.ts";
|
|
9
|
+
import type { CRUDRepositoryOptions } from "./CRUDRepositoryOptions.ts";
|
|
10
|
+
|
|
11
|
+
describe("CRUDRepositoryOptions", () => {
|
|
12
|
+
it("defaults are identity", () => {
|
|
13
|
+
const read: CRUDRepositoryOptions = {
|
|
14
|
+
ids: ["id"],
|
|
15
|
+
entity: "users",
|
|
16
|
+
readProperties: ["id"],
|
|
17
|
+
};
|
|
18
|
+
const built = new CRUDRepositoryBuilder().parts(new MockConnection(), read);
|
|
19
|
+
expect(DefaultStatementTextRenderer.instance.render(built.statements.select())).toBe("SELECT id FROM users");
|
|
20
|
+
expect(built.propertyMappings.map("x")).toBe("x");
|
|
21
|
+
expect(built.propertyMappings.reverseMap("x")).toBe("x");
|
|
22
|
+
const withId: CRUDRepositoryOptions = { ids: ["id"] };
|
|
23
|
+
expect(new CRUDRepositoryBuilder().parts(new MockConnection(), withId).ids).toEqual(["id"]);
|
|
24
|
+
const fromType: CRUDRepositoryOptions<{ id: number }> = {
|
|
25
|
+
type: class {
|
|
26
|
+
id = 0;
|
|
27
|
+
},
|
|
28
|
+
ids: ["id"],
|
|
29
|
+
};
|
|
30
|
+
expect(new CRUDRepositoryBuilder<{ id: number }>().parts(new MockConnection(), fromType).ids).toEqual(["id"]);
|
|
31
|
+
expect(new ReadonlyRepositoryBuilder().parts(new MockConnection(), {}).ids).toEqual([]);
|
|
32
|
+
expect(new CRUDRepositoryBuilder().parts(new MockConnection(), { entity: "users" }).ids).toEqual([]);
|
|
33
|
+
expect(
|
|
34
|
+
new CRUDRepositoryBuilder().parts(new MockConnection(), {
|
|
35
|
+
write: new DefaultWriteEnrichmentStrategy(),
|
|
36
|
+
}).ids,
|
|
37
|
+
).toEqual(["id"]);
|
|
38
|
+
class Named {
|
|
39
|
+
id = 0;
|
|
40
|
+
}
|
|
41
|
+
expect(
|
|
42
|
+
new CRUDRepositoryBuilder<Named>().parts(new MockConnection(), {
|
|
43
|
+
type: Named,
|
|
44
|
+
write: new DefaultWriteEnrichmentStrategy<Named>(),
|
|
45
|
+
}).ids,
|
|
46
|
+
).toEqual(["id"]);
|
|
47
|
+
expect(
|
|
48
|
+
new CRUDRepositoryBuilder().build(new MockConnection(), { ids: ["id"], entity: "users" }),
|
|
49
|
+
).toBeInstanceOf(CRUDRepository);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("uses the mapped table and columns", () => {
|
|
53
|
+
const statements = new CRUDRepositoryStatements("users", ["id", "name"]);
|
|
54
|
+
expect(DefaultStatementTextRenderer.instance.render(statements.select())).toBe("SELECT id, name FROM users");
|
|
55
|
+
expect(DefaultStatementTextRenderer.instance.render(statements.insert([{ name: "id", value: 1 }]))).toBe(
|
|
56
|
+
"INSERT INTO users (id) VALUES ($id)",
|
|
57
|
+
);
|
|
58
|
+
expect(DefaultStatementTextRenderer.instance.render(statements.update([{ name: "name", value: "a" }]))).toBe(
|
|
59
|
+
"UPDATE users SET name = $name",
|
|
60
|
+
);
|
|
61
|
+
expect(
|
|
62
|
+
DefaultStatementTextRenderer.instance.render(statements.update([{ name: "name", value: "a" }], new Where(new Operator.Equals("id", 1)))),
|
|
63
|
+
).toBe("UPDATE users SET name = $name WHERE id = $id");
|
|
64
|
+
expect(DefaultStatementTextRenderer.instance.render(statements.delete(new Where(new Operator.Equals("id", 1))))).toBe(
|
|
65
|
+
"DELETE FROM users WHERE id = $id",
|
|
66
|
+
);
|
|
67
|
+
expect(UpdateStatement.parameterList([{ name: "name", value: "a" }])).toEqual([
|
|
68
|
+
{ name: "name", value: "a" },
|
|
69
|
+
]);
|
|
70
|
+
expect(DefaultStatementTextRenderer.instance.render(statements.delete())).toBe("DELETE FROM users");
|
|
71
|
+
const inserted = statements.selectInsertedId("id");
|
|
72
|
+
expect(inserted.table).toBe("users");
|
|
73
|
+
expect(inserted.column).toBe("id");
|
|
74
|
+
expect(() => DefaultStatementTextRenderer.instance.render(inserted)).toThrow("provider must implement SelectInsertIdStatement");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReadonlyRepositoryMappingOptions } from "./ReadonlyRepositoryMappingOptions.ts";
|
|
2
|
+
import type { Cells } from "./converters/Cell.ts";
|
|
3
|
+
import type { IWriteEnrichmentStrategy } from "./IWriteEnrichmentStrategy.ts";
|
|
4
|
+
|
|
5
|
+
export type CRUDRepositoryOptions<T = Cells> = ReadonlyRepositoryMappingOptions<T> & {
|
|
6
|
+
ids?: string[];
|
|
7
|
+
write?: IWriteEnrichmentStrategy<T>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Cell } from "./converters/Cell.ts";
|
|
2
|
+
import type { Field } from "./builders/Field.ts";
|
|
3
|
+
import type { IMapper } from "./mappers/IMapper.ts";
|
|
4
|
+
import { IdentityMapper } from "./mappers/IdentityMapper.ts";
|
|
5
|
+
import { StatementMappers } from "./StatementMappers.ts";
|
|
6
|
+
import { DeleteStatement } from "./statements/DeleteStatement.ts";
|
|
7
|
+
import { InsertStatement } from "./statements/InsertStatement.ts";
|
|
8
|
+
import { SelectInsertedIdStatement } from "./statements/SelectInsertedIdStatement.ts";
|
|
9
|
+
import { UpdateStatement } from "./statements/UpdateStatement.ts";
|
|
10
|
+
import type { IWhere } from "./statements/IWhere.ts";
|
|
11
|
+
import { ReadonlyRepositoryStatements } from "./ReadonlyRepositoryStatements.ts";
|
|
12
|
+
|
|
13
|
+
const same = (_name: string, value: Cell): Cell => value;
|
|
14
|
+
|
|
15
|
+
export class CRUDRepositoryStatements extends ReadonlyRepositoryStatements {
|
|
16
|
+
private readonly mappings: StatementMappers;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
table: string,
|
|
20
|
+
columns: readonly string[],
|
|
21
|
+
entityMappers: IMapper<string, string> = new IdentityMapper(),
|
|
22
|
+
propertyMappers: IMapper<string, string> = new IdentityMapper(),
|
|
23
|
+
) {
|
|
24
|
+
super(table, columns);
|
|
25
|
+
this.mappings = new StatementMappers(entityMappers, propertyMappers);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
insert = (fields: Field[]): InsertStatement =>
|
|
29
|
+
this.mappings.apply(new InsertStatement(this.table, fields), same) as InsertStatement;
|
|
30
|
+
|
|
31
|
+
update = (
|
|
32
|
+
fields: Field[],
|
|
33
|
+
where?: IWhere,
|
|
34
|
+
cell: (name: string, value: Cell) => Cell = same,
|
|
35
|
+
): UpdateStatement =>
|
|
36
|
+
this.mappings.apply(new UpdateStatement(this.table, fields, where), cell) as UpdateStatement;
|
|
37
|
+
|
|
38
|
+
delete = (where?: IWhere, cell: (name: string, value: Cell) => Cell = same): DeleteStatement =>
|
|
39
|
+
this.mappings.apply(new DeleteStatement(this.table, where), cell) as DeleteStatement;
|
|
40
|
+
|
|
41
|
+
selectInsertedId = (column: string): SelectInsertedIdStatement =>
|
|
42
|
+
this.mappings.apply(new SelectInsertedIdStatement(this.table, column), same) as SelectInsertedIdStatement;
|
|
43
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { DatasourceError } from "./DatasourceError.ts";
|
|
2
|
+
import { DeleteEnrichmentStrategy } from "./DeleteEnrichmentStrategy.ts";
|
|
3
|
+
import type { Enrichment } from "./Enrichment.ts";
|
|
4
|
+
import type { ICRUDRepository } from "./ICRUDRepository.ts";
|
|
5
|
+
import type { Scalar } from "./builders/Scalar.ts";
|
|
6
|
+
import { Operator, Where } from "./statements/index.ts";
|
|
7
|
+
|
|
8
|
+
type Props = Record<string, Scalar | object>;
|
|
9
|
+
|
|
10
|
+
const get = <TItem>(item: TItem, name: string): Scalar | object | undefined =>
|
|
11
|
+
(item as never as Props)[name];
|
|
12
|
+
|
|
13
|
+
const present = (value: Scalar | object | undefined): value is Scalar =>
|
|
14
|
+
value !== undefined && value !== null && typeof value !== "object" && value !== 0 && value !== 0n && value !== "";
|
|
15
|
+
|
|
16
|
+
const linkWhere = (
|
|
17
|
+
association: NonNullable<Enrichment["association"]>,
|
|
18
|
+
parentKey: Scalar,
|
|
19
|
+
relatedKey: Scalar,
|
|
20
|
+
): Where =>
|
|
21
|
+
new Where(
|
|
22
|
+
new Operator.And(
|
|
23
|
+
new Operator.Equals(association.parent, parentKey),
|
|
24
|
+
new Operator.Equals(association.related, relatedKey),
|
|
25
|
+
),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export class CascadeDeleteEnrichmentStrategy<T> extends DeleteEnrichmentStrategy<T> {
|
|
29
|
+
async deleteChildren<TChild extends object>(
|
|
30
|
+
writer: ICRUDRepository<TChild>,
|
|
31
|
+
enrichment: Enrichment,
|
|
32
|
+
parent: T,
|
|
33
|
+
deleteNested: (rows: TChild[]) => Promise<void>,
|
|
34
|
+
): Promise<void> {
|
|
35
|
+
const existing = await DeleteEnrichmentStrategy.load(writer, enrichment, parent);
|
|
36
|
+
await deleteNested(existing);
|
|
37
|
+
for (const row of existing) await writer.delete(row, DeleteEnrichmentStrategy.childrenWhere(writer, enrichment, parent));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async deleteLinked<TChild extends object>(writer: ICRUDRepository<TChild>, enrichment: Enrichment, parent: T): Promise<void> {
|
|
41
|
+
const association = enrichment.association;
|
|
42
|
+
if (!association) throw new DatasourceError("Missing association");
|
|
43
|
+
const key = get(parent, enrichment.sourceProperty);
|
|
44
|
+
if (!present(key)) return;
|
|
45
|
+
for (const row of await DeleteEnrichmentStrategy.loadLinks(writer, association.parent, key)) {
|
|
46
|
+
const id = get(row, association.related);
|
|
47
|
+
if (!present(id)) continue;
|
|
48
|
+
await writer.delete(row, linkWhere(association, key, id));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DefaultCreateEnrichmentStrategy } from "./DefaultCreateEnrichmentStrategy.ts";
|
|
2
|
+
import { DatasourceError } from "./DatasourceError.ts";
|
|
3
|
+
import { DeleteEnrichmentStrategy } from "./DeleteEnrichmentStrategy.ts";
|
|
4
|
+
import type { Enrichment } from "./Enrichment.ts";
|
|
5
|
+
import type { ICRUDRepository } from "./ICRUDRepository.ts";
|
|
6
|
+
import { UpdateEnrichmentStrategy } from "./UpdateEnrichmentStrategy.ts";
|
|
7
|
+
|
|
8
|
+
export class CascadeDeleteUpdateEnrichmentStrategy<T> extends UpdateEnrichmentStrategy<T> {
|
|
9
|
+
private readonly create = new DefaultCreateEnrichmentStrategy<T>();
|
|
10
|
+
|
|
11
|
+
async updateChildren<TChild extends object>(writer: ICRUDRepository<TChild>, enrichment: Enrichment, parent: T): Promise<void> {
|
|
12
|
+
for (const row of await DeleteEnrichmentStrategy.load(writer, enrichment, parent))
|
|
13
|
+
await writer.delete(row, DeleteEnrichmentStrategy.childrenWhere(writer, enrichment, parent));
|
|
14
|
+
await this.create.createChildren(writer, enrichment, parent);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async updateLinked<TChild extends object>(writer: ICRUDRepository<TChild>, enrichment: Enrichment, parent: T): Promise<void> {
|
|
18
|
+
const association = enrichment.association;
|
|
19
|
+
if (!association) throw new DatasourceError("Missing association");
|
|
20
|
+
const parentKey = this.requiredKey(parent, enrichment);
|
|
21
|
+
for (const row of await DeleteEnrichmentStrategy.loadLinks(writer, association.parent, parentKey)) {
|
|
22
|
+
const id = this.getCell(row, association.related);
|
|
23
|
+
if (!this.presentCell(id)) continue;
|
|
24
|
+
await writer.delete(row, this.linkWhere(association, parentKey, id));
|
|
25
|
+
}
|
|
26
|
+
await this.create.createLinked(writer, enrichment, parent);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
MockCommand,
|
|
4
|
+
Native,
|
|
5
|
+
MockConnection,
|
|
6
|
+
MockReader,
|
|
7
|
+
MetaDataRowTypeConverter,
|
|
8
|
+
TransformMapper,
|
|
9
|
+
} from "./index.ts";
|
|
10
|
+
|
|
11
|
+
class NameValue {
|
|
12
|
+
name = "";
|
|
13
|
+
value = "";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class Contact {
|
|
17
|
+
name = "";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class User {
|
|
21
|
+
id = 0;
|
|
22
|
+
username = "";
|
|
23
|
+
email = "";
|
|
24
|
+
contact_name1 = "";
|
|
25
|
+
contact_name2 = "";
|
|
26
|
+
contacts: Contact[] = [];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const userContactsMapper = () =>
|
|
30
|
+
new TransformMapper<User, User>(
|
|
31
|
+
(row) => {
|
|
32
|
+
row.contacts = [
|
|
33
|
+
Object.assign(new Contact(), { name: row.contact_name1 }),
|
|
34
|
+
Object.assign(new Contact(), { name: row.contact_name2 }),
|
|
35
|
+
];
|
|
36
|
+
return row;
|
|
37
|
+
},
|
|
38
|
+
(user) => {
|
|
39
|
+
user.contact_name1 = user.contacts[0]?.name ?? "";
|
|
40
|
+
user.contact_name2 = user.contacts[1]?.name ?? "";
|
|
41
|
+
return user;
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
describe("Command", () => {
|
|
46
|
+
it("executeReader returns NameValue objects", async () => {
|
|
47
|
+
const command = new MockCommand(new MockConnection());
|
|
48
|
+
command.reader = new MockReader([{ name: "theme", value: "dark" }]);
|
|
49
|
+
const reader = await command.executeReader("SELECT name, value FROM settings");
|
|
50
|
+
const converter = new MetaDataRowTypeConverter<NameValue>();
|
|
51
|
+
const items: NameValue[] = [];
|
|
52
|
+
while (await reader.next()) {
|
|
53
|
+
items.push(converter.convert(reader.current!, NameValue));
|
|
54
|
+
}
|
|
55
|
+
expect(items[0]?.name).toBe("theme");
|
|
56
|
+
expect(items[0]?.value).toBe("dark");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("execute insert update and delete", async () => {
|
|
60
|
+
const command = new MockCommand(new MockConnection());
|
|
61
|
+
await command.executeNative(new Native("insert"), [
|
|
62
|
+
{ name: "id", value: 1 },
|
|
63
|
+
{ name: "name", value: "a" },
|
|
64
|
+
]);
|
|
65
|
+
await command.executeNative(new Native("update"), [
|
|
66
|
+
{ name: "id", value: 1 },
|
|
67
|
+
{ name: "name", value: "A" },
|
|
68
|
+
]);
|
|
69
|
+
await command.executeNative(new Native("delete"), [{ name: "id", value: 1 }]);
|
|
70
|
+
expect(command.executeCalls.map((call) => call.text)).toEqual([
|
|
71
|
+
"insert",
|
|
72
|
+
"update",
|
|
73
|
+
"delete",
|
|
74
|
+
]);
|
|
75
|
+
expect(command.executeCalls[0]?.parameters?.map((parameter) => parameter.name)).toEqual([
|
|
76
|
+
"id",
|
|
77
|
+
"name",
|
|
78
|
+
]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("executeReader maps flat contacts", async () => {
|
|
82
|
+
const command = new MockCommand(new MockConnection());
|
|
83
|
+
command.reader = new MockReader([
|
|
84
|
+
{
|
|
85
|
+
id: 1,
|
|
86
|
+
username: "bobby",
|
|
87
|
+
email: "bob@asdf.com",
|
|
88
|
+
contact_name1: "bob",
|
|
89
|
+
contact_name2: "roberta",
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
const reader = await command.executeReader(
|
|
93
|
+
"SELECT contact_name1, contact_name2, email, id, username FROM users",
|
|
94
|
+
);
|
|
95
|
+
const converter = new MetaDataRowTypeConverter<User>();
|
|
96
|
+
const mapper = userContactsMapper();
|
|
97
|
+
let user: User | undefined;
|
|
98
|
+
while (await reader.next()) {
|
|
99
|
+
user = mapper.map(converter.convert(reader.current!, User));
|
|
100
|
+
}
|
|
101
|
+
expect(user?.username).toBe("bobby");
|
|
102
|
+
expect(user?.email).toBe("bob@asdf.com");
|
|
103
|
+
expect(user?.contacts.map((contact) => contact.name)).toEqual(["bob", "roberta"]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { CommandMiddlewareHost } from "./index.ts";
|
|
3
|
+
|
|
4
|
+
describe("CommandMiddlewareHost", () => {
|
|
5
|
+
it("base execute methods require a driver", () => {
|
|
6
|
+
const host = new CommandMiddlewareHost();
|
|
7
|
+
expect(() => host.execute("SELECT id FROM users")).toThrow("executeNative");
|
|
8
|
+
expect(() => host.execute(" ")).toThrow("empty command");
|
|
9
|
+
expect(() => host.executeReader("SELECT id FROM users")).toThrow("executeReaderNative");
|
|
10
|
+
expect(() => host.executeReader("")).toThrow("empty command");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("rewrites the text and runs afterCommand", async () => {
|
|
14
|
+
const host = new CommandMiddlewareHost();
|
|
15
|
+
const seen: string[] = [];
|
|
16
|
+
let used = "";
|
|
17
|
+
host.addMiddleware({
|
|
18
|
+
beforeCommand: (text) => {
|
|
19
|
+
seen.push(`before:${text}`);
|
|
20
|
+
return { text: "SELECT 2" };
|
|
21
|
+
},
|
|
22
|
+
afterCommand: (text, _params, results, elapsedMs) => {
|
|
23
|
+
seen.push(`after:${text}:${results.length}:${elapsedMs >= 0}`);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
const result = await host.run("SELECT 1", undefined, async (text) => {
|
|
27
|
+
used = text;
|
|
28
|
+
seen.push("op");
|
|
29
|
+
return { value: 7, rows: [{ id: 1 }] };
|
|
30
|
+
});
|
|
31
|
+
expect(result).toBe(7);
|
|
32
|
+
expect(used).toBe("SELECT 2");
|
|
33
|
+
expect(seen[0]).toBe("before:SELECT 1");
|
|
34
|
+
expect(seen[1]).toBe("op");
|
|
35
|
+
expect(seen[2]?.startsWith("after:SELECT 2:1:true")).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("runs with no middleware", async () => {
|
|
39
|
+
const host = new CommandMiddlewareHost();
|
|
40
|
+
expect(await host.run("", undefined, async () => ({ value: "ok", rows: [] }))).toBe(
|
|
41
|
+
"ok",
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("skips the command when beforeCommand throws", async () => {
|
|
46
|
+
const host = new CommandMiddlewareHost();
|
|
47
|
+
let ran = false;
|
|
48
|
+
host.addMiddleware({
|
|
49
|
+
beforeCommand: () => {
|
|
50
|
+
throw new Error("blocked");
|
|
51
|
+
},
|
|
52
|
+
afterCommand: () => {
|
|
53
|
+
ran = true;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
await expect(
|
|
57
|
+
host.run("select", undefined, async () => {
|
|
58
|
+
ran = true;
|
|
59
|
+
return { value: 1, rows: [] };
|
|
60
|
+
}),
|
|
61
|
+
).rejects.toThrow("blocked");
|
|
62
|
+
expect(ran).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("runs afterCommand with error when the command fails", async () => {
|
|
66
|
+
const host = new CommandMiddlewareHost();
|
|
67
|
+
let captured: Error | undefined;
|
|
68
|
+
host.addMiddleware({
|
|
69
|
+
beforeCommand: () => undefined,
|
|
70
|
+
afterCommand: (_q, _p, _r, _e, error) => {
|
|
71
|
+
captured = error;
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
await expect(
|
|
75
|
+
host.run("select", undefined, async () => {
|
|
76
|
+
throw new Error("fail-op");
|
|
77
|
+
}),
|
|
78
|
+
).rejects.toThrow("fail-op");
|
|
79
|
+
expect(captured?.message).toBe("fail-op");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("wraps a non-Error throw for afterCommand", async () => {
|
|
83
|
+
const host = new CommandMiddlewareHost();
|
|
84
|
+
let captured: Error | undefined;
|
|
85
|
+
host.addMiddleware({
|
|
86
|
+
beforeCommand: () => undefined,
|
|
87
|
+
afterCommand: (_q, _p, _r, _e, error) => {
|
|
88
|
+
captured = error;
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
await expect(
|
|
92
|
+
host.run("select", undefined, async () => {
|
|
93
|
+
throw "string-fail";
|
|
94
|
+
}),
|
|
95
|
+
).rejects.toBe("string-fail");
|
|
96
|
+
expect(captured?.message).toBe("string-fail");
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { ICommandMiddleware } from "./ICommandMiddleware.ts";
|
|
2
|
+
import type { IReader } from "./IReader.ts";
|
|
3
|
+
import type { Parameter } from "./Parameter.ts";
|
|
4
|
+
import type { Response } from "./Response.ts";
|
|
5
|
+
import type { Row } from "./Row.ts";
|
|
6
|
+
import type { Cell, Cells } from "./converters/Cell.ts";
|
|
7
|
+
import type { IStatement } from "./statements/IStatement.ts";
|
|
8
|
+
import { DefaultStatementTextRenderer } from "./statements/DefaultStatementTextRenderer.ts";
|
|
9
|
+
import { Native } from "./statements/Native.ts";
|
|
10
|
+
import { StatementParser } from "./statements/StatementParser.ts";
|
|
11
|
+
|
|
12
|
+
const asError = (error: unknown): Error =>
|
|
13
|
+
error instanceof Error ? error : new Error(String(error));
|
|
14
|
+
|
|
15
|
+
type ExecuteBody = { result: Cell; rowsAffected: number };
|
|
16
|
+
|
|
17
|
+
const resultOf = (value: Cell | object | null): Cell =>
|
|
18
|
+
value instanceof Date ||
|
|
19
|
+
value instanceof Uint8Array ||
|
|
20
|
+
value === null ||
|
|
21
|
+
typeof value === "string" ||
|
|
22
|
+
typeof value === "number" ||
|
|
23
|
+
typeof value === "boolean" ||
|
|
24
|
+
typeof value === "bigint"
|
|
25
|
+
? value
|
|
26
|
+
: String(value);
|
|
27
|
+
|
|
28
|
+
const isResponse = (value: object): value is ExecuteBody =>
|
|
29
|
+
"rowsAffected" in value && typeof (value as ExecuteBody).rowsAffected === "number";
|
|
30
|
+
|
|
31
|
+
const logged = <T>(value: T, rows: readonly Row[]): readonly Row[] =>
|
|
32
|
+
rows.length > 0 || value === null || typeof value !== "object" || !isResponse(value)
|
|
33
|
+
? rows
|
|
34
|
+
: [{ result: resultOf(value.result), rowsAffected: value.rowsAffected }];
|
|
35
|
+
|
|
36
|
+
export class CommandMiddlewareHost {
|
|
37
|
+
private readonly middlewares: ICommandMiddleware[] = [];
|
|
38
|
+
|
|
39
|
+
addMiddleware(middleware: ICommandMiddleware): this {
|
|
40
|
+
this.middlewares.push(middleware);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
execute(text: string, parameters?: Parameter[]): Promise<Response> {
|
|
45
|
+
if (!text.trim()) throw new Error("empty command");
|
|
46
|
+
return this.executeStatement(StatementParser.parse(text), parameters);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
executeReader(text: string, parameters?: Parameter[]): Promise<IReader<Cells>> {
|
|
50
|
+
if (!text.trim()) throw new Error("empty command");
|
|
51
|
+
return this.executeReaderStatement(StatementParser.parse(text), parameters);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
executeStatement(statement: IStatement, parameters?: Parameter[]): Promise<Response> {
|
|
55
|
+
return this.executeNative(
|
|
56
|
+
new Native(DefaultStatementTextRenderer.instance.render(statement)),
|
|
57
|
+
parameters,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
executeReaderStatement(
|
|
62
|
+
statement: IStatement,
|
|
63
|
+
parameters?: Parameter[],
|
|
64
|
+
): Promise<IReader<Cells>> {
|
|
65
|
+
return this.executeReaderNative(
|
|
66
|
+
new Native(DefaultStatementTextRenderer.instance.render(statement)),
|
|
67
|
+
parameters,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
executeNative(_text: Native, _parameters?: Parameter[]): Promise<Response> {
|
|
72
|
+
throw new Error("executeNative");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
executeReaderNative(_text: Native, _parameters?: Parameter[]): Promise<IReader<Cells>> {
|
|
76
|
+
throw new Error("executeReaderNative");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async run<T>(
|
|
80
|
+
text: string,
|
|
81
|
+
params: Parameter[] | undefined,
|
|
82
|
+
fn: (
|
|
83
|
+
text: string,
|
|
84
|
+
params?: Parameter[],
|
|
85
|
+
) => Promise<{ value: T; rows: readonly Row[] }>,
|
|
86
|
+
): Promise<T> {
|
|
87
|
+
let q = text.trim();
|
|
88
|
+
let p = params;
|
|
89
|
+
for (const middleware of this.middlewares) {
|
|
90
|
+
const rewritten = await middleware.beforeCommand(q, p);
|
|
91
|
+
if (rewritten) {
|
|
92
|
+
q = rewritten.text;
|
|
93
|
+
p = rewritten.params as Parameter[] | undefined;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const start = performance.now();
|
|
98
|
+
try {
|
|
99
|
+
const { value, rows } = await fn(q, p);
|
|
100
|
+
const elapsedMs = performance.now() - start;
|
|
101
|
+
for (const middleware of this.middlewares) {
|
|
102
|
+
await middleware.afterCommand(q, p, logged(value, rows), elapsedMs);
|
|
103
|
+
}
|
|
104
|
+
return value;
|
|
105
|
+
} catch (error) {
|
|
106
|
+
const elapsedMs = performance.now() - start;
|
|
107
|
+
for (const middleware of this.middlewares) {
|
|
108
|
+
await middleware.afterCommand(q, p, [], elapsedMs, asError(error));
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { afterAll, afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { Datasource, DatasourceFactory, MockDriver } from "./index.ts";
|
|
3
|
+
|
|
4
|
+
const envKeys = [
|
|
5
|
+
"INSTALLED_PROVIDERS",
|
|
6
|
+
"DATASOURCE_URL",
|
|
7
|
+
"PROVIDER",
|
|
8
|
+
] as const;
|
|
9
|
+
const savedEnv = Object.fromEntries(envKeys.map((key) => [key, process.env[key]]));
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
for (const key of envKeys) delete process.env[key];
|
|
13
|
+
DatasourceFactory.register("sqlite", new MockDriver());
|
|
14
|
+
process.env.PROVIDER = "sqlite";
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(() => DatasourceFactory.reset());
|
|
18
|
+
|
|
19
|
+
afterAll(() => {
|
|
20
|
+
for (const key of envKeys) {
|
|
21
|
+
if (savedEnv[key] === undefined) delete process.env[key];
|
|
22
|
+
else process.env[key] = savedEnv[key];
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe("Connection", () => {
|
|
27
|
+
it("create from default", async () => {
|
|
28
|
+
const ds = Datasource.default;
|
|
29
|
+
const connection = await ds.createConnection();
|
|
30
|
+
await connection.open();
|
|
31
|
+
await connection.close();
|
|
32
|
+
expect(connection.isOpen).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
});
|