Unify DDL execution and dry-run into shared processCreate methods#207
Merged
Unify DDL execution and dry-run into shared processCreate methods#207
Conversation
4df5b3c to
478a046
Compare
…methods Extract TemporaryTable to a standalone public class. Add DdlMode enum (CREATE/UPDATE/SPECIFY), processCreateMaterializedView(), and processCreateTable() to HoptimatorDdlUtils so HoptimatorDdlExecutor fully delegates to them. Add specifyFromSql() and specifyCreateTable() as the unified !specify entry points used by QuidemTestBase and HoptimatorAppConfig. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
478a046 to
650f764
Compare
Code Coverage
|
ryannedolan
approved these changes
Apr 15, 2026
Collaborator
ryannedolan
left a comment
There was a problem hiding this comment.
neat! Much needed improvement.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
HoptimatorDdlExecutorand the!specifydry-run path (used by the CLI, Quidem tests, and more internally) implemented the same DDL pipeline — schema validation, query planning, sink schema setup, deployer invocation, and rollback — in several completely separate code paths. Any fix or feature had to be applied many times, and paths have already drifted:TemporaryTablewas a private inner class ofHoptimatorDdlExecutor, inaccessible to the shared pathCollections.emptyList()as materializations instead ofconn.materializations(), causing source table connector configs to be absent from the generated SQLSolution
Extract the shared logic into
HoptimatorDdlUtilsand parameterize the divergence point with aDdlModeenum. This gives us a common entry point to support other SQL DDL types as well.New / changed production code
TemporaryTable— extracted from a private inner class ofHoptimatorDdlExecutorto a standalone public class with a simplified 2-arg constructor. Retains the fullInitializerExpressionFactorysupport (via a 3-arg overload) so that column default expressions and generation strategies are preserved. Note the intent is to reuse this piece later withinDdlModeenum (CREATE/UPDATE/SPECIFY) —executeDeployers()either callsDeploymentService.create/updateor collectsdeployer.specify()output;mutable()gates the schema conflict check.processCreateMaterializedView()— single 11-step pipeline forCREATE MATERIALIZED VIEW, shared byHoptimatorDdlExecutorand all dry-run callers. Logging routed throughconn.getLogger()so the connection's dual-logger (SLF4J + connection hooks) is used, matching the original executor behavior.processCreateTable()— same forCREATE TABLE. Includes the fullColumnDef/InitializerExpressionFactorymachinery for column default expressions so no behavior is dropped.specifyFromSql()— unified entry point for!specifyin the CLI, Quidem tests, and more internally. HandlesCREATE TABLE,CREATE MATERIALIZED VIEW, plainSELECT, andINSERT INTO. Returns aSpecifyResultcontaining:specs— YAML artifacts from each deployersinkRowType— output row type, derived from the query plan (no double planning: for CREATE MV,rootis computed once and reused for bothDeploymentService.planand the row type)viewPath— fully-qualified path of the sink, used by callers to construct Avro namespace and schema nameHoptimatorDdlExecutor— simplified to a thin dispatcher: validates, picksDdlMode.CREATEvsUPDATE, delegates toprocessCreate*, wraps exceptions asDdlException.Bug fixes
removeTableunconditionallyprocessCreateMaterializedViewwhich uses the correct conditional rollbackpipeline.job().sink()is null for plain SELECTspecifyFromSqlSELECT path now registers a virtualDEFAULT.SINKand callsplan.setSink()conn.materializations()instead ofCollections.emptyList()Test changes
HoptimatorDdlUtilsTest— 40+ new tests covering:processCreateMaterializedViewandprocessCreateTablevalidation paths (schema not found, non-database schema, duplicate view, IF NOT EXISTS, overwrite physical table)DdlModebehavior andColumnDefpreconditionsspecifyFromSqlSELECT path: correctSpecifyResultfields asserted via@Mock MockedStatic<DeploymentService>; schema restoration verified after callHoptimatorDdlExecutorTest— consolidatedHoptimatorDdlExecutorDdlTestandHoptimatorDdlExecutorMockServiceTestinto a single file. Trimmed to 2 tests per delegated DDL method (one happy path, oneDdlExceptionwrapping) since the validation logic now lives inHoptimatorDdlUtilsTest.kafka-ddl-create-table.id— addedCREATE TABLE IF NOT EXISTSintegration test verifying the mutable no-op path returns(0 rows modified)cleanly.This PR is also a precursor to the coming Logical table work which also needs similar functionality.