Skip to content
This repository


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

SQLAlchemy Dialect and ORM Extension for Akiban Server

branch: master

Fetching latest commit…


Cannot retrieve the latest commit at this time

Octocat-spinner-32 sqlalchemy_akiban add get_table_names(), and a not-yet-practical get foreign keys November 26, 2012
Octocat-spinner-32 test add new exclusions November 26, 2012
Octocat-spinner-32 .gitignore initial commit. September 29, 2012
Octocat-spinner-32 README.rst add an import October 26, 2012
Octocat-spinner-32 - move dialect into a package October 04, 2012
Octocat-spinner-32 setup.cfg - rename this to sqlalchemy_akiban September 30, 2012
Octocat-spinner-32 write the README October 26, 2012


SQLAlchemy-Akiban provides a SQLAlchemy dialect for Akiban, as well as a Core/ORM extension library allowing direct control of Akiban nested SELECT statements and result sets.


SQLAlchemy-Akiban depends on:

  • Akiban for Python - this is an extension for the psycopg2 DBAPI, in order to provide nested result support.
  • SQLAlchemy 0.8 - The dialect has been developed against SQLAlchemy 0.8, which has one small API change to support nested result sets. Less critically it also supports generation of a WHERE clause using an ORM relationship attribute (see the example in ORM->Explicit Nesting).


Connect format is similar to that of a regular Postgresql database:

from sqlalchemy import create_engine

engine = create_engine("akiban+psycopg2://@localhost:15432/")

The Engine above will produce connections when the Engine.connect method is called.

Nested Result Sets

The dialect introduces a new type called NestedResult, the value of which is a new SQLAlchemy ResultProxy representing a nested result:

with engine.begin() as conn:
    result = conn.execute(
                "SELECT, "
                "(SELECT, "
                "FROM order "
                "WHERE AS order "
                "FROM customer")
    for row in result:
        print "customer id:", row['id']
        for order_row in row['order']:
            print "order id:", order_row['id']
            print "order data:", order_row['data']

DDL Integration

Currently, Akiban requires the GROUPING keyword on all foreign keys. The dialect adds this keyword when emitting DDL for foreign keys:

from sqlalchemy import MetaData, Table, Column, String, Integer, ForeignKey
metadata = MetaData()
customer = Table('customer',
    Column('id', Integer, primary_key=True),
    Column('name', String(20)),

order = Table('order',
    Column('id', Integer, primary_key=True),
    Column('customer_id', Integer, ForeignKey('')),
    Column('order_info', String(20)),


Will emit DDL like:

CREATE TABLE customer (
    name VARCHAR(20) NULL,
    PRIMARY KEY (id)

CREATE TABLE "order" (
    customer_id INTEGER NULL,
    order_info VARCHAR(20) NULL,
    PRIMARY KEY (id),
    GROUPING FOREIGN KEY(customer_id) REFERENCES customer (id)

Nested Select Constructs

Moving up a level, the dialect introduces a new Core construct nested which is an extension of SQLAlchemy's "scalar select" construct. This construct is a drop-in replacement for a standard select() subquery, and is a marker intercepted by the Akiban dialect indicating that column and typing information about a "nested result" should be carried over from statement to result set:

from sqlalchemy import select
from sqlalchemy_akiban import nested

sub_stmt = nested([order]).where(order.c.customer_id
stmt = select([sub_stmt]).where( == 1)

result = conn.execute(stmt)

The above will produce SQL like the following:

    (SELECT "order".id, "order".customer_id,
    FROM "order" WHERE "order".customer_id = AS o
FROM customer WHERE = %(id_1)s

Within the result set, nested columns will be targetable not just by column name but also by column object, and any SQLAlchemy-side type converters in place will take effect for these columns:

for row in result:
    print "customer id:", row[]
    for order_row in row['order']:
        print "order id:", order_row[]
        print "order data:", order_row[]

ORM Integration

SQLAlchemy-Akiban includes ORM extensions, importable from the sqlalchemy_akiban.orm package.

Nested Eager Loading

The orm.nestedload() and orm.nestedload_all() provide relationship eager loading making usage of an embedded nested result. These are used just like SQLAlchemy's own orm.joinedload() and orm.subqueryload() functions:

from sqlalchemy.orm import relationship, Session
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_akiban import orm

Base = declarative_base()

class Customer(Base):
    __table__ = customer
    orders = relationship("Order")

class Order(Base):
    __table__ = order

sess = Session(engine)

for customer in sess.query(Customer).options(orm.nestedload(Customer.orders)):
    print "customer:",
    print "orders:", customer.orders

Explicit Nesting

The orm.orm_nested() function acts just like the core nested() construct, except that it is ORM-aware and accepts a Query object; it will invoke Query style loading, nested into the tuples returned by Query:

sess = Session()

n = orm.orm_nested(sess.query(, Order).filter(Customer.orders))

q = sess.query(Customer, n).filter( == 1)

for customer, orders in q:
    print "customer:",
    print "orders:", orders

Above, we're taking advantage of a new convenience feature in SQLAlchemy 0.8, which is that we can pass the Customer.orders class-level attribute directly to Query.filter() in order to generate a correlated WHERE clause. Alternatively, we could just spell this out:

Something went wrong with that request. Please try again.