kuzualchemy


Namekuzualchemy JSON
Version 0.2.0 PyPI version JSON
download
home_pageNone
SummarySQLAlchemy-like ORM for Kuzu graph database
upload_time2025-09-04 18:35:23
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseGPL-3.0
keywords kuzu graph database orm sqlalchemy cypher graph-database
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # KuzuAlchemy

A SQLAlchemy-like ORM for Kuzu graph database

<!-- KUZUALCHEMY-AUTO-UPDATE-START -->
# Version: 0.2.0
**Status**: Alpha
**Tests**: ⏳ Running tests... (Last updated: 2025-09-04 18:35:11 UTC)

[![Tests](https://github.com/FanaticPythoner/kuzualchemy/actions/workflows/test.yml/badge.svg)](https://github.com/FanaticPythoner/kuzualchemy/actions/workflows/test.yml)
[![PyPI version](https://badge.fury.io/py/kuzualchemy.svg)](https://badge.fury.io/py/kuzualchemy)
[![Python versions](https://img.shields.io/pypi/pyversions/kuzualchemy.svg)](https://pypi.org/project/kuzualchemy/)

KuzuAlchemy is an Object-Relational Mapping (ORM) library for the [Kuzu graph database](https://kuzudb.com/). It provides a SQLAlchemy-like interface for working with graph data.

> **Note**: This software is currently in alpha development. APIs may change.
<!-- KUZUALCHEMY-AUTO-UPDATE-END -->

## Table of Contents

1. [Overview](#overview)
2. [Installation](#installation)
3. [Quick Start](#quick-start)
4. [Function Reference](#function-reference)
5. [Operator Reference](#operator-reference)
6. [Model Definition](#model-definition)
7. [Field Types & Metadata](#field-types--metadata)
8. [Relationships](#relationships)
9. [Query System](#query-system)
10. [Session Management](#session-management)
11. [Advanced Features](#advanced-features)
12. [API Reference](#api-reference)
13. [Contributing](#contributing)
14. [License](#license)

## Overview

KuzuAlchemy provides the following components:

- **Core ORM** (`kuzu_orm.py`): Base classes for nodes and relationships with metadata handling
- **Session Management** (`kuzu_session.py`): Database operations with transaction support
- **Query System** (`kuzu_query.py`): Query builder with Cypher generation
- **Expression Engine** (`kuzu_query_expressions.py`): Expression system supporting Kuzu operators
- **Function Library** (`kuzu_functions.py`): Kuzu functions implemented as standalone callables
- **Field Integration** (`kuzu_query_fields.py`): QueryField methods providing fluent API access to functions

### Key Features

- **Kuzu Function Support**: Kuzu functions and operators implemented
- **ORM**: Model definition, session management, and querying capabilities
- **Type-Safe Operations**: Type safety with parameter handling and validation
- **Testing**: Test coverage for functionality
- **Error Handling**: Error handling and transaction management

## Installation

### Prerequisites

```bash
pip install kuzu pydantic
```

### Install KuzuAlchemy

```bash
pip install kuzualchemy
```

### Development Installation

```bash
git clone <repository-url>
cd kuzualchemy
pip install -e ".[dev,test]"
```

## Quick Start

### Basic Setup

```python
from kuzualchemy import (
    KuzuBaseModel, KuzuRelationshipBase,
    kuzu_node, kuzu_relationship, kuzu_field,
    KuzuDataType, KuzuSession,
    get_all_ddl
)

# Create session
session = KuzuSession(db_path="database.db")

# Initialize schema
ddl = get_all_ddl()
if ddl.strip():
    session.execute(ddl)
```

### Example

```python
import kuzualchemy as ka
from pathlib import Path

# Define your graph models
@ka.kuzu_node("Person")
class Person(ka.KuzuBaseModel):
    name: str = ka.kuzu_field(kuzu_type=ka.KuzuDataType.STRING, primary_key=True)
    age: int = ka.kuzu_field(kuzu_type=ka.KuzuDataType.INT32)
    email: str = ka.kuzu_field(kuzu_type=ka.KuzuDataType.STRING)

@ka.kuzu_relationship("KNOWS", pairs=[(Person, Person)])
class Knows(ka.KuzuRelationshipBase):
    since: int = ka.kuzu_field(kuzu_type=ka.KuzuDataType.INT32)
    strength: float = ka.kuzu_field(kuzu_type=ka.KuzuDataType.DOUBLE, default=1.0)

# Create database and session
db_path = Path("my_graph.db")
session = ka.KuzuSession(db_path)

# Create schema
session.execute(ka.get_all_ddl())

# Insert data
alice = Person(name="Alice", age=30, email="alice@example.com")
bob = Person(name="Bob", age=25, email="bob@example.com")
knows = Knows(from_node=alice, to_node=bob, since=2020, strength=0.9)

# Or, you could do `session.add_all([alice, bob, knows])`
session.add(alice)
session.add(bob)
session.add(knows)
session.commit()

# Query data
query = ka.Query(Person, session=session)
filtered_query = query.where(query.fields.age > 25)
results = filtered_query.all()

print(f"Found {len(results)} people over 25")
```

---

## Function Reference

KuzuAlchemy implements Kuzu functions across multiple categories. Each function returns a `FunctionExpression` object that can be used in queries and expressions.

### Text Functions

String manipulation and text processing functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `concat(*args)` | Concatenate multiple strings | ✓ | ✓ |
| `ws_concat(separator, *args)` | Concatenate strings with separator | ✓ | — |
| `array_extract(string_or_list, index)` | Extract element at 1-based index from string or list | ✓ | — |
| `array_slice(string_or_list, begin, end)` | Slice string or list (1-based) | ✓ | — |
| `list_element(list_value, index)` | Extract list element at index | ✓ | ✓ |
| `list_extract(list_value, index)` | Extract list element at index (alias) | ✓ | ✓ |
| `contains(string1, string2)` | Substring test | ✓ | ✓ |
| `ends_with(string1, string2)` | Ends-with test (alias of suffix) | ✓ | ✓ |
| `lower(string)` | Lowercase | ✓ | ✓ |
| `lcase(string)` | Lowercase (alias) | ✓ | ✓ |
| `left(string, count)` | Left substring | ✓ | ✓ |
| `levenshtein(s1, s2)` | Edit distance | ✓ | ✓ |
| `lpad(string, count, character)` | Left pad | ✓ | ✓ |
| `ltrim(string)` | Trim left | ✓ | ✓ |
| `prefix(string, search_string)` | Starts-with test | ✓ | — |
| `repeat(string, count)` | Repeat string | ✓ | ✓ |
| `reverse(string)` | Reverse string | ✓ | ✓ |
| `right(string, count)` | Right substring | ✓ | ✓ |
| `rpad(string, count, character)` | Right pad | ✓ | ✓ |
| `rtrim(string)` | Trim right | ✓ | ✓ |
| `starts_with(string1, string2)` | Starts-with test (alias of prefix) | ✓ | ✓ |
| `substring(string, start, length)` | Substring by 1-based start/length | ✓ | ✓ |
| `substr(string, start, length)` | Substring (alias) | ✓ | ✓ |
| `suffix(string, search_string)` | Ends-with test | ✓ | — |
| `trim(string)` | Trim both sides | ✓ | ✓ |
| `upper(string)` | Uppercase | ✓ | ✓ |
| `ucase(string)` | Uppercase (alias) | ✓ | ✓ |
| `initcap(string)` | Capitalize first letter | ✓ | ✓ |
| `string_split(string, separator)` | Split to array | ✓ | ✓ |
| `split_part(string, separator, index)` | Part at 1-based index | ✓ | ✓ |

### Pattern Matching Functions

Regular expression utilities:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `regexp_matches(string, pattern)` | Regex test | ✓ | ✓ |
| `regexp_replace(string, pattern, replacement[, options])` | Regex replace | ✓ | ✓ |
| `regexp_extract(string, pattern[, group])` | Extract first match/group | ✓ | ✓ |
| `regexp_extract_all(string, pattern[, group])` | Extract all matches/groups | ✓ | ✓ |
| `regexp_split_to_array(string, pattern[, options])` | Split by regex | ✓ | ✓ |


### List Functions

Array and list manipulation functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `list_creation(...)` | Create a list containing the argument values | ✓ | — |
| `size(value)` | Return size of string or list | ✓ | ✓ |
| `list_concat(list1, list2)` | Concatenate two lists | ✓ | ✓ |
| `range(start, stop, [step])` | Return list from start to stop with step | ✓ | — |
| `list_cat(list1, list2)` | Alias of list_concat | ✓ | ✓ |
| `array_concat(list1, list2)` | Alias of list_concat | ✓ | ✓ |
| `array_cat(list1, list2)` | Alias of list_concat | ✓ | ✓ |
| `list_append(list, element)` | Append element to list | ✓ | ✓ |
| `array_append(list, element)` | Alias of list_append | ✓ | ✓ |
| `array_push_back(list, element)` | Alias of list_append | ✓ | ✓ |
| `list_prepend(list, element)` | Prepend element to list | ✓ | ✓ |
| `array_prepend(list, element)` | Alias of list_prepend | ✓ | ✓ |
| `array_push_front(list, element)` | Alias of list_prepend | ✓ | ✓ |
| `list_position(list, element)` | Position of element in list | ✓ | ✓ |
| `list_indexof(list, element)` | Alias of list_position | ✓ | ✓ |
| `array_position(list, element)` | Alias of list_position | ✓ | ✓ |
| `array_indexof(list, element)` | Alias of list_position | ✓ | ✓ |
| `list_contains(list, element)` | Check if list contains element | ✓ | ✓ |
| `list_has(list, element)` | Alias of list_contains | ✓ | ✓ |
| `array_contains(list, element)` | Alias of list_contains | ✓ | ✓ |
| `array_has(list, element)` | Alias of list_contains | ✓ | ✓ |
| `list_slice(list, begin, end)` | Extract sub-list | ✓ | ✓ |

### Advanced List Functions

Higher-order and quantifier list functions (order matches kuzu_functions.py):

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `list_reverse(list)` | Reverse list elements | ✓ | ✓ |
| `list_sort(list[, order, nulls])` | Sort elements of list | ✓ | ✓ |
| `list_reverse_sort(list)` | Sort elements of list in DESC | ✓ | ✓ |
| `list_sum(list)` | Sum elements | ✓ | ✓ |
| `list_product(list)` | Multiply elements | ✓ | ✓ |
| `list_distinct(list)` | Remove NULLs and duplicates | ✓ | ✓ |
| `list_unique(list)` | Count unique elements | ✓ | ✓ |
| `list_any_value(list)` | First non-NULL value | ✓ | ✓ |
| `list_to_string(sep, list)` | Join elements with separator | ✓ | ✓ |
| `list_transform(list, lambda)` | Transform elements using lambda expression | ✓ | ✓ |
| `list_filter(list, lambda)` | Filter elements using lambda expression | ✓ | ✓ |
| `list_reduce(list, lambda)` | Reduce list using lambda expression | ✓ | ✓ |
| `list_has_all(list, sub_list)` | Contains all elements from sub-list | ✓ | ✓ |
| `all_func(var, list, predicate)` | All elements satisfy predicate | ✓ | ✓ |
| `any_func(var, list, predicate)` | Any element satisfies predicate | ✓ | ✓ |
| `none_func(var, list, predicate)` | No elements satisfy predicate | ✓ | ✓ |
| `single_func(var, list, predicate)` | Exactly one element satisfies predicate | ✓ | ✓ |

| `array_slice(array, start, end)` | Slice array | `ka.array_slice(field, 1, 5)` |
| `list_reverse(list)` | Reverse list | `ka.list_reverse(field)` |
| `list_sort(list)` | Sort list | `ka.list_sort(field)` |
| `list_reverse_sort(list)` | Reverse sort | `ka.list_reverse_sort(field)` |
| `list_sum(list)` | Sum elements | `ka.list_sum(field)` |
| `list_product(list)` | Product elements | `ka.list_product(field)` |
| `list_distinct(list)` | Distinct elements | `ka.list_distinct(field)` |
| `list_unique(list)` | Unique elements | `ka.list_unique(field)` |
| `list_any_value(list)` | Any element | `ka.list_any_value(field)` |
| `list_to_string(sep, list)` | Join elements | `ka.list_to_string(",", field)` |
| `list_extract(list, index)` | Extract element | `ka.list_extract(field, 1)` |
| `list_element(list, index)` | Get element | `ka.list_element(field, 1)` |
| `range(start, end, [step])` | Generate range | `ka.range(1, 10)` |

### Numeric Functions

Mathematical and numeric computation functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `pi()` | Return value of pi | ✓ | — |
| `abs(value)` | Absolute value | ✓ | ✓ |
| `ceil(value)` | Ceiling | ✓ | ✓ |
| `ceiling(value)` | Ceiling (alias) | ✓ | ✓ |
| `floor(value)` | Floor | ✓ | ✓ |
| `round(value, precision=0)` | Round to precision | ✓ | ✓ |
| `sqrt(value)` | Square root | ✓ | ✓ |
| `pow(base, exponent)` | Power | ✓ | ✓ |
| `sin(value)` | Sine | ✓ | ✓ |
| `cos(value)` | Cosine | ✓ | ✓ |
| `tan(value)` | Tangent | ✓ | ✓ |
| `asin(value)` | Arcsine | ✓ | ✓ |
| `acos(value)` | Arccosine | ✓ | ✓ |
| `atan(value)` | Arctangent | ✓ | ✓ |
| `atan2(x, y)` | Arctangent of x,y | ✓ | ✓ |
| `ln(value)` | Natural log | ✓ | ✓ |
| `log(value)` | Logarithm | ✓ | ✓ |
| `log2(value)` | Base-2 logarithm | ✓ | ✓ |
| `log10(value)` | Base-10 logarithm | ✓ | ✓ |
| `negate(value)` | Negation | ✓ | ✓ |
| `sign(value)` | Sign (-1,0,1) | ✓ | ✓ |
| `even(value)` | Round to next even | ✓ | ✓ |
| `factorial(value)` | Factorial | ✓ | ✓ |
| `gamma(value)` | Gamma function | ✓ | ✓ |
| `lgamma(value)` | Log Gamma | ✓ | ✓ |
| `bitwise_xor(x, y)` | Bitwise XOR | ✓ | ✓ |
| `cot(value)` | Cotangent | ✓ | ✓ |
| `degrees(value)` | Radians to degrees | ✓ | ✓ |
| `radians(value)` | Degrees to radians | ✓ | ✓ |

### Date Functions

Date manipulation and extraction functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `current_date()` | Current date | ✓ | — |
| `current_timestamp()` | Current timestamp | ✓ | — |
| `date_part(part, date)` | Extract date part | ✓ | ✓ |
| `date_trunc(part, date)` | Truncate date | ✓ | ✓ |
| `datepart(part, date)` | Extract date part (alias) | ✓ | ✓ |
| `datetrunc(part, date)` | Truncate date (alias) | ✓ | ✓ |
| `dayname(date)` | Day name | ✓ | ✓ |
| `monthname(date)` | Month name | ✓ | ✓ |
| `last_day(date)` | Last day of month | ✓ | ✓ |
| `greatest(...)` | Greatest of values | ✓ | ✓ |
| `least(...)` | Least of values | ✓ | ✓ |
| `make_date(year, month, day)` | Create date | ✓ | ✓ |

### Timestamp Functions

Timestamp manipulation and extraction functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `century(timestamp)` | Extract century | ✓ | ✓ |
| `epoch_ms(ms)` | Convert milliseconds to timestamp | ✓ | — |
| `to_epoch_ms(timestamp)` | Convert timestamp to milliseconds | ✓ | ✓ |


### Interval Functions

Interval manipulation and conversion functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `to_years(value)` | Convert integer to year interval | ✓ | ✓ |
| `to_months(value)` | Convert integer to month interval | ✓ | ✓ |
| `to_days(value)` | Convert integer to day interval | ✓ | ✓ |
| `to_hours(value)` | Convert integer to hour interval | ✓ | ✓ |
| `to_minutes(value)` | Convert integer to minute interval | ✓ | ✓ |
| `to_seconds(value)` | Convert integer to second interval | ✓ | ✓ |
| `to_milliseconds(value)` | Convert integer to millisecond interval | ✓ | ✓ |
| `to_microseconds(value)` | Convert integer to microsecond interval | ✓ | ✓ |


### Timestamp Functions

Timestamp manipulation and extraction functions (order matches kuzu_functions.py):

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `century(timestamp)` | Extract century | ✓ | ✓ |
| `epoch_ms(ms)` | Convert milliseconds to timestamp | ✓ | — |
| `to_epoch_ms(timestamp)` | Convert timestamp to milliseconds | ✓ | ✓ |



### Interval Functions

Interval manipulation and conversion functions:


### Map Functions

Map manipulation and access functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `map_func(keys, values)` | Create map from keys and values | ✓ | — |
| `map_extract(map, key)` | Extract value for key | ✓ | ✓ |
| `element_at(map, key)` | Extract value (alias) | ✓ | ✓ |
| `cardinality(map)` | Map size | ✓ | ✓ |
| `map_keys(map)` | Get all keys | ✓ | ✓ |
| `map_values(map)` | Get all values | ✓ | ✓ |

### Union Functions

Union type manipulation functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `union_value(tag := value)` | Create union with tag/value | ✓ | — |
| `union_tag(union)` | Get union tag | ✓ | ✓ |
| `union_extract(union, tag)` | Extract value for tag | ✓ | ✓ |

### Node/Relationship Functions

Node and relationship introspection functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `id_func(node_or_rel)` | Internal ID | ✓ | ✓ |
| `label(node_or_rel)` | Label name | ✓ | ✓ |
| `labels(node_or_rel)` | Label name (alias) | ✓ | ✓ |
| `offset(node_or_rel)` | ID offset | ✓ | ✓ |

### Recursive Relationship Functions

Recursive path and traversal functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `nodes(path)` | Get nodes from path | ✓ | ✓ |
| `rels(path)` | Get relationships from path | ✓ | ✓ |
| `properties(path, property)` | Get property from collection | ✓ | ✓ |
| `is_trail(path)` | Path is trail (repeated rels) | ✓ | ✓ |
| `is_acyclic(path)` | Path is acyclic (no repeated nodes) | ✓ | ✓ |
| `length(path)` | Path length (number of rels) | ✓ | ✓ |
| `cost(path)` | Weighted path cost | ✓ | ✓ |

### Array Functions

Array-specific mathematical and similarity functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `array_value(...)` | Construct array | ✓ | — |
| `array_distance(array1, array2)` | Euclidean distance | ✓ | ✓ |
| `array_squared_distance(array1, array2)` | Squared distance | ✓ | ✓ |
| `array_dot_product(array1, array2)` | Dot product | ✓ | ✓ |
| `array_inner_product(array1, array2)` | Inner product | ✓ | ✓ |
| `array_cross_product(array1, array2)` | Cross product | ✓ | ✓ |
| `array_cosine_similarity(array1, array2)` | Cosine similarity | ✓ | ✓ |


### Blob Functions

Binary data manipulation functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `blob(data)` | Create blob | ✓ | ✓ |
| `encode(data)` | Encode string to blob | ✓ | ✓ |
| `decode(blob)` | Decode blob to string | ✓ | ✓ |
| `octet_length(blob)` | Blob byte length | ✓ | ✓ |

### Struct Functions

Struct manipulation functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `struct_extract(struct, field)` | Extract struct field | ✓ | ✓ |

| `to_int32(value)` | Cast to int32 | `ka.to_int32(field)` |
| `to_int16(value)` | Cast to int16 | `ka.to_int16(field)` |
| `to_float(value)` | Cast to float | `ka.to_float(field)` |
| `to_date(value)` | Cast to date | `ka.to_date(field)` |
| `to_timestamp(value)` | Cast to timestamp | `ka.to_timestamp(field)` |
| `cast_as(value, type)` | Cast using AS syntax | `ka.cast_as(field, "INT64")` |
| `case([input])` | CASE expression | `ka.case()` |

### Hash Functions

Cryptographic hash functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `md5(data)` | MD5 hash | ✓ | ✓ |
| `sha256(data)` | SHA256 hash | ✓ | ✓ |
| `hash(data)` | Generic hash | ✓ | ✓ |

### UUID Functions

UUID generation and manipulation functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `gen_random_uuid()` | Generate random UUID | ✓ | — |
| `uuid(string)` | Parse UUID string | ✓ | ✓ |

### Utility Functions

Utility and miscellaneous functions:

| Function | Description | kuzu_functions | QueryField |
|----------|-------------|----------------|------------|
| `coalesce(val1, val2, ...)` | First non-NULL value | ✓ | ✓ |
| `ifnull(value, replacement)` | Replace NULL with value | ✓ | ✓ |
| `nullif(a, b)` | NULL if equal | ✓ | ✓ |
| `typeof(value)` | Get value type | ✓ | ✓ |
| `constant_or_null(constant, check)` | Constant if check non-NULL | ✓ | ✓ |
| `count_if(condition)` | 1 if condition true else 0 | ✓ | ✓ |
| `error(message)` | Raise runtime error | ✓ | ✓ |


### Casting Functions

Type conversion and casting functions:

|----------|-------------|----------------|------------|
| `to_int64(value)` | Cast to INT64 | ✓ | — |
| `to_int32(value)` | Cast to INT32 | ✓ | — |
| `to_int16(value)` | Cast to INT16 | ✓ | — |
| `to_double(value)` | Cast to DOUBLE | ✓ | — |
| `to_float(value)` | Cast to FLOAT | ✓ | — |
| `to_string(value)` | Cast to STRING | ✓ | — |
| `to_date(value)` | Cast to DATE | ✓ | — |
| `to_timestamp(value)` | Cast to TIMESTAMP | ✓ | ✓ |
| `cast(value, type)` | CAST function | ✓ | ✓ |
| `cast_as(value, type)` | CAST AS syntax | ✓ | ✓ |
| `case([input])` | Create CASE expression | ✓ | ✓ |




## Operator Reference

KuzuAlchemy operator support (exactly as implemented):

### Comparison Operators

| Operator/Method | Description | Backing Enum/Method |
|-----------------|-------------|---------------------|
| `==` | Equal to | QueryField.__eq__ -> ComparisonOperator.EQ |
| `!=` | Not equal | QueryField.__ne__ -> ComparisonOperator.NEQ |
| `<` | Less than | QueryField.__lt__ -> ComparisonOperator.LT |
| `<=` | Less than or equal | QueryField.__le__ -> ComparisonOperator.LTE |
| `>` | Greater than | QueryField.__gt__ -> ComparisonOperator.GT |
| `>=` | Greater than or equal | QueryField.__ge__ -> ComparisonOperator.GTE |
| `in_(values)` | Membership | QueryField.in_ -> ComparisonOperator.IN |
| `not_in(values)` | Not in | QueryField.not_in -> ComparisonOperator.NOT_IN |
| `between(a,b, inclusive=True)` | Range test | QueryField.between -> BetweenExpression |

### Pattern/Regex Operators

| Operator/Method | Description | Backing Enum |
|-----------------|-------------|--------------|
| `like(pattern, case_sensitive=True)` | Regex-like match | ComparisonOperator.LIKE |
| `not_like(pattern, case_sensitive=True)` | Negative match | ComparisonOperator.NOT_LIKE |
| `regex_match(pattern)` | `=~` regex match | ComparisonOperator.REGEX_MATCH |
| `not_regex_match(pattern)` | `!~` negative regex | ComparisonOperator.NOT_REGEX_MATCH |

### Contains/Prefix/Suffix Filters

| Method | Description | Backing Enum |
|--------|-------------|--------------|
| `contains_filter(value)` | Contains element/substr | ComparisonOperator.CONTAINS |
| `starts_with_filter(value, case_sensitive=True)` | Prefix match | ComparisonOperator.STARTS_WITH |
| `ends_with_filter(value, case_sensitive=True)` | Suffix match | ComparisonOperator.ENDS_WITH |
| `is_null()` | Field is NULL | ComparisonOperator.IS_NULL |
| `is_not_null()` | Field is NOT NULL | ComparisonOperator.IS_NOT_NULL |

### Logical Operators (on FilterExpression)

| Operator | Description | Backing |
|----------|-------------|---------|
| `&` | Logical AND | FilterExpression.__and__ -> LogicalOperator.AND |
| `|` | Logical OR | FilterExpression.__or__ -> LogicalOperator.OR |
| `^` | Logical XOR | FilterExpression.__xor__ -> LogicalOperator.XOR |
| `~` | Logical NOT | FilterExpression.__invert__ -> NotFilterExpression |

### Arithmetic Operators (on QueryField)

| Operator | Description | Backing |
|----------|-------------|---------|
| `+` | Addition / list concatenation | QueryField.__add__/__radd__ -> ArithmeticOperator.ADD |
| `-` | Subtraction | QueryField.__sub__/__rsub__ -> ArithmeticOperator.SUB |
| `*` | Multiplication | QueryField.__mul__/__rmul__ -> ArithmeticOperator.MUL |
| `/` | Division | QueryField.__truediv__/__rtruediv__ -> ArithmeticOperator.DIV |
| `%` | Modulo | QueryField.__mod__/__rmod__ -> ArithmeticOperator.MOD |
| `^` | Power | QueryField.__pow__/__rpow__ -> ArithmeticOperator.POW |

### Indexing/Slicing (on QueryField)

| Operator | Description | Backing Function |
|----------|-------------|------------------|
| `field[idx]` | 1-based index extract | FunctionExpression("array_extract") |
| `field[a:b]` | 1-based slice | FunctionExpression("array_slice") |

---

## Model Definition

### Node Models

```python
from kuzualchemy import kuzu_node, KuzuBaseModel, kuzu_field, KuzuDataType
from typing import Optional, List
from datetime import datetime

@kuzu_node("User")  # Table name in Kuzu
class User(KuzuBaseModel):
    # Primary key
    id: int = kuzu_field(kuzu_type=KuzuDataType.INT64, primary_key=True)

    # Basic fields
    name: str = kuzu_field(kuzu_type=KuzuDataType.STRING, not_null=True)
    email: Optional[str] = kuzu_field(kuzu_type=KuzuDataType.STRING, unique=True, default=None)
    age: int = kuzu_field(kuzu_type=KuzuDataType.INT32, default=0)

    # Boolean fields
    is_active: bool = kuzu_field(kuzu_type=KuzuDataType.BOOL, default=True)

    # Timestamp fields
    created_at: datetime = kuzu_field(
        kuzu_type=KuzuDataType.TIMESTAMP,
        default=KuzuDefaultFunction.CURRENT_TIMESTAMP
    )

    # Array fields
    tags: Optional[List[str]] = kuzu_field(
        kuzu_type=ArrayTypeSpecification(element_type=KuzuDataType.STRING),
        default=None
    )
```

### Relationship Models

```python
from kuzualchemy import kuzu_relationship, KuzuRelationshipBase

@kuzu_relationship("KNOWS", pairs=[(User, User)])
class Knows(KuzuRelationshipBase):
    since: datetime = kuzu_field(kuzu_type=KuzuDataType.TIMESTAMP)
    strength: float = kuzu_field(kuzu_type=KuzuDataType.DOUBLE, default=1.0)
```

### Model Methods

Every model inherits these methods from `KuzuBaseModel`:

```python
class User(KuzuBaseModel):
    # Built-in methods available:

    def save(self, session: KuzuSession) -> None:
        """Save instance to database"""
        pass

    def delete(self, session: KuzuSession) -> None:
        """Delete instance from database"""
        pass

    @classmethod
    def query(cls, session: KuzuSession = None) -> Query:
        """Create query for this model"""
        pass

    @classmethod
    def get_primary_key_fields(cls) -> List[str]:
        """Get primary key field names"""
        pass

    @classmethod
    def get_foreign_key_fields(cls) -> Dict[str, ForeignKeyMetadata]:
        """Get foreign key fields"""
        pass
```

---

## Field Types & Metadata

### Supported Kuzu Data Types

```python
from kuzualchemy import KuzuDataType

# Numeric types
KuzuDataType.INT8, KuzuDataType.INT16, KuzuDataType.INT32, KuzuDataType.INT64
KuzuDataType.UINT8, KuzuDataType.UINT16, KuzuDataType.UINT32, KuzuDataType.UINT64
KuzuDataType.FLOAT, KuzuDataType.DOUBLE
KuzuDataType.DECIMAL, KuzuDataType.SERIAL

# String types
KuzuDataType.STRING, KuzuDataType.BLOB

# Boolean type
KuzuDataType.BOOL

# Date/time types
KuzuDataType.DATE, KuzuDataType.TIMESTAMP, KuzuDataType.INTERVAL

# UUID type
KuzuDataType.UUID

# Complex types
KuzuDataType.STRUCT, KuzuDataType.MAP, KuzuDataType.UNION
```

### Field Definition

```python
# Field definition
field = kuzu_field(
    # Basic properties
    kuzu_type=KuzuDataType.STRING,
    primary_key=False,
    unique=False,
    not_null=False,
    index=False,

    # Default values
    default="default_value",
    default_factory=lambda: "computed_default",

    # Constraints
    check_constraint="LENGTH(field_name) > 0",

    # Foreign keys
    foreign_key=ForeignKeyMetadata(
        target_model=TargetModel,
        target_field="id",
        on_delete=CascadeAction.CASCADE,
        on_update=CascadeAction.SET_NULL
    ),

    # Metadata
    alias="field_alias",
    title="Field Title",
    description="Field description"
)
```

### Array Fields

```python
from kuzualchemy.kuzu_orm import ArrayTypeSpecification

class User(KuzuBaseModel):
    # Array field definition
    tags: List[str] = kuzu_field(
        kuzu_type=ArrayTypeSpecification(element_type=KuzuDataType.STRING),
        default=None
    )
```

### Default Values

```python
from kuzualchemy.constants import KuzuDefaultFunction

class User(KuzuBaseModel):
    # Static defaults
    status: str = kuzu_field(kuzu_type=KuzuDataType.STRING, default="active")

    # Function defaults
    created_at: datetime = kuzu_field(
        kuzu_type=KuzuDataType.TIMESTAMP,
        default=KuzuDefaultFunction.CURRENT_TIMESTAMP
    )

    # Factory defaults
    uuid_field: str = kuzu_field(
        kuzu_type=KuzuDataType.UUID,
        default_factory=lambda: str(uuid.uuid4())
    )
```

---

## Relationships

### Basic Relationships

```python
from kuzualchemy import kuzu_relationship, KuzuRelationshipBase

@kuzu_relationship("FOLLOWS", pairs=[(User, User)])
class Follows(KuzuRelationshipBase):
    since: datetime = kuzu_field(kuzu_type=KuzuDataType.TIMESTAMP)
    weight: float = kuzu_field(kuzu_type=KuzuDataType.DOUBLE, default=1.0)
```

### Multi-Pair Relationships

```python
# Multiple relationship pairs
@kuzu_relationship("AUTHORED", pairs=[
    (User, {Post, Comment}),
    (Organization, Post)
])
class Authored(KuzuRelationshipBase):
    created_at: datetime = kuzu_field(kuzu_type=KuzuDataType.TIMESTAMP)
    role: str = kuzu_field(kuzu_type=KuzuDataType.STRING, default="author")
```

### Relationship Usage

```python
# Create relationships
user1 = User(id=1, name="Alice")
user2 = User(id=2, name="Bob")
follows = Follows(from_node=user1, to_node=user2, since=datetime.now())

session.add_all([user1, user2, follows])
session.commit()
```

---

## Query System

### Basic Queries

```python
from kuzualchemy import Query

# Create query
query = Query(User, session=session)

# Simple filtering
filtered = query.where(query.fields.age > 25)
results = filtered.all()

# Method chaining
results = (Query(User, session=session)
    .where(Query(User, session=session).fields.name.starts_with("A"))
    .where(Query(User, session=session).fields.age.between(20, 40))
    .order_by(Query(User, session=session).fields.name.asc())
    .limit(10)
    .all())
```

### Advanced Queries

```python
# Aggregation with HAVING: count users by age > 1
q = Query(User, session=session)
agg = q.count()  # COUNT(*) AS count
count_by_age = (
    q.group_by(q.fields.age)
     .having(ka.to_int64("count") > 1)  # compare aggregated alias post-WITH using cast
)

# Relationship join (pattern: join(TargetModel, RelationshipClass, ...))
q = Query(User, session=session)
joined = q.join(User, Follows, target_alias="u2")

# Subquery: authors older than 30
subq = Query(User, session=session).where(Query(User, session=session).fields.age > 30)
main_query = Query(Post, session=session).where(
    Query(Post, session=session).fields.author_id.in_(subq.select("id"))
)
```

### Function Usage in Queries

```python
import kuzualchemy as ka

# Text functions
query = Query(User, session=session)
text_query = query.where(
    ka.upper(query.fields.name).starts_with("A")
)

# Numeric functions
numeric_query = query.where(
    ka.abs(query.fields.age - 30) < 5
)

# List functions
list_query = query.where(
    ka.list_contains(query.fields.hobbies, "reading")
)

# Date functions
date_query = query.where(
    ka.date_part("year", query.fields.birth_date) > 1990
)
```

### Query Results

```python
# Get all results
results = query.all()  # List[ModelType]

# Get first result
first = query.first()  # ModelType | None

# Get exactly one result
one = query.one()  # ModelType (raises if 0 or >1)

# Get one or none
one_or_none = query.one_or_none()  # ModelType | None

# Check existence
exists = query.exists()  # bool

# Count results
count_query = query.count()         # Query with COUNT(*) AS count aggregation
count = count_query._execute()[0]["count"] if count_query._execute() else 0
```

---

## Session Management

### Basic Session Usage

```python
from kuzualchemy import KuzuSession
from pathlib import Path

# Create session
session = KuzuSession(db_path=Path("my_database.db"))

# Execute DDL
ddl = get_all_ddl()
if ddl.strip():
    session.execute(ddl)

# Add and commit
user = User(id=1, name="Alice", email="alice@example.com")
session.add(user)
session.commit()

# Close session
session.close()
```

### Transaction Management

```python
# Manual transactions using KuzuTransaction
from kuzualchemy import KuzuTransaction

with KuzuTransaction(session):
    user = User(id=1, name="Alice")
    session.add(user)
    # Automatic commit on success, rollback on exception

# Or using session.begin() context manager
with session.begin():
    user = User(id=1, name="Alice")
    session.add(user)
    # Automatic commit on success, rollback on exception
```

### Session Factory

```python
from kuzualchemy import SessionFactory

# Create factory
factory = SessionFactory(
    db_path="database.db",
    autoflush=True,
    autocommit=False
)

# Create sessions
session1 = factory.create_session()
session2 = factory.create_session(autocommit=True)  # Override defaults

# Session scope context manager
with factory.session_scope() as session:
    user = User(id=1, name="Alice")
    session.add(user)
    # Automatic commit/rollback
```

### Connection Management

```python
from kuzualchemy import KuzuConnection

# Direct connection usage
connection = KuzuConnection(db_path="database.db")
session = KuzuSession(connection=connection)

# Connection sharing
session1 = KuzuSession(connection=connection)
session2 = KuzuSession(connection=connection)
```

---

## Advanced Features

### Registry Management

```python
from kuzualchemy import (
    get_registered_nodes,
    get_registered_relationships,
    get_all_models,
    clear_registry,
    validate_all_models
)

# Access registered models
nodes = get_registered_nodes()
relationships = get_registered_relationships()
all_models = get_all_models()

# Validate all models
validation_errors = validate_all_models()

# Clear registry (useful for testing)
clear_registry()
```

### Enhanced Base Model with Enum Conversion

```python
from kuzualchemy import BaseModel
from enum import Enum

class Status(Enum):
    ACTIVE = "active"
    INACTIVE = "inactive"

@kuzu_node("Account")
class Account(BaseModel):  # Automatic enum conversion
    status: Status = kuzu_field(kuzu_type=KuzuDataType.STRING)

    # BaseModel automatically converts enums to/from string values
```

### Foreign Key Support

```python
from kuzualchemy import ForeignKeyMetadata, CascadeAction

@kuzu_node("Post")
class Post(KuzuBaseModel):
    id: int = kuzu_field(kuzu_type=KuzuDataType.INT64, primary_key=True)
    title: str = kuzu_field(kuzu_type=KuzuDataType.STRING)
    author_id: int = kuzu_field(
        kuzu_type=KuzuDataType.INT64,
        foreign_key=ForeignKeyMetadata(
            target_model=User,
            target_field="id",
            on_delete=CascadeAction.CASCADE
        )
    )
```

### Custom Functions

```python
# All Kuzu functions are available as standalone callables
import kuzualchemy as ka

# Use in queries
query = Query(User, session=session).where(
    ka.concat(query.fields.first_name, " ", query.fields.last_name).contains("Alice")
)

# Use in expressions
full_name = ka.concat(user.first_name, " ", user.last_name)
```

### Complex Expressions

```python
# Combine multiple functions and operators
complex_filter = (
    ka.upper(query.fields.name).starts_with("A") &
    (query.fields.age.between(20, 40)) &
    ka.list_contains(query.fields.tags, "python")
)

results = Query(User, session=session).where(complex_filter).all()
```

---

## API Reference

### Core Classes

#### KuzuBaseModel
Base class for all node models with built-in ORM functionality.

**Methods:**
- `save(session: KuzuSession) -> None`: Save instance to database
- `delete(session: KuzuSession) -> None`: Delete instance from database
- `query(session: KuzuSession = None) -> Query`: Create query for this model
- `get_kuzu_metadata(field_name: str) -> KuzuFieldMetadata`: Get field metadata
- `get_all_kuzu_metadata() -> Dict[str, KuzuFieldMetadata]`: Get all field metadata
- `get_primary_key_fields() -> List[str]`: Get primary key field names
- `get_foreign_key_fields() -> Dict[str, ForeignKeyMetadata]`: Get foreign key fields

#### KuzuRelationshipBase
Base class for relationship models.

**Methods:**
- Same as KuzuBaseModel plus relationship-specific functionality
- `create_between(from_node, to_node, **properties) -> KuzuRelationshipBase`: Factory to instantiate relationship between nodes
- `from_node_pk`/`to_node_pk` properties for node primary keys

#### KuzuSession
Main session class for database operations.

**Methods:**
- `execute(query: str, parameters: Dict = None) -> List[Dict]`: Execute raw query
- `add(instance: Any) -> None`: Add instance to session
- `add_all(instances: List[Any]) -> None`: Add multiple instances
- `delete(instance: Any) -> None`: Mark instance for deletion
- `commit() -> None`: Commit current transaction
- `rollback() -> None`: Rollback current transaction
- `flush() -> None`: Flush pending changes
- `close() -> None`: Close session
- `begin() -> KuzuTransaction`: Begin transaction context

#### Query[ModelType]
Type-safe query builder.

**Methods:**
- `where(expression: FilterExpression) -> Query`: Add WHERE clause
- `filter(*expressions: FilterExpression) -> Query`: Add multiple filters
- `order_by(*fields: QueryField) -> Query`: Add ORDER BY clause
- `group_by(*fields: QueryField) -> Query`: Add GROUP BY clause
- `having(expression: FilterExpression) -> Query`: Add HAVING clause
- `limit(count: int) -> Query`: Add LIMIT clause
- `offset(count: int) -> Query`: Add OFFSET clause
- `distinct() -> Query`: Add DISTINCT clause
- `all() -> List[ModelType]`: Execute and return all results
- `first() -> ModelType | None`: Execute and return first result
- `one() -> ModelType`: Execute and return exactly one result
- `one_or_none() -> ModelType | None`: Execute and return one or none
- `count() -> int`: Count results
- `exists() -> bool`: Check if results exist

### Field Definition

#### kuzu_field Function
Field definition with options:

```python
kuzu_field(
    default: Any = ...,                                    # Default value
    kuzu_type: Union[KuzuDataType, str, ArrayTypeSpecification], # Kuzu data type
    primary_key: bool = False,                            # Primary key flag
    foreign_key: ForeignKeyMetadata = None,               # Foreign key metadata
    unique: bool = False,                                 # Unique constraint
    not_null: bool = False,                              # NOT NULL constraint
    index: bool = False,                                 # Index flag
    check_constraint: str = None,                        # CHECK constraint
    default_factory: Callable[[], Any] = None,          # Default factory function
    alias: str = None,                                   # Field alias
    title: str = None,                                   # Field title
    description: str = None,                             # Field description
)
```

### Decorators

#### @kuzu_node()
Mark class as Kuzu node:

```python
@kuzu_node(
    name: str = None,                                    # Node name (defaults to class name)
    abstract: bool = False,                              # Abstract node flag
    compound_indexes: List[CompoundIndex] = None,        # Compound indexes
    table_constraints: List[str] = None,                 # Table constraints
    properties: Dict[str, Any] = None                    # Additional properties
)
```

#### @kuzu_relationship()
Mark class as Kuzu relationship:

```python
@kuzu_relationship(
    name: str = None,                                    # Relationship name
    pairs: List[Tuple[Type, Type]] = None,              # Valid node pairs
    multiplicity: RelationshipMultiplicity = MANY_TO_MANY, # Relationship multiplicity
    compound_indexes: List[CompoundIndex] = None,        # Compound indexes
    table_constraints: List[str] = None,                 # Table constraints
    properties: Dict[str, Any] = None                    # Additional properties
)
```

### Enums and Constants

#### KuzuDataType
All supported Kuzu data types:
- Numeric: `INT8`, `INT16`, `INT32`, `INT64`, `UINT8`, `UINT16`, `UINT32`, `UINT64`, `FLOAT`, `DOUBLE`, `DECIMAL`, `SERIAL`
- String: `STRING`, `BLOB`
- Boolean: `BOOL`
- Temporal: `DATE`, `TIMESTAMP`, `INTERVAL`
- Other: `UUID`, `STRUCT`, `MAP`, `UNION`

#### ComparisonOperator
Query comparison operators (from kuzu_query_expressions):
- `EQ`, `NEQ`: Equality/inequality
- `LT`, `LTE`, `GT`, `GTE`: Comparison operators
- `IN`, `NOT_IN`: List membership
- `LIKE`, `NOT_LIKE`: Pattern matching
- `IS_NULL`, `IS_NOT_NULL`: Null checks
- `CONTAINS`: String/array contains
- `STARTS_WITH`, `ENDS_WITH`: String prefix/suffix
- `EXISTS`, `NOT_EXISTS`: Existence checks

#### LogicalOperator
Logical operators for combining conditions:
- `AND`, `OR`, `NOT`, `XOR`: Boolean logic

#### AggregateFunction
Aggregate functions:
- `COUNT`, `COUNT_DISTINCT`: Counting
- `SUM`, `AVG`: Numeric aggregation
- `MIN`, `MAX`: Extrema
- `COLLECT`, `COLLECT_LIST`, `COLLECT_SET`: Collection aggregation

#### OrderDirection
Ordering directions:
- `ASC`: Ascending order
- `DESC`: Descending order

#### JoinType
Join types:
- `INNER`: Inner join
- `OPTIONAL`: Optional match (left outer join)

### Utility Functions

#### DDL Generation
- `get_all_ddl() -> str`: Generate DDL for all registered models
- `get_ddl_for_node(node_cls: Type[Any]) -> str`: Generate DDL for specific node
- `get_ddl_for_relationship(rel_cls: Type[Any]) -> str`: Generate DDL for specific relationship

#### Registry Management
- `get_registered_nodes() -> Dict[str, Type[Any]]`: Get all registered nodes
- `get_registered_relationships() -> Dict[str, Type[Any]]`: Get all registered relationships
- `get_all_models() -> Dict[str, Type[Any]]`: Get all registered models
- `clear_registry() -> None`: Clear model registry
- `validate_all_models() -> List[str]`: Validate all registered models

#### Test Utilities
- `initialize_schema(session: KuzuSession, ddl: str = None) -> None`: Initialize database schema

---

---

## Contributing

We welcome contributions to KuzuAlchemy! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

### Development Setup

```bash
# Clone repository
git clone <repository-url>
cd kuzualchemy

# Install in development mode
pip install -e ".[dev,test]"

# Run tests
pytest

# Run type checking
mypy src/

# Run linting
flake8 src/
black src/

# Build package
python -m build
```

### Testing

```bash
# Run all tests
pytest

# Run specific test categories
pytest tests/test_functions.py
pytest tests/test_integration.py

# Run with coverage
pytest --cov=kuzualchemy --cov-report=html
```

---

## License

This project is licensed under the GPL-3.0 license - see the [LICENSE](LICENSE) file for details.

---

## Conclusion

KuzuAlchemy is an Object-Relational Mapping library for the Kuzu graph database. It provides a SQLAlchemy-like interface for working with graph data.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "kuzualchemy",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "kuzu, graph, database, orm, sqlalchemy, cypher, graph-database",
    "author": null,
    "author_email": "FanaticPythoner <info@kuzualchemy.com>",
    "download_url": "https://files.pythonhosted.org/packages/1d/db/e93e2f5c8185dde067626d26c0946081f5989141069e7346055284fa8e2e/kuzualchemy-0.2.0.tar.gz",
    "platform": null,
    "description": "# KuzuAlchemy\n\nA SQLAlchemy-like ORM for Kuzu graph database\n\n<!-- KUZUALCHEMY-AUTO-UPDATE-START -->\n# Version: 0.2.0\n**Status**: Alpha\n**Tests**: \u23f3 Running tests... (Last updated: 2025-09-04 18:35:11 UTC)\n\n[![Tests](https://github.com/FanaticPythoner/kuzualchemy/actions/workflows/test.yml/badge.svg)](https://github.com/FanaticPythoner/kuzualchemy/actions/workflows/test.yml)\n[![PyPI version](https://badge.fury.io/py/kuzualchemy.svg)](https://badge.fury.io/py/kuzualchemy)\n[![Python versions](https://img.shields.io/pypi/pyversions/kuzualchemy.svg)](https://pypi.org/project/kuzualchemy/)\n\nKuzuAlchemy is an Object-Relational Mapping (ORM) library for the [Kuzu graph database](https://kuzudb.com/). It provides a SQLAlchemy-like interface for working with graph data.\n\n> **Note**: This software is currently in alpha development. APIs may change.\n<!-- KUZUALCHEMY-AUTO-UPDATE-END -->\n\n## Table of Contents\n\n1. [Overview](#overview)\n2. [Installation](#installation)\n3. [Quick Start](#quick-start)\n4. [Function Reference](#function-reference)\n5. [Operator Reference](#operator-reference)\n6. [Model Definition](#model-definition)\n7. [Field Types & Metadata](#field-types--metadata)\n8. [Relationships](#relationships)\n9. [Query System](#query-system)\n10. [Session Management](#session-management)\n11. [Advanced Features](#advanced-features)\n12. [API Reference](#api-reference)\n13. [Contributing](#contributing)\n14. [License](#license)\n\n## Overview\n\nKuzuAlchemy provides the following components:\n\n- **Core ORM** (`kuzu_orm.py`): Base classes for nodes and relationships with metadata handling\n- **Session Management** (`kuzu_session.py`): Database operations with transaction support\n- **Query System** (`kuzu_query.py`): Query builder with Cypher generation\n- **Expression Engine** (`kuzu_query_expressions.py`): Expression system supporting Kuzu operators\n- **Function Library** (`kuzu_functions.py`): Kuzu functions implemented as standalone callables\n- **Field Integration** (`kuzu_query_fields.py`): QueryField methods providing fluent API access to functions\n\n### Key Features\n\n- **Kuzu Function Support**: Kuzu functions and operators implemented\n- **ORM**: Model definition, session management, and querying capabilities\n- **Type-Safe Operations**: Type safety with parameter handling and validation\n- **Testing**: Test coverage for functionality\n- **Error Handling**: Error handling and transaction management\n\n## Installation\n\n### Prerequisites\n\n```bash\npip install kuzu pydantic\n```\n\n### Install KuzuAlchemy\n\n```bash\npip install kuzualchemy\n```\n\n### Development Installation\n\n```bash\ngit clone <repository-url>\ncd kuzualchemy\npip install -e \".[dev,test]\"\n```\n\n## Quick Start\n\n### Basic Setup\n\n```python\nfrom kuzualchemy import (\n    KuzuBaseModel, KuzuRelationshipBase,\n    kuzu_node, kuzu_relationship, kuzu_field,\n    KuzuDataType, KuzuSession,\n    get_all_ddl\n)\n\n# Create session\nsession = KuzuSession(db_path=\"database.db\")\n\n# Initialize schema\nddl = get_all_ddl()\nif ddl.strip():\n    session.execute(ddl)\n```\n\n### Example\n\n```python\nimport kuzualchemy as ka\nfrom pathlib import Path\n\n# Define your graph models\n@ka.kuzu_node(\"Person\")\nclass Person(ka.KuzuBaseModel):\n    name: str = ka.kuzu_field(kuzu_type=ka.KuzuDataType.STRING, primary_key=True)\n    age: int = ka.kuzu_field(kuzu_type=ka.KuzuDataType.INT32)\n    email: str = ka.kuzu_field(kuzu_type=ka.KuzuDataType.STRING)\n\n@ka.kuzu_relationship(\"KNOWS\", pairs=[(Person, Person)])\nclass Knows(ka.KuzuRelationshipBase):\n    since: int = ka.kuzu_field(kuzu_type=ka.KuzuDataType.INT32)\n    strength: float = ka.kuzu_field(kuzu_type=ka.KuzuDataType.DOUBLE, default=1.0)\n\n# Create database and session\ndb_path = Path(\"my_graph.db\")\nsession = ka.KuzuSession(db_path)\n\n# Create schema\nsession.execute(ka.get_all_ddl())\n\n# Insert data\nalice = Person(name=\"Alice\", age=30, email=\"alice@example.com\")\nbob = Person(name=\"Bob\", age=25, email=\"bob@example.com\")\nknows = Knows(from_node=alice, to_node=bob, since=2020, strength=0.9)\n\n# Or, you could do `session.add_all([alice, bob, knows])`\nsession.add(alice)\nsession.add(bob)\nsession.add(knows)\nsession.commit()\n\n# Query data\nquery = ka.Query(Person, session=session)\nfiltered_query = query.where(query.fields.age > 25)\nresults = filtered_query.all()\n\nprint(f\"Found {len(results)} people over 25\")\n```\n\n---\n\n## Function Reference\n\nKuzuAlchemy implements Kuzu functions across multiple categories. Each function returns a `FunctionExpression` object that can be used in queries and expressions.\n\n### Text Functions\n\nString manipulation and text processing functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `concat(*args)` | Concatenate multiple strings | \u2713 | \u2713 |\n| `ws_concat(separator, *args)` | Concatenate strings with separator | \u2713 | \u2014 |\n| `array_extract(string_or_list, index)` | Extract element at 1-based index from string or list | \u2713 | \u2014 |\n| `array_slice(string_or_list, begin, end)` | Slice string or list (1-based) | \u2713 | \u2014 |\n| `list_element(list_value, index)` | Extract list element at index | \u2713 | \u2713 |\n| `list_extract(list_value, index)` | Extract list element at index (alias) | \u2713 | \u2713 |\n| `contains(string1, string2)` | Substring test | \u2713 | \u2713 |\n| `ends_with(string1, string2)` | Ends-with test (alias of suffix) | \u2713 | \u2713 |\n| `lower(string)` | Lowercase | \u2713 | \u2713 |\n| `lcase(string)` | Lowercase (alias) | \u2713 | \u2713 |\n| `left(string, count)` | Left substring | \u2713 | \u2713 |\n| `levenshtein(s1, s2)` | Edit distance | \u2713 | \u2713 |\n| `lpad(string, count, character)` | Left pad | \u2713 | \u2713 |\n| `ltrim(string)` | Trim left | \u2713 | \u2713 |\n| `prefix(string, search_string)` | Starts-with test | \u2713 | \u2014 |\n| `repeat(string, count)` | Repeat string | \u2713 | \u2713 |\n| `reverse(string)` | Reverse string | \u2713 | \u2713 |\n| `right(string, count)` | Right substring | \u2713 | \u2713 |\n| `rpad(string, count, character)` | Right pad | \u2713 | \u2713 |\n| `rtrim(string)` | Trim right | \u2713 | \u2713 |\n| `starts_with(string1, string2)` | Starts-with test (alias of prefix) | \u2713 | \u2713 |\n| `substring(string, start, length)` | Substring by 1-based start/length | \u2713 | \u2713 |\n| `substr(string, start, length)` | Substring (alias) | \u2713 | \u2713 |\n| `suffix(string, search_string)` | Ends-with test | \u2713 | \u2014 |\n| `trim(string)` | Trim both sides | \u2713 | \u2713 |\n| `upper(string)` | Uppercase | \u2713 | \u2713 |\n| `ucase(string)` | Uppercase (alias) | \u2713 | \u2713 |\n| `initcap(string)` | Capitalize first letter | \u2713 | \u2713 |\n| `string_split(string, separator)` | Split to array | \u2713 | \u2713 |\n| `split_part(string, separator, index)` | Part at 1-based index | \u2713 | \u2713 |\n\n### Pattern Matching Functions\n\nRegular expression utilities:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `regexp_matches(string, pattern)` | Regex test | \u2713 | \u2713 |\n| `regexp_replace(string, pattern, replacement[, options])` | Regex replace | \u2713 | \u2713 |\n| `regexp_extract(string, pattern[, group])` | Extract first match/group | \u2713 | \u2713 |\n| `regexp_extract_all(string, pattern[, group])` | Extract all matches/groups | \u2713 | \u2713 |\n| `regexp_split_to_array(string, pattern[, options])` | Split by regex | \u2713 | \u2713 |\n\n\n### List Functions\n\nArray and list manipulation functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `list_creation(...)` | Create a list containing the argument values | \u2713 | \u2014 |\n| `size(value)` | Return size of string or list | \u2713 | \u2713 |\n| `list_concat(list1, list2)` | Concatenate two lists | \u2713 | \u2713 |\n| `range(start, stop, [step])` | Return list from start to stop with step | \u2713 | \u2014 |\n| `list_cat(list1, list2)` | Alias of list_concat | \u2713 | \u2713 |\n| `array_concat(list1, list2)` | Alias of list_concat | \u2713 | \u2713 |\n| `array_cat(list1, list2)` | Alias of list_concat | \u2713 | \u2713 |\n| `list_append(list, element)` | Append element to list | \u2713 | \u2713 |\n| `array_append(list, element)` | Alias of list_append | \u2713 | \u2713 |\n| `array_push_back(list, element)` | Alias of list_append | \u2713 | \u2713 |\n| `list_prepend(list, element)` | Prepend element to list | \u2713 | \u2713 |\n| `array_prepend(list, element)` | Alias of list_prepend | \u2713 | \u2713 |\n| `array_push_front(list, element)` | Alias of list_prepend | \u2713 | \u2713 |\n| `list_position(list, element)` | Position of element in list | \u2713 | \u2713 |\n| `list_indexof(list, element)` | Alias of list_position | \u2713 | \u2713 |\n| `array_position(list, element)` | Alias of list_position | \u2713 | \u2713 |\n| `array_indexof(list, element)` | Alias of list_position | \u2713 | \u2713 |\n| `list_contains(list, element)` | Check if list contains element | \u2713 | \u2713 |\n| `list_has(list, element)` | Alias of list_contains | \u2713 | \u2713 |\n| `array_contains(list, element)` | Alias of list_contains | \u2713 | \u2713 |\n| `array_has(list, element)` | Alias of list_contains | \u2713 | \u2713 |\n| `list_slice(list, begin, end)` | Extract sub-list | \u2713 | \u2713 |\n\n### Advanced List Functions\n\nHigher-order and quantifier list functions (order matches kuzu_functions.py):\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `list_reverse(list)` | Reverse list elements | \u2713 | \u2713 |\n| `list_sort(list[, order, nulls])` | Sort elements of list | \u2713 | \u2713 |\n| `list_reverse_sort(list)` | Sort elements of list in DESC | \u2713 | \u2713 |\n| `list_sum(list)` | Sum elements | \u2713 | \u2713 |\n| `list_product(list)` | Multiply elements | \u2713 | \u2713 |\n| `list_distinct(list)` | Remove NULLs and duplicates | \u2713 | \u2713 |\n| `list_unique(list)` | Count unique elements | \u2713 | \u2713 |\n| `list_any_value(list)` | First non-NULL value | \u2713 | \u2713 |\n| `list_to_string(sep, list)` | Join elements with separator | \u2713 | \u2713 |\n| `list_transform(list, lambda)` | Transform elements using lambda expression | \u2713 | \u2713 |\n| `list_filter(list, lambda)` | Filter elements using lambda expression | \u2713 | \u2713 |\n| `list_reduce(list, lambda)` | Reduce list using lambda expression | \u2713 | \u2713 |\n| `list_has_all(list, sub_list)` | Contains all elements from sub-list | \u2713 | \u2713 |\n| `all_func(var, list, predicate)` | All elements satisfy predicate | \u2713 | \u2713 |\n| `any_func(var, list, predicate)` | Any element satisfies predicate | \u2713 | \u2713 |\n| `none_func(var, list, predicate)` | No elements satisfy predicate | \u2713 | \u2713 |\n| `single_func(var, list, predicate)` | Exactly one element satisfies predicate | \u2713 | \u2713 |\n\n| `array_slice(array, start, end)` | Slice array | `ka.array_slice(field, 1, 5)` |\n| `list_reverse(list)` | Reverse list | `ka.list_reverse(field)` |\n| `list_sort(list)` | Sort list | `ka.list_sort(field)` |\n| `list_reverse_sort(list)` | Reverse sort | `ka.list_reverse_sort(field)` |\n| `list_sum(list)` | Sum elements | `ka.list_sum(field)` |\n| `list_product(list)` | Product elements | `ka.list_product(field)` |\n| `list_distinct(list)` | Distinct elements | `ka.list_distinct(field)` |\n| `list_unique(list)` | Unique elements | `ka.list_unique(field)` |\n| `list_any_value(list)` | Any element | `ka.list_any_value(field)` |\n| `list_to_string(sep, list)` | Join elements | `ka.list_to_string(\",\", field)` |\n| `list_extract(list, index)` | Extract element | `ka.list_extract(field, 1)` |\n| `list_element(list, index)` | Get element | `ka.list_element(field, 1)` |\n| `range(start, end, [step])` | Generate range | `ka.range(1, 10)` |\n\n### Numeric Functions\n\nMathematical and numeric computation functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `pi()` | Return value of pi | \u2713 | \u2014 |\n| `abs(value)` | Absolute value | \u2713 | \u2713 |\n| `ceil(value)` | Ceiling | \u2713 | \u2713 |\n| `ceiling(value)` | Ceiling (alias) | \u2713 | \u2713 |\n| `floor(value)` | Floor | \u2713 | \u2713 |\n| `round(value, precision=0)` | Round to precision | \u2713 | \u2713 |\n| `sqrt(value)` | Square root | \u2713 | \u2713 |\n| `pow(base, exponent)` | Power | \u2713 | \u2713 |\n| `sin(value)` | Sine | \u2713 | \u2713 |\n| `cos(value)` | Cosine | \u2713 | \u2713 |\n| `tan(value)` | Tangent | \u2713 | \u2713 |\n| `asin(value)` | Arcsine | \u2713 | \u2713 |\n| `acos(value)` | Arccosine | \u2713 | \u2713 |\n| `atan(value)` | Arctangent | \u2713 | \u2713 |\n| `atan2(x, y)` | Arctangent of x,y | \u2713 | \u2713 |\n| `ln(value)` | Natural log | \u2713 | \u2713 |\n| `log(value)` | Logarithm | \u2713 | \u2713 |\n| `log2(value)` | Base-2 logarithm | \u2713 | \u2713 |\n| `log10(value)` | Base-10 logarithm | \u2713 | \u2713 |\n| `negate(value)` | Negation | \u2713 | \u2713 |\n| `sign(value)` | Sign (-1,0,1) | \u2713 | \u2713 |\n| `even(value)` | Round to next even | \u2713 | \u2713 |\n| `factorial(value)` | Factorial | \u2713 | \u2713 |\n| `gamma(value)` | Gamma function | \u2713 | \u2713 |\n| `lgamma(value)` | Log Gamma | \u2713 | \u2713 |\n| `bitwise_xor(x, y)` | Bitwise XOR | \u2713 | \u2713 |\n| `cot(value)` | Cotangent | \u2713 | \u2713 |\n| `degrees(value)` | Radians to degrees | \u2713 | \u2713 |\n| `radians(value)` | Degrees to radians | \u2713 | \u2713 |\n\n### Date Functions\n\nDate manipulation and extraction functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `current_date()` | Current date | \u2713 | \u2014 |\n| `current_timestamp()` | Current timestamp | \u2713 | \u2014 |\n| `date_part(part, date)` | Extract date part | \u2713 | \u2713 |\n| `date_trunc(part, date)` | Truncate date | \u2713 | \u2713 |\n| `datepart(part, date)` | Extract date part (alias) | \u2713 | \u2713 |\n| `datetrunc(part, date)` | Truncate date (alias) | \u2713 | \u2713 |\n| `dayname(date)` | Day name | \u2713 | \u2713 |\n| `monthname(date)` | Month name | \u2713 | \u2713 |\n| `last_day(date)` | Last day of month | \u2713 | \u2713 |\n| `greatest(...)` | Greatest of values | \u2713 | \u2713 |\n| `least(...)` | Least of values | \u2713 | \u2713 |\n| `make_date(year, month, day)` | Create date | \u2713 | \u2713 |\n\n### Timestamp Functions\n\nTimestamp manipulation and extraction functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `century(timestamp)` | Extract century | \u2713 | \u2713 |\n| `epoch_ms(ms)` | Convert milliseconds to timestamp | \u2713 | \u2014 |\n| `to_epoch_ms(timestamp)` | Convert timestamp to milliseconds | \u2713 | \u2713 |\n\n\n### Interval Functions\n\nInterval manipulation and conversion functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `to_years(value)` | Convert integer to year interval | \u2713 | \u2713 |\n| `to_months(value)` | Convert integer to month interval | \u2713 | \u2713 |\n| `to_days(value)` | Convert integer to day interval | \u2713 | \u2713 |\n| `to_hours(value)` | Convert integer to hour interval | \u2713 | \u2713 |\n| `to_minutes(value)` | Convert integer to minute interval | \u2713 | \u2713 |\n| `to_seconds(value)` | Convert integer to second interval | \u2713 | \u2713 |\n| `to_milliseconds(value)` | Convert integer to millisecond interval | \u2713 | \u2713 |\n| `to_microseconds(value)` | Convert integer to microsecond interval | \u2713 | \u2713 |\n\n\n### Timestamp Functions\n\nTimestamp manipulation and extraction functions (order matches kuzu_functions.py):\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `century(timestamp)` | Extract century | \u2713 | \u2713 |\n| `epoch_ms(ms)` | Convert milliseconds to timestamp | \u2713 | \u2014 |\n| `to_epoch_ms(timestamp)` | Convert timestamp to milliseconds | \u2713 | \u2713 |\n\n\n\n### Interval Functions\n\nInterval manipulation and conversion functions:\n\n\n### Map Functions\n\nMap manipulation and access functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `map_func(keys, values)` | Create map from keys and values | \u2713 | \u2014 |\n| `map_extract(map, key)` | Extract value for key | \u2713 | \u2713 |\n| `element_at(map, key)` | Extract value (alias) | \u2713 | \u2713 |\n| `cardinality(map)` | Map size | \u2713 | \u2713 |\n| `map_keys(map)` | Get all keys | \u2713 | \u2713 |\n| `map_values(map)` | Get all values | \u2713 | \u2713 |\n\n### Union Functions\n\nUnion type manipulation functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `union_value(tag := value)` | Create union with tag/value | \u2713 | \u2014 |\n| `union_tag(union)` | Get union tag | \u2713 | \u2713 |\n| `union_extract(union, tag)` | Extract value for tag | \u2713 | \u2713 |\n\n### Node/Relationship Functions\n\nNode and relationship introspection functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `id_func(node_or_rel)` | Internal ID | \u2713 | \u2713 |\n| `label(node_or_rel)` | Label name | \u2713 | \u2713 |\n| `labels(node_or_rel)` | Label name (alias) | \u2713 | \u2713 |\n| `offset(node_or_rel)` | ID offset | \u2713 | \u2713 |\n\n### Recursive Relationship Functions\n\nRecursive path and traversal functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `nodes(path)` | Get nodes from path | \u2713 | \u2713 |\n| `rels(path)` | Get relationships from path | \u2713 | \u2713 |\n| `properties(path, property)` | Get property from collection | \u2713 | \u2713 |\n| `is_trail(path)` | Path is trail (repeated rels) | \u2713 | \u2713 |\n| `is_acyclic(path)` | Path is acyclic (no repeated nodes) | \u2713 | \u2713 |\n| `length(path)` | Path length (number of rels) | \u2713 | \u2713 |\n| `cost(path)` | Weighted path cost | \u2713 | \u2713 |\n\n### Array Functions\n\nArray-specific mathematical and similarity functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `array_value(...)` | Construct array | \u2713 | \u2014 |\n| `array_distance(array1, array2)` | Euclidean distance | \u2713 | \u2713 |\n| `array_squared_distance(array1, array2)` | Squared distance | \u2713 | \u2713 |\n| `array_dot_product(array1, array2)` | Dot product | \u2713 | \u2713 |\n| `array_inner_product(array1, array2)` | Inner product | \u2713 | \u2713 |\n| `array_cross_product(array1, array2)` | Cross product | \u2713 | \u2713 |\n| `array_cosine_similarity(array1, array2)` | Cosine similarity | \u2713 | \u2713 |\n\n\n### Blob Functions\n\nBinary data manipulation functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `blob(data)` | Create blob | \u2713 | \u2713 |\n| `encode(data)` | Encode string to blob | \u2713 | \u2713 |\n| `decode(blob)` | Decode blob to string | \u2713 | \u2713 |\n| `octet_length(blob)` | Blob byte length | \u2713 | \u2713 |\n\n### Struct Functions\n\nStruct manipulation functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `struct_extract(struct, field)` | Extract struct field | \u2713 | \u2713 |\n\n| `to_int32(value)` | Cast to int32 | `ka.to_int32(field)` |\n| `to_int16(value)` | Cast to int16 | `ka.to_int16(field)` |\n| `to_float(value)` | Cast to float | `ka.to_float(field)` |\n| `to_date(value)` | Cast to date | `ka.to_date(field)` |\n| `to_timestamp(value)` | Cast to timestamp | `ka.to_timestamp(field)` |\n| `cast_as(value, type)` | Cast using AS syntax | `ka.cast_as(field, \"INT64\")` |\n| `case([input])` | CASE expression | `ka.case()` |\n\n### Hash Functions\n\nCryptographic hash functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `md5(data)` | MD5 hash | \u2713 | \u2713 |\n| `sha256(data)` | SHA256 hash | \u2713 | \u2713 |\n| `hash(data)` | Generic hash | \u2713 | \u2713 |\n\n### UUID Functions\n\nUUID generation and manipulation functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `gen_random_uuid()` | Generate random UUID | \u2713 | \u2014 |\n| `uuid(string)` | Parse UUID string | \u2713 | \u2713 |\n\n### Utility Functions\n\nUtility and miscellaneous functions:\n\n| Function | Description | kuzu_functions | QueryField |\n|----------|-------------|----------------|------------|\n| `coalesce(val1, val2, ...)` | First non-NULL value | \u2713 | \u2713 |\n| `ifnull(value, replacement)` | Replace NULL with value | \u2713 | \u2713 |\n| `nullif(a, b)` | NULL if equal | \u2713 | \u2713 |\n| `typeof(value)` | Get value type | \u2713 | \u2713 |\n| `constant_or_null(constant, check)` | Constant if check non-NULL | \u2713 | \u2713 |\n| `count_if(condition)` | 1 if condition true else 0 | \u2713 | \u2713 |\n| `error(message)` | Raise runtime error | \u2713 | \u2713 |\n\n\n### Casting Functions\n\nType conversion and casting functions:\n\n|----------|-------------|----------------|------------|\n| `to_int64(value)` | Cast to INT64 | \u2713 | \u2014 |\n| `to_int32(value)` | Cast to INT32 | \u2713 | \u2014 |\n| `to_int16(value)` | Cast to INT16 | \u2713 | \u2014 |\n| `to_double(value)` | Cast to DOUBLE | \u2713 | \u2014 |\n| `to_float(value)` | Cast to FLOAT | \u2713 | \u2014 |\n| `to_string(value)` | Cast to STRING | \u2713 | \u2014 |\n| `to_date(value)` | Cast to DATE | \u2713 | \u2014 |\n| `to_timestamp(value)` | Cast to TIMESTAMP | \u2713 | \u2713 |\n| `cast(value, type)` | CAST function | \u2713 | \u2713 |\n| `cast_as(value, type)` | CAST AS syntax | \u2713 | \u2713 |\n| `case([input])` | Create CASE expression | \u2713 | \u2713 |\n\n\n\n\n## Operator Reference\n\nKuzuAlchemy operator support (exactly as implemented):\n\n### Comparison Operators\n\n| Operator/Method | Description | Backing Enum/Method |\n|-----------------|-------------|---------------------|\n| `==` | Equal to | QueryField.__eq__ -> ComparisonOperator.EQ |\n| `!=` | Not equal | QueryField.__ne__ -> ComparisonOperator.NEQ |\n| `<` | Less than | QueryField.__lt__ -> ComparisonOperator.LT |\n| `<=` | Less than or equal | QueryField.__le__ -> ComparisonOperator.LTE |\n| `>` | Greater than | QueryField.__gt__ -> ComparisonOperator.GT |\n| `>=` | Greater than or equal | QueryField.__ge__ -> ComparisonOperator.GTE |\n| `in_(values)` | Membership | QueryField.in_ -> ComparisonOperator.IN |\n| `not_in(values)` | Not in | QueryField.not_in -> ComparisonOperator.NOT_IN |\n| `between(a,b, inclusive=True)` | Range test | QueryField.between -> BetweenExpression |\n\n### Pattern/Regex Operators\n\n| Operator/Method | Description | Backing Enum |\n|-----------------|-------------|--------------|\n| `like(pattern, case_sensitive=True)` | Regex-like match | ComparisonOperator.LIKE |\n| `not_like(pattern, case_sensitive=True)` | Negative match | ComparisonOperator.NOT_LIKE |\n| `regex_match(pattern)` | `=~` regex match | ComparisonOperator.REGEX_MATCH |\n| `not_regex_match(pattern)` | `!~` negative regex | ComparisonOperator.NOT_REGEX_MATCH |\n\n### Contains/Prefix/Suffix Filters\n\n| Method | Description | Backing Enum |\n|--------|-------------|--------------|\n| `contains_filter(value)` | Contains element/substr | ComparisonOperator.CONTAINS |\n| `starts_with_filter(value, case_sensitive=True)` | Prefix match | ComparisonOperator.STARTS_WITH |\n| `ends_with_filter(value, case_sensitive=True)` | Suffix match | ComparisonOperator.ENDS_WITH |\n| `is_null()` | Field is NULL | ComparisonOperator.IS_NULL |\n| `is_not_null()` | Field is NOT NULL | ComparisonOperator.IS_NOT_NULL |\n\n### Logical Operators (on FilterExpression)\n\n| Operator | Description | Backing |\n|----------|-------------|---------|\n| `&` | Logical AND | FilterExpression.__and__ -> LogicalOperator.AND |\n| `|` | Logical OR | FilterExpression.__or__ -> LogicalOperator.OR |\n| `^` | Logical XOR | FilterExpression.__xor__ -> LogicalOperator.XOR |\n| `~` | Logical NOT | FilterExpression.__invert__ -> NotFilterExpression |\n\n### Arithmetic Operators (on QueryField)\n\n| Operator | Description | Backing |\n|----------|-------------|---------|\n| `+` | Addition / list concatenation | QueryField.__add__/__radd__ -> ArithmeticOperator.ADD |\n| `-` | Subtraction | QueryField.__sub__/__rsub__ -> ArithmeticOperator.SUB |\n| `*` | Multiplication | QueryField.__mul__/__rmul__ -> ArithmeticOperator.MUL |\n| `/` | Division | QueryField.__truediv__/__rtruediv__ -> ArithmeticOperator.DIV |\n| `%` | Modulo | QueryField.__mod__/__rmod__ -> ArithmeticOperator.MOD |\n| `^` | Power | QueryField.__pow__/__rpow__ -> ArithmeticOperator.POW |\n\n### Indexing/Slicing (on QueryField)\n\n| Operator | Description | Backing Function |\n|----------|-------------|------------------|\n| `field[idx]` | 1-based index extract | FunctionExpression(\"array_extract\") |\n| `field[a:b]` | 1-based slice | FunctionExpression(\"array_slice\") |\n\n---\n\n## Model Definition\n\n### Node Models\n\n```python\nfrom kuzualchemy import kuzu_node, KuzuBaseModel, kuzu_field, KuzuDataType\nfrom typing import Optional, List\nfrom datetime import datetime\n\n@kuzu_node(\"User\")  # Table name in Kuzu\nclass User(KuzuBaseModel):\n    # Primary key\n    id: int = kuzu_field(kuzu_type=KuzuDataType.INT64, primary_key=True)\n\n    # Basic fields\n    name: str = kuzu_field(kuzu_type=KuzuDataType.STRING, not_null=True)\n    email: Optional[str] = kuzu_field(kuzu_type=KuzuDataType.STRING, unique=True, default=None)\n    age: int = kuzu_field(kuzu_type=KuzuDataType.INT32, default=0)\n\n    # Boolean fields\n    is_active: bool = kuzu_field(kuzu_type=KuzuDataType.BOOL, default=True)\n\n    # Timestamp fields\n    created_at: datetime = kuzu_field(\n        kuzu_type=KuzuDataType.TIMESTAMP,\n        default=KuzuDefaultFunction.CURRENT_TIMESTAMP\n    )\n\n    # Array fields\n    tags: Optional[List[str]] = kuzu_field(\n        kuzu_type=ArrayTypeSpecification(element_type=KuzuDataType.STRING),\n        default=None\n    )\n```\n\n### Relationship Models\n\n```python\nfrom kuzualchemy import kuzu_relationship, KuzuRelationshipBase\n\n@kuzu_relationship(\"KNOWS\", pairs=[(User, User)])\nclass Knows(KuzuRelationshipBase):\n    since: datetime = kuzu_field(kuzu_type=KuzuDataType.TIMESTAMP)\n    strength: float = kuzu_field(kuzu_type=KuzuDataType.DOUBLE, default=1.0)\n```\n\n### Model Methods\n\nEvery model inherits these methods from `KuzuBaseModel`:\n\n```python\nclass User(KuzuBaseModel):\n    # Built-in methods available:\n\n    def save(self, session: KuzuSession) -> None:\n        \"\"\"Save instance to database\"\"\"\n        pass\n\n    def delete(self, session: KuzuSession) -> None:\n        \"\"\"Delete instance from database\"\"\"\n        pass\n\n    @classmethod\n    def query(cls, session: KuzuSession = None) -> Query:\n        \"\"\"Create query for this model\"\"\"\n        pass\n\n    @classmethod\n    def get_primary_key_fields(cls) -> List[str]:\n        \"\"\"Get primary key field names\"\"\"\n        pass\n\n    @classmethod\n    def get_foreign_key_fields(cls) -> Dict[str, ForeignKeyMetadata]:\n        \"\"\"Get foreign key fields\"\"\"\n        pass\n```\n\n---\n\n## Field Types & Metadata\n\n### Supported Kuzu Data Types\n\n```python\nfrom kuzualchemy import KuzuDataType\n\n# Numeric types\nKuzuDataType.INT8, KuzuDataType.INT16, KuzuDataType.INT32, KuzuDataType.INT64\nKuzuDataType.UINT8, KuzuDataType.UINT16, KuzuDataType.UINT32, KuzuDataType.UINT64\nKuzuDataType.FLOAT, KuzuDataType.DOUBLE\nKuzuDataType.DECIMAL, KuzuDataType.SERIAL\n\n# String types\nKuzuDataType.STRING, KuzuDataType.BLOB\n\n# Boolean type\nKuzuDataType.BOOL\n\n# Date/time types\nKuzuDataType.DATE, KuzuDataType.TIMESTAMP, KuzuDataType.INTERVAL\n\n# UUID type\nKuzuDataType.UUID\n\n# Complex types\nKuzuDataType.STRUCT, KuzuDataType.MAP, KuzuDataType.UNION\n```\n\n### Field Definition\n\n```python\n# Field definition\nfield = kuzu_field(\n    # Basic properties\n    kuzu_type=KuzuDataType.STRING,\n    primary_key=False,\n    unique=False,\n    not_null=False,\n    index=False,\n\n    # Default values\n    default=\"default_value\",\n    default_factory=lambda: \"computed_default\",\n\n    # Constraints\n    check_constraint=\"LENGTH(field_name) > 0\",\n\n    # Foreign keys\n    foreign_key=ForeignKeyMetadata(\n        target_model=TargetModel,\n        target_field=\"id\",\n        on_delete=CascadeAction.CASCADE,\n        on_update=CascadeAction.SET_NULL\n    ),\n\n    # Metadata\n    alias=\"field_alias\",\n    title=\"Field Title\",\n    description=\"Field description\"\n)\n```\n\n### Array Fields\n\n```python\nfrom kuzualchemy.kuzu_orm import ArrayTypeSpecification\n\nclass User(KuzuBaseModel):\n    # Array field definition\n    tags: List[str] = kuzu_field(\n        kuzu_type=ArrayTypeSpecification(element_type=KuzuDataType.STRING),\n        default=None\n    )\n```\n\n### Default Values\n\n```python\nfrom kuzualchemy.constants import KuzuDefaultFunction\n\nclass User(KuzuBaseModel):\n    # Static defaults\n    status: str = kuzu_field(kuzu_type=KuzuDataType.STRING, default=\"active\")\n\n    # Function defaults\n    created_at: datetime = kuzu_field(\n        kuzu_type=KuzuDataType.TIMESTAMP,\n        default=KuzuDefaultFunction.CURRENT_TIMESTAMP\n    )\n\n    # Factory defaults\n    uuid_field: str = kuzu_field(\n        kuzu_type=KuzuDataType.UUID,\n        default_factory=lambda: str(uuid.uuid4())\n    )\n```\n\n---\n\n## Relationships\n\n### Basic Relationships\n\n```python\nfrom kuzualchemy import kuzu_relationship, KuzuRelationshipBase\n\n@kuzu_relationship(\"FOLLOWS\", pairs=[(User, User)])\nclass Follows(KuzuRelationshipBase):\n    since: datetime = kuzu_field(kuzu_type=KuzuDataType.TIMESTAMP)\n    weight: float = kuzu_field(kuzu_type=KuzuDataType.DOUBLE, default=1.0)\n```\n\n### Multi-Pair Relationships\n\n```python\n# Multiple relationship pairs\n@kuzu_relationship(\"AUTHORED\", pairs=[\n    (User, {Post, Comment}),\n    (Organization, Post)\n])\nclass Authored(KuzuRelationshipBase):\n    created_at: datetime = kuzu_field(kuzu_type=KuzuDataType.TIMESTAMP)\n    role: str = kuzu_field(kuzu_type=KuzuDataType.STRING, default=\"author\")\n```\n\n### Relationship Usage\n\n```python\n# Create relationships\nuser1 = User(id=1, name=\"Alice\")\nuser2 = User(id=2, name=\"Bob\")\nfollows = Follows(from_node=user1, to_node=user2, since=datetime.now())\n\nsession.add_all([user1, user2, follows])\nsession.commit()\n```\n\n---\n\n## Query System\n\n### Basic Queries\n\n```python\nfrom kuzualchemy import Query\n\n# Create query\nquery = Query(User, session=session)\n\n# Simple filtering\nfiltered = query.where(query.fields.age > 25)\nresults = filtered.all()\n\n# Method chaining\nresults = (Query(User, session=session)\n    .where(Query(User, session=session).fields.name.starts_with(\"A\"))\n    .where(Query(User, session=session).fields.age.between(20, 40))\n    .order_by(Query(User, session=session).fields.name.asc())\n    .limit(10)\n    .all())\n```\n\n### Advanced Queries\n\n```python\n# Aggregation with HAVING: count users by age > 1\nq = Query(User, session=session)\nagg = q.count()  # COUNT(*) AS count\ncount_by_age = (\n    q.group_by(q.fields.age)\n     .having(ka.to_int64(\"count\") > 1)  # compare aggregated alias post-WITH using cast\n)\n\n# Relationship join (pattern: join(TargetModel, RelationshipClass, ...))\nq = Query(User, session=session)\njoined = q.join(User, Follows, target_alias=\"u2\")\n\n# Subquery: authors older than 30\nsubq = Query(User, session=session).where(Query(User, session=session).fields.age > 30)\nmain_query = Query(Post, session=session).where(\n    Query(Post, session=session).fields.author_id.in_(subq.select(\"id\"))\n)\n```\n\n### Function Usage in Queries\n\n```python\nimport kuzualchemy as ka\n\n# Text functions\nquery = Query(User, session=session)\ntext_query = query.where(\n    ka.upper(query.fields.name).starts_with(\"A\")\n)\n\n# Numeric functions\nnumeric_query = query.where(\n    ka.abs(query.fields.age - 30) < 5\n)\n\n# List functions\nlist_query = query.where(\n    ka.list_contains(query.fields.hobbies, \"reading\")\n)\n\n# Date functions\ndate_query = query.where(\n    ka.date_part(\"year\", query.fields.birth_date) > 1990\n)\n```\n\n### Query Results\n\n```python\n# Get all results\nresults = query.all()  # List[ModelType]\n\n# Get first result\nfirst = query.first()  # ModelType | None\n\n# Get exactly one result\none = query.one()  # ModelType (raises if 0 or >1)\n\n# Get one or none\none_or_none = query.one_or_none()  # ModelType | None\n\n# Check existence\nexists = query.exists()  # bool\n\n# Count results\ncount_query = query.count()         # Query with COUNT(*) AS count aggregation\ncount = count_query._execute()[0][\"count\"] if count_query._execute() else 0\n```\n\n---\n\n## Session Management\n\n### Basic Session Usage\n\n```python\nfrom kuzualchemy import KuzuSession\nfrom pathlib import Path\n\n# Create session\nsession = KuzuSession(db_path=Path(\"my_database.db\"))\n\n# Execute DDL\nddl = get_all_ddl()\nif ddl.strip():\n    session.execute(ddl)\n\n# Add and commit\nuser = User(id=1, name=\"Alice\", email=\"alice@example.com\")\nsession.add(user)\nsession.commit()\n\n# Close session\nsession.close()\n```\n\n### Transaction Management\n\n```python\n# Manual transactions using KuzuTransaction\nfrom kuzualchemy import KuzuTransaction\n\nwith KuzuTransaction(session):\n    user = User(id=1, name=\"Alice\")\n    session.add(user)\n    # Automatic commit on success, rollback on exception\n\n# Or using session.begin() context manager\nwith session.begin():\n    user = User(id=1, name=\"Alice\")\n    session.add(user)\n    # Automatic commit on success, rollback on exception\n```\n\n### Session Factory\n\n```python\nfrom kuzualchemy import SessionFactory\n\n# Create factory\nfactory = SessionFactory(\n    db_path=\"database.db\",\n    autoflush=True,\n    autocommit=False\n)\n\n# Create sessions\nsession1 = factory.create_session()\nsession2 = factory.create_session(autocommit=True)  # Override defaults\n\n# Session scope context manager\nwith factory.session_scope() as session:\n    user = User(id=1, name=\"Alice\")\n    session.add(user)\n    # Automatic commit/rollback\n```\n\n### Connection Management\n\n```python\nfrom kuzualchemy import KuzuConnection\n\n# Direct connection usage\nconnection = KuzuConnection(db_path=\"database.db\")\nsession = KuzuSession(connection=connection)\n\n# Connection sharing\nsession1 = KuzuSession(connection=connection)\nsession2 = KuzuSession(connection=connection)\n```\n\n---\n\n## Advanced Features\n\n### Registry Management\n\n```python\nfrom kuzualchemy import (\n    get_registered_nodes,\n    get_registered_relationships,\n    get_all_models,\n    clear_registry,\n    validate_all_models\n)\n\n# Access registered models\nnodes = get_registered_nodes()\nrelationships = get_registered_relationships()\nall_models = get_all_models()\n\n# Validate all models\nvalidation_errors = validate_all_models()\n\n# Clear registry (useful for testing)\nclear_registry()\n```\n\n### Enhanced Base Model with Enum Conversion\n\n```python\nfrom kuzualchemy import BaseModel\nfrom enum import Enum\n\nclass Status(Enum):\n    ACTIVE = \"active\"\n    INACTIVE = \"inactive\"\n\n@kuzu_node(\"Account\")\nclass Account(BaseModel):  # Automatic enum conversion\n    status: Status = kuzu_field(kuzu_type=KuzuDataType.STRING)\n\n    # BaseModel automatically converts enums to/from string values\n```\n\n### Foreign Key Support\n\n```python\nfrom kuzualchemy import ForeignKeyMetadata, CascadeAction\n\n@kuzu_node(\"Post\")\nclass Post(KuzuBaseModel):\n    id: int = kuzu_field(kuzu_type=KuzuDataType.INT64, primary_key=True)\n    title: str = kuzu_field(kuzu_type=KuzuDataType.STRING)\n    author_id: int = kuzu_field(\n        kuzu_type=KuzuDataType.INT64,\n        foreign_key=ForeignKeyMetadata(\n            target_model=User,\n            target_field=\"id\",\n            on_delete=CascadeAction.CASCADE\n        )\n    )\n```\n\n### Custom Functions\n\n```python\n# All Kuzu functions are available as standalone callables\nimport kuzualchemy as ka\n\n# Use in queries\nquery = Query(User, session=session).where(\n    ka.concat(query.fields.first_name, \" \", query.fields.last_name).contains(\"Alice\")\n)\n\n# Use in expressions\nfull_name = ka.concat(user.first_name, \" \", user.last_name)\n```\n\n### Complex Expressions\n\n```python\n# Combine multiple functions and operators\ncomplex_filter = (\n    ka.upper(query.fields.name).starts_with(\"A\") &\n    (query.fields.age.between(20, 40)) &\n    ka.list_contains(query.fields.tags, \"python\")\n)\n\nresults = Query(User, session=session).where(complex_filter).all()\n```\n\n---\n\n## API Reference\n\n### Core Classes\n\n#### KuzuBaseModel\nBase class for all node models with built-in ORM functionality.\n\n**Methods:**\n- `save(session: KuzuSession) -> None`: Save instance to database\n- `delete(session: KuzuSession) -> None`: Delete instance from database\n- `query(session: KuzuSession = None) -> Query`: Create query for this model\n- `get_kuzu_metadata(field_name: str) -> KuzuFieldMetadata`: Get field metadata\n- `get_all_kuzu_metadata() -> Dict[str, KuzuFieldMetadata]`: Get all field metadata\n- `get_primary_key_fields() -> List[str]`: Get primary key field names\n- `get_foreign_key_fields() -> Dict[str, ForeignKeyMetadata]`: Get foreign key fields\n\n#### KuzuRelationshipBase\nBase class for relationship models.\n\n**Methods:**\n- Same as KuzuBaseModel plus relationship-specific functionality\n- `create_between(from_node, to_node, **properties) -> KuzuRelationshipBase`: Factory to instantiate relationship between nodes\n- `from_node_pk`/`to_node_pk` properties for node primary keys\n\n#### KuzuSession\nMain session class for database operations.\n\n**Methods:**\n- `execute(query: str, parameters: Dict = None) -> List[Dict]`: Execute raw query\n- `add(instance: Any) -> None`: Add instance to session\n- `add_all(instances: List[Any]) -> None`: Add multiple instances\n- `delete(instance: Any) -> None`: Mark instance for deletion\n- `commit() -> None`: Commit current transaction\n- `rollback() -> None`: Rollback current transaction\n- `flush() -> None`: Flush pending changes\n- `close() -> None`: Close session\n- `begin() -> KuzuTransaction`: Begin transaction context\n\n#### Query[ModelType]\nType-safe query builder.\n\n**Methods:**\n- `where(expression: FilterExpression) -> Query`: Add WHERE clause\n- `filter(*expressions: FilterExpression) -> Query`: Add multiple filters\n- `order_by(*fields: QueryField) -> Query`: Add ORDER BY clause\n- `group_by(*fields: QueryField) -> Query`: Add GROUP BY clause\n- `having(expression: FilterExpression) -> Query`: Add HAVING clause\n- `limit(count: int) -> Query`: Add LIMIT clause\n- `offset(count: int) -> Query`: Add OFFSET clause\n- `distinct() -> Query`: Add DISTINCT clause\n- `all() -> List[ModelType]`: Execute and return all results\n- `first() -> ModelType | None`: Execute and return first result\n- `one() -> ModelType`: Execute and return exactly one result\n- `one_or_none() -> ModelType | None`: Execute and return one or none\n- `count() -> int`: Count results\n- `exists() -> bool`: Check if results exist\n\n### Field Definition\n\n#### kuzu_field Function\nField definition with options:\n\n```python\nkuzu_field(\n    default: Any = ...,                                    # Default value\n    kuzu_type: Union[KuzuDataType, str, ArrayTypeSpecification], # Kuzu data type\n    primary_key: bool = False,                            # Primary key flag\n    foreign_key: ForeignKeyMetadata = None,               # Foreign key metadata\n    unique: bool = False,                                 # Unique constraint\n    not_null: bool = False,                              # NOT NULL constraint\n    index: bool = False,                                 # Index flag\n    check_constraint: str = None,                        # CHECK constraint\n    default_factory: Callable[[], Any] = None,          # Default factory function\n    alias: str = None,                                   # Field alias\n    title: str = None,                                   # Field title\n    description: str = None,                             # Field description\n)\n```\n\n### Decorators\n\n#### @kuzu_node()\nMark class as Kuzu node:\n\n```python\n@kuzu_node(\n    name: str = None,                                    # Node name (defaults to class name)\n    abstract: bool = False,                              # Abstract node flag\n    compound_indexes: List[CompoundIndex] = None,        # Compound indexes\n    table_constraints: List[str] = None,                 # Table constraints\n    properties: Dict[str, Any] = None                    # Additional properties\n)\n```\n\n#### @kuzu_relationship()\nMark class as Kuzu relationship:\n\n```python\n@kuzu_relationship(\n    name: str = None,                                    # Relationship name\n    pairs: List[Tuple[Type, Type]] = None,              # Valid node pairs\n    multiplicity: RelationshipMultiplicity = MANY_TO_MANY, # Relationship multiplicity\n    compound_indexes: List[CompoundIndex] = None,        # Compound indexes\n    table_constraints: List[str] = None,                 # Table constraints\n    properties: Dict[str, Any] = None                    # Additional properties\n)\n```\n\n### Enums and Constants\n\n#### KuzuDataType\nAll supported Kuzu data types:\n- Numeric: `INT8`, `INT16`, `INT32`, `INT64`, `UINT8`, `UINT16`, `UINT32`, `UINT64`, `FLOAT`, `DOUBLE`, `DECIMAL`, `SERIAL`\n- String: `STRING`, `BLOB`\n- Boolean: `BOOL`\n- Temporal: `DATE`, `TIMESTAMP`, `INTERVAL`\n- Other: `UUID`, `STRUCT`, `MAP`, `UNION`\n\n#### ComparisonOperator\nQuery comparison operators (from kuzu_query_expressions):\n- `EQ`, `NEQ`: Equality/inequality\n- `LT`, `LTE`, `GT`, `GTE`: Comparison operators\n- `IN`, `NOT_IN`: List membership\n- `LIKE`, `NOT_LIKE`: Pattern matching\n- `IS_NULL`, `IS_NOT_NULL`: Null checks\n- `CONTAINS`: String/array contains\n- `STARTS_WITH`, `ENDS_WITH`: String prefix/suffix\n- `EXISTS`, `NOT_EXISTS`: Existence checks\n\n#### LogicalOperator\nLogical operators for combining conditions:\n- `AND`, `OR`, `NOT`, `XOR`: Boolean logic\n\n#### AggregateFunction\nAggregate functions:\n- `COUNT`, `COUNT_DISTINCT`: Counting\n- `SUM`, `AVG`: Numeric aggregation\n- `MIN`, `MAX`: Extrema\n- `COLLECT`, `COLLECT_LIST`, `COLLECT_SET`: Collection aggregation\n\n#### OrderDirection\nOrdering directions:\n- `ASC`: Ascending order\n- `DESC`: Descending order\n\n#### JoinType\nJoin types:\n- `INNER`: Inner join\n- `OPTIONAL`: Optional match (left outer join)\n\n### Utility Functions\n\n#### DDL Generation\n- `get_all_ddl() -> str`: Generate DDL for all registered models\n- `get_ddl_for_node(node_cls: Type[Any]) -> str`: Generate DDL for specific node\n- `get_ddl_for_relationship(rel_cls: Type[Any]) -> str`: Generate DDL for specific relationship\n\n#### Registry Management\n- `get_registered_nodes() -> Dict[str, Type[Any]]`: Get all registered nodes\n- `get_registered_relationships() -> Dict[str, Type[Any]]`: Get all registered relationships\n- `get_all_models() -> Dict[str, Type[Any]]`: Get all registered models\n- `clear_registry() -> None`: Clear model registry\n- `validate_all_models() -> List[str]`: Validate all registered models\n\n#### Test Utilities\n- `initialize_schema(session: KuzuSession, ddl: str = None) -> None`: Initialize database schema\n\n---\n\n---\n\n## Contributing\n\nWe welcome contributions to KuzuAlchemy! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n### Development Setup\n\n```bash\n# Clone repository\ngit clone <repository-url>\ncd kuzualchemy\n\n# Install in development mode\npip install -e \".[dev,test]\"\n\n# Run tests\npytest\n\n# Run type checking\nmypy src/\n\n# Run linting\nflake8 src/\nblack src/\n\n# Build package\npython -m build\n```\n\n### Testing\n\n```bash\n# Run all tests\npytest\n\n# Run specific test categories\npytest tests/test_functions.py\npytest tests/test_integration.py\n\n# Run with coverage\npytest --cov=kuzualchemy --cov-report=html\n```\n\n---\n\n## License\n\nThis project is licensed under the GPL-3.0 license - see the [LICENSE](LICENSE) file for details.\n\n---\n\n## Conclusion\n\nKuzuAlchemy is an Object-Relational Mapping library for the Kuzu graph database. It provides a SQLAlchemy-like interface for working with graph data.\n",
    "bugtrack_url": null,
    "license": "GPL-3.0",
    "summary": "SQLAlchemy-like ORM for Kuzu graph database",
    "version": "0.2.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/FanaticPythoner/kuzualchemy/issues",
        "Documentation": "https://kuzualchemy.readthedocs.io",
        "Homepage": "https://github.com/FanaticPythoner/kuzualchemy",
        "Repository": "https://github.com/FanaticPythoner/kuzualchemy"
    },
    "split_keywords": [
        "kuzu",
        " graph",
        " database",
        " orm",
        " sqlalchemy",
        " cypher",
        " graph-database"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "f79ed13a3ec234c2297d8c8280e01dc1c86b24ac42c5a28528df0b2bed9e2361",
                "md5": "57b858a58af1f6ffbd3c15cec004eae0",
                "sha256": "299e5fea1cf2e14996d4346f67b26f38a743751adbfd4d9f61525e26a09add49"
            },
            "downloads": -1,
            "filename": "kuzualchemy-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "57b858a58af1f6ffbd3c15cec004eae0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 106634,
            "upload_time": "2025-09-04T18:35:21",
            "upload_time_iso_8601": "2025-09-04T18:35:21.966500Z",
            "url": "https://files.pythonhosted.org/packages/f7/9e/d13a3ec234c2297d8c8280e01dc1c86b24ac42c5a28528df0b2bed9e2361/kuzualchemy-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1ddbe93e2f5c8185dde067626d26c0946081f5989141069e7346055284fa8e2e",
                "md5": "6cd8df231d4fe1821c15c1ecfb5b7f06",
                "sha256": "52d59a066326e7d6823d6d375771352e1c1c3c3d4a2f9b5b7022984c636b3552"
            },
            "downloads": -1,
            "filename": "kuzualchemy-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "6cd8df231d4fe1821c15c1ecfb5b7f06",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 125007,
            "upload_time": "2025-09-04T18:35:23",
            "upload_time_iso_8601": "2025-09-04T18:35:23.421757Z",
            "url": "https://files.pythonhosted.org/packages/1d/db/e93e2f5c8185dde067626d26c0946081f5989141069e7346055284fa8e2e/kuzualchemy-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-04 18:35:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "FanaticPythoner",
    "github_project": "kuzualchemy",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "kuzualchemy"
}
        
Elapsed time: 4.04206s