Architecture
Storage
Overview of the Cortex storage layer and SQL connectors.
Overview
Cortex provides a pluggable storage layer for SQL databases while keeping the public API stable. The entry point is CortexStorage, which exposes get_session() for SQLAlchemy sessions and client for a simple query API. Under the hood, storage delegates to connector clients created by a small factory service.
cortex.core.storage.store.CortexStorage: main storage facade used across the appcortex.core.connectors.databases.clients.service.DBClientService: builds a database client from configuration- SQL connectors that currently back storage:
CommonProtocolSQLClientfor network databases (PostgreSQL, MySQL)SQLiteClientfor file-based or in-memory SQLite
Architecture
graph TD
A[Application Code] -->|get_session()/client| B[CortexStorage]
B --> C[DBClientService]
C --> D[CommonProtocolSQLClient (PG/MySQL)]
C --> E[SQLiteClient]
D --> F[SQLAlchemy Engine/Connection]
E --> F
Key modules
cortex/core/storage/store.py- Reads environment (
CORTEX_DB_*) and selects the backend - Provides
get_session()returning a SQLAlchemy session - Exposes
.clientfor a thin query API (query,fetch_all,fetch_one,stream) Basepoints tocortex.core.storage.sqlalchemy.BaseDBModelfor migrations
- Reads environment (
cortex/core/storage/sqlalchemy.py- Defines
BaseDBModeland a Postgres-friendly naming convention for constraints/indexes
- Defines
cortex/core/connectors/databases/clients/service.py- Factory that returns the right client based on the resolved
DataSourceTypes
- Factory that returns the right client based on the resolved
cortex/core/connectors/databases/clients/SQL/common_protocol.pyCommonProtocolSQLClient(PostgreSQL/MySQL via SQLAlchemy): engine creation, pooling, session factory, query helpers
cortex/core/connectors/databases/clients/SQL/sqlite.pySQLiteClient(SQLite via SQLAlchemy): engine creation withcheck_same_thread=False, PRAGMA setup, introspection
Supported storage backends
- PostgreSQL
- MySQL
- SQLite (file-based or in-memory)
Configure via environment variables
Set the following variables (all prefixed with CORTEX_) to select and configure the storage backend. The storage layer reads these via ExecutionEnv.get_key.
Common
CORTEX_DB_TYPE: one ofpostgresql,mysql,sqlite
PostgreSQL/MySQL
CORTEX_DB_HOSTCORTEX_DB_PORTCORTEX_DB_USERNAMECORTEX_DB_PASSWORDCORTEX_DB_NAME
Example (PostgreSQL):
local.env
CORTEX_DB_TYPE=postgresql
CORTEX_DB_HOST=localhost
CORTEX_DB_PORT=5432
CORTEX_DB_USERNAME=postgres
CORTEX_DB_PASSWORD=postgres
CORTEX_DB_NAME=cortex
SQLite
For SQLite, configure either in-memory mode or a file path.
CORTEX_DB_MEMORY:trueorfalseCORTEX_DB_FILE: file path (used when memory is false)
Example (SQLite file):
local.env
CORTEX_DB_TYPE=sqlite
CORTEX_DB_MEMORY=false
CORTEX_DB_FILE=./cortexstore.db
Example (SQLite in-memory):
local.env
CORTEX_DB_TYPE=sqlite
CORTEX_DB_MEMORY=true
Using the storage layer
Obtain a SQLAlchemy session
from cortex.core.storage.store import CortexStorage
session = CortexStorage().get_session()
try:
# use session with ORM or Core
...
finally:
session.close()
Use the connector client directly
from cortex.core.storage.store import CortexStorage
client = CortexStorage().client # CommonProtocolSQLClient or SQLiteClient
# Fetch all rows as lists of mappings
rows = client.fetch_all("SELECT 1 AS one")
# Fetch single row
row = client.fetch_one("SELECT 42 AS answer")
# Stream in chunks
for chunk in client.stream("SELECT * FROM some_table", chunk_size=500):
...
Migrations and metadata
- Alembic uses
CortexStorage().Base.metadataas the target metadata. - For SQLite, Alembic is configured in batch mode in
cortex/migrations/alembic/env.pyso constraint-altering operations are supported via copy-and-recreate. - File paths for SQLite are normalized to absolute paths during migrations.
- Migrations are bundled inside the
cortexpackage atcortex/migrations/for seamless deployment.