Declarative Interface

The acid.meta module provides an ORM-like metaclass that simplifies definition of database models using Python code.

Warning

This is a work in progress! The examples here do not yet work perfectly, and the most interesting aspect is missing. A future version will use the model definitions to automatically maintain a compact encoding. For now this module is mainly a curiosity.

import acid
import acid.meta


class Base(acid.meta.Model):
    """Base for models belonging to this program. Can be used to add common
    fields, and to bind all subclasses to a particular acid.Store with a
    single call."""


class User(Base):
    email = acid.meta.Field('string')
    first = acid.meta.Field('string')
    last = acid.meta.Field('string')
    age = acid.meta.Field('ivar')

    @acid.meta.constraint
    def sane_age(self):
        """Ensure the user's age is 1..149 if they provided it."""
        return self.age is None or (0 < self.age < 150)


class Item(Base):
    user_id = acid.meta.Field('ivar')
    data = acid.meta.Field('bytes')

    @acid.meta.constraint
    def sane_user_id(self):
        """Ensure a User model exists for user_id."""
        return User.get(self.user_id) is not None


def main():
    Base.bind_store(acid.open('ListEngine'))

    user = User(email='john@example.com', first='John')
    user.save()

    user = User.get(1)
    print 'Saved user:', user

if __name__ == '__main__':
    main()

Model class

class acid.meta.Model(**kwargs)

Inherit from this class to add fields to the basic model.

classmethod bind_store(store)

Bind this class and all subclasses to a acid.Store, clearing any cached references to the previous store, if any.

store = acid.open('ListEngine')
MyModel.bind_store(store)
classmethod collection()

Return the acid.Collection used to store instances of this model. The collection handles objects understood by the underlying encoder, not Model instances.

bind_store() must be called before accessing this property.

delete()

Delete the model if it has been saved.

classmethod find(key=None, lo=None, hi=None, prefix=None, reverse=None, include=False, raw=False)

Fetch the first matching instance; see acid.Collection.find().

classmethod get(key)

Fetch an instance given its key; see acid.Collection.get().

classmethod iter(key=None, lo=None, hi=None, prefix=None, reverse=None, max=None, include=False, raw=False)

Yield matching models in key order; see acid.Store.values().

save()

Create or update the model in the database.

is_saved

True if the model has been saved already.

class acid.meta.BaseModel(**kwargs)

Basic model class implementation. This exists separately from Model to allow clean subclassing of the ModelMeta metaclass.

Field Classes

class acid.meta.Field(ftype, default=None)

Base class for all field types.

class acid.meta.List(ftype)

A list field.

Primitive Types

bool
Fixed boolean, either True or False. Encodes to 1 byte (+ tag) using the default Protocol Buffer encoding, or n+taglen bytes when used in a list.
double
Fixed 64-bit floating point. Encodes to 8 bytes (+ tag) using the default Protocol Buffer encoding, or (n*4)+taglen bytes when used in a list.
float
Fixed 32-bit floating point. Encodes to 4 bytes (+ tag) using the default Protocol Buffer encoding, or (n*4)+taglen when used in a list.
fraction
pass
decimal
pass
i32
Fixed 32-bit signed integer. Encodes to 4 bytes (+ tag) using the default Protocol Buffer encoding, or (n*4)+taglen when used in a list.
i64
Fixed 64-bit signed integer. Encodes to 4 bytes (+ tag) using the default Protocol Buffer encoding, or (n*4)+taglen when used in a list.
u32
Fixed 32-bit unsigned integer. Encodes to 4 bytes (+ tag) using the default Protocol Buffer encoding, or (n*4)+taglen when used in a list.
u64
Fixed 64-bit unsigned integer. Encodes to 4 bytes (+ tag) using the default Protocol Buffer encoding, or (n*4)+taglen when used in a list.
ivar
Variable-length 64-bit signed integer. Encodes to between 1 and 10 bytes using the default Protocol Buffer encoding. Negative numbers always encode to 10 bytes; use svar for efficient negative representation.
svar
Variable-length 64-bit signed, zig-zag integer. Encodes to between 1 and 10 bytes using the default Protocol Buffer encoding. Negative numbers are represented efficiently by interleaving them with the positive representation.
uvar
Variable-length 64-bit unsigned integer. Encodings to between 1 and 10 bytes using the default Protocol Buffer encoding.
inet4
Fixed 32-bit IPv4 address, represented as a Python string NNN.NNN.NNN.NNN. Encodes to 4 bytes (+ tag) using the default Protocol Buffer encoding, or (n*4)+taglen when used in a list.
inet4port
pass
inet6
pass
inet6port
pass
json
Any object that can be encoded using the Python JSON encoder. Encodes to variable-length string.
pickle
Any object that can be encoded using the Python pickle encoder. Encodes to variable-length string.
bytes
Variable-length bytestring. Encodes to len+varintlen+taglen bytes using the default Protocol Buffer encoding.
string
Variable-length Unicode string. Encodes to len+varintlen+taglen bytes using the default Protocol Buffer encoding.
uuid
Fixed 128-bit UUID, represented as a Python uuid.UUID. Encodes to len+varintlen+taglen bytes using the default Protocol Buffer encoding.

Specifying an index

acid.meta.index()

Mark a function as an index for the model. The function will be called during update to produce secondary indices for each item.

See acid.Index for more information on the function’s return value.

Once the model class has been constructed, accessing Model.func_name will return a acid.Index instance representing the index. The original function can still be accessed via acid.Index.func.

class Person(meta.Model):
    age = meta.Integer()

    @meta.index
    def by_age(self):
        return self.age


# Count all people 22 or older.
print('Total people older than 22:', Person.by_age.count(lo=22))

# Fetch youngest and oldest people.
youngest = Person.by_age.find()
oldest = Person.by_age.find(reverse=True)

Specifying a key function

acid.meta.key()

Mark a function as the model’s primary key function.

@meta.key
def key_func(self):
    return int(time.time() * 1000)