UltipaDocs
Products
Solutions
Resources
Company
Start Free Trial
UltipaDocs
Start Free Trial
  • Introduction
    • Quick Start
    • Configuration
    • Connection and Session
    • Executing Queries
    • Graph Management
    • Schema Management
    • Transactions
    • Data Operations
    • Bulk Import
    • Loading Files
    • Data Export
    • Health and Administration
    • Response Processing
    • Data Types
    • Error Handling
    • Quick Start
    • Configuration
    • Connection and Session
    • Executing Queries
    • Graph Management
    • Schema Management
    • Transactions
    • Data Operations
    • Bulk Import
    • Loading Files
    • Data Export
    • Graph ML Data Loaders
    • Health and Administration
    • Response Processing
    • Data Types
    • Error Handling
    • Quick Start
    • Configuration
    • Connection and Session
    • Executing Queries
    • Graph Management
    • Schema Management
    • Transactions
    • Data Operations
    • Bulk Import
    • Loading Files
    • Data Export
    • Health and Administration
    • Response Processing
    • Data Types
    • Error Handling
    • Quick Start
    • Configuration
    • Connection and Session
    • Executing Queries
    • Graph Management
    • Schema Management
    • Transactions
    • Data Operations
    • Bulk Import
    • Loading Files
    • Data Export
    • Health and Administration
    • Response Processing
    • Data Types
    • Error Handling
  1. Docs
  2. /
  3. Ultipa Drivers
  4. /
  5. Python

Data Types

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.

Property Types

The PropertyType enum defines all supported data types:

Python
from gqldb.types import PropertyType

Numeric Types

TypeDescriptionPython Type
INT3232-bit signed integerint
UINT3232-bit unsigned integerint
INT6464-bit signed integerint
UINT6464-bit unsigned integerint
FLOAT32-bit floating pointfloat
DOUBLE64-bit floating pointfloat
DECIMALArbitrary precision decimalGqldbDecimal

String Types

TypeDescriptionPython Type
STRINGVariable-length stringstr
TEXTLong textstr

Boolean and Null

TypeDescriptionPython Type
BOOLBoolean valuebool
NULLNull valueNone
UNSETUnset/unknown typeNone

Binary

TypeDescriptionPython Type
BLOBBinary databytes

Date and Time Types

TypeDescriptionPython Type
TIMESTAMPUnix timestamp with nanosecondsdatetime
DATETIMEDate and time (deprecated; decodes as LOCAL_DATETIME)GqldbLocalDateTime
DATEDate onlyGqldbDate
LOCAL_DATETIMELocal date and timeGqldbLocalDateTime
ZONED_DATETIMEDate and time with timezoneGqldbZonedDateTime
LOCAL_TIMELocal time of dayGqldbLocalTime
ZONED_TIMETime with timezoneGqldbZonedTime

Duration Types

TypeDescriptionPython Type
YEAR_TO_MONTHYear-month durationYearToMonth
DAY_TO_SECONDDay-second durationDayToSecond

Geospatial Types

TypeDescriptionPython Type
POINT2D geographic pointPoint
POINT3D3D pointPoint3D

Collection Types

TypeDescriptionPython Type
LISTOrdered listlist
SETUnordered unique setset
MAPKey-value mapdict
VECTORNumeric vectorVector

Graph Types

TypeDescriptionPython Type
NODEGraph nodeGqldbNode
EDGEGraph edgeGqldbEdge
PATHGraph pathGqldbPath

PropertyType Enum

Python
from 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

GraphType Enum

Python
from gqldb.types import GraphType

class GraphType(IntEnum):
    OPEN = 0      # Schema-less graph
    CLOSED = 1    # Schema-enforced graph
    ONTOLOGY = 2  # Ontology-enabled graph

HealthStatus Enum

Python
from gqldb.types import HealthStatus

class HealthStatus(IntEnum):
    UNKNOWN = 0
    SERVING = 1
    NOT_SERVING = 2
    SERVICE_UNKNOWN = 3

CacheType Enum

Python
from gqldb.types import CacheType

class CacheType(IntEnum):
    ALL = 0
    AST = 1
    PLAN = 2

InsertType Enum

Controls the GQL keyword emitted by insert_nodes(nodes, …) / insert_edges(edges, …):

Python
from 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.

InsertConfig

Per-call configuration for the GQL-path insert convenience methods. Extends QueryConfig:

Python
from 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

Type Classes

Node Types

Python
from 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)

Edge Types

Python
from 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)

Path Type

Python
from gqldb.types import GqldbPath

@dataclass
class GqldbPath:
    nodes: List[GqldbNode]
    edges: List[GqldbEdge]

Geospatial Types

Python
from 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.

Spatial reference system (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:

Python
from 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:

Python
from 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

Temporal Types

The temporal wrapper classes (GqldbLocalDateTime, GqldbZonedDateTime, GqldbDate, GqldbLocalTime, GqldbZonedTime) render through __str__ / str() in a single canonical form:

  • Date-time: YYYY-MM-DD HH:mm:ss[.fff] — a space separates date and time.
  • Fractional seconds are trailing-zero-trimmed, and omitted entirely when the sub-second component is zero.
  • Zoned values append the UTC offset as ±HH:MM.
  • Date-only is 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.

Python
from 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'

Duration Types

Python
from gqldb.types import YearToMonth, DayToSecond

@dataclass
class YearToMonth:
    months: int

@dataclass
class DayToSecond:
    seconds: int
    nanoseconds: int

Vector Type

Python
from 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.

TypedValue

The driver uses TypedValue internally for type-safe data transfer:

Python
from 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()}")

Parsing values from strings

TypedValue provides a symmetric pair of static/instance helpers for text round-tripping:

Python
from 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 typeAccepted string forms
POINTCanonical 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].
POINT3DCanonical 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.
BLOBBase64 (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.

Python
from 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

Type Wrapper Classes

For explicit type specification:

Python
from 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)
    }
)

Type Conversion Examples

Working with Dates

Python
from 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}")

Working with Points

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}")

Working with Collections

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}")

Complete Example

Python
from 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()