The GQLDB Python driver supports a comprehensive set of data types for storing and querying graph data. This guide covers property types, enums, and type conversions.
The PropertyType enum defines all supported data types:
Pythonfrom gqldb.types import PropertyType
| Type | Description | Python Type |
|---|---|---|
INT32 | 32-bit signed integer | int |
UINT32 | 32-bit unsigned integer | int |
INT64 | 64-bit signed integer | int |
UINT64 | 64-bit unsigned integer | int |
FLOAT | 32-bit floating point | float |
DOUBLE | 64-bit floating point | float |
DECIMAL | Arbitrary precision decimal | GqldbDecimal |
| Type | Description | Python Type |
|---|---|---|
STRING | Variable-length string | str |
TEXT | Long text | str |
| Type | Description | Python Type |
|---|---|---|
BOOL | Boolean value | bool |
NULL | Null value | None |
UNSET | Unset/unknown type | None |
| Type | Description | Python Type |
|---|---|---|
BLOB | Binary data | bytes |
| Type | Description | Python Type |
|---|---|---|
TIMESTAMP | Unix timestamp with nanoseconds | datetime |
DATETIME | Date and time (deprecated; decodes as LOCAL_DATETIME) | GqldbLocalDateTime |
DATE | Date only | GqldbDate |
LOCAL_DATETIME | Local date and time | GqldbLocalDateTime |
ZONED_DATETIME | Date and time with timezone | GqldbZonedDateTime |
LOCAL_TIME | Local time of day | GqldbLocalTime |
ZONED_TIME | Time with timezone | GqldbZonedTime |
| Type | Description | Python Type |
|---|---|---|
YEAR_TO_MONTH | Year-month duration | YearToMonth |
DAY_TO_SECOND | Day-second duration | DayToSecond |
| Type | Description | Python Type |
|---|---|---|
POINT | 2D geographic point | Point |
POINT3D | 3D point | Point3D |
| Type | Description | Python Type |
|---|---|---|
LIST | Ordered list | list |
SET | Unordered unique set | set |
MAP | Key-value map | dict |
VECTOR | Numeric vector | Vector |
| Type | Description | Python Type |
|---|---|---|
NODE | Graph node | GqldbNode |
EDGE | Graph edge | GqldbEdge |
PATH | Graph path | GqldbPath |
Pythonfrom gqldb.types import PropertyType class PropertyType(IntEnum): UNSET = 0 INT32 = 1 UINT32 = 2 INT64 = 3 UINT64 = 4 FLOAT = 5 DOUBLE = 6 STRING = 7 DATETIME = 8 # Deprecated, use TIMESTAMP TIMESTAMP = 9 TEXT = 10 BLOB = 11 POINT = 12 DECIMAL = 13 LIST = 14 SET = 15 MAP = 16 NULL = 17 BOOL = 18 LOCAL_DATETIME = 19 ZONED_DATETIME = 20 DATE = 21 ZONED_TIME = 22 LOCAL_TIME = 23 YEAR_TO_MONTH = 24 DAY_TO_SECOND = 25 RECORD = 26 POINT3D = 27 VECTOR = 28 TABLE = 29 PATH = 30 ERROR = 31 NODE = 32 EDGE = 33
Pythonfrom gqldb.types import GraphType class GraphType(IntEnum): OPEN = 0 # Schema-less graph CLOSED = 1 # Schema-enforced graph ONTOLOGY = 2 # Ontology-enabled graph
Pythonfrom gqldb.types import HealthStatus class HealthStatus(IntEnum): UNKNOWN = 0 SERVING = 1 NOT_SERVING = 2 SERVICE_UNKNOWN = 3
Pythonfrom gqldb.types import CacheType class CacheType(IntEnum): ALL = 0 AST = 1 PLAN = 2
Controls the GQL keyword emitted by insert_nodes(nodes, …) / insert_edges(edges, …):
Pythonfrom gqldb import InsertType class InsertType(IntEnum): NORMAL = 0 # INSERT — errors on duplicate _id OVERWRITE = 1 # INSERT OVERWRITE — replaces entity wholesale on duplicate _id UPSERT = 2 # UPSERT — merges new properties into existing entity on duplicate _id
OVERWRITE drops properties not present in the write. UPSERT preserves them and only overwrites the ones present in the write. They are not interchangeable.
Per-call configuration for the GQL-path insert convenience methods. Extends QueryConfig:
Pythonfrom gqldb import InsertConfig, InsertType @dataclass class InsertConfig(QueryConfig): insert_type: InsertType = InsertType.NORMAL # NORMAL / OVERWRITE / UPSERT # inherits from QueryConfig: # graph_name: str = "" # parameters: Dict[str, Any] = {} # transaction_id: int = 0 # timeout: int = 0 # read_only: bool = False # max_path_results: int = 0
Pythonfrom gqldb import NodeData, Node from gqldb.types import GqldbNode # Data for inserting nodes (input to insert_nodes) @dataclass class NodeData: id: str = "" # optional custom _id (auto-generated when empty) labels: List[str] = field(default_factory=list) properties: Dict[str, Any] = field(default_factory=dict) # Node from query results (e.g. response.alias("col").as_nodes()) @dataclass class Node: id: str = "" # user-facing identifier uuid: str = "" # system numeric handle (uint64 as decimal string); # empty when talking to pre-6.1.147 servers labels: List[str] = field(default_factory=list) properties: Dict[str, Any] = field(default_factory=dict) def to_dict(self) -> dict: ... # Internal/wire-level node representation @dataclass class GqldbNode: id: str = "" uuid: str = "" labels: List[str] = field(default_factory=list) properties: Dict[str, Any] = field(default_factory=dict)
Pythonfrom gqldb import EdgeData, Edge from gqldb.types import GqldbEdge # Data for inserting edges (input to insert_edges) @dataclass class EdgeData: id: str = "" # optional custom _id (requires WITH EDGE_ID graph) label: str = "" from_node_id: str = "" to_node_id: str = "" properties: Dict[str, Any] = field(default_factory=dict) # Edge from query results @dataclass class Edge: id: str = "" # user-facing identifier uuid: str = "" # system numeric handle; empty pre-6.1.147 label: str = "" from_node_id: str = "" to_node_id: str = "" properties: Dict[str, Any] = field(default_factory=dict) def to_dict(self) -> dict: ... # Internal/wire-level edge representation @dataclass class GqldbEdge: id: str = "" uuid: str = "" label: str = "" from_node_id: str = "" to_node_id: str = "" properties: Dict[str, Any] = field(default_factory=dict)
Pythonfrom gqldb.types import GqldbPath @dataclass class GqldbPath: nodes: List[GqldbNode] edges: List[GqldbEdge]
Pythonfrom gqldb.types import Point, Point3D @dataclass class Point: latitude: float longitude: float srid: int = 0 # spatial reference system id; 0 = unset @property def x(self) -> float: ... # alias for longitude @property def y(self) -> float: ... # alias for latitude @dataclass class Point3D: x: float y: float z: float srid: int = 0 # spatial reference system id; 0 = unset @property def longitude(self) -> float: ... # alias for x @property def latitude(self) -> float: ... # alias for y @property def height(self) -> float: ... # alias for z
The Point server validates WGS-84 bounds (longitude ∈ [-180, 180], latitude ∈ [-90, 90]). Point3D is Cartesian — the server does not enforce geographic bounds on Point3D, even when accessed through the lon/lat aliases.
srid)Both Point and Point3D carry an integer srid (spatial reference system id). A value of srid=0 means unset: the encoder leaves the CRS unspecified and the server fills in the appropriate default on round-trip — an unset 2D point normalizes to 4326 (WGS-84), an unset 3D point normalizes to 9157 (cartesian). The driver exposes the two client-side defaults as module constants:
Pythonfrom gqldb.types.data_types import DEFAULT_POINT_2D_SRID, DEFAULT_POINT_3D_SRID DEFAULT_POINT_2D_SRID # 4326 — WGS-84 (geographic) DEFAULT_POINT_3D_SRID # 0 — cartesian, no CRS (unset)
Example:
Pythonfrom gqldb.types import Point, Point3D p = Point(latitude=39.9, longitude=116.4) # srid defaults to 0 (unset -> server 4326) p_wgs = Point(latitude=39.9, longitude=116.4, srid=4326) print(p.srid) # 0 q = Point3D(x=1.0, y=2.0, z=3.0) # srid defaults to 0 (unset -> server 9157) print(q.srid) # 0
The temporal wrapper classes (GqldbLocalDateTime, GqldbZonedDateTime, GqldbDate, GqldbLocalTime, GqldbZonedTime) render through __str__ / str() in a single canonical form:
YYYY-MM-DD HH:mm:ss[.fff] — a space separates date and time.±HH:MM.YYYY-MM-DD; time-only is HH:mm:ss[.fff][±HH:MM].This canonical form is also the JSON representation (to_json() serializes temporal wrappers via str()) — a behavior change from earlier releases.
Pythonfrom gqldb.types import GqldbLocalDateTime, GqldbZonedDateTime, GqldbZonedTime str(GqldbLocalDateTime(2026, 7, 1, 15, 40, 12, 153000000)) # '2026-07-01 15:40:12.153' str(GqldbLocalDateTime(2026, 7, 1, 15, 40, 12, 0)) # '2026-07-01 15:40:12' (zero fraction omitted) str(GqldbZonedDateTime(2026, 7, 1, 15, 40, 12, 153000000, 480)) # '2026-07-01 15:40:12.153+08:00' str(GqldbZonedTime(15, 40, 12, 0, -330)) # '15:40:12-05:30'
Pythonfrom gqldb.types import YearToMonth, DayToSecond @dataclass class YearToMonth: months: int @dataclass class DayToSecond: seconds: int nanoseconds: int
Pythonfrom gqldb.types import Vector @dataclass class Vector: values: List[float] = field(default_factory=list) def __len__(self) -> int: ... # vector dimension def __iter__(self): ... # iterate over float components
len(vector) returns the dimension; iteration yields the float components in order. These mirror the server-side size(VECTOR) / ai.vector_dim(VECTOR) functions, so you don't have to round-trip a GQL query just to read a vector's dimension.
The driver uses TypedValue internally for type-safe data transfer:
Pythonfrom gqldb.types import TypedValue, PropertyType # Get typed values from a row row = response.first() if row: for tv in row.values: print(f"Type: {tv.type}, Value: {tv.to_python()}")
TypedValue provides a symmetric pair of static/instance helpers for text round-tripping:
Pythonfrom gqldb.types import TypedValue, PropertyType # Parse a string into a TypedValue of the given target type tv = TypedValue.from_string("point({latitude: 30.5, longitude: 114.3})", PropertyType.POINT) point = tv.to_python() # Serialize a TypedValue back to its canonical string form text = tv.format_value()
TypedValue.from_string(s, target_type) accepts these forms per type. An empty string parses to a NULL TypedValue.
| Target type | Accepted string forms |
|---|---|
POINT | Canonical point({latitude: 30.5, longitude: 114.3}) (keys, any order); lenient positional 30.5,114.3 or (30.5,114.3) — lat,lon order; WKT POINT(114.3 30.5) — lon FIRST (OGC order, the opposite of the comma form). Validates latitude ∈ [-90, 90], longitude ∈ [-180, 180]. |
POINT3D | Canonical point({x: 1, y: 2, z: 3}) (keys, any order); positional 1,2,3 or (1,2,3); WKT POINT(1 2 3) or POINT Z(1 2 3) — cartesian x,y,z (no lon/lat swap). |
VECTOR | [0.1,0.2,0.3] or bracket-less 0.1,0.2,0.3; [] yields an empty vector. |
BLOB | Base64 (standard) by default; a 0x / 0X prefix selects hex. |
The distinction is easy to trip over: the positional comma form is latitude first (30.5,114.3), while WKT POINT(...) is longitude first (POINT(114.3 30.5)) — both describe the same location.
Pythonfrom gqldb.types import TypedValue, PropertyType # All three parse to the same 2D point (lat 30.5, lon 114.3): TypedValue.from_string("point({latitude: 30.5, longitude: 114.3})", PropertyType.POINT) TypedValue.from_string("30.5,114.3", PropertyType.POINT) # lat,lon TypedValue.from_string("POINT(114.3 30.5)", PropertyType.POINT) # lon lat (WKT) # Vector and blob TypedValue.from_string("[0.1,0.2,0.3]", PropertyType.VECTOR) TypedValue.from_string("0x48656c6c6f", PropertyType.BLOB) # hex TypedValue.from_string("SGVsbG8=", PropertyType.BLOB) # base64
For explicit type specification:
Pythonfrom gqldb.types import Int32, UInt32, Float32, UInt64 # Wrap values with explicit types node = NodeData( labels=["Test"], properties={ "int32_val": Int32(42), "uint32_val": UInt32(100), "float32_val": Float32(3.14), "uint64_val": UInt64(9999999999) } )
Pythonfrom datetime import date, datetime # Insert with date client.gql(""" INSERT (e:Event { _id: 'e1', name: 'Conference', date: DATE('2024-06-15'), startTime: DATETIME('2024-06-15T09:00:00Z') }) """) # Query and convert response = client.gql("MATCH (e:Event) RETURN e.date, e.startTime") row = response.first() if row: event_date = row.get(0) start_time = row.get(1) print(f"Event date: {event_date}") print(f"Start time: {start_time}")
Python# Insert with location client.gql(""" INSERT (p:Place { _id: 'p1', name: 'Office', location: POINT(37.7749, -122.4194) }) """) # Query and access point response = client.gql("MATCH (p:Place) RETURN p.location") row = response.first() if row: location = row.get(0) if hasattr(location, 'latitude'): print(f"Lat: {location.latitude}, Lng: {location.longitude}")
Python# Insert with list and map client.gql(""" INSERT (u:User { _id: 'u1', name: 'Alice', tags: ['developer', 'blogger'], metadata: {level: 5, premium: true} }) """) # Query collections response = client.gql("MATCH (u:User) RETURN u.tags, u.metadata") row = response.first() if row: tags = row.get(0) # list metadata = row.get(1) # dict print(f"Tags: {tags}") print(f"Metadata: {metadata}")
Pythonfrom gqldb import GqldbClient, GqldbConfig from gqldb.types import PropertyType, NodeData from gqldb.errors import GqldbError def main(): config = GqldbConfig( hosts=["localhost:9000"], timeout=30 ) with GqldbClient(config) as client: client.login("admin", "password") client.create_graph("typeDemo") client.use_graph("typeDemo") # Insert data with various types client.gql(""" INSERT (u:User { _id: 'u1', name: 'Alice', age: 30, balance: 1234.56, active: true, joined: DATE('2023-01-15'), location: POINT(40.7128, -74.0060), tags: ['developer', 'mentor'], settings: {theme: 'dark', notifications: true} }) """) # Query and check types response = client.gql(""" MATCH (u:User {_id: 'u1'}) RETURN u.name, u.age, u.balance, u.active, u.joined, u.location, u.tags, u.settings """) row = response.first() if row: print(f"Name (str): {row.get_string(0)}") print(f"Age (int): {row.get_int(1)}") print(f"Balance (float): {row.get_float(2)}") print(f"Active (bool): {row.get_bool(3)}") print(f"Joined: {row.get(4)}") print(f"Location: {row.get(5)}") print(f"Tags: {row.get(6)}") print(f"Settings: {row.get(7)}") # Check property types print("\nProperty types:") for i, tv in enumerate(row.values): print(f" Column {i}: {tv.type.name}") client.drop_graph("typeDemo") if __name__ == "__main__": main()