Skip to content

Organize type mapping, marshaling and result sets into subfolders - #1580

Draft
trueqbit wants to merge 15 commits into
devfrom
refactor/type-mapping-marshaling-result-set
Draft

trueqbit wants to merge 15 commits into
devfrom
refactor/type-mapping-marshaling-result-set

Conversation

@trueqbit

Copy link
Copy Markdown
Collaborator

Groups the headers around C++ ↔ SQLite type conversion by layer, each consuming the one below:

sqlite3/ → type_mapping/ → marshaling/ → serialization/, result_set/

  • type_mapping/ - type level: type_printer.h, type_is_nullable.h, is_std_ptr.h, arithmetic_tag.h.
  • marshaling/ - values across the boundary to the C library, both directions: the customization points statement_binder.h, row_extractor.h, field_printer.h; what builds on them for several values at once - parameter_binders.h and struct_extractor.h (both split out of the former two), object_from_column_builder.h, column_result_proxy.h, arg_values.h, values_to_tuple.h; and the pointer-passing interface's values (pointer_value.h).
  • result_set/ - what a query yields and how it is iterated: column_result.h, result_set_view.h, result_set_iterator.h, mapped_view.h, mapped_iterator.h.

Along the way:

  • The journal_mode / locking_mode row extractors move next to their enums, so marshaling no longer depends on PRAGMA value types.
  • New closed field predicates is_integer_mapped_v (replacing three direct is_base_of<integer_printer, type_printer<F>> checks), is_pointer_arg_v and is_pointer_binding_v (replacing pattern matches on the class templates; ast/app_function.h drops its forward declarations). field_predicates_fwd.h is regrouped by what the predicates read.
  • The parameter binders are named after what they bind: parameter_binder (was field_value_binder, now the base), expression_parameter_binder (was conditional_binder), tuple_parameter_binder (was tuple_value_binder); an unused pointer overload is dropped.
  • AGENTS.md and docs/internals/vocabulary-layer.md describe the new folders and predicates; a wrong statement about where the C++17 hidden-column predicates live is corrected.

No public symbol changes; only internal headers move and internal names change.

Test plan

  • New static tests: tests/static_tests/is_integer_mapped.cpp, tests/static_tests/is_pointer_value.cpp.
  • Existing coverage of the touched code: tests/static_tests/is_bindable.cpp, is_printable.cpp, bindable_filter.cpp, row_extractor.cpp, column.cpp, is_primary_key_insertable.cpp; tests/pointer_passing_interface.cpp; tests/prepared_statement_tests/select.cpp; tests/statement_serializer_tests/bindables.cpp, conditions.cpp; tests/row_extractor.cpp.

🤖 Generated with Claude Code

`type_printer.h`, `type_is_nullable.h`, `is_std_ptr.h` and `arithmetic_tag.h` map C++ types onto
SQLite's at the type level - the declared type, nullability, the recognized nullable holders and the
storage-class tag arithmetic values are dispatched on. They get their own subfolder, apart from the
conversions of values that build on them.

Co-Authored-By: Claude Opus 5.5
The customization points converting values across the boundary to the SQLite C library -
`statement_binder.h`, `row_extractor.h`, `field_printer.h` - get their own subfolder, together with
what assembles several values at once on top of them (`object_from_column_builder.h`,
`column_result_proxy.h`, `arg_values.h`, `values_to_tuple.h`) and the pointer-passing interface's
values (`pointer_value.h`), which exist only to be bound and extracted.

Co-Authored-By: Claude Opus 5.5
The extraction of composite column results - tuples, ad-hoc structures and mapped objects - assembles
them from per-value row extractors. It moves into `marshaling/struct_extractor.h` together with
`make_row_extractor()`, including the table reference specialization that lived in
`object_from_column_builder.h`; `row_extractor.h` is left with the customization point and its
specializations for single values.

Co-Authored-By: Claude Opus 5.5
`conditional_binder`, `field_value_binder` and `tuple_value_binder` bind the parameters of a statement
in sequence through `statement_binder` - the binding counterpart of `struct_extractor`. They move into
`marshaling/parameter_binders.h` together with `bindable_filter_t`; `statement_binder.h` is left with
the customization point and its specializations for single values.

