Skip to content

Core Concepts

This page gives you the mental model for ApexBase before you dive into the API reference.

Database Root

An ApexClient opens a root directory:

from apexbase import ApexClient

client = ApexClient("./data")

The root directory contains the default database and any named databases. ApexBase stores each table as a .apex file.

Databases

ApexBase supports multiple isolated databases under one root directory. The default database maps to the root directory. Named databases live in subdirectories.

client.use_database("analytics")
client.use(database="analytics", table="events")

print(client.list_databases())
print(client.current_database)

SQL can refer to another database with database.table syntax:

client.execute("""
    SELECT u.name, e.event
    FROM default.users u
    JOIN analytics.events e ON u.id = e.user_id
""")

Tables

Tables are explicit. Create or select a table before using table-scoped methods such as store(), retrieve_all(), and list_fields().

client.create_table("users")
client.use_table("users")

You can also create tables with SQL:

client.execute("CREATE TABLE IF NOT EXISTS users")

Schemas

You may let ApexBase infer column types from the first write, or provide a schema up front for clearer contracts and faster bulk loading.

client.create_table("orders", schema={
    "order_id": "int64",
    "customer": "string",
    "total": "float64",
    "paid": "bool",
})

Records And Columns

ApexBase accepts row-oriented dictionaries, lists of dictionaries, and columnar dictionaries. For bulk ingest, columnar data is usually the fastest path.

client.store({"name": "Alice", "age": 30})

client.store([
    {"name": "Bob", "age": 25},
    {"name": "Charlie", "age": 35},
])

client.store({
    "name": ["Diana", "Eve"],
    "age": [28, 41],
})

Every stored row has an internal _id. SQL hides _id unless you request it explicitly.

ResultView

Queries return a ResultView, which can convert to Python-native rows or columnar DataFrame formats.

result = client.execute("SELECT * FROM users")

rows = result.to_dict()
pandas_df = result.to_pandas()
polars_df = result.to_polars()
arrow_table = result.to_arrow()

Use ResultView when you want to move smoothly between SQL, Python lists, Pandas, Polars, and PyArrow.

Durability

Durability is configured when opening the client:

Mode Best for Behavior
fast Local analytics, scratch data, benchmarks Prioritizes throughput
safe Application data with balanced speed and safety Synchronous writes
max Highest crash safety Fsync on each write
client = ApexClient("./data", durability="safe")

Interfaces

The same storage engine can be reached through several interfaces:

  • Python API for embedded applications and notebooks.
  • Rust embedded API for native Rust applications.
  • PostgreSQL Wire server for SQL clients and database tools.
  • Arrow Flight server for high-throughput columnar result streaming.

Start with the Python API unless you already know you need a wire protocol or Rust integration.