def test_lru_cache_clear(): cache = LRUCache(capacity=3) cache["a"] = 1 cache["b"] = 2 cache.clear() assert cache.lru == []
def test_lru_cache_get(): cache = LRUCache(capacity=3) cache["a"] = 1 cache["b"] = 1 cache["c"] = 1 cache.get("a") cache["d"] = 4 assert cache.lru == ["c", "a", "d"]
def test_lru_cache_set_multiple(): cache = LRUCache(capacity=3) cache["a"] = 1 cache["a"] = 2 cache["a"] = 3 cache["a"] = 4 assert cache.lru == ["a"]
def __init__(self, storage, cache_size=10): """ Get access to a table. :param storage: Access to the storage :type storage: StorageProxyus :param cache_size: Maximum size of query cache. """ self._storage = storage self._query_cache = LRUCache(capacity=cache_size) data = self._read() if data: self._last_id = max(i for i in data) else: self._last_id = 0
def test_lru_cache(): cache = LRUCache(capacity=3) cache["a"] = 1 cache["b"] = 2 cache["c"] = 3 _ = cache["a"] # move to front in lru queue cache["d"] = 4 # move oldest item out of lru queue assert cache.lru == ["c", "a", "d"]
class DBTable(Table): """ Represents a single TinyDB Table. """ def __init__(self, storage, cache_size=10): """ Get access to a table. :param storage: Access to the storage :type storage: StorageProxyus :param cache_size: Maximum size of query cache. """ self._storage = storage self._query_cache = LRUCache(capacity=cache_size) data = self._read() if data: self._last_id = max(i for i in data) else: self._last_id = 0 def _read(self): """ Reading access to the DB. :returns: all values :rtype: dict """ return self._storage.read() def _write(self, values): """ Writing access to the DB. :param values: the new values to write :type values: dict """ self._query_cache.clear() self._storage.write(values)
def __init__(self, name, db, cache_size=10): """ Get access to a table. :param name: The name of the table. :type name: str :param db: The parent database. :type db: tinydb.database.TinyDB :param cache_size: Maximum size of query cache. """ self.name = name self._db = db self._query_cache = LRUCache(capacity=cache_size) old_ids = self._read().keys() if old_ids: self._last_id = max(i for i in old_ids) else: self._last_id = 0
def test_lru_cache_delete(): cache = LRUCache(capacity=3) cache["a"] = 1 cache["b"] = 2 del cache["a"] try: del cache['f'] except KeyError: pass assert cache.lru == ["b"]
def test_lru_cache(): cache = LRUCache(capacity=3) cache["a"] = 1 cache["b"] = 2 cache["c"] = 3 _ = cache["a"] # move to front in lru queue cache["d"] = 4 # move oldest item out of lru queue try: _ = cache['f'] except KeyError: pass assert cache.lru == ["c", "a", "d"]
class Table(object): def __init__(self, cache_size=10): """ Implement a single table object. """ self._query_cache = LRUCache(capacity=cache_size) self.data = {} self.column_type = {} self._last_id = 0 def process_elements(self, func, cond=None, eids=None): """ Helper function for processing all elements specified by condition or IDs. A repeating pattern in TinyDB is to run some code on all elements that match a condition or are specified by their ID. This is implemented in this function. The function passed as ``func`` has to be a callable. It's first argument will be the data currently in the database. It's second argument is the element ID of the currently processed element. See: :meth:`~.update`, :meth:`.remove` :param func: the function to execute on every included element. first argument: all data second argument: the current eid :param cond: elements to use, or :param eids: elements to use :returns: the element IDs that were affected during processed """ data = self._read() if eids is not None: # Processed element specified by id for eid in eids: func(data, eid) else: # Collect affected eids eids = [] # Processed elements specified by condition for eid in list(data): if cond(data[eid]): func(data, eid) eids.append(eid) self._write(data) return eids def clear_cache(self): """ Clear the query cache. A simple helper that clears the internal query cache. """ self._query_cache.clear() def _get_next_id(self): """ Increment the ID used the last time and return it """ current_id = self._last_id + 1 self._last_id = current_id return current_id def _read(self): """ Reading access to the DB. :returns: all values :rtype: dict """ return self.data def _write(self, values): """ Writing access to the DB. :param values: the new values to write :type values: dict """ self._query_cache.clear() self.data = values def __len__(self): """ Get the total number of elements in the table. """ return len(self._read()) def all(self): """ Get all elements stored in the table. :returns: a list with all elements. :rtype: list[Element] """ return list(itervalues(self._read())) def get_column_type(self, name): """ Get the type of a specified column. """ return self.column_type[name] @property def column_name(self): """ Get all the column names. """ names = None if self.data: names = self.data[0].keys() return names def insert(self, element): """ Insert a new element into the table. :param element: the element to insert :returns: the inserted element's ID """ eid = self._get_next_id() if not isinstance(element, dict): raise ValueError('Element is not a dictionary') data = self._read() data[eid] = element self._write(data) if not self.column_type: for key, val in element.iteritems(): self.column_type[key] = type(val) return eid def insert_multiple(self, elements): """ Insert multiple elements into the table. :param elements: a list of elements to insert :returns: a list containing the inserted elements' IDs """ eids = [] data = self._read() for element in elements: eid = self._get_next_id() eids.append(eid) data[eid] = element self._write(data) if not self.column_type: for key, val in elements[0].iteritems(): self.column_type[key] = type(val) return eids def remove(self, cond=None, eids=None): """ Remove all matching elements. :param cond: the condition to check against :type cond: query :param eids: a list of element IDs :type eids: list :returns: a list containing the removed element's ID """ return self.process_elements(lambda data, eid: data.pop(eid), cond, eids) def update(self, fields, cond=None, eids=None): """ Update all matching elements to have a given set of fields. :param fields: the fields that the matching elements will have or a method that will update the elements :type fields: dict | dict -> None :param cond: which elements to update :type cond: query :param eids: a list of element IDs :type eids: list :returns: a list containing the updated element's ID """ if callable(fields): return self.process_elements(lambda data, eid: fields(data[eid]), cond, eids) else: return self.process_elements( lambda data, eid: data[eid].update(fields), cond, eids) def purge(self): """ Purge the table by removing all elements. """ self._write({}) self._last_id = 0 def search(self, cond): """ Search for all elements matching a 'where' cond. :param cond: the condition to check against :type cond: Query :returns: list of matching elements :rtype: list[Element] """ if cond in self._query_cache: return self._query_cache[cond][:] elements = [element for element in self.all() if cond(element)] self._query_cache[cond] = elements return elements[:] def get(self, cond=None, eid=None): """ Get exactly one element specified by a query or and ID. Returns ``None`` if the element doesn't exist :param cond: the condition to check against :type cond: Query :param eid: the element's ID :returns: the element or None :rtype: Element | None """ # Cannot use process_elements here because we want to return a # specific element if eid is not None: # Element specified by ID return self._read().get(eid, None) # Element specified by condition for element in self.all(): if cond(element): return element def denotation(self, name, cond=None): """ Get the denotation of a query. :param name: the column name :type name: string :param cond: the condition to check against :type cond: Query :returns: the denotation :rtype: list (not set) """ rows = [] if cond: rows = self.search(cond) else: rows = self.all() entries = [r[name] for r in rows] return entries def denotation_flatten(self, name, cond=None): """ Get the flattened denotation list of a query. """ return reduce(lambda x, y: x + y, self.denotation(name, cond)) def denotation_set(self, name, cond=None): """ Get the denotation set of a query. """ return set(self.denotation(name, cond)) def denotation_flatten_set(self, name, cond=None): """ Get the flattened denotation set of a query. """ return set(self.denotation_flatten(name, cond)) def count(self, cond=None): """ Count the elements matching a condition. :param cond: the condition use :type cond: Query """ if cond: return len(self.search(cond)) else: return len(self.all()) def argmax(self, name): """ Get the row where the value in the given column is the maximum """ s = sorted(self.all(), key=lambda k: k[name], reverse=True) targmax = [s[0]] for i in xrange(1, len(s)): if s[i] == s[0]: targmax.append(s[i]) else: break return targmax def argmin(self, name): """ Get the row where the value in the given column is the minimum """ s = sorted(self.all(), key=lambda k: k[name]) targmin = [s[0]] for i in xrange(1, len(s)): if s[i] == s[0]: targmin.append(s[i]) else: break return targmin def count_argmax(self, name): """ Get the row where the amount of values in the given column is the maximum """ s = sorted(self.all(), key=lambda k: len(k[name]), reverse=True) cargmax = [s[0]] for i in xrange(1, len(s)): if s[i] == s[0]: cargmax.append(s[i]) else: break return cargmax def count_argmin(self, name): """ Get the row where the amount of values in the given column is the minimum """ s = sorted(self.all(), key=lambda k: len(k[name])) cargmin = [s[0]] for i in xrange(1, len(s)): if s[i] == s[0]: cargmin.append(s[i]) else: break return cargmin def contains(self, cond=None, eids=None): """ Check wether the database contains an element matching a condition or an ID. If ``eids`` is set, it checks if the db contains an element with one of the specified. :param cond: the condition use :type cond: Query :param eids: the element IDs to look for """ if eids is not None: # Elements specified by ID return any(self.get(eid=eid) for eid in eids) # Element specified by condition return self.get(cond) is not None
class Table(object): """ Represents a single TinyDB Table. """ def __init__(self, name, db, cache_size=10): """ Get access to a table. :param name: The name of the table. :type name: str :param db: The parent database. :type db: tinydb.database.TinyDB :param cache_size: Maximum size of query cache. """ self.name = name self._db = db self._query_cache = LRUCache(capacity=cache_size) old_ids = self._read().keys() if old_ids: self._last_id = max(i for i in old_ids) else: self._last_id = 0 def process_elements(self, func, cond=None, eids=None): """ Helper function for processing all elements specified by condition or IDs. A repeating pattern in TinyDB is to run some code on all elements that match a condition or are specified by their ID. This is implemented in this function. The function passed as ``func`` has to be a callable. It's first argument will be the data currently in the database. It's second argument is the element ID of the currently processed element. See: :meth:`~.update`, :meth:`.remove` :param func: the function to execute on every included element. first argument: all data second argument: the current eid :param cond: elements to use :param eids: elements to use """ data = self._read() if eids is not None: # Processed element specified by id for eid in eids: func(data, eid) else: # Processed elements specified by condition for eid in list(data): if cond(data[eid]): func(data, eid) self._write(data) def _get_next_id(self): """ Increment the ID used the last time and return it """ current_id = self._last_id + 1 self._last_id = current_id return current_id def _read(self): """ Reading access to the DB. :returns: all values :rtype: dict """ raw_data = self._db._read_table(self.name) data = {} for key in list(raw_data): eid = int(key) data[eid] = Element(raw_data[key], eid) return data def _write(self, values): """ Writing access to the DB. :param values: the new values to write :type values: dict """ self._query_cache.clear() self._db._write_table(values, self.name) def __len__(self): """ Get the total number of elements in the table. """ return len(self._read()) def all(self): """ Get all elements stored in the table. :returns: a list with all elements. :rtype: list[Element] """ return list(self._read().values()) def insert(self, element): """ Insert a new element into the table. :param element: the element to insert :returns: the inserted element's ID """ eid = self._get_next_id() data = self._read() data[eid] = element self._write(data) return eid def insert_multiple(self, elements): """ Insert multiple elements into the table. :param elements: a list of elements to insert :returns: a list containing the inserted elements' IDs """ eids = [] data = self._read() for element in elements: eid = self._get_next_id() eids.append(eid) data[eid] = element self._write(data) return eids def remove(self, cond=None, eids=None): """ Remove all matching elements. :param cond: the condition to check against :type cond: query :param eids: a list of element IDs :type eids: list """ self.process_elements(lambda data, eid: data.pop(eid), cond, eids) def update(self, fields, cond=None, eids=None): """ Update all matching elements to have a given set of fields. :param fields: the fields that the matching elements will have or a method that will update the elements :type fields: dict | (dict, int) -> None :param cond: which elements to update :type cond: query :param eids: a list of element IDs :type eids: list """ if callable(fields): _update = lambda data, eid: fields(data[eid]) else: _update = lambda data, eid: data[eid].update(fields) self.process_elements(_update, cond, eids) def purge(self): """ Purge the table by removing all elements. """ self._write({}) self._last_id = 0 def search(self, cond): """ Search for all elements matching a 'where' cond. :param cond: the condition to check against :type cond: Query :returns: list of matching elements :rtype: list[Element] """ if cond in self._query_cache: return self._query_cache[cond] elements = [element for element in self.all() if cond(element)] self._query_cache[cond] = elements return elements def get(self, cond=None, eid=None): """ Get exactly one element specified by a query or and ID. Returns ``None`` if the element doesn't exist :param cond: the condition to check against :type cond: Query :param eid: the element's ID :returns: the element or None :rtype: Element | None """ # Cannot use process_elements here because we want to return a # specific element if eid is not None: # Element specified by ID return self._read().get(eid, None) # Element specified by condition for element in self.all(): if cond(element): return element def count(self, cond): """ Count the elements matching a condition. :param cond: the condition use :type cond: Query """ return len(self.search(cond)) def contains(self, cond=None, eids=None): """ Check wether the database contains an element matching a condition or an ID. If ``eids`` is set, it checks if the db contains an element with one of the specified. :param cond: the condition use :type cond: Query :param eids: the element IDs to look for """ if eids is not None: # Elements specified by ID return any(self.get(eid=eid) for eid in eids) # Element specified by condition return self.get(cond) is not None def __enter__(self): """ Allow the database to be used as a context manager. :return: the table instance """ return self def __exit__(self, *args): """ Try to close the storage after being used as a context manager. """ _ = args self._db._storage.close() close = __exit__
def test_lru_cache_unlimited_explicit(): cache = LRUCache(capacity=None) for i in range(100): cache[i] = i assert len(cache.lru) == 100
def test_lru_cache_unlimited(): cache = LRUCache() for i in range(100): cache[i] = i assert len(cache.lru) == 100
class Table(object): """ Represents a single TinyDB Table. """ def __init__(self, storage, cache_size=10): """ Get access to a table. :param storage: Access to the storage :type storage: StorageProxyus :param cache_size: Maximum size of query cache. """ self._storage = storage self._query_cache = LRUCache(capacity=cache_size) data = self._read() if data: self._last_id = max(i for i in data) else: self._last_id = 0 def process_elements(self, func, cond=None, eids=None): """ Helper function for processing all elements specified by condition or IDs. A repeating pattern in TinyDB is to run some code on all elements that match a condition or are specified by their ID. This is implemented in this function. The function passed as ``func`` has to be a callable. It's first argument will be the data currently in the database. It's second argument is the element ID of the currently processed element. See: :meth:`~.update`, :meth:`.remove` :param func: the function to execute on every included element. first argument: all data second argument: the current eid :param cond: elements to use, or :param eids: elements to use :returns: the element IDs that were affected during processed """ data = self._read() if eids is not None: # Processed element specified by id for eid in eids: func(data, eid) else: # Collect affected eids eids = [] # Processed elements specified by condition for eid in list(data): if cond(data[eid]): func(data, eid) eids.append(eid) self._write(data) return eids def clear_cache(self): """ Clear the query cache. A simple helper that clears the internal query cache. """ self._query_cache.clear() def _get_next_id(self): """ Increment the ID used the last time and return it """ current_id = self._last_id + 1 self._last_id = current_id return current_id def _read(self): """ Reading access to the DB. :returns: all values :rtype: dict """ return self._storage.read() def _write(self, values): """ Writing access to the DB. :param values: the new values to write :type values: dict """ self._query_cache.clear() self._storage.write(values) def __len__(self): """ Get the total number of elements in the table. """ return len(self._read()) def all(self): """ Get all elements stored in the table. :returns: a list with all elements. :rtype: list[Element] """ return list(itervalues(self._read())) def insert(self, element): """ Insert a new element into the table. :param element: the element to insert :returns: the inserted element's ID """ eid = self._get_next_id() if not isinstance(element, dict): raise ValueError('Element is not a dictionary') data = self._read() data[eid] = element self._write(data) return eid def insert_multiple(self, elements): """ Insert multiple elements into the table. :param elements: a list of elements to insert :returns: a list containing the inserted elements' IDs """ eids = [] data = self._read() for element in elements: eid = self._get_next_id() eids.append(eid) data[eid] = element self._write(data) return eids def remove(self, cond=None, eids=None): """ Remove all matching elements. :param cond: the condition to check against :type cond: query :param eids: a list of element IDs :type eids: list :returns: a list containing the removed element's ID """ return self.process_elements(lambda data, eid: data.pop(eid), cond, eids) def update(self, fields, cond=None, eids=None): """ Update all matching elements to have a given set of fields. :param fields: the fields that the matching elements will have or a method that will update the elements :type fields: dict | dict -> None :param cond: which elements to update :type cond: query :param eids: a list of element IDs :type eids: list :returns: a list containing the updated element's ID """ if callable(fields): return self.process_elements(lambda data, eid: fields(data[eid]), cond, eids) else: return self.process_elements( lambda data, eid: data[eid].update(fields), cond, eids) def purge(self): """ Purge the table by removing all elements. """ self._write({}) self._last_id = 0 def search(self, cond): """ Search for all elements matching a 'where' cond. :param cond: the condition to check against :type cond: Query :returns: list of matching elements :rtype: list[Element] """ if cond in self._query_cache: return self._query_cache[cond] elements = [element for element in self.all() if cond(element)] self._query_cache[cond] = elements return elements def get(self, cond=None, eid=None): """ Get exactly one element specified by a query or and ID. Returns ``None`` if the element doesn't exist :param cond: the condition to check against :type cond: Query :param eid: the element's ID :returns: the element or None :rtype: Element | None """ # Cannot use process_elements here because we want to return a # specific element if eid is not None: # Element specified by ID return self._read().get(eid, None) # Element specified by condition for element in self.all(): if cond(element): return element def count(self, cond): """ Count the elements matching a condition. :param cond: the condition use :type cond: Query """ return len(self.search(cond)) def contains(self, cond=None, eids=None): """ Check wether the database contains an element matching a condition or an ID. If ``eids`` is set, it checks if the db contains an element with one of the specified. :param cond: the condition use :type cond: Query :param eids: the element IDs to look for """ if eids is not None: # Elements specified by ID return any(self.get(eid=eid) for eid in eids) # Element specified by condition return self.get(cond) is not None
class Table(object): """ Represents a single TinyDB Table. """ def __init__(self, name, db, cache_size=10): """ Get access to a table. :param name: The name of the table. :type name: str :param db: The parent database. :type db: tinydb.database.TinyDB :param cache_size: Maximum size of query cache. """ self.name = name self._db = db self._query_cache = LRUCache(capacity=cache_size) old_ids = self._read().keys() if old_ids: self._last_id = max(i for i in old_ids) else: self._last_id = 0 def process_elements(self, func, cond=None, eids=None): """ Helper function for processing all elements specified by condition or IDs. A repeating pattern in TinyDB is to run some code on all elements that match a condition or are specified by their ID. This is implemented in this function. The function passed as ``func`` has to be a callable. It's first argument will be the data currently in the database. It's second argument is the element ID of the currently processed element. See: :meth:`~.update`, :meth:`.remove` :param func: the function to execute on every included element. first argument: all data second argument: the current eid :param cond: elements to use :param eids: elements to use """ data = self._read() if eids is not None: # Processed element specified by id for eid in eids: func(data, eid) else: # Processed elements specified by condition for eid in list(data): if cond(data[eid]): func(data, eid) self._write(data) def _get_next_id(self): """ Increment the ID used the last time and return it """ current_id = self._last_id + 1 self._last_id = current_id return current_id def _read(self): """ Reading access to the DB. :returns: all values :rtype: dict """ raw_data = self._db._read(self.name) data = {} for key in list(raw_data): eid = int(key) data[eid] = Element(raw_data[key], eid) return data def _write(self, values): """ Writing access to the DB. :param values: the new values to write :type values: dict """ self._query_cache.clear() self._db._write(values, self.name) def __len__(self): """ Get the total number of elements in the table. """ return len(self._read()) def all(self): """ Get all elements stored in the table. :returns: a list with all elements. :rtype: list[Element] """ return list(self._read().values()) def insert(self, element): """ Insert a new element into the table. :param element: the element to insert :returns: the inserted element's ID """ eid = self._get_next_id() data = self._read() data[eid] = element self._write(data) return eid def insert_multiple(self, elements): """ Insert multiple elements into the table. :param elements: a list of elements to insert :returns: a list containing the inserted elements' IDs """ return [self.insert(element) for element in elements] def remove(self, cond=None, eids=None): """ Remove all matching elements. :param cond: the condition to check against :type cond: query :param eids: a list of element IDs :type eids: list """ self.process_elements(lambda data, eid: data.pop(eid), cond, eids) def update(self, fields, cond=None, eids=None): """ Update all matching elements to have a given set of fields. :param fields: the fields that the matching elements will have or a method that will update the elements :type fields: dict | (dict, int) -> None :param cond: which elements to update :type cond: query :param eids: a list of element IDs :type eids: list """ if callable(fields): _update = lambda data, eid: fields(data[eid]) else: _update = lambda data, eid: data[eid].update(fields) self.process_elements(_update, cond, eids) def purge(self): """ Purge the table by removing all elements. """ self._write({}) self._last_id = 0 def search(self, cond): """ Search for all elements matching a 'where' cond. :param cond: the condition to check against :type cond: Query :returns: list of matching elements :rtype: list[Element] """ if cond in self._query_cache: return self._query_cache[cond] elements = [e for e in self.all() if cond(e)] self._query_cache[cond] = elements return elements def get(self, cond=None, eid=None): """ Get exactly one element specified by a query or and ID. Returns ``None`` if the element doesn't exist :param cond: the condition to check against :type cond: Query :param eid: the element's ID :returns: the element or None :rtype: Element | None """ # Cannot use process_elements here because we want to return a # specific element if eid is not None: # Element specified by ID return self._read().get(eid, None) # Element specified by condition elements = self.search(cond) if elements: return elements[0] def count(self, cond): """ Count the elements matching a condition. :param cond: the condition use :type cond: Query """ return len(self.search(cond)) def contains(self, cond=None, eids=None): """ Check wether the database contains an element matching a condition or an ID. If ``eids`` is set, it checks if the db contains an element with one of the specified. :param cond: the condition use :type cond: Query :param eids: the element IDs to look for """ if eids is not None: # Elements specified by ID return any(self.get(eid=eid) for eid in eids) # Element specified by condition return self.count(cond) > 0 def __enter__(self): """ Allow the database to be used as a context manager. :return: the table instance """ return self def __exit__(self, *args): """ Try to close the storage after being used as a context manager. """ _ = args self._db._storage.close() close = __exit__
class Table(object): """ Represents a single TinyDB Table. """ def __init__(self, storage, cache_size=10): """ Get access to a table. :param storage: Access to the storage :type storage: StorageProxyus :param cache_size: Maximum size of query cache. """ self._storage = storage self._query_cache = LRUCache(capacity=cache_size) data = self._read() if data: self._last_id = max(i for i in data) else: self._last_id = 0 def process_elements(self, func, cond=None, eids=None): """ Helper function for processing all elements specified by condition or IDs. A repeating pattern in TinyDB is to run some code on all elements that match a condition or are specified by their ID. This is implemented in this function. The function passed as ``func`` has to be a callable. It's first argument will be the data currently in the database. It's second argument is the element ID of the currently processed element. See: :meth:`~.update`, :meth:`.remove` :param func: the function to execute on every included element. first argument: all data second argument: the current eid :param cond: elements to use, or :param eids: elements to use :returns: the element IDs that were affected during processed """ data = self._read() if eids is not None: # Processed element specified by id for eid in eids: func(data, eid) else: # Collect affected eids eids = [] # Processed elements specified by condition for eid in list(data): if cond(data[eid]): func(data, eid) eids.append(eid) self._write(data) return eids def clear_cache(self): """ Clear the query cache. A simple helper that clears the internal query cache. """ self._query_cache.clear() def _get_next_id(self): """ Increment the ID used the last time and return it """ current_id = self._last_id + 1 self._last_id = current_id return current_id def _read(self): """ Reading access to the DB. :returns: all values :rtype: dict """ return self._storage.read() def _write(self, values): """ Writing access to the DB. :param values: the new values to write :type values: dict """ self._query_cache.clear() self._storage.write(values) def __len__(self): """ Get the total number of elements in the table. """ return len(self._read()) def all(self): """ Get all elements stored in the table. :returns: a list with all elements. :rtype: list[Element] """ return list(itervalues(self._read())) def insert(self, element): """ Insert a new element into the table. :param element: the element to insert :returns: the inserted element's ID """ eid = self._get_next_id() if not isinstance(element, dict): raise ValueError("Element is not a dictionary") data = self._read() data[eid] = element self._write(data) return eid def insert_multiple(self, elements): """ Insert multiple elements into the table. :param elements: a list of elements to insert :returns: a list containing the inserted elements' IDs """ eids = [] data = self._read() for element in elements: eid = self._get_next_id() eids.append(eid) data[eid] = element self._write(data) return eids def remove(self, cond=None, eids=None): """ Remove all matching elements. :param cond: the condition to check against :type cond: query :param eids: a list of element IDs :type eids: list :returns: a list containing the removed element's ID """ return self.process_elements(lambda data, eid: data.pop(eid), cond, eids) def update(self, fields, cond=None, eids=None): """ Update all matching elements to have a given set of fields. :param fields: the fields that the matching elements will have or a method that will update the elements :type fields: dict | dict -> None :param cond: which elements to update :type cond: query :param eids: a list of element IDs :type eids: list :returns: a list containing the updated element's ID """ if callable(fields): return self.process_elements(lambda data, eid: fields(data[eid]), cond, eids) else: return self.process_elements(lambda data, eid: data[eid].update(fields), cond, eids) def purge(self): """ Purge the table by removing all elements. """ self._write({}) self._last_id = 0 def search(self, cond): """ Search for all elements matching a 'where' cond. :param cond: the condition to check against :type cond: Query :returns: list of matching elements :rtype: list[Element] """ if cond in self._query_cache: return self._query_cache[cond] elements = [element for element in self.all() if cond(element)] self._query_cache[cond] = elements return elements def get(self, cond=None, eid=None): """ Get exactly one element specified by a query or and ID. Returns ``None`` if the element doesn't exist :param cond: the condition to check against :type cond: Query :param eid: the element's ID :returns: the element or None :rtype: Element | None """ # Cannot use process_elements here because we want to return a # specific element if eid is not None: # Element specified by ID return self._read().get(eid, None) # Element specified by condition for element in self.all(): if cond(element): return element def count(self, cond): """ Count the elements matching a condition. :param cond: the condition use :type cond: Query """ return len(self.search(cond)) def contains(self, cond=None, eids=None): """ Check wether the database contains an element matching a condition or an ID. If ``eids`` is set, it checks if the db contains an element with one of the specified. :param cond: the condition use :type cond: Query :param eids: the element IDs to look for """ if eids is not None: # Elements specified by ID return any(self.get(eid=eid) for eid in eids) # Element specified by condition return self.get(cond) is not None