Exemple #1
0
        def compile_binary(binary):
            """Assemble a SyncRule given a single binary condition."""

            if binary.operator != operators.eq or not isinstance(
                    binary.left, schema.Column) or not isinstance(
                        binary.right, schema.Column):
                return

            source_column = None
            dest_column = None

            if foreign_keys is None:
                if binary.left.table == binary.right.table:
                    raise exceptions.ArgumentError(
                        "need foreign_keys argument for self-referential sync")

                if binary.left in util.Set(
                    [f.column for f in binary.right.foreign_keys]):
                    dest_column = binary.right
                    source_column = binary.left
                elif binary.right in util.Set(
                    [f.column for f in binary.left.foreign_keys]):
                    dest_column = binary.left
                    source_column = binary.right
            else:
                if binary.left in foreign_keys:
                    source_column = binary.right
                    dest_column = binary.left
                elif binary.right in foreign_keys:
                    source_column = binary.left
                    dest_column = binary.right

            if source_column and dest_column:
                if self.direction == ONETOMANY:
                    self.syncrules.append(
                        SyncRule(self.parent_mapper,
                                 source_column,
                                 dest_column,
                                 dest_mapper=self.child_mapper))
                elif self.direction == MANYTOONE:
                    self.syncrules.append(
                        SyncRule(self.child_mapper,
                                 source_column,
                                 dest_column,
                                 dest_mapper=self.parent_mapper))
                else:
                    if not issecondary:
                        self.syncrules.append(
                            SyncRule(self.parent_mapper,
                                     source_column,
                                     dest_column,
                                     dest_mapper=self.child_mapper,
                                     issecondary=issecondary))
                    else:
                        self.syncrules.append(
                            SyncRule(self.child_mapper,
                                     source_column,
                                     dest_column,
                                     dest_mapper=self.parent_mapper,
                                     issecondary=issecondary))
def _sort(tuples, allitems, allow_cycles=False, ignore_self_cycles=False):
    nodes = {}
    edges = _EdgeCollection()

    for item in list(allitems) + [t[0] for t in tuples] + [t[1] for t in tuples]:
        if id(item) not in nodes:
            node = _Node(item)
            nodes[item] = node

    for t in tuples:
        if t[0] is t[1]:
            if allow_cycles:
                n = nodes[t[0]]
                n.cycles = util.Set([n])
            elif not ignore_self_cycles:
                raise CircularDependencyError("Self-referential dependency detected " + repr(t))
            continue
        childnode = nodes[t[1]]
        parentnode = nodes[t[0]]
        edges.add((parentnode, childnode))

    queue = []
    for n in nodes.values():
        if not edges.has_parents(n):
            queue.append(n)

    output = []
    while nodes:
        if not queue:
            # edges remain but no edgeless nodes to remove; this indicates
            # a cycle
            if allow_cycles:
                for cycle in _find_cycles(edges):
                    lead = cycle[0][0]
                    lead.cycles = util.Set()
                    for edge in cycle:
                        n = edges.remove(edge)
                        lead.cycles.add(edge[0])
                        lead.cycles.add(edge[1])
                        if n is not None:
                            queue.append(n)
                    for n in lead.cycles:
                        if n is not lead:
                            n._cyclical = True
                            for (n,k) in list(edges.edges_by_parent(n)):
                                edges.add((lead, k))
                                edges.remove((n,k))
                continue
            else:
                # long cycles not allowed
                raise CircularDependencyError("Circular dependency detected " + repr(edges) + repr(queue))
        node = queue.pop()
        if not hasattr(node, '_cyclical'):
            output.append(node)
        del nodes[node.item]
        for childnode in edges.pop_node(node):
            queue.append(childnode)
    return output
Exemple #3
0
    def __init__(self, session):
        if session.weak_identity_map:
            self.identity_map = attributes.InstanceDict()
        else:
            self.identity_map = {}

        self.new = util.Set()  #OrderedSet()
        self.deleted = util.Set()
        self.logger = logging.instance_logger(self, echoflag=session.echo_uow)
Exemple #4
0
    def _determine_remote_side(self):
        if not self.remote_side:
            if self.direction is sync.MANYTOONE:
                self.remote_side = util.Set(self._opposite_side)
            elif self.direction is sync.ONETOMANY or self.direction is sync.MANYTOMANY:
                self.remote_side = util.Set(self.foreign_keys)

        self.local_side = util.Set(self._opposite_side).union(
            util.Set(self.foreign_keys)).difference(self.remote_side)
