Skip to main content
TuringDB supports a subset of the Cypher query language, extended with versioning, metadata introspection, and flexible property matching. This guide covers the supported syntax and features, including MATCH, CREATE, property filters, node ID injection, metaqueries, and available data types.
In our autumn 2025 release we will be supporting nearly 100% of Cypher.

⚙️ Basics

Queries are built by referencing nodes and edges. TuringDB supports the standard CYPHER syntax, in that nodes are denoted using parentheses (), whilst edges are denoted using square brackets []. For example, (n) would denote a node named n, whilst [e] would denote an edge named e. Nodes and edges can have both label and property constraints. As in standard CYPHER, property constraints are specified using curly brackets {}, whilst labels are specified using colon : syntax. An example of a node with a label constraint would be (n:Person). An example of an edge with a property constraint would be [e{duration=10}]. Property and label constraints may be combined, for instance, (n:Person{name="John"}) specifies a node which both has the label Person, and a name property with the value John. Nodes and edges can have label and property multiple constraints, which are specified in a comma-separated list: (n:Person,Man{name=”John”, age=20}). These lists can be arbitrarily long.

Summary:

Queries are built around nodes and edges:
  • Nodes are written in parentheses () e.g. (n) - a node with alias n
  • Edges are written in square brackets [] e.g. [e] - an edge with alias e
You can add:
  • Labels with a colon : - e.g. (n:Person)
  • Property constraints with curly braces {} - e.g. [e{duration=10}]
  • Both at once - e.g. (n:Person{name="John"})
Multiple labels and properties can be specified:
(n:Person,Man{name="John", age=20})

🔍 Queries

Queries are built up of combinations of nodes and edges, as specified above. TuringDB supports two main query operations: MATCH and CREATE.

MATCH queries

MATCH queries are used to retrieve nodes, edges, and their property values from the database via specification of relationships and properties. It is easiest to demonstrate the syntax of a MATCH query with a concrete example:
MATCH (n)-[e]-(m) RETURN n 
The above query will look for nodes in the database which have at least one edge to a different node. The query will return the internal ID of the node n.
When using RETURN n, other implementations of CYPHER may return all properties of n, whilst TuringDB only returns the internal ID of n.
Specifying the direction of edges (e.g. <-[e]-) is not currently supported in TuringDB. All edges are implicitly directed from left-to-right.
MATCH queries are flexible: they can contain a single node and no edges, or any number of node, edge pairs. For example:
MATCH (n) RETURN n
will match all nodes in the database. An example of a multi-hop MATCH query would be:
MATCH (n)-[e]-(m)-[f]-(p) RETURN p

Queries have variables, which in the above examples are those such as n, m, e, etc. Variables are a way to give a name to a node or an edge, so that those nodes or edges can be specified in the RETURN clause. However, if you do not want to return an edge or its properties, the edge need not have a name. For example:
MATCH (n)--(m) RETURN m
Both node and edges can omit a variable name if they specify at least a label constraint:
MATCH (:Person)-[:FriendsWith]-(m) RETURN m
You can also return multiple properties using a comma separated list:
MATCH (n:Person)--(m:Person) RETURN n.name, m.age
Combining the syntax of MATCH queries, and the ability to specify constraints, here are a few examples of some syntactically correct TuringDB MATCH queries:
  • MATCH (n:Person) return n.name
  • MATCH (:Person)—(n:Person) return n.age
  • MATCH (n:Person,Woman,SoftwareEngineer)—(m)-[e]-(p:Man)-[f]-(q) return e,f
Note that whilst all the above the queries are all syntactically valid, if the graph does not have a node property which is used in a query, it will fail to execute.

RETURN clauses also support the * operator, as such:
MATCH (n:Person)-[e]-(m) RETURN *
which is equivalent to:
MATCH (n:Person)-[e]-(m) RETURN n, e, m
That is, RETURN * is equivalent to returning all entities in the MATCH query.

CREATE queries

CREATE queries follow exactly the same syntax as MATCH queries when it comes to specifying nodes, edges, and property/label constraints, but they do not have RETURN clauses. There is also the additional requirement that all nodes and edges must have at least one label. This means a query such as
CREATE (n)
is not valid, whilst
CREATE (n:Person)
is a valid query. Because CREATE queries have no RETURN clause, there is no requirement to declare any names for any variables. This means we can have queries such as
CREATE (:Person)-[:FriendsWith]-(:Person)
However, naming variables can be useful if you want to create multiple edges to or from a given node. For instance, if you would like to create a triangle pattern, this can be achieved using the following approach
CREATE (a:Corner)-[:Edge]-(b:Corner), (b)-[:Edge]-(c:Corner), (c)-[:Edge]-(a)
This can also be achieved over multiple CREATE queries using Node ID injection.

🧾Data Types

TuringDB offers the following data types for node and edge properties:
  • String
  • Boolean
  • Integer (signed)
  • Unsigned integer
  • Double (decimal)
By default, if you create a property with a whole-number numeric value, it will be stored in the database engine as a signed integer. If you would like to explicitly use an unsigned value, you can use the u suffix after the numeric value in your create query:
CREATE (n:Person{age=20u, name="Jane"})
MATCH queries provide an automatic coercion from integer to unsigned integer, so if the above CREATE query is submitted, and you run
MATCH (n{age=20}) return n.name
and it will match the node created above, returning
+------+
| Jane |
|------|
|  ... |
+------+
However, the opposite coercion is not supported: if you use the u suffix in a MATCH query, the query will attempt to match an unsigned integer property.
If you query a property with a type which does not match the type of the property stored in the database, the query will not execute (aside from the coercion described above).
String properties can be enclosed using double quotes ("), single quotes ('), or backticks (```).

🧩 Operators

TuringDB allows you to query against node and edge properties using the : or = operators, which both operate in exactly the same way: exact matching of the property value. This means both the following queries are equivalent:
MATCH (n{name="Matt", age:20, hasPhD=false}) RETURN n
MATCH (n{name:"Matt", age=20, hasPhD:false}) RETURN n
Additionally, TuringDB supports the approximate string operator, ~=, which is explained here.

🔐 Node ID Injection

It is possible to reference existing nodes in the database using their internal ID.
The internal ID of a node, n, is the value returned by the query MATCH (n) return n.
Node ID injection can be performed using the @ operator or the AT keyword. The basic syntax is flexible, as
MATCH (n @ 1) RETURN n.name
MATCH (n:Person @ 1) RETURN n.name
MATCH (n:Person{name="Jane"} @ 1) RETURN n.name
MATCH (n:Person @ 1 {name="Jane}) RETURN n.name
MATCH (n @ 1 {name="Jane}) RETURN n.name
MATCH (n {name="Jane} @ 1) RETURN n.name
are all valid uses of the @ operator to perform injection by node ID. Further, replacing @ with AT is equally valid in all the above cases. It is also possible to inject a number of node IDs, which can be achieved by providing a comma-separated list of node IDs:
MATCH (n:Person @ 1, 2, 3) return n.name
which will return the name property values for the nodes with IDs 1, 2, and 3.

📮 Metaqueries

On top of supporting queries which return or alter information in the graph, TuringDB supports a number of “metaqueries” which return information, or metadata, about the graph. These queries follow the CALL syntax, and the following variants are supported:
  1. CALL PROPERTIES () - returns a column of all the different node and edge properties and their types in the database
  2. CALL LABELS () - returns a column of all the different node labels
  3. CALL EDGETYPES() - returns a column of all the different edge types (edge equivalent of node labels)
  4. CALL LABELSETS () - returns a two columns describing combinations of node labels
These metaqueries are useful for exploring the data which is available in the graph, and using this to plan MATCH queries.

🪛 Commands

Outside of CYPHER, there are a number of commands which you can use to interact with the TuringDB engine.
CommandExplanation
CREATE GRAPH <graph name>Create a graph with the specified name
LOAD GRAPH <graph name>Load the specified graph. Requires the graph files to be accessible to the TuringDB instance
HISTORYPrints the history of the version control system
CHANGE NEWCreates a new change, returning a column with the ID of the created change
CHANGE SUBMITWhen checked out on a specific change, submits all changes made to the “master branch”
CHANGE DELETEDeletes the currently checked out change
CHANGE LISTLists the currently active (uncommitted) changes
LIST GRAPHLists the available graphs

🛣️ Roadmap

Whilst TuringDB currently supports a subset of CYPHER, by the next release, the support will be close to 100%. We also plan to support more features outside of CYPHER, which we already do with the string approximation operator, ~=.
I