add compose cache to Mapper

This commit is contained in:
Sam G. 2024-05-07 03:56:13 -07:00
parent 0d394c9bec
commit 686e1efd3a
4 changed files with 67 additions and 5 deletions

View File

@ -19,10 +19,6 @@ class Accessor[C: Component](metaclass=ABCMeta):
Access wrapper class for complex queries and easy integration with Composer tables.
Implements high-level access to things like common constrained SELECT queries.
Parameters:
engine: SQLAlchemy engine to use for queries. Engine is initialized dynamically as
a property (based on the config) if not provided
Instance variables:
access_log: time-indexed log of access queries performed
'''

View File

@ -105,7 +105,7 @@ class Collector[C: Component]:
return receipt
def collect_inserts(self, receipts:list[str]|None=None):
def collect_inserts(self, receipts: list[str] | None = None):
'''
Collect insert-ready dictionaries for the core primitive schema. This method is
effectively a light wrapper around the File and Note-based collection logic

View File

@ -0,0 +1,43 @@
from co3.indexer import Indexer
class RelationalIndexer(Indexer):
_cls_select_cache = {}
_cls_groupby_cache = defaultdict(dict)
def __init__(self, accessor, cache_select=True, cache_groupby=True):
self.accessor = accessor
# set instance caches; if remains None, methods can't index
self._select_cache = None
self._groupby_cache = None
if cache_groupby and not cache_select:
raise ValueError('cannot cache groupbys without select caching enabled')
if cache_select:
self._select_cache = self._cls_select_cache
if cache_groupby:
self._groupby_cache = self._cls_groupby_cache
self._access_lock = threading.Lock()
def cache_clear(self, group_by_only=False):
self._groupby_cache.clear()
if not group_by_only:
self._select_cache.clear()
def cache_block(
self,
table,
**kwargs,
):
'''
Provide a user-friendly, dynamically re-indexable
'''
return CacheBlock(
indexer = self,
table = table,
**kwargs,
)

View File

@ -388,6 +388,12 @@ class ComposableMapper[C: ComposableComponent](Mapper[C]):
automatic discovery structures could help constrain schema definitions to be
more in-line with the CO3 operational model. That all being said, this is a
large amount of complexity and should likely be avoided until necessary.
.. admonition:: Instance variables
- ``type_compose_cache``: index for previously computed compositions. This index
is reset if either ``attach`` or ``attach_many`` is
called to allow possible new type propagation.
'''
def __init__(
self,
@ -400,6 +406,18 @@ class ComposableMapper[C: ComposableComponent](Mapper[C]):
self.attr_compose_map = attr_compose_map
self.coll_compose_map = coll_compose_map
self.type_compose_cache = {}
def attach(self, *args, **kwargs):
self.type_compose_cache = {}
super().attach(*args, **kwargs)
def attach_many(self, *args, **kwargs):
self.type_compose_cache = {}
super().attach_many(*args, **kwargs)
def compose(
self,
co3_ref: CO3 | type[CO3],
@ -426,6 +444,9 @@ class ComposableMapper[C: ComposableComponent](Mapper[C]):
if isinstance(co3_ref, CO3):
type_ref = co3_ref.__class__
if type_ref in self.type_compose_cache:
return self.type_compose_cache[type_ref]
comp_agg = None
last_attr_comp = None
last_coll_comps = None
@ -489,4 +510,6 @@ class ComposableMapper[C: ComposableComponent](Mapper[C]):
last_attr_comp = attr_comp
last_coll_comps = coll_list
self.type_compose_cache[type_ref] = comp_agg
return comp_agg