Skip to main content

SQLAlchemy dialect and Active Record ORM for SEMOSS databases

Project description

sqlalchemy-semoss

PyPI version Python License: MIT

SQLAlchemy dialect and Active Record ORM for SEMOSS databases.

Makes SEMOSS's ai_server.DatabaseEngine accessible through standard Python database interfaces — PEP 249 DB-API 2.0, SQLAlchemy dialect, and an Active Record ORM with save(), get(), find(), all(), and where().

Architecture

Your Application
       │
   sqlalchemy_semoss.orm        Active Record (save/delete/get/find/where)
       │
   sqlalchemy_semoss.dialect    SQLAlchemy Dialect (extends PGDialect)
       │
   sqlalchemy_semoss.dbapi      PEP 249 DB-API 2.0 (Connection, Cursor)
       │
   ai_server.DatabaseEngine     SEMOSS runtime (execQuery, insertData, ...)
       │
   PostgreSQL / RDBMS           Actual database

Installation

pip install sqlalchemy-semoss

Note: The ai_server module is provided by the SEMOSS runtime and does not need to be installed separately when running inside SEMOSS. For external development/testing, install pip install ai-server-sdk.

Quick Start

1. Raw DB-API

Use the PEP 249 interface directly for full control:

from sqlalchemy_semoss import connect

conn = connect(engine_id="your-engine-uuid")
cursor = conn.cursor()

cursor.execute("SELECT * FROM users WHERE active = %s", (True,))
for row in cursor.fetchall():
    print(row)

cursor.close()
conn.close()

2. Active Record ORM

Define models with SQLAlchemy columns, then use Rails-style methods:

from sqlalchemy_semoss import configure, SemossModel
from sqlalchemy import Column, Integer, String, DateTime

# Call once at startup
configure("your-engine-uuid")

class User(SemossModel):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)
    email = Column(String(255))

# Create
user = User(name="Alice", email="alice@example.com")
user.save()
print(user.id)  # auto-populated via RETURNING

# Read
user = User.get(1)                          # by primary key
users = User.find(name="Alice")             # by conditions
all_users = User.all()                      # all records
count = User.count(name="Alice")            # count

# Query builder
users = (User.where(active=True)
             .order_by("-created_at")
             .limit(10)
             .all())

first = User.where(name="Alice").first()

# Update
user.name = "Bob"
user.save()

# Delete
user.delete()

3. SQLAlchemy Engine

Use the dialect directly with SQLAlchemy's create_engine:

from sqlalchemy_semoss import create_engine

engine = create_engine("your-engine-uuid")

# Or via URL string (works after pip install due to entry-point registration):
from sqlalchemy import create_engine as sa_create_engine
engine = sa_create_engine("semoss://your-engine-uuid")

Building Framework Adapters

The DB-API layer (connect, SemossCursor) provides everything needed to build integrations with frameworks like APScheduler, LangGraph, Celery, etc.

from sqlalchemy_semoss import connect

conn = connect(engine_id="your-engine-uuid")
cursor = conn.cursor()

# Execute any SQL
cursor.execute("CREATE TABLE IF NOT EXISTS jobs (id VARCHAR PRIMARY KEY, state TEXT)")
cursor.execute("INSERT INTO jobs (id, state) VALUES (%s, %s)", ("job-1", "pending"))
cursor.execute("SELECT * FROM jobs WHERE id = %s", ("job-1",))
row = cursor.fetchone()

See the SemossDB example app for working APScheduler and LangGraph adapter implementations.

API Reference

Module-Level Functions

Function Description
connect(engine_id, insight_id=None) Create a DB-API 2.0 connection
configure(engine_id, **kwargs) Initialize the ORM (call once at startup)
create_engine(engine_id, **kwargs) Create a SQLAlchemy Engine
get_session() Get a new SQLAlchemy Session
get_engine() Get the configured SQLAlchemy Engine

Classes

Class Description
SemossConnection DB-API 2.0 Connection (wraps DatabaseEngine)
SemossCursor DB-API 2.0 Cursor (execute, fetch, iterate)
SemossDialect SQLAlchemy dialect (extends PGDialect)
SemossModel Active Record base class (extend for your models)
SemossBase SQLAlchemy DeclarativeBase (for advanced use)
QueryBuilder Chainable query builder (returned by Model.where())

Active Record Methods

Instance methods:

Method Description
save() INSERT (new) or UPDATE (existing). Returns self.
delete() DELETE this record.

Class methods:

Method Description
Model.get(pk) Find by primary key. Returns instance or None.
Model.find(**kwargs) Find all matching conditions (AND).
Model.all() Return all records.
Model.count(**kwargs) Count matching records.
Model.where(**kwargs) Start a chainable QueryBuilder.

QueryBuilder methods:

Method Description
.where(**kwargs) Add filter conditions (AND).
.order_by(*cols) Order results. Prefix with - for DESC.
.limit(n) Limit results.
.offset(n) Skip first n results.
.all() Execute and return all matches.
.first() Execute and return first match or None.
.count() Execute and return count.

How It Works

SQL Routing

The SEMOSS DatabaseEngine exposes four methods. The driver classifies each SQL statement and routes it accordingly:

SQL Type Method Called
SELECT, WITH, SHOW, EXPLAIN database.execQuery(query=sql)
INSERT database.insertData(query=sql)
UPDATE database.updateData(query=sql)
DELETE, TRUNCATE database.removeData(query=sql)
CREATE, ALTER, DROP database.execQuery(query=sql)

INSERT ... RETURNING: DML statements with a RETURNING clause are routed through execQuery (not insertData) since they return a result set. This is how save() populates auto-generated fields like primary keys.

Parameter Interpolation

Since DatabaseEngine methods accept only final SQL strings, parameters are interpolated before execution. The cursor handles escaping of strings, numbers, dates, booleans, bytes, and None (→ NULL).

Auto-Commit

SEMOSS database operations auto-commit individually. commit() and rollback() are no-ops.

Limitations

  • No transactions — each operation auto-commits; rollback is not supported
  • No SQLAlchemy session queriessession.execute(select(Model)) is not supported; use Active Record methods instead
  • No relationshipsrelationship() and ForeignKey joins are not supported through Active Record
  • No server-side cursors — results are fetched eagerly in one RPC call
  • Schema reflection — best-effort via information_schema; may not work on all SEMOSS backends

Contributing

Contributions are welcome! Please open an issue or pull request on GitHub.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqlalchemy_semoss-0.1.1.tar.gz (19.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sqlalchemy_semoss-0.1.1-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

Details for the file sqlalchemy_semoss-0.1.1.tar.gz.

File metadata

  • Download URL: sqlalchemy_semoss-0.1.1.tar.gz
  • Upload date:
  • Size: 19.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.8

File hashes

Hashes for sqlalchemy_semoss-0.1.1.tar.gz
Algorithm Hash digest
SHA256 444fe3fec1125ffe50e55d435947496cc9046bd34e51d423086bc751ef084dca
MD5 ee2f2fdf4e53aaa895a3660b22d01d7f
BLAKE2b-256 8ee1bf395ad766fa6ca3f3fbc900b766e9be4b8fd023a6ebcbe3a5c4106c5531

See more details on using hashes here.

File details

Details for the file sqlalchemy_semoss-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for sqlalchemy_semoss-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1c224eefc1aca4d996fbb7de3bf6a88785abd26247e9944e6687feaa7c9963e3
MD5 3e5d7d8391439b02e38598bb5a0ece30
BLAKE2b-256 67ead86dacfa5d1af0b3049df244578e0df5873840840bf6d1ed43c5e83e02c5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page