diff --git a/examples/distributed_counter_example.py b/examples/distributed_counter_example.py index cb93e86..7882e49 100644 --- a/examples/distributed_counter_example.py +++ b/examples/distributed_counter_example.py @@ -1,7 +1,10 @@ +from flask_boiler import fields +from flask_boiler.business_property_store import BPSchema from flask_boiler.context import Context as CTX from flask_boiler.schema import Schema from flask_boiler.fields import Integer from flask_boiler.domain_model import DomainModel +from flask_boiler.struct import Struct from flask_boiler.view_mediator_dav import ViewMediatorDAV from flask_boiler.view_model import ViewModel @@ -22,6 +25,10 @@ class CounterViewSchema(Schema): total_count = Integer(dump_only=True) +class ShardsStoreBpss(BPSchema): + shards = fields.StructuralRef(dm_cls=Shard, many=True) + + class CounterView(ViewModel): class Meta: @@ -34,7 +41,7 @@ def __init__(self, *args, **kwargs): @property def total_count(self): - return sum(v.count for _, v in self.shards.items()) + return sum(v.count for _, v in self.store.shards.items()) def set_shard(self, sid, shard): self.shards[sid] = shard @@ -62,16 +69,15 @@ def notify(cls, obj): def start(self): - struct = dict() + struct = Struct(schema_obj=ShardsStoreBpss()) for i in range(self.shard_size): doc_id = str(i) shard = Shard.new(doc_id=doc_id, ) shard.save() - struct[shard.doc_id] = (Shard, doc_id) + struct["shards"][shard.doc_id] = (Shard, doc_id) self.view_model = self.view_model_cls.get( f_notify=self.notify, struct_d=struct, once=False) - diff --git a/examples/fluttergram/tests/test_delta_dav.py b/examples/fluttergram/tests/test_delta_dav.py index 06aac17..6d39bec 100644 --- a/examples/fluttergram/tests/test_delta_dav.py +++ b/examples/fluttergram/tests/test_delta_dav.py @@ -5,6 +5,8 @@ DocumentReference, Query from examples.fluttergram.domain_models import Post, User +from flask_boiler.business_property_store import BPSchema +from flask_boiler.struct import Struct from flask_boiler.view import DocumentAsView from flask_boiler.view_mediator_dav import ViewMediatorDAV, \ @@ -21,20 +23,25 @@ class PostDAVSchema(schema.Schema): post = fields.Embedded(dump_only=True) +class PostStoreBpss(BPSchema): + consumer = fields.StructuralRef(dm_cls=User) + post = fields.StructuralRef(dm_cls=Post) + + class PostDAV(DocumentAsView): class Meta: schema_cls = PostDAVSchema @property def post(self): - return self.business_properties["post"] + return self.store.post @classmethod def new(cls, *args, consumer_id, post_id, **kwargs): ref = User._get_collection().document(consumer_id).collection("feed") \ .document(post_id) - struct = dict() + struct = Struct(schema_obj=PostStoreBpss()) struct["consumer"] = (User, consumer_id) struct["post"] = (Post, post_id) diff --git a/flask_boiler/business_property_store.py b/flask_boiler/business_property_store.py index 299408a..cb7df6c 100644 --- a/flask_boiler/business_property_store.py +++ b/flask_boiler/business_property_store.py @@ -31,7 +31,7 @@ def structural_ref_fields(self): class BusinessPropertyStore: - def __init__(self, struct, snapshot_container, schema_obj): + def __init__(self, struct, snapshot_container): super().__init__() self._container = snapshot_container self.struct = struct diff --git a/flask_boiler/view_model.py b/flask_boiler/view_model.py index ffa3efd..61c0d7d 100644 --- a/flask_boiler/view_model.py +++ b/flask_boiler/view_model.py @@ -105,13 +105,12 @@ def __init__(self, struct_d=None, f_notify=None, *args, **kwargs): :param kwargs: """ super().__init__(*args, **kwargs) - self.business_properties: Dict[str, DomainModel] = dict() self.snapshot_container = SnapshotContainer() if not isinstance(struct_d, Struct): raise ValueError self._struct_d = struct_d self.store = BusinessPropertyStore( - struct=self._struct_d, schema_obj=struct_d.schema_obj, + struct=self._struct_d, snapshot_container=self.snapshot_container) self._on_update_funcs: Dict[str, Tuple] = dict() self.listener = None diff --git a/tests/color_fixtures.py b/tests/color_fixtures.py index 17936a7..40863be 100644 --- a/tests/color_fixtures.py +++ b/tests/color_fixtures.py @@ -1,6 +1,12 @@ import pytest as pytest +from google.type.color_pb2 import Color from flask_boiler import schema, fields, domain_model, view_model, factory +from flask_boiler.business_property_store import BPSchema +from flask_boiler.model_registry import ModelRegistry +from flask_boiler.struct import Struct +from flask_boiler.utils import random_id +from flask_boiler.view_model import ViewModel from .fixtures import setup_app @@ -12,6 +18,78 @@ class ColorDomainModelBase(domain_model.DomainModel): _collection_name = "colors" +class RainbowStoreBpss(BPSchema): + colors = fields.StructuralRef(dm_cls=Color, many=True) + + +class RainbowSchemaDAV(schema.Schema): + rainbow_name = fields.Raw(dump_only=True) + colors = fields.Raw(dump_only=True) + + +@pytest.fixture +def rainbow_vm(CTX): + + if ModelRegistry.get_cls_from_name("RainbowViewModelDAV") is not None: + return ModelRegistry.get_cls_from_name("RainbowViewModelDAV") + + class RainbowViewModelDAV(ViewModel): + + _schema_cls = RainbowSchemaDAV + _color_d = dict() + + @property + def colors(self): + res = list() + for key in sorted(self._color_d): + res.append(self._color_d[key]) + return res + + @property + def rainbow_name(self): + res = list() + for key in sorted(self._color_d): + res.append(self._color_d[key]) + return "-".join(res) + + def set_color(self, color_name): + self._color_d[color_name] = color_name + + def get_vm_update_callback(self, dm_cls, *args, **kwargs): + + if dm_cls == Color: + def callback(vm: RainbowViewModelDAV, dm: Color): + vm.set_color(dm.name) + return callback + else: + return super().get_vm_update_callback(dm_cls, *args, **kwargs) + + @classmethod + def create_from_color_names(cls, color_names, **kwargs): + struct = Struct(schema_obj=RainbowStoreBpss()) + struct["colors"] = { + "doc_id_{}".format(color_name): + (Color, "doc_id_{}".format(color_name)) + for color_name in color_names + } + + vm_id = random_id() + doc_ref = CTX.db.collection("RainbowDAV").document(vm_id) + return super().get(doc_ref=doc_ref, + struct_d=struct, + once=False, + **kwargs) + + @classmethod + def new(cls, color_names: str=None, **kwargs): + color_name_list = color_names.split("+") + return cls.create_from_color_names( + color_names=color_name_list, + **kwargs) + + return RainbowViewModelDAV + + @pytest.fixture def color_refs(request): diff --git a/tests/test_bpstore.py b/tests/test_bpstore.py index 9d4bd8e..a2cdf49 100644 --- a/tests/test_bpstore.py +++ b/tests/test_bpstore.py @@ -1,3 +1,5 @@ +from flask_boiler.snapshot_container import SnapshotContainer +from flask_boiler.struct import Struct from .color_fixtures import color_refs, Color from .fixtures import CTX from flask_boiler import fields @@ -14,9 +16,8 @@ def test_get_manifest(color_refs): cian_id = color_refs[0].id - struct = { - "favorite_color": cian_id - } + struct = Struct(schema_obj=SomeSchema()) + struct["favorite_color"] = (Color, cian_id) g, gr, manifest = BusinessPropertyStore._get_manifests(struct, SomeSchema()) @@ -31,17 +32,16 @@ def test_get_manifest(color_refs): def test_update(CTX, color_refs): cian_id = color_refs[0].id - struct = { - "favorite_color": cian_id - } + struct = Struct(schema_obj=SomeSchema()) + struct["favorite_color"] = (Color, cian_id) class Store(BusinessPropertyStore): - _schema_cls = SomeSchema + pass - store = Store(struct) + store = Store(struct=struct, snapshot_container=SnapshotContainer()) store._container.set( 'projects/flask-boiler-testing/databases/(default)/documents/colors/doc_id_cian', CTX.db.document('projects/flask-boiler-testing/databases/(default)/documents/colors/doc_id_cian').get() ) - + store.refresh() assert isinstance(store.favorite_color, Color) diff --git a/tests/test_document_as_view.py b/tests/test_document_as_view.py index 62465eb..05caf2b 100644 --- a/tests/test_document_as_view.py +++ b/tests/test_document_as_view.py @@ -6,86 +6,33 @@ from flask_boiler import schema, fields, view, domain_model, factory, \ view_model, view_mediator +from flask_boiler.business_property_store import BPSchema from flask_boiler.referenced_object import ReferencedObject +from flask_boiler.struct import Struct from flask_boiler.utils import random_id from flask_boiler.view_mediator_dav import ViewMediatorDAV from flask_boiler.view_model import PersistableMixin, ViewModelMixin from .fixtures import CTX -from .color_fixtures import color_refs, ColorSchema, ColorDomainModelBase, Color +from .color_fixtures import color_refs, ColorSchema, ColorDomainModelBase, \ + Color, rainbow_vm from tests.fixtures import setup_app -def test_rainbow_stuffs(CTX, setup_app, color_refs): +def test_rainbow_stuffs(CTX, setup_app, color_refs, rainbow_vm): app = setup_app + RainbowViewModelDAV = rainbow_vm assert isinstance(app, Flask) - vm_id = random_id() - - class RainbowSchemaDAV(schema.Schema): - rainbow_name = fields.Raw(dump_only=True) - colors = fields.Raw(dump_only=True) - - class RainbowViewModelDAV(view.DocumentAsView): - - _schema_cls = RainbowSchemaDAV - _color_d = dict() - - @property - def colors(self): - res = list() - for key in sorted(self._color_d): - res.append(self._color_d[key]) - return res - - @property - def rainbow_name(self): - res = list() - for key in sorted(self._color_d): - res.append(self._color_d[key]) - return "-".join(res) - - def set_color(self, color_name): - self._color_d[color_name] = color_name - - def get_vm_update_callback(self, dm_cls, *args, **kwargs): - - if dm_cls == Color: - def callback(vm: RainbowViewModelDAV, dm: Color): - vm.set_color(dm.name) - return callback - else: - return super().get_vm_update_callback(dm_cls, *args, **kwargs) - - @classmethod - def create_from_color_names(cls, color_names, **kwargs): - struct = dict() - - for color_name in color_names: - obj_type = Color - doc_id = "doc_id_{}".format(color_name) - - struct[color_name] = (obj_type, doc_id) - doc_ref = CTX.db.collection("RainbowDAV").document(vm_id) - return super().get(doc_ref=doc_ref, - struct_d=struct, - once=False, - **kwargs) - - @classmethod - def new(cls, color_names: str=None, **kwargs): - color_name_list = color_names.split("+") - return cls.create_from_color_names( - color_names=color_name_list, - **kwargs) - def notify(self): self.save() obj = RainbowViewModelDAV.new("yellow+magenta+cian", f_notify=notify) + vm_id = obj.doc_ref.id + # time.sleep(3) assert CTX.db.collection("RainbowDAV").document(vm_id).get().to_dict() == { diff --git a/tests/test_flask_as_view.py b/tests/test_flask_as_view.py index cf5b931..f23c1dd 100644 --- a/tests/test_flask_as_view.py +++ b/tests/test_flask_as_view.py @@ -8,63 +8,20 @@ view_model, view_mediator from .fixtures import CTX -from .color_fixtures import color_refs, ColorSchema, ColorDomainModelBase, Color +from .color_fixtures import color_refs, ColorSchema, ColorDomainModelBase, \ + Color, rainbow_vm from tests.fixtures import setup_app -def test_rainbow_stuffs(CTX, setup_app, color_refs): +def test_rainbow_stuffs(CTX, setup_app, color_refs, rainbow_vm): app = setup_app assert isinstance(app, Flask) test_client = app.test_client() - class RainbowSchema(schema.Schema): - rainbow_name = fields.Raw(dump_only=True) - colors = fields.Raw(dump_only=True) - - class RainbowViewModel(view.FlaskAsView): - - _schema_cls = RainbowSchema - _color_d = dict() - - @property - def colors(self): - res = list() - for key in sorted(self._color_d): - res.append(self._color_d[key]) - return res - - @property - def rainbow_name(self): - res = list() - for key in sorted(self._color_d): - res.append(self._color_d[key]) - return "-".join(res) - - def set_color(self, color_name): - self._color_d[color_name] = color_name - - def get_vm_update_callback(self, dm_cls, *args, **kwargs): - def update_func(vm: RainbowViewModel, dm: Color): - vm.set_color(dm.name) - return update_func - - @classmethod - def get_from_color_names(cls, color_names): - struct = dict() - - for color_name in color_names: - obj_type = Color - doc_id = "doc_id_{}".format(color_name) - - struct[color_name] = (obj_type, doc_id) - return super().get(struct_d=struct, once=True) - - @classmethod - def new(cls, color_names: str=None): - color_name_list = color_names.split("+") - return cls.get_from_color_names(color_names=color_name_list) + class RainbowViewModel(rainbow_vm): + pass mediator = view_mediator.ViewMediator( view_model_cls=RainbowViewModel, diff --git a/tests/test_model_registry.py b/tests/test_model_registry.py index d175c21..8e3bd00 100644 --- a/tests/test_model_registry.py +++ b/tests/test_model_registry.py @@ -30,3 +30,13 @@ def test_get_children(): assert RModelSup._get_children() == {RModelA, RModelB} assert RModelA._get_parents() == {RModelSup,} + +def test_register_subclass(): + + class CModelParent(model_registry.BaseRegisteredModel): + pass + + class CModelChild(CModelParent): + pass + + assert CModelChild.__name__ == "CModelChild" diff --git a/tests/test_view.py b/tests/test_view.py index 7c4f0e9..04935e0 100644 --- a/tests/test_view.py +++ b/tests/test_view.py @@ -8,7 +8,9 @@ from flask import Flask -from tests.color_fixtures import Color, PaletteViewModel, vm, color_refs +from flask_boiler.struct import Struct +from tests.color_fixtures import Color, PaletteViewModel, vm, color_refs, \ + RainbowStoreBpss from tests.fixtures import setup_app from .fixtures import CTX @@ -50,7 +52,8 @@ def update_func(vm: RainbowView, dm: Color): @classmethod def get_from_color_names(cls, color_names): - struct = dict() + + struct = Struct(schema_obj=RainbowStoreBpss()) order_gen = count() order_d = dict() @@ -61,9 +64,9 @@ def get_from_color_names(cls, color_names): order_d[doc_id] = next(order_gen) - struct[color_name] = (obj_type, doc_id,) + struct["colors"][doc_id] = (obj_type, doc_id,) - return cls.get(struct_d=struct, order_d=order_d) + return cls.get(struct_d=struct, order_d=order_d, once=True) return RainbowView