loosen type Mapper args, add more Database tests

This commit is contained in:
Sam G. 2024-04-18 12:31:16 -07:00
parent 6caf2631b8
commit 0509487b62
6 changed files with 61 additions and 29 deletions

View File

@ -56,7 +56,7 @@ class RelationalAccessor[R: Relation](Accessor[R]):
connection, connection,
text: str text: str
): ):
connection.exec #connection.exec
raise NotImplementedError raise NotImplementedError
def select( def select(
@ -104,11 +104,17 @@ class SQLAccessor(RelationalAccessor[SQLTable]):
mappings=False, mappings=False,
include_cols=False, include_cols=False,
): ):
res_method = utils.db.sa_exec_dicts res = SQLEngine.execute(
if mappings: connection,
res_method = utils.db.sa_exec_mappings sql,
bind_params=bind_params,
include_cols=include_cols
)
return res_method(self.database.engine, sa.text(sql), bind_params=bind_params, include_cols=include_cols) if mappings:
return res.mappings().all()
else:
return self.result_dicts(res)
def select( def select(
self, self,

View File

@ -37,13 +37,13 @@ class Collector[C: Component]:
def __init__(self, schema: Schema[C]): def __init__(self, schema: Schema[C]):
self.schema = schema self.schema = schema
self._inserts = defaultdict(lambda: defaultdict(list)) self._inserts = {}
@property @property
def inserts(self): def inserts(self):
return self._inserts_from_receipts() return self._inserts_from_receipts()
def _inserts_from_receipts(self, receipts: list=None, pop=False): def _inserts_from_receipts(self, receipts: list[str]|None=None, pop=False):
''' '''
Group up added inserts by Component, often to be used directly for bulk insertion. Group up added inserts by Component, often to be used directly for bulk insertion.
Optionally provide a list of `receipts` to group up only the corresponding subset of Optionally provide a list of `receipts` to group up only the corresponding subset of
@ -104,7 +104,7 @@ class Collector[C: Component]:
return receipt return receipt
def collect_inserts(self, receipts=None): def collect_inserts(self, receipts:list[str]|None=None):
''' '''
Collect insert-ready dictionaries for the core primitive schema. This method is Collect insert-ready dictionaries for the core primitive schema. This method is
effectively a light wrapper around the File and Note-based collection logic effectively a light wrapper around the File and Note-based collection logic

View File

@ -157,17 +157,25 @@ class Mapper[C: Component]:
self.attach(_type, attr_comp, coll_groups=coll_groups) self.attach(_type, attr_comp, coll_groups=coll_groups)
def get_attribute_comp( def get_attr_comp(
self, self,
type_ref: type[CO3] co3_ref: CO3 | type[CO3]
) -> C | None: ) -> C | None:
type_ref = co3_ref
if isinstance(co3_ref, CO3):
type_ref = co3_ref.__class__
return self.attribute_comps.get(type_ref, None) return self.attribute_comps.get(type_ref, None)
def get_collation_comp( def get_coll_comp(
self, self,
type_ref: type[CO3], co3_ref: CO3 | type[CO3],
group=str | None, group=str | None,
) -> C | None: ) -> C | None:
type_ref = co3_ref
if isinstance(co3_ref, CO3):
type_ref = co3_ref.__class__
return self.collation_groups.get(type_ref, {}).get(group, None) return self.collation_groups.get(type_ref, {}).get(group, None)
def collect( def collect(
@ -201,7 +209,7 @@ class Mapper[C: Component]:
receipts = [] receipts = []
for _cls in reversed(obj.__class__.__mro__[:-2]): for _cls in reversed(obj.__class__.__mro__[:-2]):
attribute_component = self.get_attribute_comp(_cls) attribute_component = self.get_attr_comp(_cls)
# require an attribute component for type consideration # require an attribute component for type consideration
if attribute_component is None: if attribute_component is None:
@ -222,7 +230,7 @@ class Mapper[C: Component]:
_, action_groups = obj.action_registry.get(action_key, (None, [])) _, action_groups = obj.action_registry.get(action_key, (None, []))
for action_group in action_groups: for action_group in action_groups:
collation_component = self.get_collation_comp(_cls, group=action_group) collation_component = self.get_coll_comp(_cls, group=action_group)
if collation_component is None: if collation_component is None:
continue continue
@ -331,7 +339,7 @@ class ComposableMapper[C: ComposableComponent](Mapper[C]):
def compose( def compose(
self, self,
obj: CO3 | type[CO3], co3_ref: CO3 | type[CO3],
action_groups: list[str] | None = None, action_groups: list[str] | None = None,
*compose_args, *compose_args,
**compose_kwargs, **compose_kwargs,
@ -348,13 +356,13 @@ class ComposableMapper[C: ComposableComponent](Mapper[C]):
Parameters: Parameters:
obj: either a CO3 instance or a type reference obj: either a CO3 instance or a type reference
''' '''
class_ref = obj type_ref = co3_ref
if isinstance(obj, CO3): if isinstance(co3_ref, CO3):
class_ref = obj.__class__ type_ref = co3_ref.__class__
attr_comp_agg = None attr_comp_agg = None
for _cls in reversed(class_ref.__mro__[:-2]): for _cls in reversed(type_ref.__mro__[:-2]):
attr_comp = self.get_attribute_comp(_cls) attr_comp = self.get_attr_comp(_cls)
# require an attribute component for type consideration # require an attribute component for type consideration
if attr_comp is None: if attr_comp is None:
@ -364,7 +372,7 @@ class ComposableMapper[C: ComposableComponent](Mapper[C]):
coll_comp_agg = attr_comp coll_comp_agg = attr_comp
if action_groups is not None: if action_groups is not None:
for action_group in action_groups: for action_group in action_groups:
coll_comp = self.get_collation_comp(_cls, group=action_group) coll_comp = self.get_coll_comp(_cls, group=action_group)
if coll_comp is None: if coll_comp is None:
continue continue

View File

@ -7,14 +7,14 @@ def test_mapper_getters():
veg_comp = veg.vegetable_schema.get_component('vegetable') veg_comp = veg.vegetable_schema.get_component('vegetable')
tom_comp = veg.vegetable_schema.get_component('tomato') tom_comp = veg.vegetable_schema.get_component('tomato')
assert veg.vegetable_mapper.get_attribute_comp(veg.Vegetable) is veg_comp assert veg.vegetable_mapper.get_attr_comp(veg.Vegetable) is veg_comp
assert veg.vegetable_mapper.get_attribute_comp(veg.Tomato) is tom_comp assert veg.vegetable_mapper.get_attr_comp(veg.Tomato) is tom_comp
tom_aging = veg.vegetable_schema.get_component('tomato_aging_states') tom_aging = veg.vegetable_schema.get_component('tomato_aging_states')
tom_cooking = veg.vegetable_schema.get_component('tomato_cooking_states') tom_cooking = veg.vegetable_schema.get_component('tomato_cooking_states')
assert veg.vegetable_mapper.get_collation_comp(veg.Tomato, 'aging') is tom_aging assert veg.vegetable_mapper.get_coll_comp(veg.Tomato, 'aging') is tom_aging
assert veg.vegetable_mapper.get_collation_comp(veg.Tomato, 'cooking') is tom_cooking assert veg.vegetable_mapper.get_coll_comp(veg.Tomato, 'cooking') is tom_cooking
def test_mapper_attach(): def test_mapper_attach():
assert veg.vegetable_mapper.attach( assert veg.vegetable_mapper.attach(

View File

@ -20,6 +20,24 @@ def test_database_insert():
tomato = veg.Tomato('t1', 5) tomato = veg.Tomato('t1', 5)
veg.vegetable_mapper.collect(tomato) veg.vegetable_mapper.collect(tomato)
# test instance as arg
tom_comp = veg.vegetable_mapper.get_attr_comp(tomato)
inserts = veg.vegetable_mapper.collector.collect_inserts()
tom_inserts = inserts.get(tom_comp)
assert tom_inserts is not None
with db.engine.connect() as connection:
assert db.manager.insert(
connection,
tom_comp,
tom_inserts,
) is not None
def test_database_insert_many():
tomato = veg.Tomato('t2', 5)
veg.vegetable_mapper.collect(tomato)
with db.engine.connect() as connection: with db.engine.connect() as connection:
assert db.manager.insert_many( assert db.manager.insert_many(
connection, connection,

View File

@ -7,14 +7,14 @@ def test_mapper_getters():
veg_comp = veg.vegetable_schema.get_component('vegetable') veg_comp = veg.vegetable_schema.get_component('vegetable')
tom_comp = veg.vegetable_schema.get_component('tomato') tom_comp = veg.vegetable_schema.get_component('tomato')
assert veg.vegetable_mapper.get_attribute_comp(veg.Vegetable) is veg_comp assert veg.vegetable_mapper.get_attr_comp(veg.Vegetable) is veg_comp
assert veg.vegetable_mapper.get_attribute_comp(veg.Tomato) is tom_comp assert veg.vegetable_mapper.get_attr_comp(veg.Tomato) is tom_comp
tom_aging = veg.vegetable_schema.get_component('tomato_aging_states') tom_aging = veg.vegetable_schema.get_component('tomato_aging_states')
tom_cooking = veg.vegetable_schema.get_component('tomato_cooking_states') tom_cooking = veg.vegetable_schema.get_component('tomato_cooking_states')
assert veg.vegetable_mapper.get_collation_comp(veg.Tomato, 'aging') is tom_aging assert veg.vegetable_mapper.get_coll_comp(veg.Tomato, 'aging') is tom_aging
assert veg.vegetable_mapper.get_collation_comp(veg.Tomato, 'cooking') is tom_cooking assert veg.vegetable_mapper.get_coll_comp(veg.Tomato, 'cooking') is tom_cooking
def test_mapper_attach(): def test_mapper_attach():
assert veg.vegetable_mapper.attach( assert veg.vegetable_mapper.attach(