Skip to content

fix(core,layout): Resolve review findings across core and layout#185

Merged
mhiro2 merged 10 commits into
mainfrom
fix/core-layout-correctness-and-perf
Jun 5, 2026
Merged

fix(core,layout): Resolve review findings across core and layout#185
mhiro2 merged 10 commits into
mainfrom
fix/core-layout-correctness-and-perf

Conversation

@mhiro2

@mhiro2 mhiro2 commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fix correctness defects in core schema handling: case-insensitive foreign-key target comparison, duplicate stable_id rejection on import, and an un-bypassable FocusSpec depth clamp.
  • Remove the unused, diverged duplicate SchemaGraph builder from relune-core (production builds use the layout builder).
  • Fix layout defects: a panic on very large rank/position counts, broken Mermaid relationship-label escaping, and self-loops that ignored layout-direction mirroring.
  • Cut quadratic hot paths in layout (edge-label collision, prefix grouping, force group packing) while keeping output byte-for-byte identical where geometry is unaffected.

Changes

  • 66b3ef8 fix(core): reject duplicate stable_id on schema import
    • import_schema now rejects duplicate (not just empty) table/view/enum identifiers, preventing silent last-wins collapse in diff/overlay which key by stable_id.
  • 2d480b5 refactor(core): make FocusSpec depth clamp impossible to bypass
    • Make FocusSpec::depth private with a depth() accessor and route every construction site through FocusSpec::new, so the MAX_FOCUS_DEPTH clamp can no longer be skipped by direct struct construction.
  • 5561235 refactor(core)!: remove unused duplicate SchemaGraph builder
    • Remove SchemaGraph/GraphNode/GraphEdge/GraphBuildError and the EnumIndex helper; production graph building lives in relune-layout and the removed builder had diverged (no view→view edges, dead guard).
    • Keep NodeKind/EdgeKind/SqlRelation/collect_sql_relations since the layout crate depends on them.
  • e02d1ff fix(layout): avoid count_crossings panic on very large layouts
    • Pack crossing positions into a u64 (32 bits each) instead of a 16-bit-asserted usize, removing the panic for ranks with more than 65536 nodes.
  • 6f1ab13 perf(layout): precompute node adjacency for force group packing
    • Precompute connected node-index pairs once into a HashSet so group-packing connectivity checks are O(1) lookups instead of a full edge rescan per call.
  • 03ae1d0 fix(layout): keep Mermaid relationship labels valid without escapes
    • Replace quotes and control characters in relationship labels rather than backslash-escaping them, since Mermaid quoted strings do not honor escapes and previously broke or rendered stray backslashes.
  • d6d5b90 fix(layout): mirror self-loop routes to match layout direction
    • Reflect self-loop geometry across the node center for RightToLeft/BottomToTop so loops follow the mirrored node coordinates instead of always bulging east; only self-loop geometry changes, with regression snapshots updated.
  • 03ab84d perf(layout): index edge-label obstacles with a spatial grid
    • Index node and edge obstacle footprints in a uniform grid so each edge considers only nearby obstacles, replacing the per-pass O(E²) sweep.
    • Return candidates in ascending index order to preserve the original obstacle ordering, keeping the order-sensitive overlap-area sum byte-for-byte identical.
  • 7d799da fix(core): compare foreign key target identifiers case-insensitively
    • Fold FK target table/schema (diff) and FK source-column matching (layout graph) to case-insensitive comparison, matching the rest of identifier handling and avoiding spurious modified/add-remove diffs.
  • cdbfdee perf(layout): prune build_prefix_groups to near-linear comparisons
    • Sort names and stop comparing once the common prefix can no longer form a meaningful group prefix, yielding the same adjacency (and groups) as the exhaustive all-pairs scan, including the non-contiguous-component case.

mhiro2 added 10 commits June 4, 2026 23:57
import_schema only rejected empty identifiers; duplicate non-empty ids
silently collapsed entries because diff/overlay key tables by stable_id
(last-wins in the HashMap). Reject duplicate table/view/enum ids with a
clear ImportError.
The depth field was public, so direct struct construction (in the CLI
and app) skipped the MAX_FOCUS_DEPTH clamp that FocusSpec::new and serde
applied. Make depth private with a depth() accessor and route every
construction site through FocusSpec::new.
SchemaGraph::from_schema duplicated the graph builder that lives in
relune-layout, was only exercised by relune-core's own tests, and had
diverged (it never emitted view->view dependency edges and carried a
dead always-true guard). Production builds go through the layout
builder, so remove SchemaGraph/GraphNode/GraphEdge/GraphBuildError and
the EnumIndex helper. NodeKind/EdgeKind/SqlRelation/collect_sql_relations
stay (the layout crate depends on them).

