Pluggable graph interface for Hoptimator topology + Mermaid renderer#222
Merged
Conversation
Collaborator
|
Can we see example input/output in the PR description? GH will render mermaid! |
324fbb1 to
39213d9
Compare
Code Coverage
|
Collaborator
Author
Done! |
Collaborator
|
Really neat. Wondering why we need the |
Collaborator
Author
This is what I am actively working on! claude did some weird stuff I am unwinding |
Introduces the visualization framework consumed by the `!graph` command in a follow-up commit: - `com.linkedin.hoptimator.graph` (in hoptimator-api): GraphNode, GraphEdge, GraphTarget, PipelineGraph data model + GraphProvider and GraphRenderer SPIs. - New `hoptimator-graph` module hosting the Mermaid renderer plus CronHumanizer (renders cron expressions in trigger labels as English via cron-utils CronDescriptor, falling through to the raw cron string on parse failure). The renderer is registered via META-INF/services and discovered by GraphService (added in the next commit).
Hooks the graph SPI from the previous commit up to a working data path: - GraphService (hoptimator-jdbc): the dispatch entry point. Walks Calcite's schema tree to resolve a user-typed identifier (TWO_LEVEL.NAME or THREE_LEVEL.SCHEMA.NAME) to a GraphTarget, loads GraphProvider and GraphRenderer impls via ServiceLoader, and dispatches. - PipelineGraphBuilder + K8sGraphProvider (hoptimator-k8s): direction-aware traversal of Pipeline / TableTrigger / View references that produces a PipelineGraph rooted at the target. - LogicalTable detection: HoptimatorJdbcSchema.isLogical() lazily walks its downstream Calcite connection to spot any sub-schema tagged with the new LogicalSchemaMarker, so the JDBC layer can surface LogicalTable targets without baking driver-specific URL prefixes or class names into the adapter. LogicalTableSchema implements the marker. isLogical() lives on HoptimatorJdbcSchema rather than the Database SPI to keep Database a thin K8s-CRD surface free of planner concerns. - GraphService resolves identifiers to MaterializedView (view), LogicalTable (marker hit), or Resource (everything else with a HoptimatorJdbcSchema backing) targets; failures throw SQLException with the offending segment in the message rather than silently building a degenerate graph.
Surfaces the visualization framework as a single Sqlline command: - `!graph <identifier> [depth]` in hoptimator-cli renders the resolved target as Mermaid. Depth defaults to a reasonable bound and negative depths error. The command auto-detects target kind via the resolver in the previous commit, so users do not need separate `!graph table` / `!graph view` / `!graph logical` variants. - Quidem-driven integration scripts under hoptimator-k8s, hoptimator-logical, and hoptimator-mysql (k8s-graph.id, k8s-trigger-graph.id, logical-graph.id, mysql-graph.id) that exercise the resolver + Mermaid renderer end-to-end against the test catalogs each module already ships. Driven by the new graph-aware harness in QuidemTestBase. - Sample logicaldb.yaml updated to expose a logical table that the integration scripts can exercise.
f97296a to
536c97c
Compare
ryannedolan
approved these changes
May 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a generic graph interface to Hoptimator — a pluggable model for representing the topology of pipelines, triggers, and logical tables — together with an initial Mermaid renderer that's wired into the sqlline !graph command. The interface is the point; Mermaid is one rendering of it.
The graph interface (hoptimator-api)
The data model and SPI live where the rest of Hoptimator's public surface lives, so a renderer or backend can depend on them without pulling K8s, util, or anything else:
The dispatcher (hoptimator-jdbc)
GraphService in hoptimator-jdbc is the runtime entry point — buildGraph(identifier, depth, conn), render(graph, format), availableFormats(). Sits alongside the other service classes (ValidationService). Doesn't know about K8s or Mermaid; just ServiceLoaders providers and renderers and dispatches.
A future deployment substrate (non-K8s, RPC-backed, in-process) or a different rendering target (D3 JSON for an interactive web view, DOT for graphviz, etc.) plugs in without touching anything in this PR.
The K8s provider (hoptimator-k8s)
K8sGraphProvider is the only provider in this PR. It uses PipelineGraphBuilder to traverse the K8s state: starts at the target, uses the depends-on-<slug> labels to find Pipelines and TableTriggers in O(matches) on the server, parses the
directional source/sink annotations to draw edges, and recurses up to a configurable depth.
The Mermaid renderer (hoptimator-graph)
New module — exists solely to hold the Mermaid renderer (and any future renderers we don't want bloating hoptimator-util). MermaidRenderer in com.linkedin.hoptimator.graph.mermaid is registered as the default for format "mermaid". Produces a
flowchart with subgraphs for LogicalTable tiers, distinct node shapes per type, and dotted edges for trigger flows. Other renderers can register against the same SPI without changing this one.
Test plan
Known limitations
Examples
Command:
Result:
flowchart TD subgraph n0["LogicalTable logical-testevent"] direction LR subgraph s_nearline["nearline"] n2[("KAFKA.testevent")] end subgraph s_offline["offline"] n3[("MYSQL.testdb.testevent")] end subgraph s_online["online"] n5[("VENICE.testevent")] end n1[/"logical-testevent-nearline-to-offline<br/>kind: FlinkSessionJob<br/>engine: Flink"/] n4[/"logical-testevent-nearline-to-online<br/>kind: FlinkSessionJob<br/>engine: Flink"/] n6{"logical-testevent-offline-trigger<br/>(paused)"} end n2 --> n1 n1 --> n3 n2 --> n4 n4 --> n5 n3 -.-> n6 n6 -.-> n5Command:
Result:
flowchart LR subgraph n0["Materialized View"] n1[/"ads-multi<br/>kind: FlinkSessionJob<br/>engine: Flink"/] end n2[("ADS.PAGE_VIEWS")] n3[("PROFILE.MEMBERS")] n4[("ADS.MULTI")] n2 --> n1 n3 --> n1 n1 --> n4flowchart LR n0[("ADS.PAGE_VIEWS")] n1[/"ads-pageviews-reverse-field-order<br/>kind: FlinkSessionJob<br/>engine: Flink"/] n2[("ADS.AD_CLICKS")] n3[/"ads-multi<br/>kind: FlinkSessionJob<br/>engine: Flink"/] n4[("PROFILE.MEMBERS")] n5[("ADS.MULTI")] n2 --> n1 n1 --> n0 n0 --> n3 n4 --> n3 n3 --> n5