Exemplo n.º 1
0
 def _get_subfield_defaults(cls):
     total = {"data": {}, "computed": {"_mjson_revert_patch": None}}
     for k, v in cls.subfields["data"].items():
         total["data"][k] = json_encode(v.default)
     for k, v in cls.subfields["computed"].items():
         total["computed"][k] = json_encode(v.default)
     return total
Exemplo n.º 2
0
 def patch_json_field(self):
     if self.status == Status.DELETED:
         return
     assert self.status in (Status.NORMAL, Status.WORKING), self.status
     total_default = self.subfield_defaults
     _schema_changed = False
     old_status = self.__dict__["status"]
     for json_field_name in total_default:
         json_field = self.__dict__[json_field_name]
         field_default = total_default[json_field_name]
         for key, value in field_default.items():
             if key not in json_field:
                 if callable(value):
                     value = safe_call(value, self)
                 json_field[key] = json_deepcopy_with_callable(value)
                 _schema_changed = True
                 self.__dict__["status"] = Status.DIRTY
                 self._mjson_revert_patch.update(
                     {"status": json_encode(old_status), json_field_name: {"_schema_changed": _schema_changed}}
                 )
         for k in [k for k in json_field.keys() if k not in field_default]:
             del json_field[k]
             _schema_changed = True
             self.__dict__["status"] = Status.DIRTY
             self._mjson_revert_patch.update(
                 {"status": json_encode(old_status), json_field_name: {"_schema_changed": _schema_changed}}
             )
     if _schema_changed and settings.IS_UNIT_TEST:
         self._mjson_on_init = deepcopy(self.mjson)
         self._mjson_on_init["status"] = json_encode(old_status)
Exemplo n.º 3
0
 def _init_no_inited_subfields(self):
     for k, v in self.data.items():
         if v is None and k[0] != "_":
             subfield = self.get_subfield(k)
             assert subfield.null, console_log("{} 는 null 이 허용되지 않습니다.".format(subfield.subfield_name))
         elif callable(v):
             self.data[k] = json_encode(safe_call(v, self))
     for k, v in self.computed.items():
         if v is None and k[0] != "_":
             subfield = self.get_subfield(k)
             assert subfield.null
         elif callable(v):
             self.computed[k] = json_encode(safe_call(v, self))
Exemplo n.º 4
0
    def test_data_setter(self):
        instance = Dummy()
        old_computed = deepcopy(instance.computed)
        old_data = deepcopy(instance.data)
        with ForceChanger(instance):
            instance.uri = "/uri/1/"
        assert instance.computed["uri"] == "/uri/1/"
        old_computed["uri"] = "/uri/1/"
        old_computed["uri_hash"] = json_encode(instance.uri_hash)
        assert instance.computed == old_computed

        instance.data = {"temp": 1}
        assert instance.data["temp"] == 1
        old_data["temp"] = 1
        assert instance.data == old_data

        instance.data = {"temp": 0}
        assert instance.data["temp"] == 0
        old_data["temp"] = 0
        assert instance.data == old_data

        instance.monitors.append(0)
        assert instance.data["monitors"] == [0]
        old_data["monitors"] = [0]
        assert instance.data == old_data
Exemplo n.º 5
0
 def __get__(self, instance, owner):
     if not instance:
         return self
     field_name, subfield_name, subfield_type, expire = (
         self.field_name,
         self.subfield_name,
         self.subfield_type,
         self.expire,
     )
     json_field = getattr(instance, field_name)
     value = json_field[subfield_name]
     if callable(value):
         try:
             value = value(instance)
         except Exception as e:
             msg = "{}: {}".format(e.__class__.__name__, str(e))
             if "NoneType" in msg or "DoesNotExist" in msg:
                 return None
             else:
                 raise e
         assert not callable(value)
         assert self.check_schema(value)
         value = json_encode(value)
         json_field[subfield_name] = value
     value_decoded = json_decode(value, subfield_type)
     return value_decoded
Exemplo n.º 6
0
 def onchange_subfield(self, field_name, subfield_name, old, new):
     assert old != new, "old 와 new 값이 같은 경우는 원천적으로 발생되지 않도록 해야 합니다."
     old_status, _mjson_revert_patch, subfields = (self.status, self._mjson_revert_patch, self.subfields)
     subfield = subfields[field_name][subfield_name]
     assert not isinstance(subfield, SubfieldWrapper)
     if old_status == Status.CREATING:
         # TODO : save() 호출 자체를 없애고 나면 이것도 없애기
         # 이때는 on_create 이후 별도로 onchange 이벤트를 일괄 발생시킴
         return
     if subfield_name not in _mjson_revert_patch[field_name]:
         _mjson_revert_patch[field_name][subfield_name] = json_encode(old)
     with ForceChanger(self):
         if old_status not in (Status.NEW, Status.NO_SYNC):
             self.status = Status.DIRTY
         self._process_dependent_computed(subfield_name)
         # original
         onchange_func_name = ONCHANGE_FUNC_NAME.format(subfield_name)
         func = getattr(self, onchange_func_name, None)
         func and func(old, new)
         # wrappers
         for wrapper in subfields["_wrapper_reverse"].get(subfield_name, []):
             onchange_func_name = ONCHANGE_FUNC_NAME.format(wrapper.wrapper_subfield_name)
             func = getattr(self, onchange_func_name, None)
             func and func(old, new)
     self._process_expire_onchange(subfield_name)
Exemplo n.º 7
0
    def test_data_setter(self):
        with Transaction() as tran:
            instance = Dummy.objects.create()
        old_data = deepcopy(instance.data)
        old_computed = deepcopy(instance.computed)
        old_transaction_id = tran.id
        with tran:
            with ForceChanger(instance):
                instance.uri = "/uri/1/"
            instance.save()

        with Transaction():
            instance_old = instance
            instance = Dummy.objects.get(id=instance.id)
            assert id(instance_old) != id(instance)
            assert instance.computed["uri"] == "/uri/1/"
            old_computed["uri"] = "/uri/1/"
            old_computed["uri_hash"] = json_encode(instance.uri_hash)
            old_computed["_mjson_revert_patch"] = {
                "data": {},
                "status": 10,
                "version": 1,
                "computed": {
                    "uri": None,
                    "uri_hash": None
                },
                "computed_uri_hash": None,
                "last_transaction": old_transaction_id,
            }
            assert instance.computed == old_computed
            instance.data = {"temp": 1}
            instance.save()

        with Transaction():
            instance_old = instance
            instance = Dummy.objects.get(id=instance.id)
            assert id(instance_old) != id(instance)
            assert instance.data["temp"] == 1
            old_data["temp"] = 1
            assert instance.data == old_data
            instance.data = {"temp": 0}
            instance.save()

        with Transaction():
            instance_old = instance
            instance = Dummy.objects.get(id=instance.id)
            assert id(instance_old) != id(instance)
            assert instance.data["temp"] == 0
            old_data["temp"] = 0
            assert instance.data == old_data
            instance.monitors.append(0)
            instance.save()

        with Transaction():
            instance_old = instance
            instance = Dummy.objects.get(id=instance.id)
            assert id(instance_old) != id(instance)
            assert instance.data["monitors"] == [0]
            old_data["monitors"] = [0]
            assert instance.data == old_data
Exemplo n.º 8
0
 def convert_filter(self, model, parts, value, lookup_type, raw):
     if self.filter:
         assert lookup_type == "exact", console_log(
             "filter 가 지정된 subfield 에 대해서는 exact 검색만 가능합니다.", lookup_type)
         return self.filter(model, value)
     assert lookup_type not in ("isnull", ), console_log(
         "subfield 에 대해 지원되지 않는 lookup_type 입니다.", lookup_type)
     return {
         "{}__{}__{}".format(self.field_name, LOOKUP_SEP.join(parts), lookup_type):
         json_encode(value)
     }
Exemplo n.º 9
0
 def __set__(self, instance, patch):
     instance.assert_changeable(self.field_name)
     assert self.check_schema(patch)
     d = super().__get__(instance, instance.__class__)
     old = d[:]
     # address 가 바뀌면 안되기 때문에 성능을 약간 희생해서라도 이렇게 구현
     d.clear()
     patch = [json_encode(e) for e in patch]
     d.extend(patch)
     if old != d:
         instance.onchange_subfield(self.field_name, self.subfield_name,
                                    old, d)
     return old
Exemplo n.º 10
0
 def __set__(self, instance, value):
     cls, subfield_type, normalize, lf_name, field_name, subfield_name, create_only = (
         instance.__class__,
         self.subfield_type,
         self.normalize,
         self.subfield_name,
         self.field_name,
         self.subfield_name,
         self.create_only,
     )
     json_field = getattr(instance, field_name)
     if normalize and value is not None:
         old = value
         value = normalize(value)
         if instance.status == Status.NEW and old != value:
             if instance.raw is None:
                 instance.raw = {}
             instance.raw[lf_name] = old
     # value 를 subfield_type 으로 변환. 따라서 json_decode() 는 형변환도 구현해야 함
     value = json_decode(value, subfield_type)
     # old
     old = json_field[subfield_name]
     if callable(old):
         old = None
     old = json_decode(old, subfield_type)
     if old != value:
         # TODO : if 블럭 밖에 있으면 에러 발생. 장고 내부 코드 확인 후 조처 ( django.db.models.query )
         """
         if annotation_col_map:
             for attr_name, col_pos in annotation_col_map.items():
                 setattr(obj, attr_name, row[col_pos])
         """
         if create_only:
             assert instance.status in (Status.CREATING,
                                        Status.NEW), console_log(
                                            "{}.{} = {} ({})".format(
                                                self.owner.__name__,
                                                self.subfield_name, value,
                                                instance.status))
             assert old is None
             assert value is not None
         assert self.check_schema(value), console_log(
             "{}.check_schema({}) is fail!".format(self.subfield_name,
                                                   value))
         instance.assert_changeable(field_name)
         json_field[subfield_name] = json_encode(value)
         instance.onchange_subfield(field_name, subfield_name, old, value)
     return old
Exemplo n.º 11
0
 def __setattr__(self, field_name, value):
     # __dict__ setter
     if field_name[0] == "_" or not self._is_initialized:
         self.__dict__[field_name] = value
         return
     # object setter
     # TODO : 모두 확정된 후 로컬상수변수로 대체하여 튜닝
     if field_name in self.field_names_needs_object_setter:
         return object.__setattr__(self, field_name, value)
     # for overrides super().delete()
     if field_name == "id" and value is None:
         return
     # set field
     old = getattr(self, field_name)
     if old != value:
         # for django admin
         if value is None and field_name in ("data", "computed"):
             return
         # check pre condition
         self.assert_changeable(field_name)
         # change value
         if field_name == "data":
             for subfield, subvalue in value.items():
                 setattr(self, subfield, subvalue)
         elif field_name == "status":
             assert old.check_route(value), "해당 status 변경은 허용되지 않습니다: {} --> {}".format(old, value)
             self.__dict__["status"] = value
         elif field_name == "computed":
             assert not settings.IS_UNIT_TEST, "computed field 직접 세팅은 허용되지 않습니다."
             # for django admin
             console_log("try change of computed field is ignored")
         else:
             if self.status in (Status.NORMAL, Status.WORKING):
                 self.__setattr__("status", Status.DIRTY)
             self.__dict__[field_name] = value
         # make revert patch
         if field_name not in self._mjson_revert_patch and field_name in self.field_names:
             self._mjson_revert_patch[field_name] = json_encode(old)
         # raw
         if field_name == "raw":
             assert self.status in (Status.CREATING, Status.NEW)
             self.init_data_by_raw()
Exemplo n.º 12
0
 def remove(self, value):
     encoded = json_encode(value)
     index = self._d.index(encoded)
     del self._d[index]
     return index
Exemplo n.º 13
0
 def append(self, value):
     self._d.append(json_encode(value))
Exemplo n.º 14
0
 def __setitem__(self, key, value):
     self._d[key] = json_encode(value)
Exemplo n.º 15
0
 def encoder(d, k, v):
     patch[k] = json_encode(v)
Exemplo n.º 16
0
 def __setattr__(self, key, value):
     if key[0] == "_":
         self.__dict__[key] = json_encode(value)
         return
     patch = {key: value}
     self._setter(patch)
Exemplo n.º 17
0
 def mjson(self):
     mjson = {}
     for field_name in self.field_names:
         mjson[field_name] = json_encode(getattr(self, field_name))
     return mjson
Exemplo n.º 18
0
 def encoder(d, k, v, storage):
     patch[k] = json_encode(v)