Skip to content

Type Conversion API

The type_conversion module provides utilities for converting between Python and Java types when working with ArcadeDB's Java backend.

Overview

The type_conversion module enables:

  • Automatic Conversion: Seamless Python ↔ Java type conversion
  • Collection Handling: Lists, sets, maps, and nested structures
  • Date/Time Support: datetime, date, and time objects
  • Decimal Precision: High-precision decimal numbers
  • Binary Data: Bytes and byte arrays
  • Type Safety: Validation and error handling

Why Type Conversion?

ArcadeDB Python bindings wrap a Java database engine. When you:

  • Set properties on records → Python values converted to Java
  • Read properties from records → Java values converted to Python
  • Pass query parameters → Python values converted to Java
  • Receive query results → Java values converted to Python

The type_conversion module handles this automatically.

Conversion Functions

convert_python_to_java

from arcadedb_embedded.type_conversion import convert_python_to_java

java_value = convert_python_to_java(python_value)

Convert Python value to Java object for ArcadeDB.

Supported Conversions:

Python Type Java Type
None null
bool Boolean
int Integer or Long
float Double
str String
bytes byte[]
datetime LocalDateTime
date LocalDate
time LocalTime
Decimal BigDecimal
list ArrayList
tuple ArrayList
set HashSet
dict HashMap

Example:

from arcadedb_embedded.type_conversion import convert_python_to_java
from datetime import datetime
from decimal import Decimal

# Primitive types
java_int = convert_python_to_java(42)
java_str = convert_python_to_java("hello")
java_bool = convert_python_to_java(True)

# Date/time
java_datetime = convert_python_to_java(datetime.now())

# Decimal
java_decimal = convert_python_to_java(Decimal("123.456"))

# Collections
java_list = convert_python_to_java([1, 2, 3])
java_dict = convert_python_to_java({"key": "value"})

# Nested structures
java_nested = convert_python_to_java({
    "users": [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": 25}
    ]
})

convert_java_to_python

from arcadedb_embedded.type_conversion import convert_java_to_python

python_value = convert_java_to_python(java_value)

Convert Java object to Python value.

Supported Conversions:

Java Type Python Type
null None
Boolean bool
Integer, Long, Short, Byte int
Float, Double float
String str
byte[] bytes
LocalDateTime datetime
LocalDate date
LocalTime time
BigDecimal Decimal
List, ArrayList list
Set, HashSet set
Map, HashMap dict

Example:

from arcadedb_embedded.type_conversion import convert_java_to_python

# Read from database (automatic conversion)
result = list(db.query("sql", "SELECT FROM User WHERE username = 'alice'"))[0]

# Get Python properties (automatically converted)
username = result.get("username")  # str
age = result.get("age")            # int
tags = result.get("tags")          # list
profile = result.get("profile")    # dict

# Manual conversion (if needed for custom types)
element = result.get_element()
java_property = element.get("username")  # Uses wrapper method
# Properties are automatically converted

Type-Specific Conversions

Integers

from arcadedb_embedded.type_conversion import convert_python_to_java

# Small integers → Integer
java_int = convert_python_to_java(42)          # Java Integer

# Large integers → Long
java_long = convert_python_to_java(2**40)     # Java Long

# Reading integers (requires an active transaction)
with db.transaction():
    vertex = db.new_vertex("User")
    vertex.set("age", 30)                      # Python int → Java Integer
    age = vertex.get("age")                    # Java Integer → Python int

Floats and Decimals

from arcadedb_embedded.type_conversion import convert_python_to_java
from decimal import Decimal

# Float → Double
java_double = convert_python_to_java(3.14159)

# Decimal → BigDecimal (for precision)
java_decimal = convert_python_to_java(Decimal("123.456789"))

# Reading (requires an active transaction)
with db.transaction():
    vertex = db.new_vertex("Product")
    vertex.set("price", 19.99)                 # float → Double
    vertex.set("tax", Decimal("1.23"))         # Decimal → BigDecimal

    price = vertex.get("price")                # Double → float
    tax = vertex.get("tax")                    # BigDecimal → Decimal

Strings

# String conversion (requires an active transaction)
with db.transaction():
    vertex = db.new_vertex("User")
    vertex.set("name", "Alice")                # str → String
    name = vertex.get("name")                  # String → str

    # Unicode handling
    vertex.set("emoji", "Hello 👋 World 🌍")
    emoji = vertex.get("emoji")                # Full Unicode support

Dates and Times

from datetime import datetime, date, time

# datetime → LocalDateTime (requires an active transaction)
with db.transaction():
    vertex = db.new_vertex("Event")
    vertex.set("timestamp", datetime.now())

    # date → LocalDate
    vertex.set("birthDate", date(1990, 1, 15))

    # time → LocalTime
    vertex.set("startTime", time(14, 30, 0))

    # Reading back
    timestamp = vertex.get("timestamp")        # datetime
    birth_date = vertex.get("birthDate")       # date
    start_time = vertex.get("startTime")       # time

Binary Data

# bytes → byte[] (requires an active transaction)
binary_data = b"Hello World"
with db.transaction():
    vertex = db.new_vertex("File")
    vertex.set("data", binary_data)

    # Reading back
    data = vertex.get("data")                  # bytes
    print(data.decode("utf-8"))                # "Hello World"

Lists and Sets

# list → ArrayList (requires an active transaction)
with db.transaction():
    vertex = db.new_vertex("User")
    vertex.set("tags", ["python", "java", "database"])
    tags = vertex.get("tags")                  # list

    # set → HashSet
    vertex.set("roles", {"admin", "user"})
    roles = vertex.get("roles")                # set

    # Nested lists
    vertex.set("matrix", [[1, 2], [3, 4]])
    matrix = vertex.get("matrix")              # [[1, 2], [3, 4]]

Dictionaries (Maps)

# dict → HashMap (requires an active transaction)
with db.transaction():
    vertex = db.new_vertex("User")
    vertex.set("profile", {
        "firstName": "Alice",
        "lastName": "Smith",
        "address": {
            "city": "New York",
            "zip": "10001"
        }
    })

    # Reading back
    profile = vertex.get("profile")            # dict
    print(profile["firstName"])                # "Alice"
    print(profile["address"]["city"])          # "New York"

Query Parameter Conversion

from datetime import datetime

# Query parameters are automatically converted
results = db.query(
    "sql",
    "SELECT FROM User WHERE age > ? AND createdAt > ?",
    25, datetime(2024, 1, 1)  # Python types converted to Java
)

# Reading results (automatically converted back to Python)
for result in results:
    name = result.get("name")         # str
    age = result.get("age")           # int
    created = result.get("createdAt") # datetime

Collection Type Preservation

# Lists preserve order (requires an active transaction)
with db.transaction():
    vertex = db.new_vertex("Sequence")
    vertex.set("numbers", [3, 1, 4, 1, 5, 9])
    numbers = vertex.get("numbers")            # [3, 1, 4, 1, 5, 9]

    # Sets remove duplicates
    vertex.set("unique", {3, 1, 4, 1, 5, 9})
    unique = vertex.get("unique")              # {1, 3, 4, 5, 9}

    # Dicts preserve keys
    vertex.set("mapping", {"a": 1, "b": 2, "c": 3})
    mapping = vertex.get("mapping")            # {"a": 1, "b": 2, "c": 3}

Complete Example

import arcadedb_embedded as arcadedb
from datetime import datetime, date
from decimal import Decimal

# Create database
db = arcadedb.create_database("./type_demo")

# Create schema (auto-transactional)
db.schema.create_vertex_type("Product")

# Test all type conversions
with db.transaction():
    product = db.new_vertex("Product")

    # Primitives
    product.set("productId", 12345)                    # int
    product.set("name", "Laptop")                      # str
    product.set("inStock", True)                       # bool
    product.set("price", 999.99)                       # float
    product.set("tax", Decimal("50.00"))               # Decimal

    # Date/time
    product.set("createdAt", datetime.now())           # datetime
    product.set("releaseDate", date(2024, 1, 15))      # date

    # Collections
    product.set("tags", ["electronics", "laptop"])     # list
    product.set("categories", {"computers", "tech"})   # set

    # Nested structures
    product.set("specs", {
        "cpu": "Intel i7",
        "ram": "16GB",
        "storage": ["512GB SSD", "1TB HDD"]
    })                                                  # dict

    # Binary
    product.set("thumbnail", b"PNG\x89...")            # bytes

    product.save()

# Read back and verify types
results = list(db.query("sql", "SELECT FROM Product"))
product = results[0]

print(f"Product ID: {product.get('productId')} ({type(product.get('productId')).__name__})")
print(f"Name: {product.get('name')} ({type(product.get('name')).__name__})")
print(f"In Stock: {product.get('inStock')} ({type(product.get('inStock')).__name__})")
print(f"Price: {product.get('price')} ({type(product.get('price')).__name__})")
print(f"Tax: {product.get('tax')} ({type(product.get('tax')).__name__})")
print(f"Created At: {product.get('createdAt')} ({type(product.get('createdAt')).__name__})")
print(f"Tags: {product.get('tags')} ({type(product.get('tags')).__name__})")

db.close()

Output:

Product ID: 12345 (int)
Name: Laptop (str)
In Stock: True (bool)
Price: 999.99 (float)
Tax: 50.00 (Decimal)
Created At: 2024-01-15 10:30:45.123456 (datetime)
Tags: ['electronics', 'laptop'] (list)

Manual Conversion

Most of the time, conversions happen automatically. But you can manually convert when needed:

from arcadedb_embedded.type_conversion import convert_python_to_java, convert_java_to_python

# Manual Python → Java
python_data = {"name": "Alice", "age": 30}
java_map = convert_python_to_java(python_data)

# Use Java object directly (requires an active transaction)
with db.transaction():
    java_record = db.new_vertex("User")._java_object
    java_record.set("profile", java_map)

# Manual Java → Python
java_property = java_record.get("profile")
python_dict = convert_java_to_python(java_property)
print(python_dict)  # {"name": "Alice", "age": 30}

Best Practices

1. Use Native Python Types

# ✅ Good: Use Python types
vertex.set("tags", ["python", "java"])
vertex.set("count", 42)
vertex.set("timestamp", datetime.now())

# ❌ Bad: Manually convert (unnecessary)
from arcadedb_embedded.type_conversion import convert_python_to_java
vertex.set("tags", convert_python_to_java(["python", "java"]))  # Redundant

2. Use Decimal for Money

from decimal import Decimal

# ✅ Good: Decimal for precise values
vertex.set("price", Decimal("19.99"))
vertex.set("tax", Decimal("1.60"))

# ❌ Bad: Float for money (precision loss)
vertex.set("price", 19.99)  # May lose precision

3. Consistent Collection Types

# ✅ Good: Consistent types
vertex.set("tags", ["tag1", "tag2", "tag3"])  # All strings

# ⚠️ Mixed types work but can be confusing
vertex.set("mixed", [1, "two", 3.0, True])

4. Handle None Values

# ✅ Good: Check for None
age = vertex.get("age")
if age is not None:
    print(f"Age: {age}")
else:
    print("Age not set")

# ❌ Bad: Assume value exists
print(f"Age: {vertex.get('age')}")  # May be None

Type Conversion Limitations

1. Custom Python Classes

# ❌ Custom classes not supported
class MyClass:
    def __init__(self, value):
        self.value = value

vertex.set("custom", MyClass(42))  # ❌ Error

# ✅ Convert to dict first
vertex.set("custom", {"value": 42})  # ✅ Works

2. Complex Nested Structures

# ✅ Reasonable nesting works
vertex.set("data", {
    "level1": {
        "level2": {
            "level3": [1, 2, 3]
        }
    }
})

# ⚠️ Very deep nesting may impact performance

3. Large Binary Data

# ✅ Small binary data
vertex.set("icon", b"PNG\x89...")  # OK

# ⚠️ Large binary data (consider file storage)
with open("large_file.bin", "rb") as f:
    data = f.read()  # May be very large
    vertex.set("file", data)  # May impact memory

Troubleshooting

Type Mismatch Errors

# ❌ Error: Expected list, got dict
vertex.set("tags", {"tag1": 1})  # Wrong type

# ✅ Fix: Use correct type
vertex.set("tags", ["tag1"])

Precision Loss with Floats

# ⚠️ Float precision issues
price = 19.99
tax = 0.01
total = price + tax  # May not be exactly 20.00

# ✅ Use Decimal
from decimal import Decimal
price = Decimal("19.99")
tax = Decimal("0.01")
total = price + tax  # Exactly 20.00

Date/Time Timezone Issues

from datetime import datetime, timezone

# ⚠️ Naive datetime (no timezone)
now = datetime.now()  # Local time, no timezone

# ✅ Aware datetime (with timezone)
now_utc = datetime.now(timezone.utc)  # UTC time

See Also