Skip to content

feat: close database layer gaps for 1.0#40

Merged
markshust merged 1 commit intodevelopfrom
feature/db-layer-1.0-gaps
Apr 24, 2026
Merged

feat: close database layer gaps for 1.0#40
markshust merged 1 commit intodevelopfrom
feature/db-layer-1.0-gaps

Conversation

@markshust
Copy link
Copy Markdown
Collaborator

@markshust markshust commented Apr 24, 2026

Summary

Ten targeted hardenings to the database layer, query builder, and entity/repository surface — the last pass before 1.0.

  • Primary keys: int|string across find/findOrFail/exists/relationship loaders. MissingPrimaryKeyException thrown at metadata-parse time — no more silent 'id' fallback.
  • Query builder: min/max/sum/avg aggregates, count(?string) widened, GROUP BY / HAVING, DISTINCT, UNION / UNION ALL, column aliasing (COUNT(*) as total). Shared IdentifierValidator routes all dynamic identifier checks.
  • Bulk insert: insertBatch(Entity[]) — single multi-row INSERT, per-entity Creating/Created events, MySQL lastInsertId + offset / PostgreSQL RETURNING.
  • JSON as EAV alternative: #[Column(type: 'json')] with array / ?array, unlimited nesting. Full query operators: whereJsonContains, whereJsonExists, whereJsonMissing, arrow-path syntax (data->user->name, data->>name) in where() and select(). MySQL (JSON_EXTRACT/JSON_UNQUOTE/JSON_CONTAINS/JSON_CONTAINS_PATH) and PostgreSQL (-> / ->> / @> / jsonb_path_exists). Array-root-only is a permanent design boundary.
  • Specs + eager-load: new EntityQueryBuilderInterface widens QuerySpecification::apply() parameter. Specs now express eager loading fluently via $builder->with('author') inside apply(). Fixes pre-existing bug where matching() passed the raw inner builder to specs.

All public additions land on an interface first. Both marko/database-mysql and marko/database-pgsql drivers implement every new method in lockstep. Docs and package READMEs updated.

Test plan

  • All tests pass via composer test (4816 passed, 0 failed)
  • Verify db-layer-1.0-gaps is merged before cutting 1.0
  • Spot-check the updated docs pages render correctly
  • Run composer test:all to include destructive integration tests before release cut

🤖 Generated with Claude Code

Ten targeted hardenings across the database layer, query builder, and
entity/repository surface:

- String/UUID primary key support (int|string on find/findOrFail/exists)
- Loud primary key validation (MissingPrimaryKeyException at metadata parse;
  removed silent 'id' column fallbacks)
- Aggregate functions on QueryBuilder (min/max/sum/avg; count widened)
- GROUP BY / HAVING on QueryBuilder
- DISTINCT / UNION / UNION ALL on QueryBuilder
  (UnionShapeMismatchException on column-count mismatch)
- Column aliasing in select() with a shared IdentifierValidator
- insertBatch(Entity[]) with per-entity Creating/Created lifecycle events,
  single multi-row INSERT, MySQL lastInsertId+offset / PostgreSQL RETURNING
- JSON column type (#[Column(type: 'json')]) with array / ?array support,
  JSON_THROW_ON_ERROR, JSONB on PostgreSQL; array-root-only scope is
  a permanent design boundary
- EntityQueryBuilderInterface extends QueryBuilderInterface with with();
  QuerySpecification::apply() widened to it so specs express eager
  loading fluently; fixed a pre-existing bug where matching() passed
  the raw inner builder
- JSON query operators (whereJsonContains / whereJsonExists /
  whereJsonMissing) plus arrow-path syntax (data->user->name,
  data->>name) in where() and select(); MySQL JSON_EXTRACT/JSON_UNQUOTE/
  JSON_CONTAINS/JSON_CONTAINS_PATH and PostgreSQL native -> / ->> / @> /
  jsonb_path_exists

All public additions land on an interface first. Both
marko/database-mysql and marko/database-pgsql drivers implement
every new method in lockstep.

Documentation updated in docs/src/content/docs/packages/ for database,
database-mysql, and database-pgsql pages, plus a slimmed
packages/database/README.md per the project docs standard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the enhancement New feature or request label Apr 24, 2026
@markshust markshust merged commit 2973d65 into develop Apr 24, 2026
4 checks passed
@github-actions github-actions Bot removed the enhancement New feature or request label Apr 24, 2026
@markshust markshust deleted the feature/db-layer-1.0-gaps branch April 24, 2026 15:06
@github-actions github-actions Bot added the enhancement New feature or request label Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant