Skip to content

Commit

Permalink
Simple domain creation. syncdb (though not post-syncdb handlers) now …
Browse files Browse the repository at this point in the history
…works.
  • Loading branch information
Dan Fairs committed May 1, 2011
1 parent 0854fe6 commit 36a49e5
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 14 deletions.
72 changes: 64 additions & 8 deletions simpledb/db/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,57 @@
NonrelDatabaseValidation, NonrelDatabaseIntrospection, \
NonrelDatabaseCreation

# We don't use this, but `model` needs to be imported first due to a
# relative import in boto.sdb.db.manager.get_manager, which is called in
# a metaclass. This would otherwise be called during our next import line,
# pulling in SDBManager, thus causing an ImportError due to a cyclic import.
from boto.sdb.db import model
from boto.sdb.db.manager.sdbmanager import SDBManager
import boto

class HasConnection(object):

@property
def sdb(self):
if not hasattr(self, '_sdb'):
settings = self.connection.settings_dict
self._sdb = boto.connect_sdb(
aws_access_key_id=settings['AWS_ACCESS_KEY_ID'],
aws_secret_access_key=settings['AWS_SECRET_ACCESS_KEY'])
return self._sdb

# TODO: You can either use the type mapping defined in NonrelDatabaseCreation
# or you can override the mapping, here:
class DatabaseCreation(NonrelDatabaseCreation):
pass
class DatabaseCreation(NonrelDatabaseCreation, HasConnection):
data_types = dict(NonrelDatabaseCreation.data_types, **{
'EmailField': 'unicode',
'URLField': 'unicode',
'CharField': 'unicode',
'CommaSeparatedIntegerField': 'unicode',
'IPAddressField': 'unicode',
'SlugField': 'unicode',
'FileField': 'unicode',
'FilePathField': 'unicode',
'TextField': 'unicode',
'XMLField': 'unicode',
'IntegerField': 'unicode',
'SmallIntegerField': 'unicode',
'PositiveIntegerField': 'unicode',
'PositiveSmallIntegerField': 'unicode',
'BigIntegerField': 'unicode',
'GenericAutoField': 'unicode',
'AutoField': 'unicode',
'DecimalField': 'unicode',
})

def sql_create_model(self, model, style, known_models=set()):
""" We don't actually return any SQL here, but we do go right ahead
and create a domain for the model.
"""
domain_name = '%s.%s' % (model._meta.app_label, model.__name__)
self.sdb.create_domain(domain_name)
return [], {}


class DatabaseFeatures(NonrelDatabaseFeatures):
pass
Expand All @@ -20,8 +67,14 @@ class DatabaseClient(NonrelDatabaseClient):
class DatabaseValidation(NonrelDatabaseValidation):
pass

class DatabaseIntrospection(NonrelDatabaseIntrospection):
pass
class DatabaseIntrospection(NonrelDatabaseIntrospection, HasConnection):

def table_names(self):
""" We map tables onto AWS domains.
"""
rs = self.sdb.get_all_domains()
return [d.name for d in rs]


class DatabaseWrapper(NonrelDatabaseWrapper):
def __init__(self, *args, **kwds):
Expand All @@ -32,7 +85,10 @@ def __init__(self, *args, **kwds):
self.creation = DatabaseCreation(self)
self.validation = DatabaseValidation(self)
self.introspection = DatabaseIntrospection(self)
# TODO: connect to your DB here (if needed)
self.db_connection = connect(
self.settings_dict['HOST'], self.settings_dict['PORT'],
self.settings_dict['USER'], self.settings_dict['PASSWORD'])

def create_manager(self, domain_name):
return SDBManager(cls=None, db_name=domain_name,
db_user=self.settings_dict['AWS_ACCESS_KEY_ID'],
db_passwd=self.settings_dict['AWS_SECRET_ACCESS_KEY'],
db_host=None, db_port=None, db_table=None, ddl_dir=None,
enable_ssl=True)
23 changes: 17 additions & 6 deletions simpledb/db/compiler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import datetime
import sys

from simpledb.db.query import SimpleDBQuery

from django.db.models.sql.constants import LOOKUP_SEP, MULTI, SINGLE
from django.db.models.sql.where import AND, OR
from django.db.utils import DatabaseError, IntegrityError
Expand Down Expand Up @@ -47,27 +49,33 @@ def _func(*args, **kwargs):
try:
return func(*args, **kwargs)
# TODO: Replace this with your DB error class
except YourDatabaseError, e:
except Exception, e:
import pdb; pdb.set_trace()

raise DatabaseError, DatabaseError(*tuple(e)), sys.exc_info()[2]
return _func

class BackendQuery(NonrelQuery):

def __init__(self, compiler, fields):
super(BackendQuery, self).__init__(compiler, fields)
# TODO: add your initialization code here
self.db_query = LowLevelQuery(self.connection.db_connection)
domain = self.query.model._meta.db_table
self.db_query = SimpleDBQuery(
self.connection.create_manager(domain), self.query.model)

# This is needed for debugging
def __repr__(self):
# TODO: add some meaningful query string for debugging
return '<BackendQuery: ...>'
return '<BackendQuery: %s>' % self.query.model._meta.db_table

@safe_call
def fetch(self):
def fetch(self, low_mark=None, high_mark=None):
# TODO: run your low-level query here
low_mark, high_mark = self.limits
#low_mark, high_mark = self.limits
if high_mark is None:
# Infinite fetching

results = self.db_query.fetch_infinite(offset=low_mark)
elif high_mark > low_mark:
# Range fetching
Expand Down Expand Up @@ -131,7 +139,10 @@ def add_filter(self, column, lookup_type, negated, db_type, value):
op, value = op(lookup_type, value)

db_value = self.convert_value_for_db(db_type, value)
self.db_query.filter(column, op, db_value)

# XXX check this is right
self.db_query.filter('%s %s' % (column, op), db_value)
#self.db_query.filter(column, op, db_value)

class SQLCompiler(NonrelCompiler):
query_class = BackendQuery
Expand Down
59 changes: 59 additions & 0 deletions simpledb/db/query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from boto.sdb.db.query import Query as BotoQuery
from boto.sdb.db.property import Property

def model_adapter(django_model):
properties = {}
for field in django_model._meta.fields:
default = field.default
if callable(default):
default = default()
choices = [c[0] for c in getattr(field, 'choices', ())]
properties[field.name] = Property(
verbose_name=field.verbose_name,
name=field.name,
default=default,
required=not field.null,
choices=choices,
unique=field.unique
)

class ModelAdapter(django_model):
""" Adapter to provide the API that boto expects its models to have for
normal Django models
"""

# Used by SDBManager._get_all_descendents. Might need to implement
# this for model inheritance...
__sub_classes__ = ()

# Override __name__ as boto uses this to figure out the
# __type__ attributes.
__name__ = '%s.%s' % (django_model._meta.app_label, django_model.__name__)

@classmethod
def find_property(cls, prop_name):
""" Find the named property. Returns None if the property can't
be found
"""
return properties.get(prop_name)

return ModelAdapter

class SimpleDBQuery(BotoQuery):

def __init__(self, manager, model, limit=None, next_token=None):
self.manager = manager
self.model_class = model_adapter(model)
self.limit = limit
self.offset = 0
self.filters = []
self.select = None
self.sort_by = None
self.rs = None
self.next_token = next_token

def fetch_infinite(self, offset):
return self.manager.query(self)

def fetch_range(self, count, low_mark):
raise NotImplementedError

0 comments on commit 36a49e5

Please sign in to comment.