Skip to content

feat(core): accept the resolved reference paths when building a row mapper - #361

Merged
zantvoort merged 1 commit into
mainfrom
feat/fetch-paths-object-mapper
Aug 2, 2026
Merged

feat(core): accept the resolved reference paths when building a row mapper#361
zantvoort merged 1 commit into
mainfrom
feat/fetch-paths-object-mapper

Conversation

@zantvoort

Copy link
Copy Markdown
Collaborator

Problem

select().fetch(...) widens the select list: a named reference is selected as the referenced table's columns rather than as its foreign key column. The row mapper has to be built for that wider shape, which QueryImpl and PreparedQueryImpl do by passing the plan derived from Sql.fetchPaths().

The overload that carries the plan is public but takes FetchPlan, which is package-private, so it is public in name only. st.orm.core.template.impl is exported, so an out-of-tree query executor can reach ObjectMapperFactory, but it cannot name that parameter type and is left with the three-argument overload, which resolves the mapper for the declared shape. Reading a fetching statement through such an executor then fails on the arity mismatch: the statement returns the wide row, the mapper is compiled for the narrow one, and no mapper matches the column count.

Change

Publish an overload taking the paths themselves, in the form Sql.fetchPaths() already reports them, and demote the FetchPlan overload to package-private. Its callers, QueryImpl, PreparedQueryImpl and ObjectMapperFactoryTest, all sit in the package.

The javadoc records the condition an external caller has to honour: the paths apply only when the rows are read back as the statement's own data type, since reading the same statement as anything else, a primary key for a ref stream in particular, consumes the columns by that type's own shape. That mirrors QueryImpl.Environment.fetchPlanFor.

Verification

ObjectMapperFactoryTest, FetchElementTest, FetchSizeTest and RefFetchIntegrationTest pass (50 tests). Behaviour of the in-tree executors is unchanged: they keep calling the FetchPlan overload.

…apper

A statement that resolves references widens its select list, so the row mapper
has to be built for that wider shape. The overload carrying the plan took the
package-private FetchPlan, which no executor outside the package can name, so a
third-party query executor could only build mappers for the declared shape and
failed on the arity mismatch.

Take the paths instead, in the form Sql.fetchPaths() already reports them, and
keep FetchPlan internal.
Copilot AI review requested due to automatic review settings August 2, 2026 11:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes ObjectMapperFactory usable by out-of-tree query executors when a SELECT widens its row shape due to resolved reference paths (as reported by Sql.fetchPaths()), by exposing a public overload that accepts those paths directly.

Changes:

  • Added a new public ObjectMapperFactory.getObjectMapper(..., Collection<String> fetchPaths) overload that converts paths to a FetchPlan.
  • Demoted the FetchPlan overload to package-private (keeping in-package callers unchanged) and expanded Javadoc guidance for external callers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +95 to +97
@Nonnull Collection<String> fetchPaths) throws SqlTemplateException {
return getObjectMapper(columnCount, type, refFactory, FetchPlan.of(fetchPaths));
}
@zantvoort zantvoort added this to the 1.13.1 milestone Aug 2, 2026
@zantvoort
zantvoort merged commit ed65afe into main Aug 2, 2026
8 checks passed
@zantvoort
zantvoort deleted the feat/fetch-paths-object-mapper branch August 2, 2026 12:51
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.

2 participants