Skip to content

Load table schemas lazily and in bulk in Registry - #83

Open
roxblnfk wants to merge 3 commits into
2.xfrom
feat/bulk-schema-loading
Open

Load table schemas lazily and in bulk in Registry#83
roxblnfk wants to merge 3 commits into
2.xfrom
feat/bulk-schema-loading

Conversation

@roxblnfk

Copy link
Copy Markdown
Member

🔍 What was changed

  • Registry::linkTable() no longer introspects the table immediately — it only records the database/table pair.
  • The first getTableSchema() call loads every pending table per database through Database::getSchemas() (perf(Schema): bulk table introspection (getSchemas) database#265): a constant number of catalog queries per database instead of a full introspection per table.
  • On a cycle/database version without getSchemas() the Registry falls back to the old per-table path, so the behaviour is only faster, never different.

How it works

  • linkTable() stores schema: null; all linked tables stay pending until a schema is first requested.
  • The first getTableSchema() groups pending tables by database and loads each group in one bulk call; entities sharing a table receive the same AbstractTable instance, missing tables come back as STATUS_NEW schemas.
  • A table linked after the first load (embedded relations do this) reuses the already loaded instance; only genuinely new tables are fetched.

Why?

Fixing cycle/orm#466: on a remote database with 60–100 ms round-trip latency, schema compilation of hundreds of entities takes minutes because each table is introspected separately. Benchmarked against Postgres with 200 tables (13 columns, 2 indexes, FK each): 1200 queries / 3.7 s per-table vs 6 queries / 0.6 s bulk; at 100 ms RTT that is ~2 minutes vs ~0.6 s.

One behavioural note: introspection errors now surface at the first getTableSchema() call instead of inside linkTable().

Checklist

linkTable() no longer introspects the table right away: it only records the database/table pair, and the first getTableSchema() call loads every pending table per database through Database::getSchemas() — one constant-cost batch instead of a full introspection per table (cycle/orm#466). On cycle/database without getSchemas() the old per-table path is used, so the required version stays ^2.20.

Entities sharing a table still receive the same AbstractTable instance, and a table linked after the first load (embedded relations) reuses the already loaded schema.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Covers the paths the lazy loading introduced: schema sharing between entities on one table, a table linked after the first bulk load reusing the loaded instance, the per-table fallback for cycle/database without getSchemas() (via a LegacyDatabase fixture), and the exception on a table implementation without getSchema().

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.47826% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.09%. Comparing base (cde7e2a) to head (918e0b6).

Files with missing lines Patch % Lines
src/Registry.php 93.47% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##                2.x      #83      +/-   ##
============================================
+ Coverage     94.97%   95.09%   +0.12%     
- Complexity      595      602       +7     
============================================
  Files            46       46              
  Lines          1711     1734      +23     
============================================
+ Hits           1625     1649      +24     
+ Misses           86       85       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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