Skip to content

feat(isthmus): introduce a ConverterProvider builder#1036

Open
nielspardon wants to merge 3 commits into
mainfrom
feat/converterprovider-builder-api
Open

feat(isthmus): introduce a ConverterProvider builder#1036
nielspardon wants to merge 3 commits into
mainfrom
feat/converterprovider-builder-api

Conversation

@nielspardon

@nielspardon nielspardon commented Jul 24, 2026

Copy link
Copy Markdown
Member

Summary

Add ConverterProvider.builder() and a nested Builder — a readable, forward-compatible way to
configure a ConverterProvider, most importantly to supply a full Calcite SqlParser.Config now
that the parsers consume the provider's config (#1035). ConverterProvider.DEFAULT_SQL_PARSER_CONFIG
(SqlParser.Config.DEFAULT + TO_UPPER + SqlDdlParserImpl.FACTORY + LENIENT) is exposed as the
base for customized configs, e.g. DEFAULT_SQL_PARSER_CONFIG.withUnquotedCasing(Casing.UNCHANGED).

Sole construction path + subclassing seam

All public ConverterProvider constructors are @Deprecated in favour of builder(), and DEFAULT
is builder().build(). Subclassing routes through a new protected ConverterProvider(Builder) seam
— the single place instances are created — so adding a component later touches only the builder and
this constructor, never a subclass super(...) call. DynamicConverterProvider and
AutomaticDynamicFunctionMappingConverterProvider construct via super(builder).

Now that the provider is fully configurable, call sites that still used global defaults are routed
through it: the builder's typeConverter reaches the scalar/aggregate/window converters, and the
CREATE-statement catalog reader uses the provider's type factory and connection config.

Compatibility

Source-compatible — no public API removed, deprecated constructors still delegate to the builder,
and behavior is unchanged for the default provider.

Stack (#983 split, merge bottom-up)

  1. feat(isthmus)!: inject ConverterProvider into the SQL statement parsers #1035 — inject ConverterProvider into the SQL statement parsers (merged)
  2. feat(isthmus): introduce a ConverterProvider builder #1036 — this PR
  3. feat(isthmus): configurable unquoted identifier casing via the ConverterProvider builder #1037 — configurable unquoted identifier casing via the builder

Add ConverterProvider.builder() and a nested Builder that carries a full Calcite
SqlParser.Config alongside extensions, typeFactory, the function converters,
typeConverter and executionBehavior. getSqlParserConfig() now returns the stored
config, and DEFAULT_SQL_PARSER_CONFIG (the isthmus default: DEFAULT + TO_UPPER +
SqlDdlParserImpl.FACTORY + LENIENT) is exposed as the recommended base for
customization.

Make the builder the sole public construction path: a protected
ConverterProvider(Builder) is the stable subclassing seam (build() and the
delegating public constructors route through it), and all public constructors are
@deprecated in favour of builder(). DEFAULT is now builder().build(). The two
subclasses, DynamicConverterProvider and
AutomaticDynamicFunctionMappingConverterProvider, gain a public (Builder)
constructor calling super(builder) and deprecate their positional constructors.
Callers, tests and examples are migrated to builder()/DEFAULT.
…nverterProvider

processCreateStatementsToCatalog now builds the CalciteCatalogReader with the
injected ConverterProvider's type factory (getTypeFactory()) and connection
config (getCalciteConnectionConfig()) rather than the hardcoded
SubstraitTypeSystem.TYPE_FACTORY / SqlConverterBase.CONNECTION_CONFIG, so a
custom provider's type factory and connection config are honored end-to-end.
The no-arg overload now delegates to the ConverterProvider overload (with
DEFAULT), removing the duplicated reader construction. Behavior is unchanged
for the default provider — same type factory and connection config.
@nielspardon
nielspardon force-pushed the feat/converterprovider-builder-api branch from b065c1c to defa554 Compare July 25, 2026 06:41
…rter

Two spots still used TypeConverter.DEFAULT instead of the provider's:

- ConverterProvider(Builder) built the scalar/aggregate/window function
  converters via their 2-arg constructors, which fall back to
  TypeConverter.DEFAULT, so a TypeConverter set through Builder.typeConverter(...)
  was ignored by those converters. Pass builder.typeConverter through.
- SqlExpressionToSubstrait.toNamedStruct converted column types with
  TypeConverter.DEFAULT; use the injected provider's getTypeConverter().

Behavior is unchanged for the default provider, whose type converter is
TypeConverter.DEFAULT.
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