Co-Authored-By: Claude Opus 5.5
What a query yields and how it is iterated - `column_result.h` with `column_result_of_t`, and the lazy
views and iterators over a select and over the mapped objects of a table - get their own subfolder,
one layer above the marshaling they consume.

Co-Authored-By: Claude Opus 5.5
The `row_extractor` specializations for `journal_mode` and `locking_mode` move from `row_extractor.h`
into `journal_mode.h` and `locking_mode.h`, the way a user's type carries its own mapping. The
marshaling layer no longer depends on the PRAGMA value types.

Co-Authored-By: Claude Opus 5.5
Whether a C++ type maps to SQLite's INTEGER type was asked in three places by inspecting the
`type_printer` customization point directly - `is_base_of<integer_printer, type_printer<F>>` - for the
rowid alias capability, the AUTOINCREMENT check of a column and the choice between an ORDER BY
expression and a positional ordinal. `is_integer_mapped_v` is a closed field predicate, declared in
`field_predicates_fwd.h` and defined with the point it reads in `type_printer.h`, and those consumers
ask it instead. A custom type whose type printer derives from `integer_printer` still qualifies.

Co-Authored-By: Claude Opus 5.5
`is_pointer_arg_v` and `is_pointer_binding_v` are declared in `field_predicates_fwd.h` and defined with
the types in `pointer_value.h`, which now also forward-declares them regardless of the SQLite version.
Their consumers grammar-match through them instead of pattern-matching the class templates: the
`statement_binder` and `row_extractor` specializations, the serializer of bound values, and the check of
pointer values in an application-defined function call, which no longer needs its own forward
declarations - accepting a null pointer binding moves into the pointer data type check.

`field_predicates_fwd.h` is regrouped into namespace blocks by what the predicates read: capabilities
derived from the type, the type mapping's and the marshaling's customization points, and the
pointer-passing interface's values.

Co-Authored-By: Claude Opus 5.5
Consumers reach the vocabulary through its umbrellas, never through an `algorithms/` file directly:
`app_function.h`, `order_by.h`, `column.h` and `parameter_binders.h` include `node_algorithms.h`
instead of `field_predicates_fwd.h`.

Co-Authored-By: Claude Opus 5.5
`is_hidden_column_of_vtab_v` is neither declared in `field_predicates_fwd.h` nor defined in
`field_predicates.h`: like `is_hidden_field_of_vtab_v`, it is the C++17 fallback of the concepts in
`field_predicates_concepts.h`, declared and defined there. `field_predicates.h` defines
`is_text_value_v` besides `is_rowid_alias_capable_v` and does not need `member_traits/`.

Co-Authored-By: Claude Opus 5.5
`is_integer_mapped`, `is_pointer_arg` and `is_pointer_binding` follow the vocabulary's shape of an
alias template over the variable template, instead of copying the derived structs of `is_bindable`
and `is_printable`.

Co-Authored-By: Claude Opus 5.5
The comments of the field predicates state what a predicate checks; where it is defined is said once per
namespace block. The other new comments drop their wordiness.

Co-Authored-By: Claude Opus 5.5
`field_value_binder` binds values that are all parameters, and is now the base `parameter_binder`;
`conditional_binder`, the AST iteration callable binding an expression's bindable nodes and skipping
the others, becomes `expression_parameter_binder` deriving from it. The strict binder no longer needs a
deleted overload for non-bindable values, as its only overload is constrained to bindable ones.

`field_value_binder`'s overload for a pointer to a value is dropped: no caller passes one - the binders
are handed field values via `std::invoke()` on member pointers, and only `tuple_value_binder` receives the
pointers `object_field_value()` returns for setters. For a raw pointer field such as `const char*` it would
even have been preferred over binding the value itself.

Co-Authored-By: Claude Opus 5.5
It binds the elements of a tuple as the parameters of a statement, named like `parameter_binder` and
`expression_parameter_binder`.

Co-Authored-By: Claude Opus 5.5

This branch has not been deployed

No deployments
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