4.3. Data Types and Operators in xGT

TQL provides both scalar and composite data types along with operators to manipulate them. A scalar data type represents a single item while a composite data type represents multiple items.

4.3.1. Scalar Data Types

A scalar data type can be stored as a frame property and returned from a query. They can be constructed as literals and passed as query parameters. The following scalar data types are supported in xGT. Each column of the schema of a frame must be one of these data types.

4.3.1.1. BOOLEAN

The BOOLEAN type supports the storage of two values: true or false. Use the case-insensitive keywords TRUE or FALSE or the integer values 1 or 0 to assign a BOOLEAN.

4.3.1.2. INTEGER

The INTEGER type holds signed numeric values. It stores any value between the range of -263 and 263 - 1. Attempting to assign values outside this range causes an error.

4.3.1.3. FLOAT

The FLOAT type holds single-precision (32-bit) floating-point values. Inputs with precision greater than 32 bits are valid input but will be truncated. The case-insensitive string NaN is also an acceptable value. Any other non-decimal characters will result in an error.

4.3.1.4. DATE

The DATE type holds a date composed of a day, month, and year. The expected format for a DATE is YYYY-MM-DD where leading zeros must be given. For example, a valid DATE would be 2018-02-20. Assigning a DATE property with a valid DATETIME as described in the DATETIME section will result in the DATETIME being downcast and ignoring the time fields. Attempting to assign any other type will result in an error.

4.3.1.5. TIME

The TIME type holds a time composed of hours, minutes, seconds, and (optionally) a decimal fraction of a second. The expected format for a TIME is HH:MM:SS where leading zeros must be given. For example, a valid TIME would be 06:10:50. Optionally, a decimal fraction of a second can be included where the expected format is HH:MM:SS.S. Values with 1 to 19 decimal digits can be read in, but only a maximum of 6 decimal digits is stored. If the input decimal fraction has between 7 and 19 digits, the number stored is rounded to 6 digits. For example, a valid TIME with a decimal fraction would be 06:10:50.0206. Attempting to assign any other type will result in an error.

In addition, a time zone can be indicated, though this will be converted to a Coordinated Universal Time (UTC) and the time zone will not be retained. Time zones are expressed either with a Z to indicated UTC or with an offset in containing an hour part and an optional minute part. The hour part must be between 14 and -14, and the minute part must be in 15 minute increments. The following formats are valid with or without a decimal fraction: HH:MM:SSZ, HH:MM:SS+HH:MM, HH:MM:SS-HH:MM, HH:MM:SS+HH, and HH:MM:SS-HH. For example, 06:10:50.0206+01:15 and 06:10:50-01:00 are valid times whereas 06:10:50+16 and 06:10:50+01:17 are not valid.

4.3.1.6. DATETIME

The DATETIME type holds a valid date and time separated by either a T or a space, where the date and time must be formatted as described above. It is composed of a day, month, year, hours, minutes, seconds, and optionally microseconds. The expected format for a DATETIME is YYYY-MM-DDTHH:MM:SS, YYYY-MM-DD HH:MM:SS, YYYY-MM-DDTHH:MM:SS.S, YYYY-MM-DD HH:MM:SS.S, YYYY-MM-DDTHH:MM:SSZ (UTC), YYYY-MM-DDTHH:MM:SS+HH:MM, YYYY-MM-DDTHH:MM:SS+HH, YYYY-MM-DDTHH:MM:SS-HH:MM, or YYYY-MM-DDTHH:MM:SS-HH. For example, a valid DATETIME would be 2018-12-20T06:10:50, 2018-12-20 06:10:50.02006, or 2018-12-20T06:10:50.02006+01:15. Assigning a DATE to a DATETIME will result in the DATE being “promoted” to a DATETIME with zeros for the time fields. Attempting to assign any other type will result in an error.

4.3.1.7. IPADDRESS

The IPADDRESS type holds an IPv4 address. The expected format of an IPADDRESS is XXX.XXX.XXX.XXX where each dot-separated value is between 0 and 255. For example, a valid IPADDRESS would be 172.16.254.1. Assigning any other type (including IPv6 addresses) will result in an error.

For situations where there are both IPv4 and IPv6 addresses in a single data source, it is recommended that the schema provide a TEXT type for that data.

4.3.1.8. TEXT

The TEXT type holds a string of UTF-8 encoded Unicode characters.

4.3.2. Composite Data Types

A composite data type can be constructed as a literal. The only composite data type supported by TQL is a list. Lists can be stored as a frame property, returned from a query, or passed as a query parameter. Lists are currently not supported for Pandas frames.

4.3.2.1. Lists

xGT supports homogeneous nested lists.

A literal list is created using brackets: [1, 2, 4, 1]. They can contain vertex and edge properties, constants, or any other valid TQL expression: Brackets can be nested to form nested lists: [[1, 2, 4, 1], [5, 6, 7]].

MATCH (v:VertexFrame)-[]->(v2)
WITH [v.property1, v2.property1 + 10] AS list

An empty literal list is allowed: []. Lists of any type can also include null as a value. For example, the following are all valid literal lists:

[1, 2, NULL, 4]
[NULL, "a"]

Numeric lists can be created with the range function, which takes three arguments: the start, end, and an optional step.

WITH range(0, 10) AS list0, range(2, 14, 3) AS list1

The collect aggregator can be used to create a list from data. In the example below, it is used to create a list of property values found over all matches of a pattern:

MATCH (v:VertexFrame)
WITH collect(v.property) AS list0
MATCH (w)-[e:EdgeFrame]->()
WHERE e.value IN list0

All elements in a list must be the same data type. The one exception is numeric types. FLOAT and INTEGER can be mixed in a list. For example, the following lists are valid:

[date("2018-02-20"), date("2018-02-21"), date("2007-05-20")]
[ipaddress("172.16.254.1"), ipaddress("216.58.216.164")]
["a", "zebra"]
[1, 0.45, 7, 9.382]

The following example mixes incompatible types and is invalid:

[date("2018-02-20"), 12, "a"]

Vertex and edge variables are not allowed as list elements. For example, the lists in the following query are invalid:

MATCH (v:VertexFrame)-[e]->(v2)
WITH [v] AS list, [e] AS list2

Nested lists must be the same type at a given level across all lists. A list is considered a type, so lists cannot be mixed with other types either. The exception is that a empty or null list can be mixed with other lists. The following are valid:

[[1, 2, 3], [4, 5, 6]]
[["x"], ["a", "b"]]
[[1, 2, 3], []]
[[1, 2, 3], [null]]
[[1, 4], null]
[[[1, 4]], null]

The following are invalid because the sublists are of different types:

[[9, 12, 8], ["a", "b"]]
[[9, 12, 8], [[9, 12, 8]]]

The following is invalid because it mixes other types with the list type:

[9, 12, 8, [9, 12, 8]]

4.3.3. Supported Operators

TQL provides boolean, comparison, arithmetic, string, and list operators. “Numeric” below refers to INTEGER and FLOAT data types. “Any” refers to any of the data types described above.

4.3.3.1. Boolean Operators

xGT supports the following boolean operators:

Boolean Operators

Operator

Operand 1

Operand 2

Result

Description

NOT

BOOLEAN

N/A

BOOLEAN

Boolean negation operator.

AND

BOOLEAN

BOOLEAN

BOOLEAN

Boolean conjunction operator.

OR

BOOLEAN

BOOLEAN

BOOLEAN

Boolean disjunction operator.

XOR

BOOLEAN

BOOLEAN

BOOLEAN

Boolean exclusive disjunction operator.

4.3.3.2. Comparison Operators

xGT supports the following comparison operators:

Comparison Operators

Operator

Operand 1

Operand 2

Result

Description

IS NULL / IS NOT NULL

Any

N/A

BOOLEAN

Null check.

=

Any

Any

BOOLEAN

Equality comparison.

<>

Any

Any

BOOLEAN

Inequality comparison.

<, <=

Any

Any

BOOLEAN

Less-than, less-than equal comparison.

>, >=

Any

Any

BOOLEAN

Greater-than, greater-than equal comparison.

For the comparison operators that have two parameters, the parameters must be of the same type or both be numeric types. When the parameters are of different numeric types, type promotion occurs automatically. All comparisons on lists perform lexicographical comparisons meaning the list elements are compared in order pairwise. If one list is longer than the other, its remaining elements are considered greater than the missing elements. For example, [1] < [1,2] evaluates to true.

4.3.3.3. Arithmetic Operators

The following arithmetic operators are supported with type promotion from integer to floating-point occurring automatically.

Arithmetic Operators

Operator

Operand 1

Operand 2

Result

Description

+

Numeric

Numeric

Numeric

Addition operator.

-

Numeric

Numeric

Numeric

Subtraction operator.

*

Numeric

Numeric

Numeric

Multiplication operator.

/

Numeric

Numeric

Numeric

Division operator.

%

Numeric

Numeric

Numeric

Modulus (remainder) operator.

^

Numeric

Numeric

Numeric

Exponentiation operator.

-

Numeric

Numeric

Unary minus operator.

4.3.3.4. String Operators

The following string operators are supported.

String Operators

Operator

Operand 1

Operand 2

Result

Description

STARTS WITH

String

String

Boolean

True if the right-hand is a prefix of the left-hand side.

ENDS WITH

String

String

Boolean

True if the right-hand is a suffix of the left-hand side.

CONTAINS

String

String

Boolean

True if the right-hand is a substring of the left-hand side.

+

String

String

String

String concatenation.

4.3.3.5. List Operators

The IN operator is used to test for membership in a list. The test expression must be of a compatible type with the elements in the list. Some examples:

a.name IN ["John", "Mary"]
b.id IN [1, 2, 3]
c.startdate IN [date("2000-01-01"), date("2002-01-01")]

The IN operator also supports nested lists:

parents IN [["John", "Mary"], ["Jacob", "Mary"]]

List concatenation is supported via the + operator. The two lists to be concatenated must have the same type.

RETURN [1, 2, 3] + [-1, 0, 1]

The subscript operator is supported to access individual elements in a list. The following example would return the integer 2.

RETURN [1, 2, 3][1]

The slicing operator is supported to retrieve sublists from an original list. The following example would return the list with elements [2, 3].

RETURN [1, 2, 3][1..2]