Skip to content

Results API

The ResultSet and Result classes provide Python-friendly interfaces for working with query results from ArcadeDB. They handle iteration, property access, and type conversion automatically.

Using Context Managers

For automatic resource cleanup, prefer using context managers:

with arcadedb.open_database("./mydb") as db:
    result_set = db.query("sql", "SELECT FROM Person WHERE age > 25")
    for result in result_set:
        print(result.get("name"))
# Database automatically closed
Examples below show explicit db.close() for clarity, but context managers are recommended in production.

Overview

When you execute a query, ArcadeDB returns a ResultSet that can be iterated to access individual Result objects. Each Result represents one row/record from your query.

Key Features:

  • Pythonic iteration: Use for loops or iterators
  • Property access: Get values by property name
  • Type conversion: Automatic conversion from Java to Python types
  • Multiple access patterns: Dict-like access, JSON export, direct properties

ResultSet Class

Iterable wrapper for query results. ResultSet is a Python iterator: iterate it with a for loop, next(), or materialize it with helpers like to_list(), first(), and one().

Creation

ResultSet objects are returned by query operations:

import arcadedb_embedded as arcadedb

db = arcadedb.open_database("./mydb")

# query() returns ResultSet
result_set = db.query("sql", "SELECT FROM Person WHERE age > 25")

# command() also returns ResultSet for SELECT queries
result_set = db.command("sql", "SELECT * FROM Person LIMIT 10")

Iteration

ResultSet implements the Python iterator protocol (__iter__/__next__), so each iteration yields a Result. Iteration consumes the underlying result set.

# Using for loop (most Pythonic)
for result in result_set:
    name = result.get("name")
    age = result.get("age")
    print(f"{name}: {age}")

# As iterator
result_set = db.query("sql", "SELECT FROM Product")
results = list(result_set)  # Convert to list of Result objects

# Or use the built-in next()
result_set = db.query("sql", "SELECT FROM Document")
first = next(result_set)  # Raises StopIteration when exhausted

to_list(convert_types: bool = True) -> List[Dict[str, Any]]

Convert all results to a list of dictionaries.

Parameters:

  • convert_types (bool): Convert Java types to Python types (default: True)

Returns:

  • List[Dict[str, Any]]: List of dictionaries with result data

Example:

results = db.query("sql", "SELECT FROM User LIMIT 10")
users = results.to_list()
print(users[0])
# {'name': 'Alice', 'age': 30, 'email': 'alice@example.com'}

iter_dicts(convert_types: bool = True) -> Iterator[Dict[str, Any]]

Iterate results as dictionaries.

Parameters:

  • convert_types (bool): Convert Java types to Python types (default: True)

Yields:

  • Result rows as dictionaries

to_json_list(batch_size: int = 10_000) -> List[Dict[str, Any]]

Bulk-materialize all rows via batched Java-side JSON serialization.

The fast path for large result sets: rows are serialized to JSON in batches on the Java side (one JPype crossing per batch instead of several per row) and parsed with the C json module. Measured ~5.5x faster than to_list() on a 10,000-row, nine-property scan (578 ms against 103 ms, laptop, 2026-09-27).

Trade-off: values carry JSON-native types. Numbers, strings, booleans, lists, and nested maps convert as expected, but DATE and DATETIME values arrive as epoch-millisecond integers (not datetime) and DECIMALs as floats. A DATE is the epoch milliseconds of midnight UTC, whatever the JVM's time zone, so it is the same integer Result.to_json() writes and datetime.fromtimestamp(ms / 1000, timezone.utc) gives the right day. (Before this was fixed it was midnight in the JVM's zone: the previous day when decoded as UTC east of UTC, humemai/arcadedb-embedded-python#116.) Use to_list() when full Python-type fidelity matters more than speed.

It is also the fast path for a small result: a one-row read through to_json_list() takes one Java crossing (a short batch ends the read) and allocates only what the row needs, about 0.022 ms for a bound openCypher point lookup against 0.037 ms before this was fixed (laptop, relative only, 2026-10-04).

Parameters:

  • batch_size (int): Rows serialized per Java crossing (default: 10_000); must be at least 1 (ValueError otherwise)

Returns:

  • List[Dict[str, Any]]: List of dictionaries with JSON-native values

Example:

rows = db.query("sql", "SELECT FROM Doc").to_json_list()

iter_json_batches(batch_size: int = 10_000) -> Iterator[List[Dict[str, Any]]]

Yield rows as lists of dicts, one Java-serialized batch at a time.

Streaming counterpart of to_json_list() with the same JSON-native type semantics; bounds memory to one batch. Falls back to chunked per-row conversion when the bridge jar is unavailable.

Parameters:

  • batch_size (int): Rows serialized per Java crossing (default: 10_000); must be at least 1 (ValueError otherwise)

Yields:

  • Lists of dictionaries (up to batch_size elements each)

Example:

for batch in db.query("sql", "SELECT FROM LargeTable").iter_json_batches():
    process_batch(batch)

to_dataframe(convert_types: bool = True)

Convert results to a pandas DataFrame. Requires pandas to be installed.

Parameters:

  • convert_types (bool): Convert Java types to Python types (default: True)

Returns:

  • pandas DataFrame

Raises:

  • ImportError: If pandas is not installed

Example:

results = db.query("sql", "SELECT FROM User")
df = results.to_dataframe()
print(df.describe())

to_columns(batch_size: int = 25_000, columns: Optional[Sequence[str]] = None)

Bulk-materialize all rows as columns: a dict of column name to numpy array (int64/float64/bool/datetime64[ms]) or Python list (strings and JSON-typed values). The fastest bulk path; to_dataframe() uses it internally.

Fixed-dimension vector properties (e.g. ARRAY_OF_FLOATS embedding columns) come back as one contiguous 2-D array of shape (rows, dim) (float32 or float64), ready for scikit-learn/faiss without per-row conversion; ragged array columns fall back to lists.

Null handling follows pandas conventions: int/datetime columns with nulls are promoted to float64 with NaN / datetime64 NaT; a null row in a vector column becomes a NaN row. Returns None when numpy or the bridge jar is unavailable (callers fall back to row-based paths).

The columns are the union of the property names of every row, in order of first appearance, because a document is schemaless: a property the first row lacks is still a column, null where a row lacks it. (Before this was fixed the columns were the first row's, and to_columns(), to_dataframe(), and to_arrow() dropped the others, humemai/arcadedb-embedded-python#113.) The result does not depend on batch_size. Finding the columns costs one pass over each row's property names (about 25% of a 200,000-row, twelve-property to_columns(), measured on the laptop, relative only); pass columns=["a", "b"] to read exactly those, as a projection would, and skip it. A row lacking one of them reads null, and a property not listed is left out.

A DECIMAL column is an object array of Decimal (None for null), exact to the last digit; it used to arrive as JSON numbers, so a double lost digits and the dtype followed the data (humemai/arcadedb-embedded-python#115).

Example:

cols = db.query("sql", "SELECT cid, embedding FROM Chunk").to_columns()
emb = cols["embedding"]        # float32, shape (n, dim)
sims = emb @ query_vector      # immediately usable

to_arrow(batch_size: int = 25_000, columns: Optional[Sequence[str]] = None)

Bulk-materialize all rows as a pyarrow.Table. Requires numpy and pyarrow.

It reads the same columnar buffer as to_columns(), so the Java side does no extra work. Two things differ. Nulls keep their column type, because Arrow carries a validity bitmap: a nullable int64 column stays int64 (where to_columns() promotes it to float64 with NaN, losing precision above 2**53), and a nullable boolean column stays boolean. Strings are cheaper, because the buffer already holds Arrow's string layout (int32 offsets and a UTF-8 blob), so a column is wrapped instead of decoded one str at a time.

The table's columns are the union of the rows' property names, as in to_columns(). A column's type does not depend on batch_size: a batch whose rows lack the column, carry it as null, or hold only empty lists in it says nothing about its type and takes the type of the other batches (humemai/arcadedb-embedded-python#114). If batches really do disagree (an int in one row, a string in another), the column becomes strings, in one batch as well as across batches. A DECIMAL column is decimal128 (decimal256 above 38 digits, strings above 76), so no digit is lost.

Parameters:

  • batch_size (int): Rows per Java crossing (default: 25_000)

Returns:

  • pyarrow.Table, or None when pyarrow, numpy, or the bridge jar is unavailable (fall back to to_columns())

Example:

table = db.query("sql", "SELECT id, name, score FROM Doc").to_arrow()
print(table.schema)

iter_chunks(size: int = 1000, convert_types: bool = True) -> Iterator[List[Dict[str, Any]]]

Iterate results in chunks for memory-efficient processing.

Parameters:

  • size (int): Chunk size (default: 1000)
  • convert_types (bool): Convert Java types to Python types (default: True)

Yields:

  • Lists of dictionaries (up to size elements each)

Example:

results = db.query("sql", "SELECT FROM User")
for chunk in results.iter_chunks(size=1000):
    process_batch(chunk)  # chunk is a list of dicts

count() -> int

Count the remaining results without building a list.

Returns:

  • int: Number of remaining results

Note: This consumes the remaining rows from the current result set. After calling count(), the iterator is exhausted.

Example:

count = db.query("sql", "SELECT FROM User").count()
print(f"Found {count} users")

first() -> Optional[Result]

Get the first result, or None if there are no results.

Returns:

  • Result or None

Example:

user = db.query("sql", "SELECT FROM User WHERE id = 1").first()
if user:
    print(user.get("name"))

one() -> Result

Get a single result, raising ValueError if there is not exactly one.

Returns:

  • Result: The single result

Raises:

  • ValueError: If zero or multiple results

Example:

user = db.query(
    "sql",
    "SELECT FROM User WHERE email = ?",
    "alice@example.com",
).one()
print(user.get("name"))

close() -> None

Close the underlying Java result set. Idempotent.

A result set is closed for you as soon as it is exhausted (by iteration or any of the to_* methods), by first() and one() once they have their row, and when the object is freed (CPython frees it as soon as nothing refers to it, e.g. after a break). Call close(), or use the result set as a context manager, when you stop reading early and keep the object around.

A result set read to its end reads as empty afterwards. One closed before its end, by first(), one(), close(), or leaving its with block, raises ArcadeDBError if you read it again: the rows it had not returned are gone, so run the query again. (Until 2026-09-29 such a read returned whatever the closed Java result set still handed out, which depended on the engine build.) To take one row and keep reading, use next(iter(rs)) rather than first().

The engine computes rows lazily, so an error in the statement can come while the rows are read, after query() returned: a division by zero on the tenth row, say. Iteration, first(), one(), count(), and every to_* and iter_* method raise it as ArcadeDBError, with the Java exception as its __cause__. (Before 26.10.1 the Java exception reached Python as it was.)

A result set, and each Result it returns, keeps its Database alive. Reading a result set after the database was closed (db.close(), or leaving the with block that opened it) raises ArcadeDBError ("Database is closed") unless it was already read to its end, because the rows it has not returned may still be read lazily from the engine. A Result that is a record row (SELECT FROM T) raises too: its properties are loaded lazily from the open database, so there is nothing to return. A Result that is a projection (SELECT name FROM T) or a command result (for example the one IMPORT DATABASE returns) holds its own values and stays readable, so it can be read after the database is closed. See Database.close().

Closing is not only memory hygiene: since 26.10.1's parallel scan (ArcadeData/arcadedb#8524) a query whose LIMIT is satisfied keeps its scan's producer threads parked until its result set is closed or arcadedb.parallelScanAbandonedTimeout (10 minutes) passes, and a few such result sets stall the next query that needs those threads (ArcadeData/arcadedb#8594). 26.10.1 development wheels built before 2026-09-28 closed nothing on exhaustion, so RID-paged reads (WHERE @rid > <last> LIMIT n) stalled on their fifth page on 8 cores. The 26.9.1 release does not have that parallel scan and is not affected.

ResultSet is also a context manager (__enter__/__exit__), so with blocks close it automatically.

Example:

# Explicit close
result_set = db.query("sql", "SELECT FROM User")
names = [r.get("name") for r in result_set]
result_set.close()

# Context-manager usage (closes automatically)
with db.query("sql", "SELECT FROM User") as result_set:
    for result in result_set:
        print(result.get("name"))

Result Class

Represents a single result row/record from a query.

Creation

Result objects are created automatically when iterating a ResultSet:

result_set = db.query("sql", "SELECT FROM Person")

# Each iteration gives you a Result
for result in result_set:
    # result is a Result object
    pass

get(name: str, convert_types: bool = True) -> Any

Get the value of a property by name.

Parameters:

  • name (str): Property name
  • convert_types (bool): Convert Java types to Python types (default: True)

Returns:

  • Any: Property value (type depends on the data), or None if property doesn't exist
    • Automatically converts Java types to Python types
    • Java Boolean → Python bool
    • Java Integer/Long → Python int
    • Java Float/Double → Python float
    • Java String → Python str
    • Java collections → Python lists/dicts

Example:

result_set = db.query("sql", "SELECT name, age, active FROM User")

for result in result_set:
    name = result.get("name")     # str
    age = result.get("age")       # int
    active = result.get("active") # bool (converted from Java Boolean)

    print(f"{name} is {age} years old, active: {active}")

    # Handle optional properties with fallback
    email = result.get("email") or "unknown@example.com"
    print(f"Email: {email}")

get_raw(name: str) -> Any

Get a property value without Java-to-Python conversion.

Parameters:

  • name (str): Property name

Returns:

  • Raw Java-backed property value, or None if the property doesn't exist

Example:

result = db.query("sql", "SELECT FROM User LIMIT 1").first()
java_value = result.get_raw("created_at")  # Java object, no conversion

has_property(name: str) -> bool

Check if a property exists in the result.

Parameters:

  • name (str): Property name to check

Returns:

  • bool: True if property exists, False otherwise

Example:

result_set = db.query("sql", "SELECT * FROM Person")

for result in result_set:
    if result.has_property("email"):
        email = result.get("email")
        print(f"Email: {email}")
    else:
        print("No email address")

get_property_names() -> List[str]

Get list of all property names in the result.

Returns:

  • List[str]: List of property names

Example:

result_set = db.query("sql", "SELECT * FROM Document LIMIT 1")

for result in result_set:
    properties = result.get_property_names()
    print(f"Properties: {', '.join(properties)}")

    for prop in properties:
        value = result.get(prop)
        print(f"  {prop}: {value}")

property_names -> List[str]

Property (attribute-style) equivalent of get_property_names(): all property names in this result.

Returns:

  • List[str]: List of property names

Example:

result = db.query("sql", "SELECT FROM User LIMIT 1").first()
print(result.property_names)
# ['name', 'email', 'age', 'created_at']

get_rid() -> Optional[str]

Get the Record ID (RID) of the result, if available.

Returns:

  • str (e.g. "#10:5") or None

Example:

result = db.query("sql", "SELECT FROM User LIMIT 1").first()
print(result.get_rid())
# #10:5

to_dict(convert_types: bool = True) -> Dict[str, Any]

Convert the result to a Python dictionary.

Parameters:

  • convert_types (bool): Convert Java types to Python types (default: True)

Returns:

  • Dict[str, Any]: Dictionary with property names as keys

Example:

result_set = db.query("sql", "SELECT name, age, city FROM Person")

# Convert all results to list of dicts
people = [result.to_dict() for result in result_set]

for person in people:
    print(person)
    # {'name': 'Alice', 'age': 30, 'city': 'NYC'}

Use Cases:

  • Converting to pandas DataFrame
  • Serialization to JSON (via json.dumps())
  • Passing data to other libraries
  • Debugging/inspection

Performance note: to_dict() converts the whole row in one call into Java, which is cheaper than one get() per property when you need several fields. For large result sets, the bulk methods are faster than any per-row access: to_json_list(), to_columns(), to_dataframe(), or to_arrow().


to_json() -> str

Convert the result to a JSON string.

Returns:

  • str: JSON representation of the result

Example:

result_set = db.query("sql", "SELECT * FROM Product WHERE price > 100")

for result in result_set:
    json_str = result.to_json()
    print(json_str)
    # {"@rid":"#1:0","@type":"Product","name":"Laptop","price":999.99}

Note: The JSON includes ArcadeDB metadata like @rid (record ID) and @type (type name).

Note: Array/list properties are serialized as JSON arrays in to_json().


Common Patterns

Converting to Lists and Dicts

ResultSet.to_list() and Result.to_dict() are eager materializers. They are the right choice when you explicitly want Python-native data, but they are not the lowest-overhead path for large result sets.

# List of dictionaries (most common)
result_set = db.query("sql", "SELECT FROM User")
users = [result.to_dict() for result in result_set]

# List of specific property values
result_set = db.query("sql", "SELECT name FROM User")
names = [result.get("name") for result in result_set]

# Dictionary keyed by ID
result_set = db.query("sql", "SELECT id, name FROM User")
user_map = {
    result.get("id"): result.get("name")
    for result in result_set
}

Pandas Integration

import arcadedb_embedded as arcadedb

db = arcadedb.open_database("./mydb")

# Query and convert to DataFrame (columnar path; requires pandas)
df = db.query("sql", "SELECT name, age, city FROM Person").to_dataframe()

print(df.head())
#      name  age    city
# 0   Alice   30     NYC
# 1     Bob   25      LA
# 2 Charlie   35  Boston

Processing Large Result Sets

For memory efficiency with large datasets:

# Stream one row at a time when you only need a few fields
result_set = db.query("sql", "SELECT name, email FROM LargeTable")

for result in result_set:
    process_row(result.get("name"), result.get("email"))

# Or process in batches of dicts
for batch in db.query("sql", "SELECT FROM LargeTable").iter_chunks(size=1000):
    process_batch(batch)

# Faster, with JSON-native values (DATE and DATETIME as epoch-millisecond
# integers, DECIMALs as floats)
for batch in db.query("sql", "SELECT FROM LargeTable").iter_json_batches():
    process_batch(batch)

Conditional Property Access

result_set = db.query("sql", "SELECT * FROM Product")

for result in result_set:
    # Safely get optional properties
    discount = (
        result.get("discount")
        if result.has_property("discount")
        else 0.0
    )

    price = result.get("price")
    final_price = price * (1 - discount)
    print(f"Price: ${final_price:.2f}")

Extracting RIDs and Types

result_set = db.query("sql", "SELECT FROM Person")

for result in result_set:
    # Get ArcadeDB metadata (a SELECT without a projection has no "@rid" column,
    # so get("@rid") would return None)
    rid = result.get_rid()                            # Record ID (e.g., "#1:0")
    rec_type = result.get_element().get_type_name()   # Type name (e.g., "Person")

    # Get user properties
    name = result.get("name")

    print(f"[{rid}] {rec_type}: {name}")

Converting Results to Vertices for Modification

Query results are read-only by default. To modify a vertex or edge returned from a query, get its Vertex or Edge object with .get_vertex() or .get_edge(), then call .modify() on it for a mutable copy. The object from .get_vertex() or .get_edge() is itself immutable: calling .set() on it raises AttributeError.

get_vertex() -> Optional[Vertex]

Get the Vertex object of a Result (if the result is a vertex). Call .modify() on it before .set().

import arcadedb_embedded as arcadedb

db = arcadedb.open_database("./mydb")

# Query returns read-only Results
result_set = db.query("sql", "SELECT FROM Person WHERE name = 'Alice'")

with db.transaction():
    for result in result_set:
        # Get the Vertex, then a mutable copy of it
        vertex = result.get_vertex()

        if vertex:
            vertex = vertex.modify()
            # Now you can modify it
            vertex.set("age", 31)
            vertex.set("updated", True)
            vertex.save()

            print(f"Updated: {result.get('name')}")

get_edge() -> Optional[Edge]

Get the Edge object of a Result (if the result is an edge). Call .modify() on it before .set().

# Query edges
result_set = db.query("sql", "SELECT FROM FRIEND_OF")

with db.transaction():
    for result in result_set:
        # Get the Edge, then a mutable copy of it
        edge = result.get_edge()

        if edge:
            edge = edge.modify()
            edge.set("strength", 0.95)
            edge.save()

get_element() -> Optional[Document]

Get the underlying element regardless of kind. Returns the matching wrapper (Document, Vertex, or Edge) or None if the result carries no element (e.g. a projection or aggregation row).

result_set = db.query("sql", "SELECT FROM Person")

with db.transaction():
    for result in result_set:
        element = result.get_element()
        if element:
            print(element.get_rid(), element.get_type_name())

Full Example: Bulk Update with Caching

import arcadedb_embedded as arcadedb

db = arcadedb.open_database("./mydb")

# Query all movies
movies = list(db.query("sql", "SELECT FROM Movie"))
print(f"Processing {len(movies)} movies...")

with db.transaction():
    for movie_result in movies:
        # Get the vertex, then a mutable copy of it
        movie = movie_result.get_vertex()

        if not movie:
            continue

        movie = movie.modify()

        # Modify the vertex
        title = movie_result.get("title")

        # Add embedding or update properties
        movie.set("processed", True)
        movie.set("updated_at", "2024-01-02")
        movie.save()

        print(f"✓ Updated: {title}")

db.close()

Key Distinction:

Object Read Write
Result (from query) ✅ Yes ❌ No
Vertex/Edge from .get_vertex()/.get_edge() ✅ Yes After .modify()
Created with db.new_vertex() ✅ Yes ✅ Yes
Looked up with db.lookup_by_rid() ✅ Yes After .modify()

Complete Examples

User Search and Display

import arcadedb_embedded as arcadedb

db = arcadedb.open_database("./users_db")

def search_users(name_pattern):
    """Search users by name pattern."""
    query = """
        SELECT name, email, created_at
        FROM User
        WHERE name LIKE ?
        ORDER BY name
    """

    result_set = db.query("sql", query, f"%{name_pattern}%")
    users = []

    for result in result_set:
        user = {
            'name': result.get("name"),
            'email': result.get("email"),
            'created_at': result.get("created_at")
        }
        users.append(user)

    return users

# Search
results = search_users("John")

print(f"Found {len(results)} users:")
for user in results:
    print(f"  {user['name']} <{user['email']}>")

db.close()

Graph Traversal Results

import arcadedb_embedded as arcadedb

db = arcadedb.open_database("./social_graph")

# Find friends of friends
query = """
    SELECT
        @rid as person_rid,
        name,
        out('Follows').out('Follows').name as friends_of_friends
    FROM Person
    WHERE name = 'Alice'
"""

result_set = db.query("sql", query)

for result in result_set:
    person_name = result.get("name")
    friends_of_friends = result.get("friends_of_friends")

    print(f"{person_name}'s extended network:")

    # get() has already converted the Java collection to a Python list
    if friends_of_friends:
        for friend in friends_of_friends:
            print(f"  - {friend}")

db.close()

Aggregation Results

import arcadedb_embedded as arcadedb

db = arcadedb.open_database("./analytics_db")

# Group by and aggregation
query = """
    SELECT
        category,
        COUNT(*) as product_count,
        AVG(price) as avg_price,
        MAX(price) as max_price
    FROM Product
    GROUP BY category
    ORDER BY product_count DESC
"""

result_set = db.query("sql", query)

print("Product Statistics by Category:")
print("-" * 60)

for result in result_set:
    category = result.get("category")
    count = result.get("product_count")
    avg_price = result.get("avg_price")
    max_price = result.get("max_price")

    print(f"{category}:")
    print(f"  Products: {count}")
    print(f"  Avg Price: ${avg_price:.2f}")
    print(f"  Max Price: ${max_price:.2f}")
    print()

db.close()

Export to JSON File

import arcadedb_embedded as arcadedb
import json

db = arcadedb.open_database("./mydb")

# Export query results to JSON file
result_set = db.query("sql", "SELECT * FROM Document")

# Method 1: Using to_dict()
documents = [result.to_dict() for result in result_set]

with open("export.json", "w") as f:
    json.dump(documents, f, indent=2, default=str)

# Method 2: Using to_json() directly
result_set = db.query("sql", "SELECT * FROM Document")

with open("export_raw.jsonl", "w") as f:
    for result in result_set:
        f.write(result.to_json() + "\n")

db.close()

Cypher Query Results

import arcadedb_embedded as arcadedb

db = arcadedb.open_database("./graph_db")

# OpenCypher queries also return ResultSet
cypher_query = """
    MATCH (p:Person)-[:WORKS_AT]->(c:Company)
    WHERE c.name = 'TechCorp'
    RETURN p.name AS employee, p.role AS position
"""

result_set = db.query("opencypher", cypher_query)

print("TechCorp Employees:")
for result in result_set:
    employee = result.get("employee")
    position = result.get("position")
    print(f"  {employee} - {position}")

db.close()

Error Handling

from arcadedb_embedded import ArcadeDBError

result_set = db.query("sql", "SELECT * FROM Person")

for result in result_set:
    try:
        # Safe property access
        name = result.get("name")

        # May not exist
        if result.has_property("phone"):
            phone = result.get("phone")
        else:
            phone = "N/A"

        print(f"{name}: {phone}")

    except ArcadeDBError as e:
        print(f"Error accessing properties: {e}")
        continue

Type Handling

get(), to_dict(), and to_list() convert Java values to Python types automatically (Boolean to bool, BigDecimal to Decimal, dates to date and datetime, collections to list, set, and dict). See Type Conversion for the full table.


Performance Tips

Minimize Property Access

# Less efficient: Multiple property accesses
for result in result_set:
    if result.get("age") > 25:
        name = result.get("name")
        age = result.get("age")
        print(f"{name}: {age}")

# More efficient: Access once, reuse
for result in result_set:
    age = result.get("age")
    if age > 25:
        name = result.get("name")
        print(f"{name}: {age}")

Use to_dict() for Multiple Properties

# When accessing many properties, convert to dict once
for result in result_set:
    data = result.to_dict()

    # Now access from Python dict (faster)
    process(
        data["name"],
        data["age"],
        data["email"],
        data["phone"]
    )

Stream Processing

# Don't collect all results if you can process incrementally
result_set = db.query("sql", "SELECT * FROM LargeTable")

# Process as you iterate (memory efficient)
total = 0
for result in result_set:
    value = result.get("amount")
    total += value

# Better than:
# results = list(result_set)  # Loads everything into memory

See Also