dbcore: flexattr deletion (fix #530)

This commit is contained in:
Adrian Sampson 2014-02-08 12:31:50 -08:00
parent e609319b3d
commit 8556de8d3a
2 changed files with 67 additions and 1 deletions

View file

@ -159,6 +159,19 @@ class Model(object):
if old_value != value:
self._dirty.add(key)
def __delitem__(self, key):
"""Remove a flexible attribute from the model.
"""
if key in self._values_flex: # Flexible.
del self._values_flex[key]
self._dirty.add(key) # Mark for dropping on store.
elif key in self._getters(): # Computed.
raise KeyError('computed field {0} cannot be deleted'.format(key))
elif key in self._fields: # Fixed.
raise KeyError('fixed field {0} cannot be deleted'.format(key))
else:
raise KeyError('no such field {0}'.format(key))
def keys(self, computed=False):
"""Get a list of available field names for this object. The
`computed` parameter controls whether computed (plugin-provided)
@ -224,6 +237,12 @@ class Model(object):
else:
self[key] = value
def __delattr__(self, key):
if key.startswith('_'):
super(Model, self).__delattr__(key)
else:
del self[key]
# Database interaction (CRUD methods).
@ -237,6 +256,7 @@ class Model(object):
subvars = []
for key in self._fields:
if key != 'id' and key in self._dirty:
self._dirty.remove(key)
assignments += key + '=?,'
value = self[key]
# Wrap path strings in buffers so they get stored
@ -255,9 +275,10 @@ class Model(object):
subvars.append(self.id)
tx.mutate(query, subvars)
# Flexible attributes.
# Modified/added flexible attributes.
for key, value in self._values_flex.items():
if key in self._dirty:
self._dirty.remove(key)
tx.mutate(
'INSERT INTO {0} '
'(entity_id, key, value) '
@ -265,6 +286,14 @@ class Model(object):
(self.id, key, value),
)
# Deleted flexible attributes.
for key in self._dirty:
tx.mutate(
'DELETE FROM {0} '
'WHERE entity_id=? AND key=?'.format(self._flex_table),
(self.id, key)
)
self.clear_dirty()
def load(self):

View file

@ -182,6 +182,43 @@ class ModelTest(_common.TestCase):
other_model = self.db._get(TestModel1, model.id)
self.assertEqual(other_model.foo, 'bar')
def test_delete_flexattr(self):
model = TestModel1()
model['foo'] = 'bar'
self.assertTrue('foo' in model)
del model['foo']
self.assertFalse('foo' in model)
def test_delete_flexattr_via_dot(self):
model = TestModel1()
model['foo'] = 'bar'
self.assertTrue('foo' in model)
del model.foo
self.assertFalse('foo' in model)
def test_delete_flexattr_persists(self):
model = TestModel1()
model.add(self.db)
model.foo = 'bar'
model.store()
model = self.db._get(TestModel1, model.id)
del model['foo']
model.store()
model = self.db._get(TestModel1, model.id)
self.assertFalse('foo' in model)
def test_delete_non_existent_attribute(self):
model = TestModel1()
with self.assertRaises(KeyError):
del model['foo']
def test_delete_fixed_attribute(self):
model = TestModel1()
with self.assertRaises(KeyError):
del model['field_one']
class FormatTest(_common.TestCase):
def test_format_fixed_field(self):