Source code for pacifica.cartd.orm

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Cart Object Relational Model.

Using PeeWee to implement the ORM.
"""
# disable this for classes Cart, File and Meta (within Cart and File)
# pylint: disable=too-few-public-methods
# pylint: disable=invalid-name
import datetime
import time
from peewee import PrimaryKeyField, IntegerField, CharField, DateTimeField
from peewee import ForeignKeyField, TextField, BooleanField
from peewee import Model, OperationalError
from playhouse.migrate import SchemaMigrator, migrate
from playhouse.db_url import connect
from .config import get_config

SCHEMA_MAJOR = 1
SCHEMA_MINOR = 0
DB = connect(get_config().get('database', 'peewee_url'))


[docs]class OrmSync(object): """ Special module for syncing the orm. This module should incorporate a schema migration strategy. The supported versions migrating forward must be in a versions array containing tuples for major and minor versions. The version tuples are directly translated to method names in the orm_update class for the update between those versions. Example Version Control:: class orm_update: versions = [ (0, 1), (0, 2), (1, 0), (1, 1) ] def update_0_1_to_0_2(): pass def update_0_2_to_1_0(): pass The body of the update should follow peewee migration practices. http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#migrate """ versions = [ (0, 1), (1, 0) ]
[docs] @staticmethod def dbconn_blocking(): """Wait for the db connection.""" dbcon_attempts = get_config().getint('database', 'connect_attempts') dbcon_wait = get_config().getint('database', 'connect_wait') while dbcon_attempts: try: Cart.database_connect() return except OperationalError: # couldnt connect, potentially wait and try again time.sleep(dbcon_wait) dbcon_attempts -= 1 raise OperationalError('Failed database connect retry.')
[docs] @staticmethod def create_tables(): """Create the tables if they don't exist.""" for cls in [CartSystem, Cart, File]: if not cls.table_exists(): cls.create_table() CartSystem.get_or_create_version()
[docs] @classmethod def update_0_1_to_1_0(cls): """Update by adding the boolean column.""" migrator = SchemaMigrator(DB) migrate( migrator.add_column( 'cart', 'bundle', BooleanField(default=False, null=True) ) )
[docs] @classmethod def update_tables(cls): """Update the database to the current version.""" verlist = cls.versions db_ver = CartSystem.get_version() if verlist.index(verlist[-1]) == verlist.index(db_ver): # we have the current version don't update return with Cart.atomic(): for db_ver in verlist[verlist.index(db_ver):-1]: next_db_ver = verlist[verlist.index(db_ver)+1] method_name = 'update_{}_to_{}'.format( '{}_{}'.format(*db_ver), '{}_{}'.format(*next_db_ver) ) getattr(cls, method_name)() CartSystem.drop_table() CartSystem.create_table() CartSystem.get_or_create_version()
[docs]class CartBase(Model): """Base Cart Model class."""
[docs] @classmethod def atomic(cls): """Do the DB atomic bits.""" # pylint: disable=no-member return cls._meta.database.atomic()
# pylint: enable=no-member
[docs] @classmethod def database_connect(cls): """ Make sure database is connected. Dont reopen connection. """ # pylint: disable=no-member if not cls._meta.database.is_closed(): cls._meta.database.close() cls._meta.database.connect()
# pylint: enable=no-member
[docs] @classmethod def database_close(cls): """Close the database connection.""" # pylint: disable=no-member if not cls._meta.database.is_closed(): cls._meta.database.close()
# pylint: enable=no-member class Meta(object): """Meta object containing the database connection.""" database = DB # This model uses the pacifica_cart database.
[docs] def reload(self): """Reload my current state from the DB.""" newer_self = self.get(self._meta.primary_key == getattr( self, self._meta.primary_key.name)) for field_name in self._meta.fields.keys(): val = getattr(newer_self, field_name) setattr(self, field_name, val) self._dirty.clear()
[docs]class CartSystem(CartBase): """Cart Schema Version Model.""" part = CharField(primary_key=True) value = IntegerField(default=-1)
[docs] @classmethod def get_or_create_version(cls): """Set or create the current version of the schema.""" major = cls.get_or_create(part='major', value=SCHEMA_MAJOR) minor = cls.get_or_create(part='minor', value=SCHEMA_MINOR) return (major, minor)
[docs] @classmethod def get_version(cls): """Get the current version as a tuple.""" return (cls.get(part='major').value, cls.get(part='minor').value)
[docs] @classmethod def is_equal(cls): """Check to see if schema version matches code version.""" major, minor = cls.get_version() return major == SCHEMA_MAJOR and minor == SCHEMA_MINOR
[docs] @classmethod def is_safe(cls): """Check to see if the schema version is safe for the code.""" major, _minor = cls.get_version() return major == SCHEMA_MAJOR
[docs]class Cart(CartBase): """Cart object model.""" id = PrimaryKeyField() cart_uid = CharField(default=1) bundle_path = CharField(default='') bundle = BooleanField(default=False, null=True) creation_date = DateTimeField(default=datetime.datetime.now) updated_date = DateTimeField(default=datetime.datetime.now) deleted_date = DateTimeField(null=True) status = TextField(default='waiting') error = TextField(default='')
[docs]class File(CartBase): """File object model to keep track of what's been downloaded for a cart.""" id = PrimaryKeyField() cart = ForeignKeyField(Cart, to_field='id') file_name = CharField(default='') bundle_path = CharField(default='') hash_type = CharField(null=True) hash_value = CharField(null=True) status = TextField(default='waiting') error = TextField(default='')