BREAKING CHANGE: SchemaGraph and related types are no longer exported.
count_crossings packed (rank, position) into a usize assuming each fits
in 16 bits and asserted otherwise, so a rank with more than 65536 nodes
panicked. Pack into a u64 (32 bits each) and drop the asserts; the limit
is now unreachable for any real schema.
separate_force_groups checked connectivity with force_nodes_are_connected,
which rescanned every edge per call, making the group-vs-group case
O(group^2 * E) and the whole pass quadratic. Build the connected
node-index pairs once into a HashSet so each check is an O(1) lookup;
behaviour is unchanged (connectivity is a boolean).
Mermaid erDiagram relationship labels are quoted strings that do not
honor backslash escapes, so a literal quote terminated the string and a
backslash-escaped bracket rendered the backslash verbatim. Replace
quotes with apostrophes and control characters with spaces for
relationship labels instead of reusing the attribute-comment escaper.
Node coordinates are mirrored for RightToLeft (horizontal) and
BottomToTop (vertical) before edges are routed, but self-loops were
always built bulging east, so they pointed the wrong way for mirrored
directions. Reflect the self-loop polyline across the node's own center
to follow the mirror. Only self-loop geometry changes (regular-edge
routes and node positions are unchanged); the right_to_left and
bottom_to_top regression snapshots are updated accordingly.
resolve_edge_label_collisions rebuilt the full obstacle list (every node
plus every other edge's route, markers and label) for each edge on every
relaxation pass, giving O(E^2) behaviour that dominated layout time on
large schemas. Index node and edge obstacle footprints in a uniform grid
and query only those near each edge's reachable label region.

place_label_on_route's overlap-area sum is order-sensitive (f32 is not
associative), so the grid returns candidates in ascending index order and
rebuilds the original obstacle ordering (nodes, this edge's endpoint
markers, then other edges by index). Excluded obstacles lie outside the
reachable region and contribute exactly zero, so output is byte-for-byte
identical.
FK column names were already lowercased when diffing, but the target
table/schema were compared verbatim, so a case-only difference surfaced
as a spurious modification (or, for unnamed FKs, an add/remove pair).
The layout graph builder likewise matched FK source columns to table
columns case-sensitively, diverging from schema validation. Fold both to
case-insensitive comparison.
build_prefix_groups compared every pair of table names before the graph
was built. A pair can only share a group prefix when their common prefix
has at least two alphanumeric characters, and for sorted names the common
prefix shrinks monotonically, so each name only needs comparing against
the surrounding run that still meets that bound. The adjacency edge set
(and thus the resulting groups) is identical to the exhaustive scan,
including the non-contiguous component case now covered by a test.
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

Code Metrics Report

main (3a4c823) #185 (6a8b0ed) +/-
Coverage 94.4% 94.4% +0.0%
Test Execution Time 1m37s 1m49s +12s
Details
  |                     | main (3a4c823) | #185 (6a8b0ed) |  +/-  |
  |---------------------|----------------|----------------|-------|
+ | Coverage            |          94.4% |          94.4% | +0.0% |
  |   Files             |            100 |            100 |     0 |
  |   Lines             |          37180 |          36683 |  -497 |
- |   Covered           |          35123 |          34657 |  -466 |
- | Test Execution Time |          1m37s |          1m49s |  +12s |

Code coverage of files in pull request scope (96.1% → 96.2%)

Files Coverage +/- Status
crates/relune-app/src/lib.rs 96.2% -0.1% modified
crates/relune-app/src/usecases/export.rs 100.0% 0.0% modified
crates/relune-cli/src/commands/diff.rs 95.0% +2.4% modified
crates/relune-cli/src/commands/export.rs 92.1% 0.0% modified
crates/relune-cli/src/commands/render.rs 98.4% 0.0% modified
crates/relune-core/src/config.rs 95.8% +19.9% modified
crates/relune-core/src/diff.rs 94.5% +0.0% modified
crates/relune-core/src/export.rs 99.3% +0.6% modified
crates/relune-core/src/graph.rs 92.2% -5.3% modified
crates/relune-layout/src/diagram_export.rs 94.4% +0.2% modified
crates/relune-layout/src/focus.rs 92.6% -0.2% modified
crates/relune-layout/src/graph.rs 98.3% -0.1% modified
crates/relune-layout/src/layout/edge_routing.rs 94.9% +0.2% modified
crates/relune-layout/src/layout/force.rs 87.9% +0.4% modified
crates/relune-layout/src/order.rs 99.3% -0.1% modified
crates/relune-layout/src/route/mod.rs 99.1% +0.0% modified
crates/relune-wasm/src/request.rs 98.5% 0.0% modified

Reported by octocov

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

Schema review

Tip

✅ No risk findings — schema changes look safe to merge.

@mhiro2 mhiro2 self-assigned this Jun 5, 2026
@mhiro2 mhiro2 added the enhancement New feature or request label Jun 5, 2026
@mhiro2
mhiro2 merged commit 552e599 into main Jun 5, 2026
6 checks passed
@mhiro2
mhiro2 deleted the fix/core-layout-correctness-and-perf branch June 5, 2026 00:04
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