-from sqlalchemy import create_session, relation, mapper, join, DynamicMetaData, class_mapper, util
+from sqlalchemy import (create_session, relation, mapper, join,
+ DynamicMetaData, class_mapper, util)
from sqlalchemy import and_, or_
from sqlalchemy import Table, Column, ForeignKey
from sqlalchemy.ext.sessioncontext import SessionContext
class column(object):
def __init__(self, coltype, colname=None, foreign_key=None,
primary_key=False, *args, **kwargs):
- if isinstance( foreign_key, basestring ):
- foreign_key= ForeignKey( foreign_key )
+ if isinstance(foreign_key, basestring):
+ foreign_key = ForeignKey(foreign_key)
self.coltype = coltype
self.colname = colname
self.foreign_key = foreign_key
self.secondary = secondary
class one_to_many(relationship):
- def __init__(self, classname, colname=None, backref=None, private=False, lazy=True):
- relationship.__init__(self, classname, colname, backref, private, lazy, uselist=True)
-
+ def __init__(self, classname, colname=None, backref=None, private=False,
+ lazy=True):
+ relationship.__init__(self, classname, colname, backref, private,
+ lazy, uselist=True)
class one_to_one(relationship):
- def __init__(self, classname, colname=None, backref=None, private=False, lazy=True):
+ def __init__(self, classname, colname=None, backref=None, private=False,
+ lazy=True):
if backref is not None:
backref = create_backref(backref, uselist=False)
- relationship.__init__(self, classname, colname, backref, private, lazy, uselist=False)
+ relationship.__init__(self, classname, colname, backref, private,
+ lazy, uselist=False)
class many_to_many(relationship):
def __init__(self, classname, secondary, backref=None, lazy=True):
# up if the classes aren't specified in a proper order
#
-__deferred_classes__ = []
+__deferred_classes__ = set()
+__processed_classes__ = set()
def process_relationships(klass, was_deferred=False):
+ # first, we loop through all of the relationships defined on the
+ # class, and make sure that the related class already has been
+ # completely processed and defer processing if it has not
defer = False
for propname, reldesc in klass.relations.items():
- if not reldesc.classname in ActiveMapperMeta.classes:
- if not was_deferred: __deferred_classes__.append(klass)
+ found = False
+ for other_klass in __processed_classes__:
+ if reldesc.classname == other_klass.__name__:
+ found = True
+ break
+
+ if not found:
+ if not was_deferred: __deferred_classes__.add(klass)
defer = True
+ break
+ # next, we loop through all the columns looking for foreign keys
+ # and make sure that we can find the related tables (they do not
+ # have to be processed yet, just defined), and we defer if we are
+ # not able to find any of the related tables
+ for col in klass.columns:
+ if col.foreign_key is not None:
+ found = False
+ for other_klass in ActiveMapperMeta.classes.values():
+ table_name = col.foreign_key._colspec.rsplit('.', 1)[0]
+ if other_klass.table.fullname.lower() == table_name.lower():
+ found = True
+
+ if not found:
+ if not was_deferred: __deferred_classes__.add(klass)
+ defer = True
+ break
+
+ # if we are able to find all related and referred to tables, then
+ # we can go ahead and assign the relationships to the class
if not defer:
relations = {}
for propname, reldesc in klass.relations.items():
private=reldesc.private,
lazy=reldesc.lazy,
uselist=reldesc.uselist)
+
class_mapper(klass).add_properties(relations)
- #assign_mapper(objectstore, klass, klass.table, properties=relations,
- # inherits=getattr(klass, "_base_mapper", None))
- if was_deferred: __deferred_classes__.remove(klass)
+ if klass in __deferred_classes__:
+ __deferred_classes__.remove(klass)
+ __processed_classes__.add(klass)
+ # finally, loop through the deferred classes and attempt to process
+ # relationships for them
if not was_deferred:
- for deferred_class in __deferred_classes__:
- process_relationships(deferred_class, was_deferred=True)
-
+ # loop through the list of deferred classes, processing the
+ # relationships, until we can make no more progress
+ last_count = len(__deferred_classes__) + 1
+ while last_count > len(__deferred_classes__):
+ last_count = len(__deferred_classes__)
+ deferred = __deferred_classes__.copy()
+ for deferred_class in deferred:
+ if deferred_class == klass: continue
+ process_relationships(deferred_class, was_deferred=True)
class ActiveMapperMeta(type):
table_name = clsname.lower()
columns = []
relations = {}
- _metadata = getattr( sys.modules[cls.__module__], "__metadata__", metadata )
+ _metadata = getattr(sys.modules[cls.__module__],
+ "__metadata__", metadata)
if 'mapping' in dict:
members = inspect.getmembers(dict.get('mapping'))
if isinstance(value, relationship):
relations[name] = value
+
assert _metadata is not None, "No MetaData specified"
+
ActiveMapperMeta.metadatas.add(_metadata)
cls.table = Table(table_name, _metadata, *columns)
+ cls.columns = columns
+
# check for inheritence
- if hasattr( bases[0], "mapping" ):
+ if hasattr(bases[0], "mapping"):
cls._base_mapper= bases[0].mapper
- assign_mapper(objectstore, cls, cls.table, inherits=cls._base_mapper)
+ assign_mapper(objectstore, cls, cls.table,
+ inherits=cls._base_mapper)
else:
assign_mapper(objectstore, cls, cls.table)
cls.relations = relations
super(ActiveMapperMeta, cls).__init__(clsname, bases, dict)
+
class ActiveMapper(object):
__metaclass__ = ActiveMapperMeta
def create_tables():
for metadata in ActiveMapperMeta.metadatas:
metadata.create_all()
+
def drop_tables():
for metadata in ActiveMapperMeta.metadatas:
- metadata.drop_all()
-
+ metadata.drop_all()
\ No newline at end of file