diff options
Diffstat (limited to 'lib/sqlalchemy/ext/activemapper.py')
-rw-r--r-- | lib/sqlalchemy/ext/activemapper.py | 94 |
1 files changed, 72 insertions, 22 deletions
diff --git a/lib/sqlalchemy/ext/activemapper.py b/lib/sqlalchemy/ext/activemapper.py index 4ff7a150b..24360f3f4 100644 --- a/lib/sqlalchemy/ext/activemapper.py +++ b/lib/sqlalchemy/ext/activemapper.py @@ -1,4 +1,5 @@ -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 @@ -32,8 +33,8 @@ objectstore = Objectstore(create_session) 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 @@ -56,15 +57,18 @@ class relationship(object): 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): @@ -79,14 +83,44 @@ class many_to_many(relationship): # 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(): @@ -97,15 +131,24 @@ def process_relationships(klass, was_deferred=False): 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): @@ -115,7 +158,8 @@ 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')) @@ -147,13 +191,18 @@ class ActiveMapperMeta(type): 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 @@ -164,6 +213,7 @@ class ActiveMapperMeta(type): super(ActiveMapperMeta, cls).__init__(clsname, bases, dict) + class ActiveMapper(object): __metaclass__ = ActiveMapperMeta @@ -179,7 +229,7 @@ class ActiveMapper(object): 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 |