Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions column.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ type column struct {
i fieldIndex
}

// allocateColumns maps result set columns into the given Mapper's fields and its sub-mappers.
// It populates m.PresentColumns and m.SortedColumnIndexes, sets AncestorNames on sub-maps,
// and removes claimed entries from the provided columns map.
//
// For a mapper marked IsBasic, the function requires exactly one remaining column in
// columns and binds that single column to the mapper; otherwise it returns an error.
// For non-basic mappers, it matches basic fields by name using getColumnNameCandidates
// (honoring the mapper/sub-map delimiter and ancestor names) and records each matched
// column (including the field index). After collecting direct-field mappings it sorts
// the resulting column indexes for m.SortedColumnIndexes and then recursively allocates
// columns for each sub-map.
//
// The function mutates the Mapper structures and the input columns map. It returns any
// error returned by recursive allocation or an error when the IsBasic column constraint
// is violated.
func allocateColumns(m *Mapper, columns map[string]column) error {
presentColumns := map[string]column{}
if m.IsBasic {
Expand Down
13 changes: 12 additions & 1 deletion load.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,18 @@ func (m *Mapper) loadRows(rows *sql.Rows, colTyps []*sql.ColumnType) (*resolver,
//
// for example, if a blog has many Authors
//
// rows are actually []*Cell, theu are passed here as interface since sql scan requires []interface{}
// loadRow maps a single scanned SQL row into the resolver using the provided Mapper.
//
// It creates or reuses an element in rsv based on a computed unique id:
// - For basic mappers (m.IsBasic) the id is "row-<rowCount>" (ensures per-row identity).
// - For non-basic mappers the id is derived from the row values via getUniqueId.
//
// The function expects row to contain the scanned values as []*value.Cell (passed as []interface{} because sql.Scan requires that shape).
// For each present column it converts the corresponding Cell into the destination field (handling pointers, nullable types, basic primitives, and known struct wrappers such as Time, NullBool, NullString, etc.).
// If a column is NULL, loadRow enforces that the destination is either a pointer or a type listed in value.NullableTypes; otherwise it returns an error.
// After populating the element it initializes per-submap resolvers (if any) and recursively calls loadRow for each non-nil subMap, passing the same rowCount.
//
// Returns an error on conversion failures, attempts to load null into non-nullable destinations, or on any recursive loadRow error.
func loadRow(m *Mapper, row []interface{}, rsv *resolver, rowCount int) error {
var (
err error
Expand Down