diff --git a/configdb/db/db_api.py b/configdb/db/db_api.py index f65356fc3c900bc6318e45ab5c671c44993ef6cf..218229423ef50c059b354e7d2f94cac402a42d89 100644 --- a/configdb/db/db_api.py +++ b/configdb/db/db_api.py @@ -1,4 +1,7 @@ import functools + +from time import time + from configdb import exceptions from configdb.db import acl from configdb.db import query @@ -14,6 +17,14 @@ def with_session(fn): return _with_session_wrapper +def with_timestamp(fn): + @functools.wraps(fn) + def _with_timestamp_wrapper(self, session, entity_name, *args, **kwargs): + res = fn(self, session, entity_name, *args, **kwargs) + self.update_timestamp(session, entity_name) + return res + return _with_timestamp_wrapper + def _field_validation(field, value): return field.validate(value) @@ -102,7 +113,26 @@ class AdmDbApi(object): else: setattr(obj, field_name, new_value) + def update_timestamp(self, session, entity_name): + if entity_name in self.schema.sys_schema_tables: + #Avoid updating timestamp for tables that are not part of the schema. + return True + + data = {'name': entity_name, 'ts': int(time()) } + ts = self.schema.get_entity('__timestamp') + data = self._unpack(ts, data) + + obj = self.db.get_by_name('__timestamp', entity_name, session) + if obj: + diffs = self._diff_object(ts, obj, data) + self._apply_diff(ts, obj, diffs, session) + session.add(obj) + else: + obj = self.db.create('__timestamp', data, session) + return True + @with_session + @with_timestamp def update(self, session, entity_name, object_name, data, auth_context): """Update an existing instance.""" ent = self.schema.get_entity(entity_name) @@ -125,6 +155,7 @@ class AdmDbApi(object): return True @with_session + @with_timestamp def delete(self, session, entity_name, object_name, auth_context): """Delete an instance.""" ent = self.schema.get_entity(entity_name) @@ -141,6 +172,7 @@ class AdmDbApi(object): return True @with_session + @with_timestamp def create(self, session, entity_name, data, auth_context): """Create a new instance.""" ent = self.schema.get_entity(entity_name) @@ -160,6 +192,8 @@ class AdmDbApi(object): return True + + @with_session def get(self, session, entity_name, object_name, auth_context): """Return a specific instance.""" diff --git a/configdb/db/schema.py b/configdb/db/schema.py index e7f6a38f77568a7384a5fd1aad53da5a90266a14..b293322fc457df87b7412920952594724c1b1452 100644 --- a/configdb/db/schema.py +++ b/configdb/db/schema.py @@ -160,23 +160,23 @@ class Schema(object): A schema consists of multiple Entities, each having multiple Fields. The definition is loaded from JSON-encoded data. """ - + sys_schema_tables = [ '__timestamp'] def __init__(self, json_data): self.entities = {} schema_data = json.loads(json_data) + self._add_timestamp() for tname, tdata in schema_data.iteritems(): - if not ENTITY_NAME_PATTERN.match(tname): + if not ENTITY_NAME_PATTERN.match(tname) or tname in self.sys_schema_tables: raise exceptions.SchemaError( 'invalid entity name "%s"' % tname) self.entities[tname] = Entity(tname, tdata) - self._add_timestamp() self._relation_check() self.default_acl = acl.AclMixin() self.default_acl.set_acl(DEFAULT_ACL) def _add_timestamp(self): - ts_schema = {'name': { 'type': 'string', 'size': 16}, 'ts': {'type': 'int', 'nullable': False } } - self.entities['__timestamp__'] = Entity('__timestamp__', ts_schema) + ts_schema = {'name': { 'type': 'string', 'size': 32}, 'ts': {'type': 'int', 'nullable': False } } + self.entities['__timestamp'] = Entity('__timestamp', ts_schema) def _relation_check(self): """Verify that all relations reference existing entities."""