diff options
Diffstat (limited to 'src/sugar/datastore/datastore.py')
-rw-r--r-- | src/sugar/datastore/datastore.py | 173 |
1 files changed, 110 insertions, 63 deletions
diff --git a/src/sugar/datastore/datastore.py b/src/sugar/datastore/datastore.py index 44d0ac8..2785355 100644 --- a/src/sugar/datastore/datastore.py +++ b/src/sugar/datastore/datastore.py @@ -28,6 +28,7 @@ import gobject from sugar.datastore import dbus_helpers from sugar import mime +from sugar import dispatch class DSMetadata(gobject.GObject): __gsignals__ = { @@ -41,7 +42,7 @@ class DSMetadata(gobject.GObject): self._props = {} else: self._props = props - + default_keys = ['bundle_id', 'activity_id', 'mime_type', 'title_set_by_user'] for key in default_keys: @@ -61,13 +62,13 @@ class DSMetadata(gobject.GObject): def __contains__(self, key): return self._props.__contains__(key) - + def has_key(self, key): return self._props.has_key(key) def keys(self): return self._props.keys() - + def get_dictionary(self): return self._props @@ -75,10 +76,12 @@ class DSMetadata(gobject.GObject): return DSMetadata(self._props.copy()) def get(self, key, default=None): - if self._props.has_key(key): - return self._props[key] - else: - return default + return self._props.get(key, default) + + def update(self, d) : + for (k,v) in d.items() : + self[k] = v + class DSObject(object): def __init__(self, tree_id, version_id, metadata=None, file_path=None): @@ -91,10 +94,10 @@ class DSObject(object): def get_metadata(self): if self._metadata is None and self.tree_id is not None: - metadata = DSMetadata(dbus_helpers.get_properties(self.tree_id, self.version_id)) + metadata = DSMetadata(get_properties((self.tree_id, self.version_id))) self._metadata = metadata return self._metadata - + def set_metadata(self, metadata): if self._metadata != metadata: self._metadata = metadata @@ -103,10 +106,10 @@ class DSObject(object): def get_file_path(self, fetch=True): if fetch and self._file_path is None and self.tree_id is not None: - self.set_file_path(dbus_helpers.get_filename(self.tree_id, self.version_id)) + self.set_file_path(dbus_helpers.get_data(self.tree_id, self.version_id)) self._owns_file = True return self._file_path - + def set_file_path(self, file_path): if self._file_path != file_path: if self._file_path and self._owns_file: @@ -151,7 +154,8 @@ class DSObject(object): def get(object_id): logging.debug('datastore.get %r' % (object_id,)) tree_id, version_id = object_id - metadata = dbus_helpers.get_properties(tree_id, version_id) + metadata = dbus_helpers.find({'tree_id': tree_id, + 'version_id': version_id}, {})[0] ds_object = DSObject(tree_id, version_id, DSMetadata(metadata), None) # TODO: register the object for updates @@ -159,78 +163,70 @@ def get(object_id): def create(): metadata = DSMetadata() - metadata['mtime'] = datetime.now().isoformat() - metadata['timestamp'] = int(time.time()) return DSObject(tree_id=None, version_id=None, metadata=metadata, file_path=None) -def write(ds_object, update_mtime=True, transfer_ownership=False, +def write(ds_object, transfer_ownership=False, reply_handler=None, error_handler=None, timeout=-1): logging.debug('datastore.write') - properties = ds_object.metadata.get_dictionary().copy() - - if update_mtime: - properties['mtime'] = datetime.now().isoformat() - properties['timestamp'] = int(time.time()) + metadata = ds_object.metadata.get_dictionary() file_path = ds_object.get_file_path(fetch=False) if file_path is None: file_path = '' - # FIXME: this func will be sync for creates regardless of the handlers - # supplied. This is very bad API, need to decide what to do here. - if ds_object.tree_id: - dbus_helpers.update(ds_object.tree_id, ds_object.version_id, - properties, - file_path, - transfer_ownership, - reply_handler=reply_handler, - error_handler=error_handler, - timeout=timeout) - else: - if reply_handler or error_handler: - logging.warning('datastore.write() cannot currently be called' \ - 'async for creates, see ticket 3071') - (ds_object.tree_id, ds_object.version_id) = dbus_helpers.create(properties, - file_path, - transfer_ownership) - ds_object.metadata['tree_id'] = ds_object.tree_id - ds_object.metadata['version_id'] = ds_object.version_id - # TODO: register the object for updates - logging.debug('Written object (%s,%s) to the datastore.' % (ds_object.tree_id, ds_object.version_id)) + ds_object.object_id = dbus_helpers.save(ds_object.tree_id, + ds_object.version_id, metadata, file_path, transfer_ownership, + reply_handler=reply_handler, error_handler=error_handler, + timeout=timeout) + + ds_object.metadata['tree_id'] = ds_object.tree_id + ds_object.metadata['version_id'] = ds_object.version_id + # TODO: register the object for updates + logging.debug('Written object %r to the datastore.', ds_object.object_id) + +def write_metadata(ds_object) : + dbus_helpers.change_metadata(ds_object.tree_id, ds_object.version_id, + ds_object.metadata.get_dictionary()) def delete(object_id): - logging.debug('datastore.delete %r' % (object_id,)) + logging.debug('datastore.delete %r', object_id) tree_id, version_id = object_id dbus_helpers.delete(tree_id, version_id) -def find(query, sorting=None, limit=None, offset=None, properties=None, +def get_metadata(object_id, metadata_names=[]) : + tree_id, version_id = object_id + res = find({'tree_id': tree_id, 'version_id': version_id}) + return (res and res[0]) or None + +def find(query, options={}, sorting=None, limit=None, offset=None, properties=None, reply_handler=None, error_handler=None): query = query.copy() + options = options.copy() + querystring = query.pop('query', '') - if properties is None: - properties = [] + if properties: + options['metadata'] = properties if sorting: - query['order_by'] = sorting + options['sort'] = sorting if limit: - query['limit'] = limit + options['limit'] = limit if offset: - query['offset'] = offset - - props_list, total_count = dbus_helpers.find(query, properties, - reply_handler, error_handler) - - objects = [] - for props in props_list: - tree_id = props['tree_id'] - version_id = props['version_id'] - del props['tree_id'] - del props['version_id'] - - ds_object = DSObject(tree_id, version_id, DSMetadata(props), None) - objects.append(ds_object) + options['offset'] = offset + + if querystring : + entries, total_count = dbus_helpers.textsearch(query, options, + reply_handler, error_handler) + else : + entries, total_count = dbus_helpers.find(query, options, + reply_handler, error_handler) + + objects = [ + DSObject(metadata['tree_id'], metadata['version_id'], + DSMetadata(metadata), None) + for metadata in entries] return objects, total_count @@ -256,7 +252,58 @@ def copy(jobject, mount_point): write(new_jobject) def complete_indexing(): - return dbus_helpers.complete_indexing() + return dbus_helpers.check_ready() def get_unique_values(key): - return dbus_helpers.get_unique_values(key) + return dbus_helpers.find_unique_values({}, key) + + +class DatastoreListener(object): + + _sig_names = ['saved', 'changedMetadata', 'deleted', 'ready', 'stopped'] + + def __init__(self): + self._datastore = dbus_helpers._get_data_store() + self._signal_handlers = [ + self._datastore.connect_to_signal(sig_name[0].upper()+sig_name[1:], + getattr(self, "__datastore_%s_cb" % (sig_name,))) + for sig_name in self._sig_names] + for sig_name in self._sig_names : + setattr(self, sig_name, dispatch.Signal()) + + def __del__(self) : + try : + for handler in self._signal_handlers : + handler.remove() + except : + # ignore errors during garbage collection - the signal handlers might + # have already been collected + pass + + def __datastore_saved_cb(self, tree_id, version_id): + metadata = get_metadata((tree_id, version_id)) + self.saved.send(self, metadata=metadata) + + def __datastore_changedMetadata_cb(self, tree_id, version_id): + metadata = get_metadata((tree_id, version_id)) + self.changedMetadata.send(self, metadata=metadata) + + def __datastore_deleted_cb(self, tree_id, version_id): + self.deleted.send(self, object_id=(tree_id, version_id)) + + def __datastore_ready(self): + self.ready.send(self) + + def __datastore_stopped(self): + self.stopped.send(self) + + +_datastore_listener = None +def get_datastore_listener() : + global _datastore_listener + + if not _datastore_listener : + _datastore_listener = DatastoreListener() + + return _datastore_listener + |