Exemple #5
0
    def __init__(self, identity_map=None):
        if identity_map is not None:
            self.identity_map = identity_map
        else:
            self.identity_map = weakref.WeakValueDictionary()

        self.new = util.OrderedSet()
        self.dirty = util.Set()

        self.deleted = util.Set()
Exemple #6
0
    def flush(self, session, objects=None):
        # this context will track all the objects we want to save/update/delete,
        # and organize a hierarchical dependency structure.  it also handles
        # communication with the mappers and relationships to fire off SQL
        # and synchronize attributes between related objects.
        echo = logging.is_info_enabled(self.logger)

        flush_context = UOWTransaction(self, session)

        # create the set of all objects we want to operate upon
        if objects is not None:
            # specific list passed in
            objset = util.Set(objects)
        else:
            # or just everything
            objset = util.Set(self.identity_map.values()).union(self.new)

        # detect persistent objects that have changes
        dirty = self.locate_dirty()

        # store objects whose fate has been decided
        processed = util.Set()

        # put all saves/updates into the flush context.  detect orphans and throw them into deleted.
        for obj in self.new.union(dirty).intersection(objset).difference(
                self.deleted):
            if obj in processed:
                continue
            if object_mapper(obj)._is_orphan(obj):
                for c in [obj] + list(
                        object_mapper(obj).cascade_iterator('delete', obj)):
                    if c in processed:
                        continue
                    flush_context.register_object(c, isdelete=True)
                    processed.add(c)
            else:
                flush_context.register_object(obj)
                processed.add(obj)

        # put all remaining deletes into the flush context.
        for obj in self.deleted:
            if (objset is not None and not obj in objset) or obj in processed:
                continue
            flush_context.register_object(obj, isdelete=True)

        trans = session.create_transaction(autoflush=False)
        flush_context.transaction = trans
        try:
            flush_context.execute()
        except:
            trans.rollback()
            raise
        trans.commit()

        flush_context.post_exec()
    def add(self, edge):
        """Add an edge to this collection."""

        (parentnode, childnode) = edge
        if parentnode not in self.parent_to_children:
            self.parent_to_children[parentnode] = util.Set()
        self.parent_to_children[parentnode].add(childnode)
        if childnode not in self.child_to_parents:
            self.child_to_parents[childnode] = util.Set()
        self.child_to_parents[childnode].add(parentnode)
        parentnode.dependencies.add(childnode)
Exemple #8
0
    def __init__(self, identity_map=None, weak_identity_map=False):
        if identity_map is not None:
            self.identity_map = identity_map
        else:
            if weak_identity_map:
                self.identity_map = weakref.WeakValueDictionary()
            else:
                self.identity_map = {}

        self.new = util.Set()  #OrderedSet()
        self.deleted = util.Set()
        self.logger = logging.instance_logger(self)
Exemple #9
0
 def process_query_property(self, query, paths):
     if self.lazy:
         if paths[-1] in query._eager_loaders:
             query._eager_loaders = query._eager_loaders.difference(util.Set([paths[-1]]))
     else:
         if not self.chained:
             paths = [paths[-1]]
         res = util.Set()
         for path in paths:
             if len(path) - len(query._current_path) == 2:
                 res.add(path)
         query._eager_loaders = query._eager_loaders.union(res)
     super(EagerLazyOption, self).process_query_property(query, paths)
Exemple #10
0
 def __init__(self, engine, proxy, connection, checkfirst=False, tables=None, **kwargs):
     super(ANSISchemaGenerator, self).__init__(engine, proxy, **kwargs)
     self.checkfirst = checkfirst
     self.tables = tables and util.Set(tables) or None
     self.connection = connection
     self.preparer = self.engine.dialect.preparer()
     self.dialect = self.engine.dialect
Exemple #11
0
    def visit_update(self, update_stmt):
        # scan the table's columns for onupdates that have to be pre-set for an UPDATE
        # add these columns to the parameter list via visit_update_XXX methods
        default_params = {}
        class OnUpdateVisitor(schema.SchemaVisitor):
            def visit_column_onupdate(s, cd):
                self.visit_update_column_default(c, cd, default_params)
        vis = OnUpdateVisitor()
        for c in update_stmt.table.c:
            if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)):
                c.accept_schema_visitor(vis)

        self.isupdate = True
        colparams = self._get_colparams(update_stmt, default_params)

        self.inline_params = util.Set()
        def create_param(col, p):
            if isinstance(p, sql._BindParamClause):
                self.binds[p.key] = p
                self.binds[p.shortname] = p
                return self.bindparam_string(p.key)
            else:
                p.accept_visitor(self)
                self.inline_params.add(col)
                if isinstance(p, sql.ClauseElement) and not isinstance(p, sql.ColumnElement):
                    return "(" + self.get_str(p) + ")"
                else:
                    return self.get_str(p)
                
        text = "UPDATE " + self.preparer.format_table(update_stmt.table) + " SET " + string.join(["%s=%s" % (self.preparer.format_column(c[0]), create_param(*c)) for c in colparams], ', ')
        
        if update_stmt.whereclause:
            text += " WHERE " + self.get_str(update_stmt.whereclause)
         
        self.strings[update_stmt] = text
Exemple #12
0
def polymorphic_union(table_map, typecolname, aliasname='p_union'):
    colnames = util.Set()
    colnamemaps = {}
    types = {}
    for key in table_map.keys():
        table = table_map[key]

        # mysql doesnt like selecting from a select; make it an alias of the select
        if isinstance(table, sql.Select):
            table = table.alias()
            table_map[key] = table

        m = {}
        for c in table.c:
            colnames.add(c.name)
            m[c.name] = c
            types[c.name] = c.type
        colnamemaps[table] = m
        
    def col(name, table):
        try:
            return colnamemaps[table][name]
        except KeyError:
            return sql.cast(sql.null(), types[name]).label(name)

    result = []
    for type, table in table_map.iteritems():
        if typecolname is not None:
            result.append(sql.select([col(name, table) for name in colnames] + [sql.column("'%s'" % type).label(typecolname)], from_obj=[table]))
        else:
            result.append(sql.select([col(name, table) for name in colnames], from_obj=[table]))
    return sql.union_all(*result).alias(aliasname)
    
Exemple #13
0
 def __init__(self, arg=""):
     values = util.Set([c.strip() for c in arg.split(',')])
     self.delete_orphan = "delete-orphan" in values
     self.delete = "delete" in values or self.delete_orphan or "all" in values
     self.save_update = "save-update" in values or "all" in values
     self.merge = "merge" in values or "all" in values
     self.expunge = "expunge" in values or "all" in values
Exemple #14
0
    def flush(self, session, objects=None, echo=False):
        flush_context = UOWTransaction(self, session)

        if objects is not None:
            objset = util.Set(objects)
        else:
            objset = None

        for obj in [n for n in self.new] + [d for d in self.dirty]:
            if objset is not None and not obj in objset:
                continue
            if obj in self.deleted:
                continue
            flush_context.register_object(obj)

        for obj in self.deleted:
            if objset is not None and not obj in objset:
                continue
            flush_context.register_object(obj, isdelete=True)

        trans = session.create_transaction(autoflush=False)
        flush_context.transaction = trans
        try:
            flush_context.execute(echo=echo)
            trans.commit()
        except:
            trans.rollback()
            raise

        flush_context.post_exec()
Exemple #15
0
 def _locate_prop(self, key, start=None):
     import properties
     keys = []
     seen = util.Set()
     def search_for_prop(mapper_):
         if mapper_ in seen:
             return None
         seen.add(mapper_)
         if mapper_.props.has_key(key):
             prop = mapper_.props[key]
             if isinstance(prop, SynonymProperty):
                 prop = mapper_.props[prop.name]
             if isinstance(prop, properties.PropertyLoader):
                 keys.insert(0, prop.key)
             return prop
         else:
             for prop in mapper_.props.values():
                 if not isinstance(prop, properties.PropertyLoader):
                     continue
                 x = search_for_prop(prop.mapper)
                 if x:
                     keys.insert(0, prop.key)
                     return x
             else:
                 return None
     p = search_for_prop(start or self.mapper)
     if p is None:
         raise exceptions.InvalidRequestError("Cant locate property named '%s'" % key)
     return [keys, p]
