1# orm/sync.py 2# Copyright (C) 2005-2016 the SQLAlchemy authors and contributors 3# <see AUTHORS file> 4# 5# This module is part of SQLAlchemy and is released under 6# the MIT License: http://www.opensource.org/licenses/mit-license.php 7 8"""private module containing functions used for copying data 9between instances based on join conditions. 10 11""" 12 13from . import exc, util as orm_util, attributes 14 15 16def populate(source, source_mapper, dest, dest_mapper, 17 synchronize_pairs, uowcommit, flag_cascaded_pks): 18 source_dict = source.dict 19 dest_dict = dest.dict 20 21 for l, r in synchronize_pairs: 22 try: 23 # inline of source_mapper._get_state_attr_by_column 24 prop = source_mapper._columntoproperty[l] 25 value = source.manager[prop.key].impl.get(source, source_dict, 26 attributes.PASSIVE_OFF) 27 except exc.UnmappedColumnError: 28 _raise_col_to_prop(False, source_mapper, l, dest_mapper, r) 29 30 try: 31 # inline of dest_mapper._set_state_attr_by_column 32 prop = dest_mapper._columntoproperty[r] 33 dest.manager[prop.key].impl.set(dest, dest_dict, value, None) 34 except exc.UnmappedColumnError: 35 _raise_col_to_prop(True, source_mapper, l, dest_mapper, r) 36 37 # technically the "r.primary_key" check isn't 38 # needed here, but we check for this condition to limit 39 # how often this logic is invoked for memory/performance 40 # reasons, since we only need this info for a primary key 41 # destination. 42 if flag_cascaded_pks and l.primary_key and \ 43 r.primary_key and \ 44 r.references(l): 45 uowcommit.attributes[("pk_cascaded", dest, r)] = True 46 47 48def bulk_populate_inherit_keys( 49 source_dict, source_mapper, synchronize_pairs): 50 # a simplified version of populate() used by bulk insert mode 51 for l, r in synchronize_pairs: 52 try: 53 prop = source_mapper._columntoproperty[l] 54 value = source_dict[prop.key] 55 except exc.UnmappedColumnError: 56 _raise_col_to_prop(False, source_mapper, l, source_mapper, r) 57 58 try: 59 prop = source_mapper._columntoproperty[r] 60 source_dict[prop.key] = value 61 except exc.UnmappedColumnError: 62 _raise_col_to_prop(True, source_mapper, l, source_mapper, r) 63 64 65def clear(dest, dest_mapper, synchronize_pairs): 66 for l, r in synchronize_pairs: 67 if r.primary_key and \ 68 dest_mapper._get_state_attr_by_column( 69 dest, dest.dict, r) not in orm_util._none_set: 70 71 raise AssertionError( 72 "Dependency rule tried to blank-out primary key " 73 "column '%s' on instance '%s'" % 74 (r, orm_util.state_str(dest)) 75 ) 76 try: 77 dest_mapper._set_state_attr_by_column(dest, dest.dict, r, None) 78 except exc.UnmappedColumnError: 79 _raise_col_to_prop(True, None, l, dest_mapper, r) 80 81 82def update(source, source_mapper, dest, old_prefix, synchronize_pairs): 83 for l, r in synchronize_pairs: 84 try: 85 oldvalue = source_mapper._get_committed_attr_by_column( 86 source.obj(), l) 87 value = source_mapper._get_state_attr_by_column( 88 source, source.dict, l, passive=attributes.PASSIVE_OFF) 89 except exc.UnmappedColumnError: 90 _raise_col_to_prop(False, source_mapper, l, None, r) 91 dest[r.key] = value 92 dest[old_prefix + r.key] = oldvalue 93 94 95def populate_dict(source, source_mapper, dict_, synchronize_pairs): 96 for l, r in synchronize_pairs: 97 try: 98 value = source_mapper._get_state_attr_by_column( 99 source, source.dict, l, passive=attributes.PASSIVE_OFF) 100 except exc.UnmappedColumnError: 101 _raise_col_to_prop(False, source_mapper, l, None, r) 102 103 dict_[r.key] = value 104 105 106def source_modified(uowcommit, source, source_mapper, synchronize_pairs): 107 """return true if the source object has changes from an old to a 108 new value on the given synchronize pairs 109 110 """ 111 for l, r in synchronize_pairs: 112 try: 113 prop = source_mapper._columntoproperty[l] 114 except exc.UnmappedColumnError: 115 _raise_col_to_prop(False, source_mapper, l, None, r) 116 history = uowcommit.get_attribute_history( 117 source, prop.key, attributes.PASSIVE_NO_INITIALIZE) 118 if bool(history.deleted): 119 return True 120 else: 121 return False 122 123 124def _raise_col_to_prop(isdest, source_mapper, source_column, 125 dest_mapper, dest_column): 126 if isdest: 127 raise exc.UnmappedColumnError( 128 "Can't execute sync rule for " 129 "destination column '%s'; mapper '%s' does not map " 130 "this column. Try using an explicit `foreign_keys` " 131 "collection which does not include this column (or use " 132 "a viewonly=True relation)." % (dest_column, dest_mapper)) 133 else: 134 raise exc.UnmappedColumnError( 135 "Can't execute sync rule for " 136 "source column '%s'; mapper '%s' does not map this " 137 "column. Try using an explicit `foreign_keys` " 138 "collection which does not include destination column " 139 "'%s' (or use a viewonly=True relation)." % 140 (source_column, source_mapper, dest_column)) 141