self.children.append(TreeNode(node))
else:
self.children.append(node)
+ def __repr__(self):
+ return self._getstring(0, False)
def __str__(self):
return self._getstring(0, False)
def _getstring(self, level, expand = False):
parentnode.children.append(instance, _mapper_nohistory=True)
return False
+class TreeData(object):
+ def __init__(self, value=None):
+ self.id = None
+ self.value = value
+ def __repr__(self):
+ return "TreeData(%s, %s)" % (repr(self.id), repr(self.value))
# define the mapper. we will make "convenient" property
# names vs. the more verbose names in the table definition
root_id=tables.trees.c.root_node_id,
root=relation(TreeNode, primaryjoin=tables.trees.c.root_node_id==tables.trees.c.node_id, thiscol=tables.trees.c.root_node_id, lazy=None, uselist=False),
children=relation(TreeNode, primaryjoin=tables.trees.c.parent_node_id==tables.trees.c.node_id, thiscol=tables.trees.c.node_id, lazy=None, uselist=True, private=True),
+ data=relation(TreeData, tables.treedata, properties=dict(id=tables.treedata.c.data_id), private=True, lazy=False)
+
), extension = TreeLoader())
TreeNode.mapper
node.append('node1')
node.append(node2)
node.append('node3')
+node.children['node3'].data = TreeData('node 3s data')
node.children['node2'].append('subnode2')
+node.children['node1'].data = TreeData('node 1s data')
print "\n\n\n----------------------------"
print "Created new tree structure:"
elif isinstance(prop, ColumnProperty):
prop.columns.append(column)
else:
+ #print "WARNING: column %s not being added due to property %s" % (column.key, repr(prop))
continue
# its a ColumnProperty - match the ultimate table columns
def _init_properties(self):
[prop.init(key, self) for key, prop in self.props.iteritems()]
+
def __str__(self):
return "Mapper|" + self.class_.__name__ + "|" + self.primarytable.name
+
def hash_key(self):
return self.hashkey
except IndexError:
return None
+
def identity_key(self, *primary_keys):
return objectstore.get_id_key(tuple(primary_keys), self.class_, self.primarytable)
return self._select_whereclause(arg, **params)
def _getattrbycolumn(self, obj, column):
- return self.columntoproperty[column][0].getattr(obj)
+ try:
+ prop = self.columntoproperty[column]
+ except KeyError:
+ try:
+ prop = self.props[column.key]
+ raise "Column '%s.%s' is not available, due to conflicting property '%s':%s" % (column.table.name, column.name, column.key, repr(prop))
+ except KeyError:
+ raise "No column %s.%s is configured on mapper %s..." % (column.table.name, column.name, str(self))
+
+ return prop[0].getattr(obj)
def _setattrbycolumn(self, obj, column, value):
self.columntoproperty[column][0].setattr(obj, value)
else:
childlist = uow.attributes.get_history(obj, self.key)
for child in childlist.deleted_items() + childlist.unchanged_items():
- uow.register_deleted(child)
+ if child is not None:
+ uow.register_deleted(child)
def register_dependencies(self, uowcommit):
return (obj2, obj1)
def process_dependencies(self, task, deplist, uowcommit, delete = False):
- print self.mapper.table.name + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete)
+ #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction)
# fucntion to set properties across a parent/child object plus an "association row",
# based on a join condition
def sync_foreign_keys(binary):
- if self.direction == PropertyLoader.RIGHT:
- self._sync_foreign_keys(binary, child, obj, associationrow, clearkeys)
- else:
- self._sync_foreign_keys(binary, obj, child, associationrow, clearkeys)
+ self._sync_foreign_keys(binary, obj, child, associationrow, clearkeys)
setter = BinaryVisitor(sync_foreign_keys)
def getlist(obj, passive=True):
uowcommit.register_deleted_list(childlist)
else:
for obj in deplist:
- print "obj: " + repr(obj)
childlist = getlist(obj)
if childlist is None: continue
clearkeys = False
"""given a binary clause with an = operator joining two table columns, synchronizes the values
of the corresponding attributes within a parent object and a child object, or the attributes within an
an "association row" that represents an association link between the 'parent' and 'child' object."""
+ # TODO: precompile this into a list of simple property setters. this will allow checking for
+ # all the proper columns to be set up when the mapper is constructed and should simplify the code
+ if binary.operator == '=':
+ if binary.left.table == binary.right.table:
+ if binary.right is self.foreignkey:
+ source = binary.left
+ elif binary.left is self.foreignkey:
+ source = binary.right
+ else:
+ raise "Cant determine direction for relationship %s = %s" % (binary.left.fullname, binary.right.fullname)
+ if self.direction == PropertyLoader.LEFT:
+ self.mapper._setattrbycolumn(child, self.foreignkey, self.parent._getattrbycolumn(obj, source))
+ elif self.direction == PropertyLoader.RIGHT:
+ self.parent._setattrbycolumn(obj, self.foreignkey, self.mapper._getattrbycolumn(child, source))
+ else:
+ raise "assert failed"
+ else:
+ colmap = {binary.left.table : binary.left, binary.right.table : binary.right}
+ if colmap.has_key(self.parent.primarytable) and colmap.has_key(self.target):
+ if self.direction == PropertyLoader.LEFT:
+ print "set " + repr(child) + ":" + colmap[self.target].key + " to " + repr(obj) + ":" + colmap[self.parent.primarytable].key
+ if clearkeys:
+ self.mapper._setattrbycolumn(child, colmap[self.target], None)
+ else:
+ self.mapper._setattrbycolumn(child, colmap[self.target], self.parent._getattrbycolumn(obj, colmap[self.parent.primarytable]))
+ elif self.direction == PropertyLoader.RIGHT:
+ print "set " + repr(obj) + ":" + colmap[self.parent.primarytable].key + " to " + repr(child) + ":" + colmap[self.target].key
+ if clearkeys:
+ self.parent._setattrbycolumn(obj, colmap[self.parent.primarytable], None)
+ else:
+ self.parent._setattrbycolumn(obj, colmap[self.parent.primarytable], self.mapper._getattrbycolumn(child, colmap[self.target]))
+ else:
+ raise "assert failed"
+ elif colmap.has_key(self.parent.primarytable) and colmap.has_key(self.secondary):
+ associationrow[colmap[self.secondary].key] = self.parent._getattrbycolumn(obj, colmap[self.parent.primarytable])
+ elif colmap.has_key(self.target) and colmap.has_key(self.secondary):
+ associationrow[colmap[self.secondary].key] = self.mapper._getattrbycolumn(child, colmap[self.target])
+
+ def _compile_synchronizer(self, binary, obj, child, associationrow, clearkeys):
if binary.operator == '=':
if binary.left.table == binary.right.table:
if binary.right is self.foreignkey:
source = binary.right
else:
raise "Cant determine direction for relationship %s = %s" % (binary.left.fullname, binary.right.fullname)
- self.mapper._setattrbycolumn(child, self.foreignkey, self.parent._getattrbycolumn(obj, source))
+ if self.direction == PropertyLoader.LEFT:
+ self.mapper._setattrbycolumn(child, self.foreignkey, self.parent._getattrbycolumn(obj, source))
+ elif self.direction == PropertyLoader.RIGHT:
+ self.parent._setattrbycolumn(obj, self.foreignkey, self.mapper._getattrbycolumn(child, source))
+ else:
+ raise "assert failed"
else:
colmap = {binary.left.table : binary.left, binary.right.table : binary.right}
if colmap.has_key(self.parent.primarytable) and colmap.has_key(self.target):
- #print "set " + repr(child) + ":" + colmap[self.target].key + " to " + repr(obj) + ":" + colmap[self.parent.primarytable].key
- if clearkeys:
- self.mapper._setattrbycolumn(child, colmap[self.target], None)
+ if self.direction == PropertyLoader.LEFT:
+ print "set " + repr(child) + ":" + colmap[self.target].key + " to " + repr(obj) + ":" + colmap[self.parent.primarytable].key
+ if clearkeys:
+ self.mapper._setattrbycolumn(child, colmap[self.target], None)
+ else:
+ self.mapper._setattrbycolumn(child, colmap[self.target], self.parent._getattrbycolumn(obj, colmap[self.parent.primarytable]))
+ elif self.direction == PropertyLoader.RIGHT:
+ print "set " + repr(obj) + ":" + colmap[self.parent.primarytable].key + " to " + repr(child) + ":" + colmap[self.target].key
+ if clearkeys:
+ self.parent._setattrbycolumn(obj, colmap[self.parent.primarytable], None)
+ else:
+ self.parent._setattrbycolumn(obj, colmap[self.parent.primarytable], self.mapper._getattrbycolumn(child, colmap[self.target]))
else:
- self.mapper._setattrbycolumn(child, colmap[self.target], self.parent._getattrbycolumn(obj, colmap[self.parent.primarytable]))
+ raise "assert failed"
elif colmap.has_key(self.parent.primarytable) and colmap.has_key(self.secondary):
associationrow[colmap[self.secondary].key] = self.parent._getattrbycolumn(obj, colmap[self.parent.primarytable])
elif colmap.has_key(self.target) and colmap.has_key(self.secondary):
associationrow[colmap[self.secondary].key] = self.mapper._getattrbycolumn(child, colmap[self.target])
+
def execute(self, instance, row, identitykey, imap, isnew):
pass
objects[2].email_address = 'imnew@foo.bar'
objects[3].user = User()
objects[3].user.user_name = 'imnewlyadded'
-
self.assert_sql(db, lambda: objectstore.uow().commit(), [
(
"INSERT INTO users (user_id, user_name) VALUES (:user_id, :user_name)",
])
l = sql.select([users, addresses], sql.and_(users.c.user_id==addresses.c.address_id, addresses.c.address_id==a.address_id)).execute()
self.echo( repr(l.fetchone().row))
+
+ def testbackwardsnonmatch(self):
+ u2 = Table('users_nm', db,
+ Column('user_id', Integer, primary_key = True),
+ Column('user_name', String(20)),
+ )
+
+ a2 = Table('email_addresses_nm', db,
+ Column('address_id', Integer, primary_key = True),
+ Column('rel_user_id', Integer, ForeignKey(u2.c.user_id)),
+ Column('email_address', String(20)),
+ )
+ u2.create()
+ a2.create()
+ m = mapper(Address, a2, properties = dict(
+ user = relation(User, u2, lazy = True, uselist = False)
+ ))
+ data = [
+ {'user_name' : 'thesub' , 'email_address' : 'bar@foo.com'},
+ {'user_name' : 'assdkfj' , 'email_address' : 'thesdf@asdf.com'},
+ ]
+ objects = []
+ for elem in data:
+ a = Address()
+ a.email_address = elem['email_address']
+ a.user = User()
+ a.user.user_name = elem['user_name']
+ objects.append(a)
+ self.assert_sql(db, lambda: objectstore.commit(), [
+ (
+ "INSERT INTO users_nm (user_id, user_name) VALUES (:user_id, :user_name)",
+ {'user_id': None, 'user_name': 'thesub'}
+ ),
+ (
+ "INSERT INTO users_nm (user_id, user_name) VALUES (:user_id, :user_name)",
+ {'user_id': None, 'user_name': 'assdkfj'}
+ ),
+ (
+ "INSERT INTO email_addresses_nm (address_id, rel_user_id, email_address) VALUES (:address_id, :rel_user_id, :email_address)",
+ {'rel_user_id': 1, 'address_id': None, 'email_address': 'bar@foo.com'}
+ ),
+ (
+ "INSERT INTO email_addresses_nm (address_id, rel_user_id, email_address) VALUES (:address_id, :rel_user_id, :email_address)",
+ {'rel_user_id': 2, 'address_id': None, 'email_address': 'thesdf@asdf.com'}
+ )
+ ]
+ )
+
+
def testonetomany(self):
"""test basic save of one to many."""
m = mapper(User, users, properties = dict(