Exemple #16
0
    def assert_sort(self, tuples, node, collection=None):
        print str(node)
        def assert_tuple(tuple, node):
            if node.cycles:
                cycles = [i.item for i in node.cycles]
            else:
                cycles = []
            if tuple[0] is node.item or tuple[0] in cycles:
                tuple.pop()
                if tuple[0] is node.item or tuple[0] in cycles:
                    return
            elif len(tuple) > 1 and tuple[1] is node.item:
                assert False, "Tuple not in dependency tree: " + str(tuple)
            for c in node.children:
                assert_tuple(tuple, c)
        
        for tuple in tuples:
            assert_tuple(list(tuple), node)

        if collection is None:
            collection = []
        items = util.Set()
        def assert_unique(node):
            for item in [n.item for n in node.cycles or [node,]]:
                assert item not in items
                items.add(item)
                if item in collection:
                    collection.remove(item)
            for c in node.children:
                assert_unique(c)
        assert_unique(node)
        assert len(collection) == 0
Exemple #17
0
 def __init__(self, mapper, options):
     self.mapper = mapper
     self.options = options
     self.attributes = {}
     self.recursion_stack = util.Set()
     for opt in util.flatten_iterator(options):
         self.accept_option(opt)
Exemple #18
0
    def merge(self, object, entity_name=None, _recursive=None):
        """Copy the state of the given object onto the persistent
        object with the same identifier.

        If there is no persistent instance currently associated with
        the session, it will be loaded.  Return the persistent
        instance. If the given instance is unsaved, save a copy of and
        return it as a newly persistent instance. The given instance
        does not become associated with the session.

        This operation cascades to associated instances if the
        association is mapped with ``cascade="merge"``.
        """

        if _recursive is None:
            _recursive = util.Set()
        mapper = _object_mapper(object)
        key = getattr(object, '_instance_key', None)
        if key is None:
            merged = mapper._create_instance(self)
        else:
            if key in self.identity_map:
                merged = self.identity_map[key]
            else:
                merged = self.get(mapper.class_, key[1])
        for prop in mapper.props.values():
            prop.merge(self, object, merged, _recursive)
        if key is None:
            self.save(merged)
        return merged
Exemple #19
0
        def intersection_update(self, other):
            want, have = self.intersection(other), sautil.Set(self)
            remove, add = have - want, want - have

            for item in remove:
                self.remove(item)
            for item in add:
                self.add(item)
Exemple #20
0
        def symmetric_difference_update(self, other):
            want, have = self.symmetric_difference(other), sautil.Set(self)
            remove, add = have - want, want - have

            for item in remove:
                self.remove(item)
            for item in add:
                self.add(item)
Exemple #21
0
 def _get_noninheriting_mappers(self):
     """returns a list of UOWTasks whose mappers are not inheriting from the mapper of another UOWTask.
     i.e., this returns the root UOWTasks for all the inheritance hierarchies represented in this UOWTransaction."""
     mappers = util.Set()
     for task in self.tasks.values():
         base = task.mapper.base_mapper()
         mappers.add(base)
     return mappers
Exemple #22
0
def find_columns(clause):
    cols = util.Set()

    def visit_column(col):
        cols.add(col)

    visitors.traverse(clause, visit_column=visit_column)
    return cols
Exemple #23
0
    def traverse(self, elem, clone=True):
        if not clone:
            raise exceptions.ArgumentError(
                "AbstractClauseProcessor 'clone' argument must be True")

        return self._traverse(elem,
                              util.Set(self.stop_on or []), {},
                              _clone_toplevel=True)
Exemple #24
0
    def all_deps(self):
        """Return a set of dependencies for this node and all its cycles."""

        deps = util.Set(self.dependencies)
        if self.cycles is not None:
            for c in self.cycles:
                deps.update(c.dependencies)
        return deps
Exemple #25
0
def _organize_as_tree(nodes):
    """Given a list of nodes from a topological sort, organize the
    nodes into a tree structure, with as many non-dependent nodes
    set as siblings to each other as possible.
    
    returns nodes as 3-tuples (item, cycles, children).
    """

    if not nodes:
        return None
    # a list of all currently independent subtrees as a tuple of
    # (root_node, set_of_all_tree_nodes, set_of_all_cycle_nodes_in_tree)
    # order of the list has no semantics for the algorithmic
    independents = []
    # in reverse topological order
    for node in util.reversed(nodes):
        # nodes subtree and cycles contain the node itself
        subtree = util.Set([node])
        if node.cycles is not None:
            cycles = util.Set(node.cycles)
        else:
            cycles = util.Set()
        # get a set of dependent nodes of node and its cycles
        nodealldeps = node.all_deps()
        if nodealldeps:
            # iterate over independent node indexes in reverse order so we can efficiently remove them
            for index in xrange(len(independents)-1,-1,-1):
                child, childsubtree, childcycles = independents[index]
                # if there is a dependency between this node and an independent node
                if (childsubtree.intersection(nodealldeps) or childcycles.intersection(node.dependencies)):
                    # prepend child to nodes children
                    # (append should be fine, but previous implemetation used prepend)
                    node.children[0:0] = [(child.item, [n.item for n in child.cycles or []], child.children)]
                    # merge childs subtree and cycles
                    subtree.update(childsubtree)
                    cycles.update(childcycles)
                    # remove the child from list of independent subtrees
                    independents[index:index+1] = []
        # add node as a new independent subtree
        independents.append((node,subtree,cycles))
    # choose an arbitrary node from list of all independent subtrees
    head = independents.pop()[0]
    # add all other independent subtrees as a child of the chosen root
    # used prepend [0:0] instead of extend to maintain exact behaviour of previous implementation
    head.children[0:0] = [(i[0].item, [n.item for n in i[0].cycles or []], i[0].children) for i in independents]
    return (head.item, [n.item for n in head.cycles or []], head.children)
Exemple #26
0
    def __init__(self, uowtransaction, mapper, base_task=None):
        # the transaction owning this UOWTask
        self.uowtransaction = uowtransaction

        # base_task is the UOWTask which represents the "base mapper"
        # in our mapper's inheritance chain.  if the mapper does not
        # inherit from any other mapper, the base_task is self.
        # the _inheriting_tasks dictionary is a dictionary present only
        # on the "base_task"-holding UOWTask, which maps all mappers within
        # an inheritance hierarchy to their corresponding UOWTask instances.
        if base_task is None:
            self.base_task = self
            self._inheriting_tasks = {mapper: self}
        else:
            self.base_task = base_task
            base_task._inheriting_tasks[mapper] = self

        # the Mapper which this UOWTask corresponds to
        self.mapper = mapper

        # a dictionary mapping object instances to a corresponding UOWTaskElement.
        # Each UOWTaskElement represents one object instance which is to be saved or
        # deleted by this UOWTask's Mapper.
        # in the case of the row-based "cyclical sort", the UOWTaskElement may
        # also reference further UOWTasks which are dependent on that UOWTaskElement.
        self._objects = {}

        # a set of UOWDependencyProcessor instances, which are executed after saves and
        # before deletes, to synchronize data between dependent objects as well as to
        # ensure that relationship cascades populate the flush() process with all
        # appropriate objects.
        self._dependencies = util.Set()

        # a list of UOWTasks which are sub-nodes to this UOWTask.  this list
        # is populated during the dependency sorting operation.
        self.childtasks = []

        # a list of UOWDependencyProcessor instances
        # which derive from the UOWDependencyProcessor instances present in a
        # corresponding UOWTask's "_dependencies" set.  This collection is populated
        # during a row-based cyclical sorting operation and only corresponds to
        # new UOWTask instances created during this operation, which are also local
        # to the dependency graph (i.e. they are not present in the get_task_by_mapper()
        # collection).
        self._cyclical_dependencies = util.Set()
Exemple #27
0
    def unmodified(self):
        """a set of keys which have no uncommitted changes"""

        return util.Set([
            attr.impl.key for attr in _managed_attributes(self.class_)
            if attr.impl.key not in self.committed_state and (
                not hasattr(attr.impl, 'commit_to_state')
                or not attr.impl.check_mutable_modified(self))
        ])
Exemple #28
0
    def intersection_update(self, other):
        want, have = self.intersection(other), util.Set(self)

        remove, add = have - want, want - have

        for value in remove:
            self.remove(value)
        for value in add:
            self.add(value)
Exemple #29
0
    def symmetric_difference_update(self, other):
        want, have = self.symmetric_difference(other), util.Set(self)

        remove, add = have - want, want - have

        for value in remove:
            self.remove(value)
        for value in add:
            self.add(value)
Exemple #30
0
 def close(self):
     if self.__parent is not None:
         return
     for t in util.Set(self.__connections.values()):
         if t[2]:
             t[0].close()
         else:
             t[1].close()
     self.session.transaction = None