diff --git a/api/__init__.py b/api/__init__.py index e31759f..4f2c38b 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -38,6 +38,9 @@ from .s6_pumps import get_pump_schema, add_pump, get_pump, set_pump, delete_pump from .s7_valves import VALVES_TYPE_PRV, VALVES_TYPE_PSV, VALVES_TYPE_PBV, VALVES_TYPE_FCV, VALVES_TYPE_TCV, VALVES_TYPE_GPV from .s7_valves import get_valve_schema, add_valve, get_valve, set_valve, delete_valve +from .s8_tags import TAG_TYPE_NODE, TAG_TYPE_LINK +from .s8_tags import get_tag_schema, get_tag, set_tag + from .s9_demands import get_demand_schema, get_demand, set_demand from .s10_status import LINK_STATUS_OPEN, LINK_STATUS_CLOSED, LINK_STATUS_ACTIVE diff --git a/api/s8_tags.py b/api/s8_tags.py new file mode 100644 index 0000000..67b53b0 --- /dev/null +++ b/api/s8_tags.py @@ -0,0 +1,79 @@ +from .operation import * + +TAG_TYPE_NODE = 'NODE' +TAG_TYPE_LINK = 'LINK' + +def get_tag_schema(name: str) -> dict[str, dict[str, Any]]: + return { 't_type' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'id' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'tag' : {'type': 'str' , 'optional': True , 'readonly': False},} + + +def get_tag(name: str, t_type: str, id: str) -> dict[str, Any]: + t = None + if t_type == TAG_TYPE_NODE: + t = try_read(name, f"select * from tags_node where id = '{id}'") + elif t_type == TAG_TYPE_LINK: + t = try_read(name, f"select * from tags_link where id = '{id}'") + else: + raise Exception('Only support NODE and Link') + if t == None: + return { 't_type': t_type, 'id': id, 'tag': None } + d = {} + d['t_type'] = t_type + d['id'] = str(t['id']) + d['tag'] = str(t['tag']) if t['tag'] != None else None + return d + + +class Tag(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'tag' + self.t_type = str(input['t_type']) + self.id = str(input['id']) + self.tag = str(input['tag']) if 'tag' in input and input['tag'] != None else None + + self.f_type = f"'{self.type}'" + self.f_t_type = f"'{self.t_type}'" + self.f_id = f"'{self.id}'" + self.f_tag = f"'{self.tag}'" if self.tag != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 't_type': self.t_type, 'id': self.id, 'tag': self.tag } + + +def set_tag_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + old = Tag(get_tag(name, cs.operations[0]['t_type'], cs.operations[0]['id'])) + raw_new = get_tag(name, cs.operations[0]['t_type'], cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_tag_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Tag(raw_new) + + table = '' + if cs.operations[0]['t_type'] == TAG_TYPE_NODE: + table = 'tags_node' + elif cs.operations[0]['t_type'] == TAG_TYPE_LINK: + table = 'tags_link' + else: + raise Exception('Only support NODE and Link') + + redo_sql = f"delete from {table} where id = {new.f_id};" + if new.tag != None: + redo_sql += f"\ninsert into {table} (id, tag) values ({new.f_id}, {new.f_tag});" + + undo_sql = f"delete from {table} where id = {old.f_id};" + if old.tag != None: + undo_sql += f"\ninsert into {table} (id, tag) values ({old.f_id}, {old.f_tag});" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) + + +def set_tag(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, set_tag_cache(name, cs)) diff --git a/test_tjnetwork.py b/test_tjnetwork.py index 918f547..e33b971 100644 --- a/test_tjnetwork.py +++ b/test_tjnetwork.py @@ -1174,6 +1174,89 @@ class TestApi: self.leave(p) + def test_tag(self): + p = 'test_tag' + self.enter(p) + + add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + add_junction(p, ChangeSet({'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + assert is_junction(p, 'j1') + assert is_junction(p, 'j2') + + add_pipe(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN })) + assert is_pipe(p, 'p0') + + t = get_tag(p, TAG_TYPE_NODE, 'j1') + assert t['tag'] == None + set_tag(p, ChangeSet({'t_type': TAG_TYPE_NODE, 'id': 'j1', 'tag': 'j1t' })) + t = get_tag(p, TAG_TYPE_NODE, 'j1') + assert t['tag'] == 'j1t' + + t = get_tag(p, TAG_TYPE_NODE, 'j2') + assert t['tag'] == None + set_tag(p, ChangeSet({'t_type': TAG_TYPE_NODE, 'id': 'j2', 'tag': 'j2t' })) + t = get_tag(p, TAG_TYPE_NODE, 'j2') + assert t['tag'] == 'j2t' + + t = get_tag(p, TAG_TYPE_LINK, 'p0') + assert t['tag'] == None + set_tag(p, ChangeSet({'t_type': TAG_TYPE_LINK, 'id': 'p0', 'tag': 'p0t' })) + t = get_tag(p, TAG_TYPE_LINK, 'p0') + assert t['tag'] == 'p0t' + + self.leave(p) + + def test_tag_op(self): + p = 'test_tag_op' + self.enter(p) + + add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + add_junction(p, ChangeSet({'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + assert is_junction(p, 'j1') + assert is_junction(p, 'j2') + + add_pipe(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN })) + assert is_pipe(p, 'p0') + + cs = set_tag(p, ChangeSet({'t_type': TAG_TYPE_NODE, 'id': 'j1', 'tag': 'j1t' })).operations[0] + assert cs['type'] == 'tag' + assert cs['t_type'] == TAG_TYPE_NODE + assert cs['id'] == 'j1' + assert cs['tag'] == 'j1t' + + cs = execute_undo(p).operations[0] + assert cs['type'] == 'tag' + assert cs['t_type'] == TAG_TYPE_NODE + assert cs['id'] == 'j1' + assert cs['tag'] == None + + cs = execute_redo(p).operations[0] + assert cs['type'] == 'tag' + assert cs['t_type'] == TAG_TYPE_NODE + assert cs['id'] == 'j1' + assert cs['tag'] == 'j1t' + + cs = set_tag(p, ChangeSet({'t_type': TAG_TYPE_LINK, 'id': 'p0', 'tag': 'p0t' })).operations[0] + assert cs['type'] == 'tag' + assert cs['t_type'] == TAG_TYPE_LINK + assert cs['id'] == 'p0' + assert cs['tag'] == 'p0t' + + cs = execute_undo(p).operations[0] + assert cs['type'] == 'tag' + assert cs['t_type'] == TAG_TYPE_LINK + assert cs['id'] == 'p0' + assert cs['tag'] == None + + cs = execute_redo(p).operations[0] + assert cs['type'] == 'tag' + assert cs['t_type'] == TAG_TYPE_LINK + assert cs['id'] == 'p0' + assert cs['tag'] == 'p0t' + + self.leave(p) + + def test_demand(self): p = 'test_demand' self.enter(p) diff --git a/tjnetwork.py b/tjnetwork.py index 9f88c8e..7579f49 100644 --- a/tjnetwork.py +++ b/tjnetwork.py @@ -40,6 +40,9 @@ VALVES_TYPE_FCV = api.VALVES_TYPE_FCV VALVES_TYPE_TCV = api.VALVES_TYPE_TCV VALVES_TYPE_GPV = api.VALVES_TYPE_GPV +TAG_TYPE_NODE = api.TAG_TYPE_NODE +TAG_TYPE_LINK = api.TAG_TYPE_LINK + LINK_STATUS_OPEN = api.LINK_STATUS_OPEN LINK_STATUS_CLOSED = api.LINK_STATUS_CLOSED LINK_STATUS_ACTIVE = api.LINK_STATUS_ACTIVE @@ -334,6 +337,23 @@ def delete_valve(name: str, cs: ChangeSet) -> ChangeSet: return api.delete_valve(name, cs) +############################################################ +# tag 8.[TAGS] +############################################################ + +def get_tag_schema(name: str) -> dict[str, dict[str, Any]]: + return api.get_tag_schema(name) + +def get_tag(name: str, t_type: str, id: str) -> dict[str, Any]: + return api.get_tag(name, t_type, id) + +# example: +# set_tag(p, ChangeSet({'t_type': TAG_TYPE_NODE, 'id': 'j1', 'tag': 'j1t' })) +# set_tag(p, ChangeSet({'t_type': TAG_TYPE_LINK, 'id': 'p0', 'tag': 'p0t' })) +def set_tag(name: str, cs: ChangeSet) -> ChangeSet: + return api.set_tag(name, cs) + + ############################################################ # demand 9.[DEMANDS] ############################################################