Skip to content

chore(introspect,core): Harden schema export/diff and introspect connection lifecycle#88

Merged
mhiro2 merged 5 commits into
mainfrom
chore/export-diff-introspect-bundled-fixes
Apr 26, 2026
Merged

chore(introspect,core): Harden schema export/diff and introspect connection lifecycle#88
mhiro2 merged 5 commits into
mainfrom
chore/export-diff-introspect-bundled-fixes

Conversation

@mhiro2

@mhiro2 mhiro2 commented Apr 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • Preserve views and enums across relune-core schema export/import so JSON round-trips stop dropping them.
  • Stabilize diff_schemas view/enum matching so id-encoding drift between producers no longer manifests as phantom add+remove pairs.
  • Surface drain failures from close_pool_when_done instead of silently masking them under a successful operation result.
  • Make the introspection pool cap operator-tunable via RELUNE_DB_POOL_MAX_CONNECTIONS, with a CLI reference note.
  • Extend introspect integration coverage to empty databases, reserved-word identifiers, composite keys, enum types, cross-schema FKs, and MySQL ENUM/SET.

Changes

  • 4693570 : fix(core): preserve views and enums across schema export and import
    • Add ViewExport / EnumExport and extend SchemaExport with serde-default views / enums fields so older JSON keeps deserializing.
    • Round-trip view and enum payloads through export_schema / import_schema and reject empty id values during import.
  • e22a310 : fix(diff): match views and enums by schema-qualified name
    • Replace id-keyed maps with (schema, name) lookups normalized to lowercase, eliminating false add+remove churn when producers disagree on id encoding.
    • Add regression tests demonstrating views and enums diff cleanly across mismatched id schemes.
  • 36dedcb : fix(introspect): surface drain timeouts from close_pool_when_done
    • Wrap pool.close() with tokio::time::timeout so a hung drain emits IntrospectError::Timeout instead of disappearing into a successful return.
    • Preserve the original operation error when both fail so cleanup state never masks the root cause.
  • 4baaeaf : feat(introspect): make connection pool max overridable via env var
    • Read RELUNE_DB_POOL_MAX_CONNECTIONS to override the per-dialect pool cap; non-positive or non-numeric values fall back to the existing defaults (PostgreSQL/MySQL fan out to 6, SQLite to 1).
    • Wire the helper through PostgreSQL, MySQL, and SQLite catalogs and document the override in the CLI reference.
  • a87ff20 : test(introspect): cover empty databases, reserved words, composite keys, enums, and cross-schema FKs
    • Add testcontainers-backed cases for empty PostgreSQL/SQLite, "order"/"select" reserved-word identifiers with composite PK/FK/UNIQUE INDEX, PostgreSQL CREATE TYPE enums plus cross-schema FKs, and MySQL ENUM/SET column extraction.

mhiro2 added 5 commits April 26, 2026 22:53
Add ViewExport and EnumExport entries to SchemaExport so that view and
enum metadata survives a JSON round trip. Without this, downstream
diff workflows that go through schema-json saw every view and enum as
removed because import_schema rebuilt an empty Schema.views / .enums.
The new payloads validate that each id is non-empty, mirroring the
existing table contract, and keep the format field-additive via serde
defaults.
diff_schemas previously matched views and enums on their opaque id
field, which the parser composes from normalized identifiers and the
introspector composes from raw catalog identifiers. Any drift between
the two producers showed up as a phantom add+remove pair instead of
a modification. Switch the match key to the lowercased
(schema_name, name) pair so the contract is anchored to the data
model rather than the producer's id encoding, and add regression
tests that diff a view and an enum across mismatched id values.
Previously close_pool_when_done discarded the outcome of pool.close()
entirely, so a hung drain (e.g. a connection that never finishes
draining or has lost connectivity) silently returned the operation
result and left the caller unaware that cleanup did not complete.
Wrap the close in a 30-second timeout: if the operation succeeded but
the drain timed out, surface IntrospectError::Timeout; if the
operation already failed, that error wins so the original cause is
not masked. Narrow the function's error type to IntrospectError to
let it construct the timeout error directly without burdening callers.
Read RELUNE_DB_POOL_MAX_CONNECTIONS to override the per-dialect pool cap
(PostgreSQL/MySQL default to 6, SQLite to 1). Constrained CI runners or
unusual workloads can tune the cap without code changes; non-positive or
non-numeric values fall back to the default.
…ys, enums, and cross-schema FKs

Adds integration tests for previously uncovered shapes:
- empty PostgreSQL and SQLite databases
- PostgreSQL reserved-word table and column names with composite primary key,
  composite foreign key, and composite unique index
- PostgreSQL enum types and cross-schema foreign keys
- MySQL ENUM and SET column types
@mhiro2 mhiro2 self-assigned this Apr 26, 2026
@mhiro2 mhiro2 added the bug Something isn't working label Apr 26, 2026
@github-actions

Copy link
Copy Markdown

Code Metrics Report

main (0c5b241) #88 (a397dc4) +/-
Coverage 94.7% 94.7% +0.0%
Test Execution Time 1m24s 1m24s 0s
Details
  |                     | main (0c5b241) | #88 (a397dc4) |  +/-  |
  |---------------------|----------------|---------------|-------|
+ | Coverage            |          94.7% |         94.7% | +0.0% |
  |   Files             |             77 |            77 |     0 |
  |   Lines             |          34255 |         34529 |  +274 |
+ |   Covered           |          32442 |         32726 |  +284 |
  | Test Execution Time |          1m24s |         1m24s |    0s |

Code coverage of files in pull request scope (92.8% → 93.9%)

Files Coverage +/- Status
crates/relune-core/src/diff.rs 91.0% +1.5% modified
crates/relune-core/src/export.rs 98.7% +0.4% modified
crates/relune-introspect/src/connect.rs 94.8% -1.2% modified
crates/relune-introspect/src/mysql/catalog.rs 94.2% 0.0% modified
crates/relune-introspect/src/postgres/catalog.rs 98.2% +1.4% modified
crates/relune-introspect/src/sqlite/mod.rs 84.6% 0.0% modified

Reported by octocov

@mhiro2
mhiro2 merged commit 5548c8e into main Apr 26, 2026
5 checks passed
@mhiro2
mhiro2 deleted the chore/export-diff-introspect-bundled-fixes branch April 26, 2026 22:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant