Data Types

AGE uses a custom data type named agtype, which is the only data type returned by AGE. agtype is a superset of JSON and a custom implementation of PostgreSQL’s jsonb.

Simple Data Types

Null

In Cypher, null represents a missing or undefined value. Conceptually, null means “a missing unknown value” and behaves differently from all other values. For example, accessing a non-existent property on a vertex yields null. Most expressions that take null as input return null, including Boolean predicates in WHERE clauses. In such cases, any value that is not true is treated as false. null is not equal to null: not knowing whether two values are equal does not imply they are equal. Therefore, the expression null = null evaluates to null, not true.

Input/Output Format

Query

SELECT *
FROM cypher('graph_name', $$
    RETURN NULL
$$) AS (null_result agtype);

null displays as blank.

Result

null_result

(1 row)

agtype NULL vs. PostgreSQL NULL

The concept of NULL in agtype and in PostgreSQL is identical to that in Cypher.

Integer

The integer type stores whole numbers — numeric values without fractional components. It is a 64-bit signed field, supporting values from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. Attempts to store values outside this range raise an error.

integer offers the best balance among value range, storage size, and performance. smallint is used only when disk space is constrained. bigint is intended for cases where integer’s range is insufficient.

Input/Output Format

Query

SELECT *
FROM cypher('graph_name', $$
    RETURN 1
$$) AS (int_result agtype);

Result

| int_result |
| ---------- |
| 1          |
(1 row)    

Float

The float data type is an imprecise, variable-precision numeric type conforming to the IEEE-754 standard.

“Imprecise” means some values cannot be represented exactly in the internal format and are instead stored as approximations. Slight discrepancies may therefore occur between stored and retrieved values. Managing such errors — and their propagation through arithmetic — is the subject of an entire discipline in mathematics and computer science. While beyond the scope of this document, the following points are critical:

  • Use the numeric type for exact storage and computation (e.g., monetary amounts).
  • When performing complex calculations — especially those relying on edge-case behavior (e.g., infinity, underflow) — carefully evaluate the implementation.
  • Equality comparisons between floating-point values may not behave as expected.

Values that are too large or too small raise an error. Excessively precise inputs may be rounded. Values too close to zero to be represented distinctly from zero cause underflow errors.

In addition to ordinary numeric values, float supports several special values:

  • Infinity
  • -Infinity
  • NaN

These correspond to the IEEE 754 special values “positive infinity”, “negative infinity”, and “not-a-number”. To use these as literals in Cypher commands, they must be quoted and explicitly cast, for example:

SET x.float_value = '-Infinity'::float

Input strings for these values are matched case-insensitively.

Input/Output Format

To specify a float, include a decimal point.

Query

SELECT *
FROM cypher('graph_name', $$
    RETURN 1.0
$$) AS (float_result agtype);

Result

| float_result |
| ------------ |
| 1.0          |
(1 row)      

MXnumeric

— Coming soon —

Bool

AGE provides the standard Cypher boolean type. The boolean type has three possible states: true, false, and a third state — unknown — represented by an agtype null value.

Boolean literals are written using the keywords TRUE, FALSE, and NULL in Cypher queries.

Input/Output Format

Query

SELECT *
FROM cypher('graph_name', $$
    RETURN TRUE
$$) AS (boolean_result agtype);

Unlike PostgreSQL, AGE outputs full words (true, false) rather than single-character abbreviations (t, f).

Result

| boolean_result |
| -------------- |
| true           |
(1 row)        

String

agtype string literals support the following escape sequences:

Escape Sequence Character
\t Tab
\b Backspace
\n Line feed (newline)
\r Carriage return
\f Form feed
' Single quote
" Double quote
\\ Backslash
\uXXXX Unicode UTF-16 code point (exactly four hexadecimal digits after \u)

Input/Output Format

Strings are delimited by single quotes ('). Output uses double quotes (").

Query

SELECT *
FROM cypher('graph_name', $$
    RETURN 'This is a string'
$$) AS (string_result agtype);

Result

| string_result      |
| ------------------ |
| "This is a string" |
(1 row)            

Composite Data Types

List

All examples use WITH and RETURN clauses.

List Literals

Literal lists are created using square brackets with comma-separated elements.

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst
$$) AS (lst agtype);

Result

| lst                                |
| ---------------------------------- |
| [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
(1 row)                            

NULL in Lists

Lists may contain null values. Unlike standalone null, null inside a list appears as the literal word null.

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [null] AS lst
    RETURN lst
$$) AS (lst agtype);

Result

| lst     |
| ------- |
| [null]  |
(1 row) 

Accessing Individual Elements

Use square brackets to access individual list elements. Syntax list[start..end] returns elements from index start (inclusive) to end (exclusive).

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst[3]
$$) AS (element agtype);

Result

| element |
| ------- |
| 3       |
(1 row) 

Maps as List Elements

Query

SELECT *
FROM cypher('graph_name', $$
   WITH [0, {key: 'key_value'}, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst
$$) AS (map_value agtype);

Result

| map_value                                             |
| ----------------------------------------------------- |
| [0, {"key": "key_value"}, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
(1 row)                                               

Accessing Map Elements Inside Lists

Query

SELECT *
FROM cypher('graph_name', $$
   WITH [0, {key: 'key_value'}, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst[1].key
$$) AS (map_value agtype);

Result

| map_value   |
| ----------- |
| "key_value" |
(1 row)     

Negative Indexing

Negative indices count backward from the end of the list.

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst[-3]
$$) AS (element agtype);

Result

| element |
| ------- |
| 8       |
(1 row) 

Index Ranges

Square brackets support ranges to extract subsequences.

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst[0..3]
$$) AS (element agtype);

Result

| element   |
| --------- |
| [0, 1, 2] |
(1 row)   

Negative Index Ranges

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst[0..-5]
$$) AS (lst agtype);

Result

| lst                |
| ------------------ |
| [0, 1, 2, 3, 4, 5] |
(1 row)            

Forward Slicing

Omitting the start index defaults to 0.

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst[..4]
$$) AS (lst agtype);

Result

| lst          |
| ------------ |
| [0, 1, 2, 3] |
(1 row)      

Reverse Slicing

Omitting the end index defaults to the list length.

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst[-5..]
$$) AS (lst agtype);

Result

| lst                |
| ------------------ |
| [6, 7, 8, 9, 10]   |
(1 row)

Out-of-bounds slices are truncated silently. Out-of-bounds single-element access returns null.

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst[15]
$$) AS (element agtype);

Result

| element |
| ------- |
|         |
(1 row) 

Query

SELECT *
FROM cypher('graph_name', $$
    WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
    RETURN lst[5..15]
$$) AS (element agtype);

Result

| element             |
| ------------------- |
| [5, 6, 7, 8, 9, 10] |
(1 row)             

Map

Maps can be constructed directly in Cypher.

Literal Maps Using Simple Data Types

A simple map can be built using basic agtype values.

Query

SELECT *
FROM cypher('graph_name', $$
    WITH {int_key: 1, float_key: 1.0, numeric_key: 1::numeric, bool_key: true, string_key: 'Value'} AS m
    RETURN m
$$) AS (m agtype);

Result

| m                                                                                                    |
| ---------------------------------------------------------------------------------------------------- |
| {"int_key": 1, "bool_key": true, "float_key": 1.0, "string_key": "Value", "numeric_key": 1::numeric} |
(1 row)

Literal Maps Using Composite Data Types

Maps may contain composite types — e.g., lists and nested maps.

Query

SELECT *
FROM cypher('graph_name', $$
    WITH {listKey: [{inner: 'Map1'}, {inner: 'Map2'}], mapKey: {i: 0}} AS m
    RETURN m
$$) AS (m agtype);

Result

| m                                                                       |
| ----------------------------------------------------------------------- |
| {"mapKey": {"i": 0}, "listKey": [{"inner": "Map1"}, {"inner": "Map2"}]} |
(1 row)                                                                 

Property Access on Maps

Query

SELECT *
FROM cypher('graph_name', $$
    WITH {int_key: 1, float_key: 1.0, numeric_key: 1::numeric, bool_key: true, string_key: 'Value'} AS m
    RETURN m.int_key
$$) AS (int_key agtype);

Result

| int_key |
| ------- |
| 1       |
(1 row) 

Accessing List Elements Within Maps

Query

SELECT *
FROM cypher('graph_name', $$
    WITH {listKey: [{inner: 'Map1'}, {inner: 'Map2'}], mapKey: {i: 0}} AS m
    RETURN m.listKey[0]
$$) AS (m agtype);

Result

| m                 |
| ----------------- |
| {"inner": "Map1"} |
(1 row)           

Simple Entities

Entities have unique, comparable identifiers used to determine equality.

Each entity is assigned a set of properties, each uniquely identified within the set by its property key.

GraphId

Simple entities are assigned a unique graphid. A graphid is a unique combination of a label ID and a sequence number assigned per label. Note that graphids may overlap across different graphs.

A graphid is fundamentally a signed 64-bit integer (int64).

The 64 bits are partitioned as follows:

<--- 16 bits ---> <----------- 48 bits ----------->
Label ID Entry ID
(bits 63–48) (bits 47–0)
  • Label ID: The upper 16 bits, ranging from 1 to 65535 (PG_UINT16_MAX). 0 is invalid.
  • Entry ID: The lower 48 bits, ranging from 1 to 281474976710655 (0x0000ffffffffffff). 0 is invalid.

Labels

Labels are identifiers that classify vertices and edges into specific categories.

  • Edges must have a label; vertices are not required to have one.
  • Label names must be distinct between vertices and edges.

For information on creating labeled entities, see the CREATE clause.

Note!
In YMatrix AGE, labels are implemented as database tables — i.e., one label maps to exactly one table.

Properties

Both vertices and edges may have properties. Properties are key-value pairs, where each property name must be a string.

Vertex

  • A vertex is a fundamental graph entity with independent existence and unique identity.
  • A vertex may be assigned a label.
  • A vertex may have zero or more outgoing edges.
  • A vertex may have zero or more incoming edges.

Data Format

Field Name Description
id The vertex’s graphid
label The vertex’s label name
properties Properties associated with the vertex
{id:1; label: 'label_name'; properties: {prop1: value1, prop2: value2}}::vertex

Converting a Map to a Vertex

Query

SELECT *
FROM cypher('graph_name', $$
        WITH {id: 0, label: "label_name", properties: {i: 0}}::vertex AS v
        RETURN v
$$) AS (v agtype);

Result

| v                                                                |
| ---------------------------------------------------------------- |
| {"id": 0, "label": "label_name", "properties": {"i": 0}}::vertex |
(1 row)                                                          

Edge

An edge is a directed connection between two nodes — a source node and a target node. An outgoing edge is viewed from the source node’s perspective; an incoming edge is viewed from the target node’s perspective. Each edge is assigned exactly one edge type.

Data Format

Field Name Description
id The edge’s graphid
startid The graphid of the source node
endid The graphid of the target node
label The edge’s label name
properties Properties associated with the edge

Output Format

{id: 3; startid: 1; endid: 2; label: 'edge_label'; properties: {prop1: value1, prop2: value2}}::edge

Converting a Map to an Edge

Query

SELECT *
FROM cypher('graph_name', $$
        WITH {id: 2, start_id: 0, end_id: 1, label: "label_name", properties: {i: 0}}::edge AS e
        RETURN e
$$) AS (e agtype);

Result

| e                                                                                          |
| ------------------------------------------------------------------------------------------ |
| {"id": 2, "label": "label_name", "end_id": 1, "start_id": 0, "properties": {"i": 0}}::edge |
(1 row)                                                                                    

Composite Entities

Path

A path is an alternating sequence of vertices and edges. A path must begin with a vertex and contain at least one edge.

Converting a List to a Path

Query

SELECT *
FROM cypher('graph_name', $$
        WITH [{id: 0, label: "label_name_1", properties: {i: 0}}::vertex,
              {id: 2, start_id: 0, end_id: 1, label: "edge_label", properties: {i: 0}}::edge,
              {id: 1, label: "label_name_2", properties: {}}::vertex
             ]::path AS p
        RETURN p
$$) AS (p agtype);

Result

| p                                                                                                                                                                                                                                    |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [{"id": 0, "label": "label_name_1", "properties": {"i": 0}}::vertex, {"id": 2, "label": "edge_label", "end_id": 1, "start_id": 0, "properties": {"i": 0}}::edge, {"id": 1, "label": "label_name_2", "properties": {}}::vertex]::path |
(1 row)