Skip to content

Feature/websocket bolt support#64

Merged
genezhang merged 43 commits intomainfrom
feature/websocket-bolt-support
Feb 3, 2026
Merged

Feature/websocket bolt support#64
genezhang merged 43 commits intomainfrom
feature/websocket-bolt-support

Conversation

@genezhang
Copy link
Copy Markdown
Owner

This pull request introduces major new features and compatibility improvements for Neo4j Browser integration, especially around path and node queries, as well as enhanced RETURN clause support for procedures. It also updates test scripts, dependency management, and social network benchmark schemas for better accuracy and reliability. The most important changes are summarized below:

Neo4j Browser Compatibility & Query Features:

  • Added support for path UNION queries, enabling MATCH p=()-->() RETURN p to work in Neo4j Browser by generating a UNION ALL across all relationship types with consistent JSON property formatting. This ensures visualization of all connected edges with properties in the Browser. [1] [2]
  • Implemented label-less node queries, allowing MATCH (n) RETURN n to return all node types via UNION ALL, making the Neo4j Browser "dot" exploration feature fully functional. [1] [2]
  • Full RETURN clause evaluation for procedures, supporting complex aggregations (e.g., COLLECT, COUNT, array slicing) for procedure-only queries—enabling Neo4j Browser schema sidebar to auto-populate as expected. [1] [2]

Testing & Developer Tooling:

  • Added a comprehensive integration test script (scripts/test/quick_neo4j_test.sh) to automate setup, execution, and validation of Neo4j Browser compatibility with ClickGraph, including health checks, data setup, and container orchestration.
  • Added a Python test (scripts/test/test_bolt_path_variables.py) to validate Bolt protocol support for path variable queries, ensuring correct operation of UNION path and typed path queries through Neo4j Browser.

Benchmark & Schema Corrections:

  • Updated the social network benchmark schema mappings to match actual database columns, fixing property and ID mappings for nodes and edges (e.g., corrects name, created_at, liked_at, composite keys, and property names). [1] [2] [3] [4]

Dependency Management:

  • Added tokio-tungstenite and futures-util as dependencies to support async WebSocket/Bolt protocol features.

Documentation & Status Updates:

  • Updated STATUS.md and CHANGELOG.md to reflect new features, improved test pass rates, and removal of regression warnings, providing a clear summary of current capabilities and recent progress. [1] [2]

These changes collectively ensure robust Neo4j Browser compatibility, improve developer experience, and enhance test coverage and schema correctness.

- Add tokio-tungstenite and futures-util dependencies
- Implement WebSocketBoltAdapter with AsyncRead/AsyncWrite
- Add protocol detection (HTTP GET vs Bolt magic preamble)
- Route connections: WebSocket or TCP based on first 4 bytes
- Enables Neo4j Browser, Neodash, and other browser tools
- Reuses existing Bolt protocol handler for both transports
- Wait up to 120 seconds for cargo run to compile and start
- Poll health endpoint every 2 seconds
- Show progress updates every 10 seconds
- Exit early if process dies or times out
- Add is_procedure_union_query() detection function
- Add execute_procedure_union() execution function
- Extract procedure names before async calls to avoid Send issues
- Export functions from procedures module

Part of WebSocket Bolt + Neo4j Browser integration.
Enables Neo4j Browser schema sidebar to populate.
- Changes signature from &CypherStatement<'a> to &str
- Parses internally before extracting procedure names
- Avoids Send trait issues with Rc<RefCell<>> in AST
- Drops AST before any async calls

This enables the function to be called from async contexts
without lifetime/Send conflicts.
…eCall

The parser was treating 'CALL ... UNION ALL CALL ...' as a standalone
ProcedureCall, which prevented UNION support. Now it looks ahead for
UNION keyword and treats it as Query if present.

Also added comprehensive debug logging and completed HTTP handler
integration for procedure UNION execution.

Tests:
- CALL db.labels() → 4 records ✓
- CALL db.labels() UNION ALL CALL db.relationshipTypes() → 10 records ✓
- 3-procedure UNION → 22 records ✓
- All 923 unit tests passing ✓
Integrated UNION ALL support into Bolt handler, matching HTTP implementation.
Uses same pattern: detect UNION, extract procedure names synchronously, then
execute async without lifetimes.

Tests via neo4j-driver:
- CALL db.labels() → 2 records ✓
- 2-procedure UNION → 4 records ✓
- 3-procedure UNION → 6 records ✓

Both HTTP and Bolt now fully support procedure UNION queries needed for
Neo4j Browser schema sidebar!
Neo4j Browser requires several dbms.* procedures during initialization:
- dbms.clientConfig() - Returns empty config
- dbms.security.showCurrentUser() - Returns stub user
- dbms.procedures() - Lists all available procedures
- dbms.functions() - Returns empty list (functions not supported)

Without these, Browser fails during connection handshake and never displays
the schema sidebar, even though db.labels() and db.relationshipTypes() work.

Tests:
- All 8 procedures callable via Bolt ✓
- db.labels() returns 6 labels ✓
- db.relationshipTypes() returns 10 types ✓
- dbms procedures return stub/empty results ✓
Changed two parse_query() calls to parse_cypher_statement() to properly
handle UNION ALL queries. The old parse_query() didn't support UNION syntax.

Now UNION queries parse correctly, but still fail at planning stage if they
contain unlabeled nodes/relationships (MATCH (n) or MATCH ()-[]->()).

This fixes the 'Unexpected tokens after query: UNION ALL' errors but reveals
the underlying limitation that we need labeled patterns to determine which
tables to query.

Progress:
- ✅ UNION parsing works
- ✅ Procedure calls work (db.labels, db.relationshipTypes, dbms.*)
- ❌ Unlabeled MATCH patterns still not supported (separate issue)
Parser now checks for RETURN keyword (in addition to UNION) to route
CALL...YIELD...RETURN queries to the Query parser instead of ProcedureCall.

Also updated get_query_type() to classify CALL with RETURN as Read query.
CALL without RETURN is still QueryType::Call.

Neo4j Browser sends: CALL db.labels() YIELD label RETURN {...} UNION ALL ...
This needs to be treated as a read query, not a procedure call.

Status: Code changes complete but not yet verified working. Next step is to
confirm query type classification with debug logging and verify Browser
sidebar populates.

Related: Need to implement proper read-only procedure checking instead of
assuming CALL with RETURN is always read-only.
- generate_scan() creates Union of all node types when no label specified
- Add multi-label scan detection in plan_builder with recursive unwrapping
- Add is_multi_label_scan flag to RenderPlan to preserve special columns
- Use json_builder for uniform _label, _id, _properties columns in UNION
- Add deduplication in json_builder to avoid duplicate node types

Enables MATCH (n) RETURN n queries that return heterogeneous nodes.
- Add try_transform_multi_label_row() to detect and transform special columns
- Fix find_final_projection() to handle Union plans
- Generate proper Neo4j elementId format (Label:id)
- Derive legacy id field from actual ID property values

Enables proper Neo4j Browser visualization of heterogeneous node results.
- Add return_evaluator.rs for evaluating RETURN clauses on procedure results
- Support aggregation functions: COLLECT, COUNT with distinct
- Support array slicing: [..1000], [5..], [2..10]
- Support map literals and list construction
- Handle Neo4j Browser schema sidebar queries with UNION ALL

Enables Browser queries like:
CALL db.labels() YIELD label RETURN {name:'labels', data:COLLECT(label)[..1000]}
- Fix pattern_comp_users property mapping (name: name, not name: full_name)
- Minor handler improvements for query processing
- Document label-less node queries feature
- Document RETURN clause evaluation for procedures
- Update test statistics
The posts_bench table uses user_id, not author_id.
Also fixed property mapping (post_date -> created_at).
- Modified to_render_plan_with_ctx to pass plan_ctx through for
  TypedVariable lookup (fixes path variable recognition)
- Added contains_graph_joins() helper to detect GraphJoins wrapped in
  Limit/Skip/OrderBy nodes
- Enhanced expand_path_variable() to differentiate VLP vs fixed-hop:
  - VLP paths use CTE columns (path_nodes, path_edges, etc.)
  - Fixed-hop paths produce tuple('path', start, end, rel)
- Use plan_builder_utils::extract_limit/skip for proper LIMIT handling

Query: MATCH p=()-[r:AUTHORED]->() RETURN p LIMIT 1
Now generates valid SQL instead of 'Unknown identifier p' error
- Add Path struct methods: new(), single_hop(), to_packstream()
- Add to_unbound_packstream() for Relationship in Path encoding
- Enhance ReturnItemType::Path with component aliases (start, end, rel)
- Implement transform_to_path() for fixed-hop paths
- Add helper functions: find_node_in_row(), find_relationship_in_row()
- Create placeholder nodes/relationships when data unavailable

This enables Neo4j Browser to visualize path queries like:
MATCH p=()-[r:TYPE]->() RETURN p
- Extract relationship type from composite keys (AUTHORED::User::Post -> AUTHORED)
- Infer node labels from composite key components
- Fix elementId format for relationships (simpler ID-based format)
- Add detailed logging for path transformation debugging

Now paths show correct labels (User, Post) and relationship type (AUTHORED)
instead of placeholder values.

Properties still need schema-based expansion (complex due to denormalized tables).
When RETURN p (path), now automatically expands properties for:
- Start node (all schema-mapped properties)
- End node (all schema-mapped properties)
- Relationship (all schema-mapped properties)

This enables full Neo4j Browser visualization with property panels.

Implementation:
- expand_path_variable() now calls expand_base_table_entity() or
  expand_cte_entity() for each path component
- Properties appear as u.name, u.email, r.post_date in SELECT
- Bolt transformer extracts these via transform_to_node/relationship

HTTP test shows properties now included in result.
Next: Test in Neo4j Browser to verify Bolt path encoding.
- Added comprehensive debug logging in transform_row and find_node_in_row_with_label
- Fixed LIKED edge schema: like_date -> liked_at column mapping
- Fixed FRIENDS_WITH edge schema: user1_id/user2_id -> user_id_1/user_id_2, since_date -> since

Schema mappings now match actual ClickHouse table columns.

Issue: Path node properties still not showing in Neo4j Browser.
HTTP endpoint shows properties correctly, but Bolt transformer not extracting them.
Need to investigate row format discrepancy between HTTP and Bolt responses.
Path queries like MATCH p=(u)-[r]->(po) RETURN p now work and display
in Neo4j Browser with correct:
- Node labels (User, Post)
- Relationship types (AUTHORED)
- Graph structure and visualization

Known limitation: Node/relationship properties not included in paths yet.
Root cause: GraphRel SQL rendering only includes relationship + end node
in FROM clause, omitting start node table. Properties would require:
1. Fixing anchor table selection for path queries, OR
2. Adding CTEs to fetch node properties separately, OR
3. Client-side lazy loading (fetch properties on click)

For direct node/relationship returns (RETURN n, RETURN r), properties
work correctly. Issue only affects path variable returns (RETURN p).

This is sufficient for basic Neo4j Browser visualization. Properties
can be added in follow-up work.
- Path queries with path variables now prevent SingleTableScan optimization
- FK-edge patterns no longer create duplicate JOINs for relationship alias
- Start node table correctly included in FROM clause for path queries
- Fixes: MATCH p=(u)-[r]->(po) RETURN p now generates correct SQL
… denormalization

- Re-enabled property expansion in expand_path_variable() for fixed-hop paths
- Added denormalized alias registration for FK-edge patterns in FkEdgeJoin handler
- Properties now included in SELECT: u.*, po.*, r.*
- Still needs: FK-edge property resolution (r.* should map to po.* columns)
- Modified expand_base_table_entity() to check plan_ctx for FK-edge denormalization
- FK-edge relationships now select properties from anchor node table
- Example: r.content selects from po.content when r is on po table
- Correctly handles task-local QueryContext vs plan_ctx denormalization
- Query executes successfully: MATCH p=(u)-[r:AUTHORED]->(po) RETURN p
- Fixed is_path_variable() heuristic to exclude anonymous node aliases (t1, t2, etc)
- Anonymous nodes are now correctly registered as Node variables instead of Path
- Property expansion now works for all path components (named and anonymous)
- Fixed PATTERN_COMP_FOLLOWS schema mapping (removed non-existent follow_date)

Result: Path queries like MATCH p=()-[r]->() RETURN p now return all node and
relationship properties, enabling full visualization in Neo4j Browser.

All 939 unit tests passing.
- Relationships now get unique identity values based on (start_id << 20) | end_id
- Previously all relationships had identity=0, causing Neo4j Browser to deduplicate
- Now properly displays all relationships in path queries (e.g., 4 edges among 7 nodes)

Result: MATCH p=()-[r:AUTHORED]->() RETURN p now visualizes correctly with all
unique relationships visible, not collapsed into a single edge.
- Enhanced parse_outgoing() to detect both -> and --> patterns
- Enhanced parse_incoming() to detect both <- and <-- patterns
- Added parse_double_dash() to detect -- (undirected) patterns
- Updated is_start_of_a_relationship() to use all detectors

This fixes parser to correctly recognize ()-->() patterns used by
Neo4j Browser's 'dot' feature for exploring all relationships.

Parser now successfully parses MATCH p=()-->() RETURN p, but planner
still needs work to expand to UNION of relationship types.
…patterns

The comment stripper was treating '-->' as a line comment (-- followed by >),
which caused MATCH p=()-->() RETURN p to be stripped to just MATCH p=().

Fix:
- Check for '-->' pattern and treat as relationship, not comment
- Check for '<--' pattern by looking at previous character
- Add comprehensive tests for relationship patterns

This fixes the AST transformation issue where ConnectedPattern was being
lost during comment stripping phase.

Impact:
- Parser now correctly receives ()-->() as ConnectedPattern
- Relationship type inference triggered: 'Both nodes untyped, expanding to all 10 relationship types'
- However, VLP infrastructure needs label-less node support (next step)

Related: Neo4j Browser dot query support
- Handles patterns like ()-->() where both nodes are untyped and multiple relationship types exist
- Generates UNION ALL with one branch per relationship type, each processed as typed pattern
- Each branch gets unique aliases (a_0, b_0) to avoid plan_ctx conflicts
- Registers original aliases (a, b) and branch aliases for proper SQL generation
- Path variables (p=()-->()) registered but NOT YET IMPLEMENTED (SQL generation missing)
- Works perfectly for queries like: MATCH ()-->() RETURN count(*)
- Tested: Returns 26 results across all relationship types

Known Limitations:
- Path variable support (p=()-->()) requires implementation in SQL generator
- Path expansion only works for VLP queries with recursive CTEs currently
- Single-hop path variables need inline array construction in SELECT clause

TODO:
- Implement path variable SQL generation for non-VLP patterns
- Refactor to extract common 'disconnected pattern' logic (reduce duplication)
- Added contains_union() helper to detect Union in plan tree
- Added Union detection in to_render_plan_with_ctx()
- Issue: Union branches are rendered via extract_union() which calls
  to_render_plan() without plan_ctx
- Root cause: extract_union() at line 639 renders Union without plan_ctx
- Need different approach: Either add plan_ctx param to extract_union(),
  or handle Union rendering entirely in to_render_plan_with_ctx()

Current status: MATCH p=()-->() RETURN p still fails with 'Unknown identifier p'
Added infrastructure to pass plan_ctx through Union branch rendering:
- Created extract_union_with_ctx() method to bridge plan_ctx
- Added Union handler in to_render_plan_with_ctx() for direct Union nodes
- Updated GraphJoins handler to use extract_union_with_ctx()

Status: Infrastructure complete, but path variables still not working
- Typed patterns: SELECT tuple('fixed_path', 'a', 'b', 't4') AS p ✅
- UNION patterns: SELECT p AS p ❌ (no expansion)

Root cause: Path variable registered in plan_ctx with ORIGINAL aliases (a, b, t3)
but UNION branches use BRANCH aliases (t1_0, t2_0, t3). The tuple expansion
needs to use branch-specific aliases, not original ones.

Next step: Modify path variable expansion in select_builder.rs to detect
UNION context and use branch-specific aliases for tuple construction.

Test:
- MATCH p=(a:User)-[:FOLLOWS]->(b:User) RETURN p → Works ✅
- MATCH p=()-->() RETURN p → Fails (Unknown identifier p) ❌
Added find_graph_rel_for_path() to find actual GraphRel in plan tree
and use its connection aliases for path tuple construction. This is
critical for UNION branches which use branch-specific aliases (t1_0,
t2_0) instead of registered aliases (a, b).

Changes:
- Added find_graph_rel_for_path() helper in select_builder.rs
- Modified expand_path_variable() to try GraphRel lookup first
- Falls back to registered aliases if GraphRel not found
- Uses String instead of &str for aliases to support both paths

Status: Infrastructure complete but path still not expanding
- Typed: MATCH p=(a:User)-[:FOLLOWS]->(b:User) RETURN p ✅ Works
- UNION: MATCH p=()-->() RETURN p ❌ Still fails

Next: Debug why path registration or expansion isn't happening for UNION
Added fallback logic to detect path variables by finding GraphRel in plan tree
when path is not registered in plan_ctx. This is needed for UNION patterns where
fully untyped patterns (()-->()) don't go through the multi-type UNION expansion
that registers path variables.

Changes:
- Added GraphRel fallback in TableAlias expansion (both with and without plan_ctx)
- Simplified path registration in traversal.rs (removed nested conditions)
- Creates TypedVariable on-the-fly from GraphRel metadata

Status: Still failing - path not being expanded in UNION branches
- Log messages not appearing, so code paths aren't being reached
- UNION branches show 'SELECT p AS p' instead of tuple expansion
- Needs further investigation of rendering flow

Next: Debug why fallback code isn't executing despite being in place
THE FIX: Each UNION branch now wraps its GraphRel in a Projection that includes
the path variable in the SELECT list. This makes UNION branches work exactly like
typed patterns.

Root cause analysis:
- Typed patterns: GraphRel → (continues processing) → outer Projection adds path
- UNION patterns: Creates Union(GraphRel branches) → returns early with 'continue'
- Problem: UNION branches were bare GraphRel nodes without Projection
- Solution: Wrap each branch in Projection(GraphRel) with path variable item

Changes in traversal.rs:
- Lines 429-451: Wrap GraphRel in Projection when path_variable is present
- Each branch gets: Projection { items: [TableAlias(p)], input: GraphRel(...) }
- Leverages existing path expansion infrastructure in select_builder.rs

Test results:
- MATCH p=()-->() RETURN p LIMIT 1 → {"p":["fixed_path","t1_3","t2_3","t3"]} ✅
- MATCH p=(a:User)-[:FOLLOWS]->(b:User) RETURN p → Works ✅
- Path variable expansion uses branch-specific aliases (t1_0, t2_0, t3)

This fix leverages the existing standard flow as requested - each UNION branch
now goes through the same Projection→path expansion flow as typed patterns.
Added comprehensive Neo4j Browser setup guide and test script.

New files:
- NEO4J_BROWSER_SETUP.md: Complete guide for connecting Neo4j Browser to ClickGraph
- scripts/test/test_bolt_path_variables.py: Automated test for path variables via Bolt

Test results via Bolt protocol:
✅ MATCH p=()-->() RETURN p → Works! Returns proper Path objects
✅ MATCH p=(a:User)-[:FOLLOWS]->(b:User) RETURN p → Works!
✅ Count queries and all basic operations working

Neo4j Browser connection:
- URL: bolt://localhost:7687
- Auth: None required
- Ready for production use!

This confirms the path variable fix works end-to-end through the full stack:
Query → Planning → Rendering → SQL → Results → Bolt Protocol → Neo4j Browser
…able property expansion

- Added Projection handler in plan_builder.rs to pass plan_ctx through when rendering
- This enables path variable property expansion in UNION branches
- Added diagnostic logging to trace plan rendering flow
- Issue: Handler not being invoked as expected - needs debugging of query plan structure
- Union may not be nested in GraphJoins.input as expected
… separate query

MAJOR REFACTORING to leverage existing standard flow instead of custom logic:

Key Insight (from user): Each UNION branch is logically a separate query with its own RETURN.
So instead of trying to propagate properties from outer Projection, each branch should
have its own Projection that independently expands RETURN p.

Changes:
- Each UNION branch wrapped in Projection (like separate 'MATCH...RETURN p' queries)
- Added Projection handler to to_render_plan_with_ctx() that passes plan_ctx
- Enhanced extract_union_with_ctx() with detailed logging to trace Union discovery
- Union branches rendered via to_render_plan_with_ctx() to ensure plan_ctx availability

Architecture:
Union → [Projection(RETURN p) → GraphRel, Projection(RETURN p) → GraphRel, ...]

Each Projection independently expands path variable using standard flow.

Status: Path tuple returns correctly, but properties still not expanding.
Next: Debug why Projection handler with plan_ctx isn't triggering property expansion.
Added WARN-level logging throughout select_builder.rs and plan_builder.rs to trace:
- When expand_path_variable() is called
- When TableAlias is processed in Projection
- Plan_ctx availability at each step
- Union rendering flow

Key Finding:
- Typed patterns: expand_path_variable IS called with plan_ctx ✓
- UNION patterns: expand_path_variable NOT called at all ✗

Root Cause Identified:
UNION branches are rendered via standard to_render_plan() (no plan_ctx),
not to_render_plan_with_ctx(). This happens because:
1. Query plan: Limit → Union → [Projection branches]
2. Limit.to_render_plan() calls Union.to_render_plan() (no plan_ctx)
3. Union.to_render_plan() calls branch.to_render_plan() (no plan_ctx)
4. Projection.to_render_plan() calls extract_select_items(self, None) ← NO PLAN_CTX!

Next: Need different approach that doesn't rely on plan_ctx flow through rendering.
Simplest possible approach:
- GraphRel.extract_select_items() adds path tuple if path_variable exists
- No plan_ctx needed, no complex expansion logic

Implementation:
- Modified select_builder.rs GraphRel handler to add path tuple
- Removed Projection wrapping from UNION branches in traversal.rs
- Added extensive logging to trace execution flow

Key Discovery:
UNION branch structure: GraphJoins -> Projection -> GraphRel
- GraphJoins delegates to Projection.extract_select_items()
- Projection processes its own items (just TableAlias(p))
- GraphRel.extract_select_items() is NOT called for branches!

Next: Need to make Projection recognize when it should delegate to GraphRel for path variables,
or make the path tuple logic work at the Projection level instead.
- Add JSON format for path UNION branches (consistent 4-column schema)
- Fix denormalized relationship property expansion via schema lookup
- Add unique prefixes (_s_, _e_, _r_) for ClickHouse alias collision
- Strip prefixes in Bolt transformer for clean Neo4j Browser display
- Support MATCH p=()-->() RETURN p with all relationship types

Files modified:
- render_plan/plan_builder.rs: Path UNION detection, JSON conversion
- render_plan/plan_builder_helpers.rs: convert_path_branches_to_json()
- render_plan/select_builder.rs: Denormalized relationship properties
- server/bolt_protocol/result_transformer.rs: JSON parsing, prefix stripping
- Add Path UNION query support (Neo4j Browser dot feature)
- Update test status (936/936 passing)
- Mark feature as complete with full architectural details
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR targets improved Neo4j Browser compatibility (especially Bolt/WebSocket transport and Neo4j “dot” exploration queries), expands path/node query support via UNION-based planning/rendering, and adds procedure RETURN-clause evaluation so Neo4j Browser metadata queries work.

Changes:

  • Add WebSocket transport detection on the Bolt port and a WebSocket→AsyncRead/AsyncWrite adapter for Bolt.
  • Expand support for untyped node/path exploration queries using UNION rendering and JSON/property formatting for Neo4j Browser.
  • Add procedure-only query handling improvements (including UNION of procedures) and a RETURN-clause evaluator for procedure results; update docs/scripts/deps accordingly.

Reviewed changes

Copilot reviewed 42 out of 44 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/server/mod.rs Detects WebSocket vs raw TCP on the Bolt listener and routes to the appropriate transport handler.
src/server/handlers.rs Adds procedure-only UNION routing for HTTP query handler.
src/server/bolt_protocol/websocket.rs New WebSocket transport adapter implementing AsyncRead/AsyncWrite for Bolt over WebSocket.
src/server/bolt_protocol/result_transformer.rs Adds Path transformation and multi-label row handling for Neo4j-compatible Bolt results.
src/server/bolt_protocol/mod.rs Exposes the new websocket module.
src/server/bolt_protocol/handler.rs Adds procedure-only UNION/RETURN evaluation support in Bolt execution path.
src/server/bolt_protocol/graph_objects.rs Adds Packstream encoding support for Path and unbound relationships.
src/render_plan/select_builder.rs Extends SELECT extraction for path variables and denormalized/FK-edge property expansion.
src/render_plan/plan_builder_utils.rs Adds/threads is_multi_label_scan flag default in a render-plan builder path.
src/render_plan/plan_builder_helpers.rs Adds helper to normalize path-UNION branches into consistent JSON columns.
src/render_plan/plan_builder.rs Adds multi-label scan + path-UNION special-case rendering and introduces ctx-aware UNION rendering.
src/render_plan/mod.rs Extends RenderPlan with is_multi_label_scan marker to preserve special SELECT columns.
src/render_plan/join_builder.rs Avoids duplicate JOIN emission for FK-edge/denormalized relationship patterns.
src/query_planner/plan_ctx/table_ctx.rs Refines heuristic detection for path variables vs anonymous node aliases.
src/query_planner/plan_ctx/mod.rs Adds logging and path-variable heuristic registration in PlanCtx insertion.
src/query_planner/mod.rs Adjusts query-type classification for CALL with/without RETURN.
src/query_planner/logical_plan/plan_builder.rs Adds additional logging around MATCH/path patterns.
src/query_planner/logical_plan/match_clause/view_scan.rs Marks relationships as denormalized when relationship table matches a node table.
src/query_planner/logical_plan/match_clause/traversal.rs Adds UNION expansion for fully-untyped multi-type relationships and supports anonymous nodes.
src/query_planner/logical_plan/match_clause/helpers.rs Generates a UNION of ViewScans for label-less node scans (MATCH (n) RETURN n).
src/query_planner/analyzer/match_type_inference.rs Expands relationship inference for both-untyped nodes to all relationship types (UNION ALL).
src/query_planner/analyzer/graph_join/inference.rs Registers denormalized aliases for FK-edges and disables SingleTableScan optimization when returning paths.
src/procedures/return_evaluator.rs New module to evaluate RETURN clauses over procedure results (aggregation/slicing).
src/procedures/mod.rs Registers dbms.* stubs and re-exports procedure helpers/return evaluator.
src/procedures/executor.rs Adds helpers for procedure-only statement detection, UNION execution, and RETURN evaluation.
src/procedures/dbms_stubs.rs Adds stub implementations required by Neo4j Browser.
src/procedures/db_relationship_types.rs Deduplicates/normalizes relationship type names (handles composite keys).
src/procedures/db_labels.rs Deduplicates/normalizes label names (handles qualified keys).
src/open_cypher_parser/path_pattern.rs Adds parsing support for --, <--, --> relationship patterns.
src/open_cypher_parser/mod.rs Adjusts statement parsing to distinguish standalone CALL vs CALL-with-RETURN/UNION.
src/open_cypher_parser/common.rs Updates comment stripping to avoid treating some relationship patterns as comments.
src/open_cypher_parser/call_clause.rs Adds parsing support for YIELD in CALL clauses.
src/open_cypher_parser/ast.rs Extends CallClause AST to include optional YIELD items.
src/clickhouse_query_generator/multi_type_vlp_joins.rs Switches JSON property serialization to type-preserving JSON builder helper.
src/clickhouse_query_generator/mod.rs Exposes new json_builder utilities.
src/clickhouse_query_generator/json_builder.rs New helper for generating type-preserving JSON SQL and multi-type UNION SQL.
scripts/test/test_bolt_path_variables.py Adds a manual Bolt test for path-variable queries via neo4j-driver.
scripts/test/quick_neo4j_test.sh Adds a quick end-to-end script to run ClickGraph + Neo4j Browser smoke checks.
scripts/server/start_server_background.sh Adds a Linux background server launcher script with configurable env.
benchmarks/social_network/schemas/social_benchmark.yaml Updates benchmark schema mappings for certain relationships/properties.
STATUS.md Updates project status and highlights new Neo4j compatibility features.
Cargo.toml Adds tokio-tungstenite and futures-util dependencies.
Cargo.lock Locks new dependency graph for WebSocket support.
CHANGELOG.md Documents Neo4j Browser compatibility features and procedure RETURN evaluation.
Comments suppressed due to low confidence (1)

src/open_cypher_parser/common.rs:94

  • strip_comments still treats plain -- as a line comment unless it’s --> or <--. With the new parser support for undirected patterns (--), queries like MATCH p=()--() RETURN p will be truncated as a comment (--(). Consider also exempting -- when it’s followed by a relationship continuation (e.g., next non-whitespace char is ( or [), or drop -- comment support in favor of Cypher’s // and /* */ to avoid ambiguity.
        // Check for line comment (-- or //)
        // BUT: `-->` and `<--` are NOT comments (they're Cypher relationship patterns!)
        if ch == '-' && chars.peek() == Some(&'-') {
            // Peek ahead to check if this is `-->` or part of `<--` (relationship patterns, not comments)
            let mut lookahead = chars.clone();
            lookahead.next(); // skip second '-'

            // Check for `-->`  (outgoing relationship)
            if lookahead.peek() == Some(&'>') {
                result.push(ch);
                continue;
            }

            // Check if previous character was `<` (making this `<--` incoming relationship)
            // We already pushed the `<`, so check the last char in result
            if result.chars().last() == Some('<') {
                result.push(ch);
                continue;
            }

            // It's actually a `--` comment
            chars.next(); // consume second '-'
                          // Skip until newline
            for c in chars.by_ref() {
                if c == '\n' {
                    result.push('\n'); // preserve newline
                    break;
                }
            }
            continue;
        }

Comment thread src/server/bolt_protocol/websocket.rs
Comment thread src/server/bolt_protocol/result_transformer.rs
Comment thread src/render_plan/select_builder.rs Outdated
Comment thread benchmarks/social_network/schemas/social_benchmark.yaml Outdated
Comment thread benchmarks/social_network/schemas/social_benchmark.yaml Outdated
- WebSocket Close frame returns EOF for graceful disconnect (websocket.rs)
- Downgrade info/warn logs to trace/debug in hot paths (result_transformer.rs, select_builder.rs)
- Fix AUTHORED from_id: user_id -> author_id (social_benchmark.yaml)
- Fix LIKED like_date mapping (social_benchmark.yaml)
- Update tests for new untyped pattern behavior
@genezhang genezhang merged commit 6755d22 into main Feb 3, 2026
2 checks passed
@genezhang genezhang deleted the feature/websocket-bolt-support branch February 3, 2026 02:28
genezhang added a commit that referenced this pull request Feb 5, 2026
- AUTHORED: from_id author_id -> user_id (matches actual ClickHouse column)
- LIKED: property like_date -> liked_at (matches actual column name)

These schema mismatches were causing 'Identifier cannot be resolved' errors
in path queries. Schema was previously fixed in 55c0790 but accidentally
reverted in PR #64 (websocket bolt support).
genezhang added a commit that referenced this pull request Feb 17, 2026
Issue #1 (Neo4j Desktop WebSocket connection) was fixed on Feb 2, 2026
in PR #64 which added full WebSocket Bolt transport support.

Active issues: 2 (was 3)
- Shortest path performance on dense graphs
- Aggregation semantics on empty results

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

2 participants