Skip to content

Casts 2.0: Class-based cast hierarchy and schema-to-Row auto-wiring #192

Open

Description

@JJJ

Background

Issue #13 added automated data typing via a callable-based $cast attribute on Column and a $casts array on Row (via Traits\Cast). This is the "wimpy" but practical foundation — any PHP callable works, auto-detection covers common types, and it ships without any schema wiring.

This issue tracks the next-generation design: a proper Cast class hierarchy, parameterized casts, and automatic schema-to-Row wiring so subclasses need zero boilerplate.


1. Casts/ directory

A new directory parallel to Operators/ and Parsers/, with an abstract base and concrete types:

Casts/
  Base.php         abstract — single public static cast( mixed $value ): mixed
  Boolean.php      (bool)
  DateTime.php     returns a DateTime object or formatted string (TBD)
  Decimal.php      (float) with configurable precision
  Integer.php      (int)
  Json.php         json_decode / json_encode
  Serialized.php   maybe_unserialize / serialize
  Text.php         (string)

Static cast() methods — unlike Operators, Cast classes carry no state and fire O(rows × columns) times. Static methods avoid per-property instantiation overhead while still being callable via [Integer::class, 'cast'].

Cast classes passed as the $cast attribute or in $casts are automatically recognised and invoked without the caller needing to reference the method name:

new Column( array( 'name' => 'count', 'type' => 'bigint', 'cast' => Casts\Integer::class ) );

2. Parameterized casts

Some types need configuration that a bare callable can't carry. A Casts\Base instance (rather than a static call) solves this:

new Column( array(
    'name' => 'amount',
    'type' => 'decimal',
    'cast' => new Casts\Decimal( precision: 2 ),
) );

Column::cast() checks instanceof Casts\Base and calls ->cast( $value ) on the instance, falling back to the existing callable path for everything else. Fully backwards-compatible.


3. Schema-to-Row auto-wiring (Phase 2)

The current $casts array on Row requires manual duplication of what the Schema already knows. The end goal is zero boilerplate for standard types:

class Ad extends Row {
    protected $schema = Ads_Schema::class;
    // $casts auto-populated from Column definitions — no manual array needed
}

Row::get_cast_map() resolves casts in priority order:

  1. Explicit $casts overrides on the subclass
  2. Column $cast attributes from $schema::get_columns()
  3. Auto-detected cast from column type (already in place)

4. Validators 2.0 (companion issue)

The write-side $validate callable is intentionally left as-is for now — it needs Column context ($this->default, $this->unsigned, $this->allow_null) that makes a pure static class awkward. A Validators/ hierarchy is worth a separate issue once the Casts pattern is proven, with the key design question being how to thread Column state into validator instances cleanly.


Compatibility

The callable path ('cast' => 'intval', 'cast' => 'maybe_unserialize') must remain fully supported. Cast classes are additive sugar on top of it, not a replacement.

Activity

  1. self-assigned this
    on May 23, 2026
  2. added this to the 4.0.0 milestone on May 23, 2026
  3. added
    type: FeatureNew capability or behavior.
    area: Database/KernCore database objects in src/Database/Kern.
    area: Database/TraitsShared database traits and reusable object behavior.
    object: CastCasting behavior and cast-related traits or handlers.
    object: ColumnColumn definitions, validation, casting, and SQL fragments.
    object: RowRow objects and row-level data behavior.
    object: SchemaSchema objects, table definitions, and schema comparison.
    on May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area: Database/KernCore database objects in src/Database/Kern.area: Database/TraitsShared database traits and reusable object behavior.object: CastCasting behavior and cast-related traits or handlers.object: ColumnColumn definitions, validation, casting, and SQL fragments.object: RowRow objects and row-level data behavior.object: SchemaSchema objects, table definitions, and schema comparison.type: FeatureNew capability or behavior.

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions