Repository navigation
Graphersal 0.2.2
A patch release of the 0.2 line. It brings GQL read queries, marked experimental, and fixes how value filters treat a string that names a step label. It changes no format: stores, snapshots and journals of 0.2.1 are read and written exactly as before. Its API additions are additive (a new feature, new methods, a new #[non_exhaustive] error variant).
Prebuilt binaries
The graphersal command line tool is attached to this release for Linux (x86_64, aarch64), macOS (arm64, x86_64) and Windows (x86_64), with a SHA256SUMS file and build provenance attestations (gh attestation verify <archive> --repo graphersal/graphersal); cargo binstall graphersal-cli installs it too. The Linux binaries are static musl builds, which run on every distribution but use musl's slower memory allocator: build from source for benchmarks (Performance of the prebuilt Linux binaries).
Added
- GQL read queries (experimental) (GQL Queries):
g.gql(query)runs a query in GQL, the ISO graph query language (ISO/IEC 39075), on the same graph and engine as Gremlin. The query is compiled into an ordinary traversal plan, so the optimizer, property indexes,profile(), resource limits, cancellation, permissions and custom storages apply as they do to Gremlin; each result row is a map from column name to value (Result Shape). Experimental means:gql()only reads (every write clause is refused), the supported subset grows from version to version, and the rows, errors and plans of a construct may still change in a later version. Gremlin stays the complete, stable interface.- Supported (The Supported Subset):
MATCHandOPTIONAL MATCH,WHERE,LET,FILTER, Cypher'sWITH,RETURNwith aggregation,GROUP BY,DISTINCT,ORDER BY,OFFSET/LIMIT;FOR(CypherUNWIND) withWITH ORDINALITY/OFFSET; queries that start withoutMATCH; node and edge patterns, label expressions, quantified edges (-[:knows]->{1,3}) and quantified path patterns ((a) ((x)-[:created]->(s)<-[:created]-(y)){1,2} (b)), path variables (trail semantics: no edge bound twice in a match);EXISTSsubqueries and Cypher pattern predicates; map projections, list and pattern comprehensions andRECORD {..}for JSON-shaped answers; Cypher'sCOUNT { },COLLECT { },all()/any()/none()/single()andreduce(); composite queries (UNION,UNION ALL,NEXT);CALL { }subqueries run per row (OPTIONAL CALL); parameters ($name); three-valued logic; the GQL scalar functions (strings, numbers,CAST) and the common openCypher ones (toInteger,substring,split,round,keys,nodes(p), ...). - ISO first, Cypher spellings accepted (Cypher Aliases): where GQL and Cypher differ, GQL wins; unambiguous Cypher spellings with the same meaning are accepted as aliases (
SKIP,!=,toUpper(),-->, ...). There is no Graphersal-only syntax. - Errors (Errors): a query that does not parse or bind fails before anything runs, with a GQLSTATUS code, a caret under the offending text and a
Help:line; constructs outside the subset are refused by name with an alternative (Refused Constructs). Size limits (pattern edges, subqueries, nesting) are errors, never a cut result. - Plans (Plans and Performance): a GQL query and its Gremlin twin get the same plan where they mean the same;
profile()shows the internalgql:*steps; an equality on an indexed property and an id lookup per row are served directly. - Everywhere: Rust
GraphTraversalSource::gqlandgql_with(query, params)(featuregql, off by default, no dependencies, builds for wasm32), the Rhai DSLg.gql(query)/g.gql(query, params), the CLI and REPL, Python (graph.query("g.gql(...)")), the playground (GQL examples), and the MCP server's toolgql. New errorTraverserError::GqlwithGqlErrorKind. - Not yet: writes (
INSERT,SET,DELETE, ...),EXCEPT/INTERSECT, path modes and shortest paths, a quantifier nested in a quantified path pattern (Conformance, Current Limitations).
- Supported (The Supported Subset):
Changed
- A value filter compares a string as a value, never as a step label (Predicates):
has(key, P.eq("a")),is("a"),has_value, theirPforms,any/all/noneand a jpathhascompared a string that named a step label (as("a")) with the labelled element instead of the string itself, sog.v(1).as("vadas").out("knows").has("name", P.eq("vadas"))returned nothing. They now compare the literal, as TinkerPop does; onlywhere(P)andwhere(P).by(..)read step labels. A traversal that relied on the old behaviour should usewhere(P.eq("a")). As a side effect, a property index now also serves a stringP.eqinside child traversals andunion()operands. - The profile table's
Stepcolumn is as wide as the longest step text (Profiling): at least 60 characters (70 with nested steps), at most 160, then.... It was cut at 60/70, which hid annotations such as[index: ..]. The playground's Text view uses the same rule.