Skip to content

Let an alternative execution engine be selected, with MySQL as the default - #24

Open
dionmcm wants to merge 2 commits into
upstream/mysql-fixesfrom
upstream/engine-seam
Open

Let an alternative execution engine be selected, with MySQL as the default#24
dionmcm wants to merge 2 commits into
upstream/mysql-fixesfrom
upstream/engine-seam

Conversation

@dionmcm

@dionmcm dionmcm commented Aug 29, 2026

Copy link
Copy Markdown
Member

The seam only. No second engine in this PR. rvf.execution.engine defaults to mysql via matchIfMissing = true, so a deployment that sets nothing gets the beans it gets today.

Stacked on #23; review that first.

What it adds

piece what it does
@ConditionalOnMysqlEngine meta-annotation, applied to the nine MySQL-specific beans
ExecutionEngine property contract. Anything not exactly duckdb is mysql, so a typo cannot start the service without its database half
MysqlPersistenceConfig @EntityScan/@EnableJpaRepositories moved out of Config to be conditional. Bean-for-bean identical in mysql mode
SqlAssertionValidationService interface ValidationRunner depends on instead of MysqlValidationService. The MySQL class implements it with a one-line delegate to existing runRF2MysqlValidations
ReleaseAcquisitionService the four acquisition methods moved verbatim from ValidationVersionLoader. Not conditional: acquiring files is engine-independent. ValidationVersionLoader keeps deprecated delegates
DuckDbEngineEnvironmentPostProcessor excludes JPA/datasource auto-configuration when the engine is not mysql, so a no-database deployment does not fail on a missing URL. References no engine implementation
MySqlQueryTransformer sentinel substitution extracted from AssertionExecutionService, unchanged, with unit tests it did not have
AssertionGroupImporter.resolveGroups resolves group membership from groups.xml/policies.xml without a database
controllers AssertionController, AssertionGroupController, ReleaseController and AssertionHelper gated (they administer database tables). TestUploadFileController and AutomatedTestController deliberately not: gating them leaves a service that starts and cannot be asked to validate

Two things to look at

MySqlQueryTransformer is useful even without a second engine. Those substitution rules are a specification — <PROSPECTIVE>, <PREVIOUS>, <DEPENDENCY>, and the rule that a statement holding an unbound sentinel is dropped per statement, not per assertion. They previously could only be exercised by running MySQL. Now 171 lines of unit test.

ReleaseAcquisitionService is the only change that moves code rather than adding an annotation, so it is where a behaviour change would hide. The methods are byte-identical to the originals, which remain as delegates.

Separability

This branch compiles and its tests pass with no org.ihtsdo.rvf.core.service.duck package present. Nothing here imports one.

Selecting duckdb in this build is a startup failure, not a fallback: nothing implements SqlAssertionValidationService in that mode.

Verification

clean upstream-develop   213 run, 0 failures, 142 errors, 21 skipped
+ #23                    219 run, 0 failures, 142 errors, 21 skipped
+ this PR                241 run, 0 failures, 142 errors, 21 skipped

Same 142 pre-existing errors (Testcontainers, no Docker daemon). 22 tests added.

Also removes four duplicated import lines in AssertionExecutionService.

…fault

Adds the seam only. There is no second engine in this PR, and MySQL behaviour is
unchanged: `rvf.execution.engine` defaults to `mysql` through
`matchIfMissing = true`, so a deployment that sets nothing gets exactly the beans
it gets today.

What the seam is:

* `@ConditionalOnMysqlEngine` - one meta-annotation, applied to the beans that
  are MySQL-specific: AssertionExecutionService, MysqlValidationService,
  MysqlFailuresExtractor, AssertionServiceImpl, ValidationVersionLoader,
  ReleaseDataManager, ResourceDataLoader, RvfDynamicDataSource, and the
  `dataSource` bean.
* `ExecutionEngine` - the property contract. Anything that is not exactly
  `duckdb` is `mysql`, deliberately: a typo must not be able to start the
  service with its database half missing.
* `MysqlPersistenceConfig` - `@EntityScan` and `@EnableJpaRepositories` moved out
  of `Config` so they can be conditional. Bean-for-bean identical in mysql mode.
* `SqlAssertionValidationService` - the interface `ValidationRunner` now depends
  on, instead of naming `MysqlValidationService` directly. `MysqlValidationService`
  implements it with a one-line delegate to its existing
  `runRF2MysqlValidations`.
* `ReleaseAcquisitionService` - the four acquisition methods lifted verbatim out
  of `ValidationVersionLoader`, which stays MySQL-only because it also loads
  schemas. Deliberately NOT conditional: acquiring files is engine-independent,
  and this is what lets `ValidationRunner` run without the MySQL half.
  `ValidationVersionLoader` keeps deprecated one-line delegates so existing
  callers are unaffected.
* `DuckDbEngineEnvironmentPostProcessor` - excludes Boot's JPA and datasource
  auto-configuration when the engine is not mysql, so a no-database deployment
  does not fail on a missing URL. Registered through spring.factories. It holds
  no reference to any engine implementation.
* `MySqlQueryTransformer` - the sentinel substitution rules extracted from
  AssertionExecutionService, unchanged, with the unit tests they never had. They
  are a specification any engine has to match, and they were previously only
  expressible by running MySQL.
* `AssertionGroupImporter.resolveGroups` - resolves group membership from
  groups.xml and policies.xml without a database, which the assertion tables
  previously required. `ManifestResolveProbe` exercises it standalone.
* `AssertionsDatabaseImporter` gains pre-requisites.sql handling, which routes
  through the extracted transformer.

The seam does not depend on a second engine: this branch compiles and its tests
pass with no `org.ihtsdo.rvf.core.service.duck` package present at all. Selecting
`duckdb` here is a startup failure rather than a silent fallback - nothing
implements `SqlAssertionValidationService` in that mode - which is the honest
behaviour for a build that carries no such engine.

Full suite on this host, offline Maven, no Docker:

  clean upstream-develop   213 run, 0 failures, 142 errors, 21 skipped
  + the bug-fix PR          219 run, 0 failures, 142 errors, 21 skipped
  + this PR                 241 run, 0 failures, 142 errors, 21 skipped

Same 142 pre-existing errors at every step, all of them Testcontainers with no
Docker daemon. 22 tests added, none broken.

Also removes four duplicated import lines this refactor had accumulated in
AssertionExecutionService.
AssertionHelper injects AssertionExecutionService, which is now MySQL-only, so
without this the application cannot start at all under a non-mysql engine: the
context fails with 'No qualifying bean of type AssertionExecutionService' while
building assertionHelper for assertionController.

Gated, because they administer a database an alternative engine need not have -
they reach ReleaseDataManager and AssertionGroupRepository directly:
AssertionController, AssertionGroupController, ReleaseController, AssertionHelper.

Deliberately NOT gated: TestUploadFileController and AutomatedTestController.
Their only MySQL coupling is the AssertionService interface, and an alternative
engine has to supply that itself. Gating them would leave an application that
boots and cannot be asked to validate anything, which is worse than not
starting.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant