Skip to content

Record and RecordCollection

Record

A Record represents a single row from a query result. It provides multiple ways to access column values.

Accessing Values

row = db.query('SELECT empno, firstname, lastname FROM employees').one()

# By column name (dictionary-style)
print(row['firstname'])

# By attribute
print(row.firstname)

# By column index (0-based)
print(row[0])  # empno
print(row[1])  # firstname

# With a default value
print(row.get('middle_name', 'N/A'))

Getting Keys and Values

row = db.query('SELECT empno, firstname, lastname FROM employees').one()

print(row.keys())    # ['empno', 'firstname', 'lastname']
print(row.values())  # ['000010', 'CHRISTINE', 'HAAS']

Conversion Methods

row = db.query('SELECT empno, firstname FROM employees').one()

# To dictionary
d = row.as_dict()
# {'empno': '000010', 'firstname': 'CHRISTINE'}

# To tuple
t = row.as_tuple()
# ('000010', 'CHRISTINE')

# To list
l = row.as_list()
# ['000010', 'CHRISTINE']

# To JSON string
j = row.as_json()
# '{"empno": "000010", "firstname": "CHRISTINE"}'

# To JSON with formatting options
j = row.as_json(indent=2)

Pydantic Model Conversion

Map a record to a Pydantic model:

from pydantic import BaseModel

class Employee(BaseModel):
    empno: str
    firstname: str
    lastname: str

row = db.query('SELECT empno, firstname, lastname FROM employees').one()
emp = row.as_model(Employee)
print(emp.firstname)  # CHRISTINE

The as_model() method also works with Python dataclasses or any class that accepts keyword arguments in its constructor.

String Representation

row = db.query('SELECT empno, firstname FROM employees').one()
print(row)
# <Record {"empno": "000010", "firstname": "CHRISTINE"}>

RecordCollection

A RecordCollection is a lazy container of Record objects returned by db.query(). Rows are fetched from the database cursor on demand.

Lazy Evaluation

Rows are only fetched when accessed. This means you can start processing results before the entire query has completed:

rows = db.query('SELECT * FROM large_table')
# No rows fetched yet

first = rows[0]    # Fetches the first row
# Only one row fetched

for row in rows:   # Fetches remaining rows one by one
    process(row)

Iteration

rows = db.query('SELECT * FROM employees')
for row in rows:
    print(row.firstname, row.lastname)

Indexing

rows = db.query('SELECT * FROM employees')

first = rows[0]     # First row
third = rows[2]     # Third row
last = rows[-1]     # Last row (requires fetching all rows)

Slicing

Slicing returns a new RecordCollection:

rows = db.query('SELECT * FROM employees')

first_five = rows[0:5]     # First 5 rows
from_third = rows[2:]      # From third row onward (fetches all)
last_three = rows[-3:]     # Last 3 rows (fetches all)

for row in first_five:
    print(row.firstname)

Length

rows = db.query('SELECT * FROM employees')

# len() returns count of rows fetched so far
print(len(rows))  # 0 (nothing fetched yet)

rows.all()
print(len(rows))  # Total row count

Bulk Conversion

rows = db.query('SELECT * FROM employees')

# All as Record objects
records = rows.all()

# All as dictionaries
dicts = rows.all(as_dict=True)
# or: dicts = rows.as_dict()

# All as tuples
tuples = rows.all(as_tuple=True)
# or: tuples = rows.as_tuple()

# All as JSON strings
json_list = rows.all(as_json=True)
# or: json_list = rows.as_json()

DataFrame Conversion

Convert the entire result set to a Pandas DataFrame:

rows = db.query('SELECT * FROM employees')
df = rows.as_DataFrame()

# Use any Pandas operations
print(df.describe())
print(df.to_csv())
print(df.groupby('department').mean())

Requires pandas to be installed. Raises NotImplementedError with an installation hint if Pandas is missing.

Pydantic Model Conversion

Convert all rows to a list of Pydantic model instances:

from pydantic import BaseModel

class Employee(BaseModel):
    firstnme: str
    lastname: str

rows = db.query('SELECT firstnme, lastname FROM employees')
employees = rows.as_model(Employee)

for emp in employees:
    print(f'{emp.firstnme} {emp.lastname}')

Convenience Methods

one(default=None)

Returns the first record, or default if the result set is empty:

row = db.query('SELECT * FROM employees WHERE id = ?', 42).one()
if row is None:
    print('Employee not found')

scalar(default=None)

Returns the first column of the first row. Ideal for aggregate queries:

count = db.query('SELECT COUNT(*) FROM employees').scalar()
name = db.query('SELECT firstname FROM employees WHERE id = ?', 42).scalar(default='Unknown')

!!! note scalar() automatically closes the cursor after reading the value.

Table Display

When printed, a RecordCollection renders as a formatted table:

rows = db.query('SELECT empno, firstname, lastname FROM employees')
print(rows)
empno |firstname|lastname
------|---------|--------
000010|CHRISTINE|HAAS
000020|MICHAEL  |THOMPSON

Closing a RecordCollection

If you're done with a result set before all rows have been consumed, close it to release the database cursor:

rows = db.query('SELECT * FROM large_table')
first = rows[0]
rows.close()  # Release the cursor

If all rows have been fetched (via iteration, all(), or indexing past the end), the cursor is closed automatically.