From 692e23bb630bee363fa4919d9167763d0c135f04 Mon Sep 17 00:00:00 2001 From: unknowncoder05 <49960321+unknowncoder05@users.noreply.github.com> Date: Wed, 11 Aug 2021 07:55:04 -0500 Subject: [PATCH 1/2] basic construct functionalities --- .../chat/feed/models/feed.model.json | 6 +- .../chat/feed/models/message.model.json | 2 +- .../chat/feed/models/reaction.model.json | 6 +- .../chat/models/conversation.model.json | 6 +- .../chat/models/message.model.json | 6 +- .../chat/services/conversation.service.json | 4 +- .../utils/auth/user/models/user.model.json | 4 +- .../global/utils/models/pagination.model.json | 2 +- compiler/compiler.py | 3 +- compiler/json_compiler/Compiler.py | 120 ++++++++++++------ .../compiled/json/construct.app.json | 87 +++++++++++++ .../samples/construct.app.json | 16 +++ .../samples/utils/models/human.model.json | 50 ++++++++ 13 files changed, 252 insertions(+), 60 deletions(-) create mode 100644 compiler/sample_blueprints/compiled/json/construct.app.json create mode 100644 compiler/sample_blueprints/samples/construct.app.json create mode 100644 compiler/sample_blueprints/samples/utils/models/human.model.json diff --git a/blueprints/global/communication/chat/feed/models/feed.model.json b/blueprints/global/communication/chat/feed/models/feed.model.json index eb5f475..523207f 100644 --- a/blueprints/global/communication/chat/feed/models/feed.model.json +++ b/blueprints/global/communication/chat/feed/models/feed.model.json @@ -10,18 +10,18 @@ }, "create":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "list":{ "__extends":{ - "from":"attributes" + "__from":"attributes" } }, "get":{ "__extends":{ - "from":"create", + "__from":"create", "__excludes":[ "id"] } } diff --git a/blueprints/global/communication/chat/feed/models/message.model.json b/blueprints/global/communication/chat/feed/models/message.model.json index dc95f98..338fac1 100644 --- a/blueprints/global/communication/chat/feed/models/message.model.json +++ b/blueprints/global/communication/chat/feed/models/message.model.json @@ -8,6 +8,6 @@ "feed":{"type":"feed", "required":true, "user":"__user"} }, "__extends":{ - "from":"global.communication.chat.models.message" + "__from":"global.communication.chat.models.message" } } \ No newline at end of file diff --git a/blueprints/global/communication/chat/feed/models/reaction.model.json b/blueprints/global/communication/chat/feed/models/reaction.model.json index 39126d8..943a225 100644 --- a/blueprints/global/communication/chat/feed/models/reaction.model.json +++ b/blueprints/global/communication/chat/feed/models/reaction.model.json @@ -11,18 +11,18 @@ }, "create":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "list":{ "__extends":{ - "from":"attributes" + "__from":"attributes" } }, "get":{ "__extends":{ - "from":"create", + "__from":"create", "__excludes":[ "id"] } } diff --git a/blueprints/global/communication/chat/models/conversation.model.json b/blueprints/global/communication/chat/models/conversation.model.json index 19fb5cb..cdfef90 100644 --- a/blueprints/global/communication/chat/models/conversation.model.json +++ b/blueprints/global/communication/chat/models/conversation.model.json @@ -12,18 +12,18 @@ }, "create":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "list":{ "__extends":{ - "from":"attributes" + "__from":"attributes" } }, "get":{ "__extends":{ - "from":"create", + "__from":"create", "__excludes":[ "id"] } } diff --git a/blueprints/global/communication/chat/models/message.model.json b/blueprints/global/communication/chat/models/message.model.json index 5424c15..629950f 100644 --- a/blueprints/global/communication/chat/models/message.model.json +++ b/blueprints/global/communication/chat/models/message.model.json @@ -13,18 +13,18 @@ }, "create":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "list":{ "__extends":{ - "from":"attributes" + "__from":"attributes" } }, "get":{ "__extends":{ - "from":"create", + "__from":"create", "__excludes":[ "id"] } } diff --git a/blueprints/global/communication/chat/services/conversation.service.json b/blueprints/global/communication/chat/services/conversation.service.json index 580b882..c8b63d4 100644 --- a/blueprints/global/communication/chat/services/conversation.service.json +++ b/blueprints/global/communication/chat/services/conversation.service.json @@ -19,14 +19,14 @@ "list user conversations":{ "request":{ "__extends":{ - "from":"global.utils.models.pagination.request", + "__from":"global.utils.models.pagination.request", "include":["page", "page_size"] }, "user" : {"type": "__conversation.__user.attributes.id"} }, "response":{ "__extends":{ - "from":"global.utils.models.pagination.response", + "__from":"global.utils.models.pagination.response", "include":["total_count", "page_count"] }, "conversations" : {"many": true, "type": "__conversation.list"} diff --git a/blueprints/global/utils/auth/user/models/user.model.json b/blueprints/global/utils/auth/user/models/user.model.json index 5f7e636..06d40ed 100644 --- a/blueprints/global/utils/auth/user/models/user.model.json +++ b/blueprints/global/utils/auth/user/models/user.model.json @@ -8,13 +8,13 @@ "create":{ "request":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "response":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__includes":["id"] } } diff --git a/blueprints/global/utils/models/pagination.model.json b/blueprints/global/utils/models/pagination.model.json index 2c04c41..f33d973 100644 --- a/blueprints/global/utils/models/pagination.model.json +++ b/blueprints/global/utils/models/pagination.model.json @@ -6,7 +6,7 @@ }, "response":{ "__extends":{ - "from":"request" + "__from":"request" }, "total_count":{ "type":"int", "min":0}, "page_count":{ "type":"int", "min":0}, diff --git a/compiler/compiler.py b/compiler/compiler.py index 663ce12..6854fac 100644 --- a/compiler/compiler.py +++ b/compiler/compiler.py @@ -19,4 +19,5 @@ def main(): main() # python .\compiler.py c "json.v1" ../blueprints/examples/facebook/main.app.json -# python .\compiler.py c "json.v1" ./sample_blueprints/samples/import.app.json \ No newline at end of file +# python .\compiler.py c "json.v1" ./sample_blueprints/samples/import.app.json +# python .\compiler.py c "json.v1" ./sample_blueprints/samples/construct.app.json diff --git a/compiler/json_compiler/Compiler.py b/compiler/json_compiler/Compiler.py index c7281d3..3211225 100644 --- a/compiler/json_compiler/Compiler.py +++ b/compiler/json_compiler/Compiler.py @@ -13,49 +13,85 @@ def load_json_as_dict(file_name): with open(file_name, "r") as f: return json.load(f) -def special_flags_processing(json_dict, args = {}, *, base_folder=None, base_dict={}, object_route=""): +def extends(json_dict, *, base_folder=None, base_dict={}, object_route=""): + extends_from = json_dict[SPECIAL_FIELD_FLAG+"extends"][SPECIAL_FIELD_FLAG+"from"].split(".") + attr_build = {} + if len(extends_from) == 1: + new_route = ".".join(object_route.split(".")+[extends_from[0]]) + if extends_from[0] in base_dict: + attr_build = special_flags_processing(base_dict[extends_from[0]], base_dict=base_dict, object_route = new_route) + else: + CustomLogging.error(f"Attribute {extends_from[0]} not found \n{base_dict}") + else: + attr_file_name = search_json(json_dict[SPECIAL_FIELD_FLAG+"extends"][SPECIAL_FIELD_FLAG+"from"], base_folder=base_folder) + if not attr_file_name: + CustomLogging.error(f"{json_dict[SPECIAL_FIELD_FLAG+'extends'][SPECIAL_FIELD_FLAG+'from']} path does not exists in") + attr_json = load_json_as_dict(attr_file_name) + attr_build = json_global_compile( + attr_json, + args = json_dict[SPECIAL_FIELD_FLAG+"extends"], + base_folder = os.path.dirname(attr_file_name), + object_route=json_dict[SPECIAL_FIELD_FLAG+"extends"][SPECIAL_FIELD_FLAG+"from"] + ) + is_excluding = SPECIAL_FIELD_FLAG+"excludes" in json_dict[SPECIAL_FIELD_FLAG+"extends"] + is_including = SPECIAL_FIELD_FLAG+"includes" in json_dict[SPECIAL_FIELD_FLAG+"extends"] + if is_including and is_excluding: + CustomLogging.error("can not use excludes and includes in a same block") + if is_including: + new_attr_build = {} + for include in json_dict[SPECIAL_FIELD_FLAG+"extends"][SPECIAL_FIELD_FLAG+"includes"]: + if include not in attr_build: + CustomLogging.error(f"{object_route} include error: attribute {include} not in {json_dict[SPECIAL_FIELD_FLAG+'extends'][SPECIAL_FIELD_FLAG+'from']}") + new_attr_build[include] = attr_build[include] + attr_build = new_attr_build + if is_excluding: + for exclude in json_dict[SPECIAL_FIELD_FLAG+"extends"][SPECIAL_FIELD_FLAG+"excludes"]: + if exclude in attr_build: + attr_build.pop(exclude) + else: + CustomLogging.warning(f"exclude error: attribute {exclude} not in {json_dict[SPECIAL_FIELD_FLAG+'extends'][SPECIAL_FIELD_FLAG+'from']}") + json_dict.update(attr_build) + json_dict.pop(SPECIAL_FIELD_FLAG+"extends") + return json_dict +def cosntruct_replace(main_object, arg_replace, value): + if type(main_object) == str: + return main_object.replace(arg_replace, value) + response_json = {} + for attribute in main_object: + attribute_new_name = attribute.replace(arg_replace, value) + attribute_new_value = main_object[attribute] + if type(attribute_new_value) == dict: + attribute_new_value = cosntruct_replace(attribute_new_value, arg_replace, value) + elif type(attribute_new_value) == list: + attribute_new_value = [ cosntruct_replace(element, arg_replace, value) for element in attribute_new_value ] + response_json[attribute_new_name] = attribute_new_value + return response_json +def cosntructor(json_dict, *, args = {}, object_route=""): + json_dict.pop(SPECIAL_FIELD_FLAG+"constructor") + response_json = copy.deepcopy(json_dict) + args_to_check = copy.deepcopy(args) + args_to_check.pop(SPECIAL_FIELD_FLAG+"from") + if SPECIAL_FIELD_FLAG+"excludes" in args_to_check: + args_to_check.pop(SPECIAL_FIELD_FLAG+"excludes") + if SPECIAL_FIELD_FLAG+"includes" in args_to_check: + args_to_check.pop(SPECIAL_FIELD_FLAG+"includes") + for arg in args: + new_value = cosntruct_replace(response_json, SPECIAL_FIELD_FLAG+arg, args[arg]) + response_json = new_value + return response_json +def special_flags_processing(json_dict, *, args = {}, base_folder=None, base_dict={}, object_route=""): if SPECIAL_FIELD_FLAG+"constructor" in json_dict: - json_dict.pop(SPECIAL_FIELD_FLAG+"constructor") + json_dict = cosntructor(json_dict, args=args) + base_dict = copy.deepcopy(json_dict) if SPECIAL_FIELD_FLAG+"extends" in json_dict: - extends_from = json_dict[SPECIAL_FIELD_FLAG+"extends"]["from"].split(".") - attr_build = {} - if len(extends_from) == 1: - if extends_from[0] in base_dict: - attr_build = special_flags_processing(base_dict[extends_from[0]], base_dict=base_dict, object_route = object_route+"."+extends_from[0]) - else: - CustomLogging.error(f"Attribute not found {object_route}.{extends_from[0]}\n{base_dict}") - else: - attr_file_name = search_json(json_dict[SPECIAL_FIELD_FLAG+"extends"]["from"], base_folder=base_folder) - if not attr_file_name: - CustomLogging.error(f"{json_dict[SPECIAL_FIELD_FLAG+'extends']['from']} path does not exists in") - attr_json = load_json_as_dict(attr_file_name) - attr_build = json_global_compile(attr_json, base_folder = os.path.dirname(attr_file_name),object_route=json_dict[SPECIAL_FIELD_FLAG+"extends"]["from"]) - is_excluding = SPECIAL_FIELD_FLAG+"excludes" in json_dict[SPECIAL_FIELD_FLAG+"extends"] - is_including = SPECIAL_FIELD_FLAG+"includes" in json_dict[SPECIAL_FIELD_FLAG+"extends"] - if is_including and is_excluding: - CustomLogging.error("can not use excludes and includes in a same block") - if is_including: - new_attr_build = {} - for include in json_dict[SPECIAL_FIELD_FLAG+"extends"][SPECIAL_FIELD_FLAG+"includes"]: - if include not in attr_build: - CustomLogging.error(f"include error: attribute {include} not in {json_dict[SPECIAL_FIELD_FLAG+'extends']['from']}") - new_attr_build[include] = attr_build[include] - attr_build = new_attr_build - if is_excluding: - for exclude in json_dict[SPECIAL_FIELD_FLAG+"extends"][SPECIAL_FIELD_FLAG+"excludes"]: - if exclude in attr_build: - attr_build.pop(exclude) - else: - CustomLogging.warning(f"exclude error: attribute {exclude} not in {json_dict[SPECIAL_FIELD_FLAG+'extends']['from']}") - json_dict.update(attr_build) - json_dict.pop(SPECIAL_FIELD_FLAG+"extends") + json_dict = extends(json_dict, base_folder=base_folder, base_dict=base_dict, object_route=object_route) for attribute in json_dict: if type(json_dict[attribute]) == dict: - json_dict[attribute] = special_flags_processing(json_dict[attribute], args, base_folder=base_folder, base_dict=base_dict, object_route=f"{object_route}.{attribute}") + json_dict[attribute] = special_flags_processing(json_dict[attribute], args=args, base_folder=base_folder, base_dict=base_dict, object_route=f"{object_route}.{attribute}") return copy.deepcopy(json_dict) -def json_global_compile(json_dict, args = {}, *, base_folder=None, base_dict={}, object_route= ""): - data = special_flags_processing(json_dict, args, base_folder=base_folder, base_dict=json_dict, object_route=object_route) +def json_global_compile(json_dict, *, args = {}, base_folder=None, base_dict={}, object_route= ""): + data = special_flags_processing(json_dict, args=args, base_folder=base_folder, base_dict=json_dict, object_route=object_route) return data class Compiler: blueprint: dict = {} @@ -68,18 +104,20 @@ def __init__(self, main_file) -> None: def compile_models(self): if MODELS_FIELD not in self.blueprint and EXTENDS_FIELD not in self.blueprint: CustomLogging.error("models is not defined") - build = json_global_compile(self.blueprint) + build = json_global_compile(self.blueprint, base_folder=self.main_folder) for model in build["models"].copy(): model_file_name = self.main_file - if type(model) == str: + if type(build["models"][model]) == str: model_file_name = search_json( build["models"][model], base_folder=self.main_folder) if not model_file_name: CustomLogging.error(build["models"][model], "path does not exists in") continue model_json = load_json_as_dict(model_file_name) - elif type(model) == dict: - model_json = model + elif type(build["models"][model]) == dict: + model_json = build["models"][model] + else: + CustomLogging.error(f"invalid model {model}") model_build = json_global_compile(model_json, base_folder = os.path.dirname(model_file_name), object_route=model) build["models"][model] = model_build pp = pprint.PrettyPrinter(indent=2) diff --git a/compiler/sample_blueprints/compiled/json/construct.app.json b/compiler/sample_blueprints/compiled/json/construct.app.json new file mode 100644 index 0000000..3ad6a4f --- /dev/null +++ b/compiler/sample_blueprints/compiled/json/construct.app.json @@ -0,0 +1,87 @@ +{ + "models":{ + "human":{ + "attributes":{ + "id":{ + "type":"id" + }, + "nacimiento":{ + "max":20, + "required":true, + "type":"date" + }, + "nombre":{ + "max":20, + "required":true, + "type":"str" + }, + "sector":{ + "max":100, + "required":true, + "type":"str" + } + }, + "create":{ + "request":{ + "nacimiento":{ + "max":20, + "required":true, + "type":"date" + }, + "nombre":{ + "max":20, + "required":true, + "type":"str" + }, + "sector":{ + "max":100, + "required":true, + "type":"str" + } + }, + "response":{ + "id":{ + "type":"id" + } + } + }, + "get":{ + "request":{ + "id":{ + "type":"id" + } + }, + "response":{ + "nacimiento":{ + "max":20, + "required":true, + "type":"date" + }, + "nombre":{ + "max":20, + "required":true, + "type":"str" + }, + "sector":{ + "max":100, + "required":true, + "type":"str" + } + } + }, + "list":{ + "response":{ + "nombre":{ + "max":20, + "required":true, + "type":"str" + } + } + } + } + }, + "name":"construct", + "services":{ + "human":"utils.services.human" + } + } \ No newline at end of file diff --git a/compiler/sample_blueprints/samples/construct.app.json b/compiler/sample_blueprints/samples/construct.app.json new file mode 100644 index 0000000..f9be1be --- /dev/null +++ b/compiler/sample_blueprints/samples/construct.app.json @@ -0,0 +1,16 @@ +{ + "name": "construct", + "models": { + "human":{ + "__extends":{ + "__from":"utils.models.human", + "name":"nombre", + "birth":"nacimiento", + "sector":"sector" + } + } + }, + "services": { + "human":"utils.services.human" + } +} \ No newline at end of file diff --git a/compiler/sample_blueprints/samples/utils/models/human.model.json b/compiler/sample_blueprints/samples/utils/models/human.model.json new file mode 100644 index 0000000..65ebfa0 --- /dev/null +++ b/compiler/sample_blueprints/samples/utils/models/human.model.json @@ -0,0 +1,50 @@ +{ + "__constructor":{ + "__description": "a human model", + "name":{"type":"str", "default":"name"}, + "birth":{"type":"date", "default":"birth"}, + "sector":{"type":"str", "default":"sector"} + }, + "attributes":{ + "id": {"type":"id"}, + "__name":{"type":"str", "max":20, "required":true}, + "__birth":{"type":"date", "max":20, "required":true}, + "__sector":{"type":"str", "max":100, "required":true} + }, + "create":{ + "request":{ + "__extends":{ + "__from":"attributes", + "__excludes":["id"] + } + }, + "response":{ + "__extends":{ + "__from":"attributes", + "__includes":["id"] + } + } + }, + "list":{ + "response":{ + "__extends":{ + "__from":"attributes", + "__includes":["__name"] + } + } + }, + "get":{ + "request":{ + "__extends":{ + "__from":"attributes", + "__includes":["id"] + } + }, + "response":{ + "__extends":{ + "__from":"attributes", + "__excludes":["id"] + } + } + } +} \ No newline at end of file From 06533c4a7745bd48baf0a1208a9ffddaaeb0eb7d Mon Sep 17 00:00:00 2001 From: unknowncoder05 <49960321+unknowncoder05@users.noreply.github.com> Date: Thu, 12 Aug 2021 07:57:08 -0500 Subject: [PATCH 2/2] constructor default values --- .../chat/models/message.model.json | 3 ++- compiler/json_compiler/Compiler.py | 19 +++++++++++++++---- .../samples/construct.app.json | 3 +-- .../samples/utils/models/human.model.json | 4 ++-- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/blueprints/global/communication/chat/models/message.model.json b/blueprints/global/communication/chat/models/message.model.json index 629950f..4374be9 100644 --- a/blueprints/global/communication/chat/models/message.model.json +++ b/blueprints/global/communication/chat/models/message.model.json @@ -1,7 +1,8 @@ { "__constructor":{ "user":{ - "description":"user to be used" + "type":"str", + "description":"route to user to be used" } }, "attributes":{ diff --git a/compiler/json_compiler/Compiler.py b/compiler/json_compiler/Compiler.py index 3211225..c9b2f3c 100644 --- a/compiler/json_compiler/Compiler.py +++ b/compiler/json_compiler/Compiler.py @@ -9,7 +9,9 @@ SPECIAL_FIELD_FLAG = "__" EXTENDS_FIELD = SPECIAL_FIELD_FLAG+"extends" - +def set_type(object, to_type): + # TODO: implement type serialization + return object def load_json_as_dict(file_name): with open(file_name, "r") as f: return json.load(f) @@ -67,7 +69,7 @@ def cosntruct_replace(main_object, arg_replace, value): response_json[attribute_new_name] = attribute_new_value return response_json def cosntructor(json_dict, *, args = {}, object_route=""): - json_dict.pop(SPECIAL_FIELD_FLAG+"constructor") + constructor_dict = json_dict.pop(SPECIAL_FIELD_FLAG+"constructor") response_json = copy.deepcopy(json_dict) args_to_check = copy.deepcopy(args) args_to_check.pop(SPECIAL_FIELD_FLAG+"from") @@ -75,8 +77,17 @@ def cosntructor(json_dict, *, args = {}, object_route=""): args_to_check.pop(SPECIAL_FIELD_FLAG+"excludes") if SPECIAL_FIELD_FLAG+"includes" in args_to_check: args_to_check.pop(SPECIAL_FIELD_FLAG+"includes") - for arg in args: - new_value = cosntruct_replace(response_json, SPECIAL_FIELD_FLAG+arg, args[arg]) + for arg_to_check in args_to_check: + if arg_to_check not in constructor_dict: + CustomLogging.warning(f"error in constructor: invalid parameter {arg_to_check}") + else: + constructor_dict.pop(arg_to_check) # remove argument so we know it already was defined + for default_attribute in constructor_dict: + if default_attribute.startswith(SPECIAL_FIELD_FLAG): + continue + args_to_check[default_attribute] = set_type(constructor_dict[default_attribute]["default"], constructor_dict[default_attribute]["type"]) + for arg in args_to_check: + new_value = cosntruct_replace(response_json, SPECIAL_FIELD_FLAG+arg, args_to_check[arg]) response_json = new_value return response_json def special_flags_processing(json_dict, *, args = {}, base_folder=None, base_dict={}, object_route=""): diff --git a/compiler/sample_blueprints/samples/construct.app.json b/compiler/sample_blueprints/samples/construct.app.json index f9be1be..2fe5d1a 100644 --- a/compiler/sample_blueprints/samples/construct.app.json +++ b/compiler/sample_blueprints/samples/construct.app.json @@ -5,8 +5,7 @@ "__extends":{ "__from":"utils.models.human", "name":"nombre", - "birth":"nacimiento", - "sector":"sector" + "birth":"nacimiento" } } }, diff --git a/compiler/sample_blueprints/samples/utils/models/human.model.json b/compiler/sample_blueprints/samples/utils/models/human.model.json index 65ebfa0..12a4d45 100644 --- a/compiler/sample_blueprints/samples/utils/models/human.model.json +++ b/compiler/sample_blueprints/samples/utils/models/human.model.json @@ -1,8 +1,8 @@ { + "__description": "a human model", "__constructor":{ - "__description": "a human model", "name":{"type":"str", "default":"name"}, - "birth":{"type":"date", "default":"birth"}, + "birth":{"type":"str", "default":"birth"}, "sector":{"type":"str", "default":"sector"} }, "attributes":{