Skip to main content

ISO GQL

RushDB accepts ISO/IEC 39075 Graph Query Language (GQL) statements for reading and writing the property graph. This page describes the profile RushDB implements, how records map to GQL nodes, the statements you can use, and the boundaries of the profile. It is for developers who want a standards-based graph language rather than a vendor dialect.

PropertyValue
StatusRelease candidate
Enable with--languages gql (languages.gql: true)
Wire idgql
ProfileRushDB GQL property-graph profile v1 (ISO/IEC 39075 syntax subset)
ImplementationGrafeo graph planner and executor
Accessread and write
Parametersnamed ($name)
TransportsProtocol v1 (HTTP, gRPC)

Note: GQL is a release candidate. Reads and writes are implemented and tested against RushDB's GQL profile v1, a subset of ISO GQL. The server advertises its exclusions as limitations: noFullIsoGqlConformance, noMatchAfterWithPipeline, noNextComposition, noOrderByInWith, noShortestPath, noPatternPredicates, noListOrPatternComprehensions and noLabelAlternation. Rely on the statement forms on this page, not on the whole standard.

Data model mapping​

GQL conceptRushDB
NodeA record
Node labelThe record's single primary label
Node propertyA record property
EdgeA relationship
Edge labelThe relationship type
Edge propertyA relationship property
GraphThe request's tenant

When a statement returns a whole node, the value is the record as a JSON object with its properties plus _id (the record's dashed UUID) and __label. A returned edge carries its properties plus _id, type, source, and target (dashed UUIDs).

Profile v1 features​

The published profile (rushdb-gql-property-graph-v1) accepts these feature families:

FeatureExample
Pattern matching (match)MATCH (p:Person)-[:KNOWS]->(f:Person)
Filtering (filter)WHERE p.age >= $minAge
ProjectionRETURN p.name AS name
Parameters$minAge
OPTIONAL MATCHOPTIONAL MATCH (p)-[:KNOWS]->(f:Person)
AggregationRETURN count(p) AS total
UNWINDUNWIND [3, 1, 2] AS value
Ordering and paginationORDER BY name SKIP 1 LIMIT 1
Create nodesINSERT (:Person {name: 'Eve'})
Update propertiesSET n.age = 36
Delete nodesDELETE n
Create and delete edgesINSERT (a)-[:LIKES]->(b), DELETE r
Atomic statement commiteach write statement is one commit

Explicitly excluded: multiple labels per record, label mutation in statements, and full ISO GQL conformance.

Reading​

MATCH (n:FACTION) RETURN n.name AS name ORDER BY name

Traverse relationships:

MATCH (p:Person)-[:KNOWS]->(f:Person)
RETURN p.name AS source, f.name AS target

Optional matches keep rows with no partner, returning null:

MATCH (p:Person)
OPTIONAL MATCH (p)-[:KNOWS]->(f:Person)
RETURN p.name AS source, f.name AS target
ORDER BY source
[
{ "source": "Alice", "target": "Bob" },
{ "source": "Bob", "target": null },
{ "source": "Carol", "target": null }
]

Aggregation, UNWIND, and pagination:

MATCH (p:Person) RETURN count(p) AS total
UNWIND [3, 1, 2] AS value RETURN value ORDER BY value
MATCH (p:Person) RETURN p.name AS name ORDER BY name SKIP 1 LIMIT 1

Parameters​

Pass named parameters as a JSON object. Integers must fit a signed 64-bit integer; larger unsigned values are rejected rather than rounded.

{
"protocolVersion": 1,
"operation": {
"kind": "query",
"query": {
"kind": "statement",
"language": "gql",
"statement": "MATCH (p:Person) WHERE p.age >= $minAge RETURN p.name AS name ORDER BY name",
"parameters": { "minAge": 30 }
}
}
}

text_match(n.prop, 'query') is true when a record matches the query in the text index on that property; text_score(n.prop, 'query') is its BM25 score. n.`*` names the index over every string of the record.

MATCH (d:Doc) WHERE text_match(d.title, 'quick fox')
RETURN d.title AS title
ORDER BY text_score(d.title, 'quick fox') DESC LIMIT 10

See Full-text search.

Writing​

Send writes with mutate.statement. Each statement runs against a private copy of the tenant graph, and its complete change set is published as one commit. If the statement fails, nothing is published.

INSERT (:FACTION {name: 'Rebel Alliance'})

Create two nodes and the edge between them in one statement:

INSERT (:Person {name: 'Alice'})-[:LIKES {weight: 2}]->(:Person {name: 'Bob'})

Update and delete:

MATCH (n:Person) WHERE n.name = 'Alice' SET n.age = 36
MATCH (n:Person) WHERE n.name = 'Carol' DELETE n
MATCH ()-[r:LIKES]->() DELETE r

A write that changes nothing (for example, a MATCH ... SET with no matches) succeeds with affected: 0 and commits nothing.

Writes inside a transaction​

GQL write statements can be staged in a multi-request transaction with a statement mutation. The statement sees the transaction's earlier staged writes, and its changes commit or roll back with the transaction:

{
"protocolVersion": 1,
"operation": {
"kind": "transaction",
"transaction": {
"kind": "stage",
"transactionId": "<id from begin>",
"mutation": {
"kind": "statement",
"language": "gql",
"statement": "INSERT (:Person {name: 'Eve'})"
}
}
}
}

A transaction that stages a graph statement conflicts with any other commit to the tenant that lands before it commits. Expect write_conflict under concurrent writes and retry.

Index DDL​

GQL accepts the same index statements as Cypher. Send CREATE and DROP with mutate.statement; SHOW INDEXES is a read:

CREATE INDEX person_name IF NOT EXISTS FOR (n:Person) ON (n.name)
CREATE FULLTEXT INDEX note_body FOR (n:Note) ON EACH [n.body]
OPTIONS {indexConfig: {consistency: 'immediate'}}
DROP INDEX person_name IF EXISTS
SHOW INDEXES

When the name is omitted, the index is named <Label>_<property>. See Indexes.

Limitations​

LimitationBehavior
One label per nodeInserting a node with several labels fails; nothing is published.
No label mutationStatements cannot add or remove labels. Use the native retypeRecord mutation.
Write working setA write holds only the records and relationships it creates or changes; it is refused when they exceed 100,000 records or 64 MiB, whatever the tenant's size.
No server-side cursorResults are materialized; page with SKIP/LIMIT.
No native transportGQL is served over Protocol v1 (HTTP, gRPC) only. Bolt carries Cypher.
Partial standardOnly the profile above is supported; other ISO GQL constructs fail.

Errors​

SituationError code
GQL not enabledlanguage_disabled
Syntax the parser does not acceptunsupported
Statement error (undefined variable, type error, a write sent through query.statement)invalid_request, with the engine's reason
More than 8,192 clauses in one statementinvalid_request
Index DDL sent through query.statementinvalid_request
A write in an unsupported form (several labels, label mutation)unsupported
Deadline elapsed or request cancelled (also mid-statement)cancelled

See also​