diff --git a/api/__init__.py b/api/__init__.py index 6e6840e..22fa887 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -48,12 +48,16 @@ from .s10_status import get_status_schema, get_status, set_status from .s11_patterns import get_pattern_schema, get_pattern, set_pattern, add_pattern, delete_pattern +from .s12_curves import CURVE_TYPE_PUMP, CURVE_TYPE_EFFICIENCY, CURVE_TYPE_VOLUME, CURVE_TYPE_HEADLOSS from .s12_curves import get_curve_schema, get_curve, set_curve, add_curve, delete_curve from .s13_controls import get_control_schema, get_control, set_control from .s14_rules import get_rule_schema, get_rule, set_rule +from .s15_energy import get_global_energy_schema, get_global_energy, set_global_energy +from .s15_energy import get_pump_energy_schema, get_pump_energy, set_pump_energy + from .s16_emitters import get_emitter_schema, get_emitter, set_emitter from .s21_times import TIME_STATISTIC_NONE, TIME_STATISTIC_AVERAGED, TIME_STATISTIC_MINIMUM, TIME_STATISTIC_MAXIMUM, TIME_STATISTIC_RANGE @@ -67,3 +71,9 @@ from .s23_options import OPTION_QUALITY_NONE, OPTION_QUALITY_CHEMICAL, OPTION_QU from .s23_options import get_option_schema, get_option, set_option from .s24_coordinates import get_node_coord + +from .s25_vertices import get_vertex_schema, get_vertex, set_vertex, add_vertex, delete_vertex + +from .s26_labels import get_label_schema, get_label, set_label, add_label, delete_label + +from .s27_backdrop import get_backdrop_schema, get_backdrop, set_backdrop diff --git a/api/s11_patterns.py b/api/s11_patterns.py index f8ceb6e..7b4a6d3 100644 --- a/api/s11_patterns.py +++ b/api/s11_patterns.py @@ -16,52 +16,78 @@ def get_pattern(name: str, id: str) -> dict[str, Any]: def set_pattern_cache(name: str, cs: ChangeSet) -> SqlChangeSet: id = cs.operations[0]['id'] + f_id = f"'{id}'" old = get_pattern(name, id) - new = { 'id': id, 'factors': [] } - f_id = f"'{id}'" + new = { 'id': id } + if 'factors' in cs.operations[0]: + new['factors'] = cs.operations[0]['factors'] + else: + new['factors'] = old['factors'] # TODO: transaction ? redo_sql = f"delete from patterns where id = {f_id};" - redo_sql += f"\ndelete from _pattern where id = {f_id};" - if len(cs.operations[0]['factors']) > 0: - redo_sql += f"\ninsert into _pattern (id) values ({f_id});" - for factor in cs.operations[0]['factors']: - f_factor = float(factor) + for f_factor in new['factors']: redo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});" - new['factors'].append(factor) undo_sql = f"delete from patterns where id = {f_id};" - undo_sql += f"\ndelete from _pattern where id = {f_id};" - if len(old['factors']) > 0: - undo_sql += f"\ninsert into _pattern (id) values ({f_id});" for f_factor in old['factors']: undo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});" - redo_cs = { 'type': 'pattern' } | new - undo_cs = { 'type': 'pattern' } | old + redo_cs = g_update_prefix | { 'type': 'pattern' } | new + undo_cs = g_update_prefix | { 'type': 'pattern' } | old return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) def set_pattern(name: str, cs: ChangeSet) -> ChangeSet: - result = set_pattern_cache(name, cs) - result.redo_cs |= g_update_prefix - result.undo_cs |= g_update_prefix - return execute_command(name, result) + return execute_command(name, set_pattern_cache(name, cs)) + + +def add_pattern_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + new = { 'id': id, 'factors': cs.operations[0]['factors'] } + + # TODO: transaction ? + redo_sql = f"insert into _pattern (id) values ({f_id});" + for f_factor in new['factors']: + redo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});" + + undo_sql = f"delete from patterns where id = {f_id};" + undo_sql += f"\ndelete from _pattern where id = {f_id};" + + redo_cs = g_add_prefix | { 'type': 'pattern' } | new + undo_cs = g_delete_prefix | { 'type': 'pattern' } | { 'id': id } + + return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) def add_pattern(name: str, cs: ChangeSet) -> ChangeSet: - result = set_pattern_cache(name, cs) - result.redo_cs |= g_add_prefix - result.undo_cs |= g_delete_prefix - return execute_command(name, result) + return execute_command(name, add_pattern_cache(name, cs)) + + +def delete_pattern_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + old = get_pattern(name, id) + + redo_sql = f"delete from patterns where id = {f_id};" + redo_sql += f"\ndelete from _pattern where id = {f_id};" + + # TODO: transaction ? + undo_sql = f"insert into _pattern (id) values ({f_id});" + for f_factor in old['factors']: + undo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});" + + redo_cs = g_delete_prefix | { 'type': 'pattern' } | { 'id': id } + undo_cs = g_add_prefix | { 'type': 'pattern' } | old + + return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) def delete_pattern(name: str, cs: ChangeSet) -> ChangeSet: - cs.operations[0]['factors'] = [] - result = set_pattern_cache(name, cs) - result.redo_cs |= g_delete_prefix - result.undo_cs |= g_add_prefix - return execute_command(name, result) + return execute_command(name, delete_pattern_cache(name, cs)) diff --git a/api/s12_curves.py b/api/s12_curves.py index 14bc2ba..eb8010d 100644 --- a/api/s12_curves.py +++ b/api/s12_curves.py @@ -1,34 +1,81 @@ from .operation import * +CURVE_TYPE_PUMP = 'PUMP' +CURVE_TYPE_EFFICIENCY = 'EFFICIENCY' +CURVE_TYPE_VOLUME = 'VOLUME' +CURVE_TYPE_HEADLOSS = 'HEADLOSS' def get_curve_schema(name: str) -> dict[str, dict[str, Any]]: return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'c_type' : {'type': 'str' , 'optional': False , 'readonly': False}, 'coords' : {'type': 'list' , 'optional': False , 'readonly': False, 'element': { 'x' : {'type': 'float' , 'optional': False , 'readonly': False }, 'y' : {'type': 'float' , 'optional': False , 'readonly': False } }}} def get_curve(name: str, id: str) -> dict[str, Any]: + c_one = read(name, f"select * from _curve where id = '{id}'") cus = read_all(name, f"select * from curves where id = '{id}' order by _order") cs = [] for r in cus: cs.append({ 'x': float(r['x']), 'y': float(r['y']) }) - return { 'id': id, 'coords': cs } + d = {} + d['id'] = id + d['c_type'] = c_one['type'] + d['coords'] = cs + return d def set_curve_cache(name: str, cs: ChangeSet) -> SqlChangeSet: id = cs.operations[0]['id'] + f_id = f"'{id}'" old = get_curve(name, id) - new = { 'id': id, 'coords': [] } + old_f_type = f"'{old['c_type']}'" - f_id = f"'{id}'" + new = { 'id': id } + if 'coords' in cs.operations[0]: + new['coords'] = cs.operations[0]['coords'] + else: + new['coords'] = old['coords'] + if 'c_type' in cs.operations[0]: + new['c_type'] = cs.operations[0]['c_type'] + else: + new['c_type'] = old['c_type'] + new_f_type = f"'{new['c_type']}'" # TODO: transaction ? redo_sql = f"delete from curves where id = {f_id};" - redo_sql += f"\ndelete from _curve where id = {f_id};" - if len(cs.operations[0]['coords']) > 0: - redo_sql += f"\ninsert into _curve (id) values ({f_id});" + redo_sql += f"\nupdate _curve set type = {new_f_type} where id = {f_id};" + for xy in new['coords']: + f_x, f_y = xy['x'], xy['y'] + redo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});" + + undo_sql = f"delete from curves where id = {f_id};" + undo_sql += f"\nupdate _curve set type = {old_f_type} where id = {f_id};" + for xy in old['coords']: + f_x, f_y = xy['x'], xy['y'] + undo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});" + + redo_cs = g_update_prefix | { 'type': 'curve' } | new + undo_cs = g_update_prefix | { 'type': 'curve' } | old + + return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) + + +def set_curve(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, set_curve_cache(name, cs)) + + +def add_curve_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + new = { 'id': id, 'c_type': cs.operations[0]['c_type'], 'coords': [] } + new_f_type = f"'{new['c_type']}'" + + # TODO: transaction ? + redo_sql = f"insert into _curve (id, type) values ({f_id}, {new_f_type});" for xy in cs.operations[0]['coords']: x, y = float(xy['x']), float(xy['y']) f_x, f_y = x, y @@ -37,35 +84,38 @@ def set_curve_cache(name: str, cs: ChangeSet) -> SqlChangeSet: undo_sql = f"delete from curves where id = {f_id};" undo_sql += f"\ndelete from _curve where id = {f_id};" - if len(old['coords']) > 0: - undo_sql += f"\ninsert into _curve (id) values ({f_id});" - for xy in old['coords']: - f_x, f_y = xy['x'], xy['y'] - undo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});" - redo_cs = { 'type': 'curve' } | new - undo_cs = { 'type': 'curve' } | old + redo_cs = g_add_prefix | { 'type': 'curve' } | new + undo_cs = g_delete_prefix | { 'type': 'curve' } | { 'id' : id } return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) -def set_curve(name: str, cs: ChangeSet) -> ChangeSet: - result = set_curve_cache(name, cs) - result.redo_cs |= g_update_prefix - result.undo_cs |= g_update_prefix - return execute_command(name, result) - - def add_curve(name: str, cs: ChangeSet) -> ChangeSet: - result = set_curve_cache(name, cs) - result.redo_cs |= g_add_prefix - result.undo_cs |= g_delete_prefix - return execute_command(name, result) + return execute_command(name, add_curve_cache(name, cs)) + + +def delete_curve_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + old = get_curve(name, id) + old_f_type = f"'{old['c_type']}'" + + redo_sql = f"delete from curves where id = {f_id};" + redo_sql += f"\ndelete from _curve where id = {f_id};" + + # TODO: transaction ? + undo_sql = f"insert into _curve (id, type) values ({f_id}, {old_f_type});" + for xy in old['coords']: + f_x, f_y = xy['x'], xy['y'] + undo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});" + + redo_cs = g_delete_prefix | { 'type': 'curve' } | { 'id' : id } + undo_cs = g_add_prefix | { 'type': 'curve' } | old + + return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) def delete_curve(name: str, cs: ChangeSet) -> ChangeSet: - cs.operations[0]['coords'] = [] - result = set_curve_cache(name, cs) - result.redo_cs |= g_delete_prefix - result.undo_cs |= g_add_prefix - return execute_command(name, result) + return execute_command(name, delete_curve_cache(name, cs)) diff --git a/api/s15_energy.py b/api/s15_energy.py new file mode 100644 index 0000000..9302806 --- /dev/null +++ b/api/s15_energy.py @@ -0,0 +1,134 @@ +from .operation import * + + +def get_global_energy_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'price' : {'type': 'float' , 'optional': True , 'readonly': False}, + 'pattern' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'effic' : {'type': 'float' , 'optional': True , 'readonly': False}, + 'demand_charge' : {'type': 'float' , 'optional': True , 'readonly': False} } + + +def get_global_energy(name: str) -> dict[str, Any]: + ge = read(name, f"select * from energy_global") + d = {} + d['price'] = float(ge['price']) + d['pattern'] = str(ge['pattern']) if ge['pattern'] != None else None + d['effic'] = float(ge['effic']) + d['demand_charge'] = float(ge['demand_charge']) + return d + + +class GlobalEnergy(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'global_energy' + self.price = float(input['price']) if 'price' in input and input['price'] != None else 0.0 + self.pattern = str(input['pattern']) if 'pattern' in input and input['pattern'] != None else None + self.effic = float(input['effic']) if 'effic' in input and input['effic'] != None else 75 + self.demand_charge = float(input['demand_charge']) if 'demand_charge' in input and input['demand_charge'] != None else 0.0 + + self.f_type = f"'{self.type}'" + self.f_price = self.price + self.f_pattern = f"'{self.pattern}'" if self.pattern != None else 'null' + self.f_effic = self.effic + self.f_demand_charge = self.demand_charge + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'price': self.price, 'pattern': self.pattern, 'effic': self.effic, 'demand_charge': self.demand_charge } + + +def set_global_energy_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + old = GlobalEnergy(get_global_energy(name)) + raw_new = get_global_energy(name) + + new_dict = cs.operations[0] + schema = get_global_energy_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = GlobalEnergy(raw_new) + + redo_sql = f"update energy_global set price = {new.f_price}, pattern = {new.f_pattern}, effic = {new.f_effic}, demand_charge = {new.f_demand_charge} where _no = 0;" + undo_sql = f"update energy_global set price = {old.f_price}, pattern = {old.f_pattern}, effic = {old.f_effic}, demand_charge = {old.f_demand_charge} where _no = 0;" + + 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_global_energy(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, set_global_energy_cache(name, cs)) + + +def get_pump_energy_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'pump' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'price' : {'type': 'float' , 'optional': True , 'readonly': False}, + 'pattern' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'effic' : {'type': 'str' , 'optional': True , 'readonly': False} } + + +def get_pump_energy(name: str, pump: str) -> dict[str, Any]: + d = {} + d['pump'] = pump + pe = try_read(name, f"select * from energy_pump_price where pump = '{pump}'") + d['price'] = float(pe['price']) if pe != None else None + pe = try_read(name, f"select * from energy_pump_pattern where pump = '{pump}'") + d['pattern'] = str(pe['pattern']) if pe != None else None + pe = try_read(name, f"select * from energy_pump_effic where pump = '{pump}'") + d['effic'] = str(pe['effic']) if pe != None else None + return d + + +class PumpEnergy(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'pump_energy' + self.pump = str(input['pump']) + self.price = float(input['price']) if 'price' in input and input['price'] != None else None + self.pattern = str(input['pattern']) if 'pattern' in input and input['pattern'] != None else None + self.effic = str(input['effic']) if 'effic' in input and input['effic'] != None else None + + self.f_pump = f"'{self.pump}'" + self.f_type = f"'{self.type}'" + self.f_price = self.price if self.price != None else 'null' + self.f_pattern = f"'{self.pattern}'" if self.pattern != None else 'null' + self.f_effic = f"'{self.effic}'" if self.effic != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'pump': self.pump, 'price': self.price, 'pattern': self.pattern, 'effic': self.effic } + + +def set_pump_energy_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + old = PumpEnergy(get_pump_energy(name, cs.operations[0]['pump'])) + raw_new = get_pump_energy(name, cs.operations[0]['pump']) + + new_dict = cs.operations[0] + schema = get_pump_energy_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = PumpEnergy(raw_new) + + redo_sql = f"delete from energy_pump_price where pump = {new.f_pump};\ndelete from energy_pump_pattern where pump = {new.f_pump};\ndelete from energy_pump_effic where pump = {new.f_pump};" + if new.price != None: + redo_sql += f"\ninsert into energy_pump_price (pump, price) values ({new.f_pump}, {new.f_price});" + if new.pattern != None: + redo_sql += f"\ninsert into energy_pump_pattern (pump, pattern) values ({new.f_pump}, {new.f_pattern});" + if new.effic != None: + redo_sql += f"\ninsert into energy_pump_effic (pump, effic) values ({new.f_pump}, {new.f_effic});" + + undo_sql = f"delete from energy_pump_price where pump = {old.f_pump};\ndelete from energy_pump_pattern where pump = {old.f_pump};\ndelete from energy_pump_effic where pump = {old.f_pump};" + if old.price != None: + undo_sql += f"\ninsert into energy_pump_price (pump, price) values ({old.f_pump}, {old.f_price});" + if old.pattern != None: + undo_sql += f"\ninsert into energy_pump_pattern (pump, pattern) values ({old.f_pump}, {old.f_pattern});" + if old.effic != None: + undo_sql += f"\ninsert into energy_pump_effic (pump, effic) values ({old.f_pump}, {old.f_effic});" + + 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_pump_energy(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, set_pump_energy_cache(name, cs)) diff --git a/api/s25_vertices.py b/api/s25_vertices.py new file mode 100644 index 0000000..c668af0 --- /dev/null +++ b/api/s25_vertices.py @@ -0,0 +1,65 @@ +from .operation import * + + +def get_vertex_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'link' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'coords' : {'type': 'list' , 'optional': False , 'readonly': False, + 'element': { 'x' : {'type': 'float' , 'optional': False , 'readonly': False }, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False } }}} + + +def get_vertex(name: str, link: str) -> dict[str, Any]: + cus = read_all(name, f"select * from vertices where link = '{link}' order by _order") + cs = [] + for r in cus: + cs.append({ 'x': float(r['x']), 'y': float(r['y']) }) + return { 'link': link, 'coords': cs } + + +def set_vertex_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + link = cs.operations[0]['link'] + + old = get_vertex(name, link) + new = { 'link': link, 'coords': [] } + + f_link = f"'{link}'" + + # TODO: transaction ? + redo_sql = f"delete from vertices where link = {f_link};" + for xy in cs.operations[0]['coords']: + x, y = float(xy['x']), float(xy['y']) + f_x, f_y = x, y + redo_sql += f"\ninsert into vertices (link, x, y) values ({f_link}, {f_x}, {f_y});" + new['coords'].append({ 'x': x, 'y': y }) + + undo_sql = f"delete from vertices where link = {f_link};" + for xy in old['coords']: + f_x, f_y = xy['x'], xy['y'] + undo_sql += f"\ninsert into vertices (link, x, y) values ({f_link}, {f_x}, {f_y});" + + redo_cs = { 'type': 'vertex' } | new + undo_cs = { 'type': 'vertex' } | old + + return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) + + +def set_vertex(name: str, cs: ChangeSet) -> ChangeSet: + result = set_vertex_cache(name, cs) + result.redo_cs |= g_update_prefix + result.undo_cs |= g_update_prefix + return execute_command(name, result) + + +def add_vertex(name: str, cs: ChangeSet) -> ChangeSet: + result = set_vertex_cache(name, cs) + result.redo_cs |= g_add_prefix + result.undo_cs |= g_delete_prefix + return execute_command(name, result) + + +def delete_vertex(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0]['coords'] = [] + result = set_vertex_cache(name, cs) + result.redo_cs |= g_delete_prefix + result.undo_cs |= g_add_prefix + return execute_command(name, result) diff --git a/api/s26_labels.py b/api/s26_labels.py new file mode 100644 index 0000000..af5d01d --- /dev/null +++ b/api/s26_labels.py @@ -0,0 +1,99 @@ +from .operation import * + + +def get_label_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'x' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'label' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'node' : {'type': 'str' , 'optional': True , 'readonly': False} } + + +def get_label(name: str, x: float, y: float) -> dict[str, Any]: + d = {} + d['x'] = x + d['y'] = y + l = try_read(name, f'select * from labels where x = {x} and y = {y}') + if l == None: + d['label'] = None + d['node'] = None + else: + d['label'] = str(l['label']) + d['node'] = str(l['node']) if l['node'] != None else None + return d + + +class Label(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'label' + self.x = float(input['x']) + self.y = float(input['y']) + self.label = str(input['label']) + self.node = str(input['node']) if 'node' in input and input['node'] != None else None + + self.f_type = f"'{self.type}'" + self.f_x = self.x + self.f_y = self.y + self.f_label = f"'{self.label}'" + self.f_node = f"'{self.node}'" if self.node != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'x': self.x, 'y': self.y, 'label': self.label, 'node': self.node } + + def as_xy_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'x': self.x, 'y': self.y } + + +def set_label_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + old = Label(get_label(name, cs.operations[0]['x'], cs.operations[0]['y'])) + raw_new = get_label(name, cs.operations[0]['x'], cs.operations[0]['y']) + + new_dict = cs.operations[0] + schema = get_label_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Label(raw_new) + + redo_sql = f"update labels set label = {new.f_label}, node = {new.f_node} where x = {new.f_x} and y = {new.f_y};" + undo_sql = f"update labels set label = {old.f_label}, node = {old.f_node} where x = {old.f_x} and y = {old.f_y};" + + 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_label(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, set_label_cache(name, cs)) + + +def add_label_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + new = Label(cs.operations[0]) + + redo_sql = f"insert into labels (x, y, label, node) values ({new.f_x}, {new.f_y}, {new.f_label}, {new.f_node});" + undo_sql = f"delete from labels where x = {new.f_x} and y = {new.f_y};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_xy_dict() + + return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) + + +def add_label(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, add_label_cache(name, cs)) + + +def delete_label_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + old = Label(get_label(name, cs.operations[0]['x'], cs.operations[0]['y'])) + + redo_sql = f"delete from labels where x = {old.f_x} and y = {old.f_y};" + undo_sql = f"insert into labels (x, y, label, node) values ({old.f_x}, {old.f_y}, {old.f_label}, {old.f_node});" + + redo_cs = g_delete_prefix | old.as_xy_dict() + undo_cs = g_add_prefix | old.as_dict() + + return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) + + +def delete_label(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, delete_label_cache(name, cs)) diff --git a/api/s27_backdrop.py b/api/s27_backdrop.py new file mode 100644 index 0000000..84d4da6 --- /dev/null +++ b/api/s27_backdrop.py @@ -0,0 +1,26 @@ +from .operation import * + + +def get_backdrop_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'content' : {'type': 'str' , 'optional': False , 'readonly': False} } + + +def get_backdrop(name: str) -> dict[str, Any]: + e = read(name, f"select * from backdrop") + return { 'content': e['content'] } + + +def set_backdrop_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + old = get_backdrop(name) + + redo_sql = f"update backdrop set content = '{cs.operations[0]['content']}' where content = '{old['content']}';" + undo_sql = f"update backdrop set content = '{old['content']}' where content = '{cs.operations[0]['content']}';" + + redo_cs = g_update_prefix | { 'type': 'backdrop', 'content': cs.operations[0]['content'] } + undo_cs = g_update_prefix | { 'type': 'backdrop', 'content': old['content'] } + + return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) + + +def set_backdrop(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, set_backdrop_cache(name, cs)) diff --git a/api/s28_end.py b/api/s28_end.py new file mode 100644 index 0000000..e69de29 diff --git a/script/sql/create/0.base.sql b/script/sql/create/0.base.sql index 0d508f0..255d95b 100644 --- a/script/sql/create/0.base.sql +++ b/script/sql/create/0.base.sql @@ -2,6 +2,8 @@ create type _node_type as enum ('junction', 'reservoir', 'tank'); create type _link_type as enum ('pipe', 'pump', 'valve'); +create type _curve_type as enum ('PUMP', 'EFFICIENCY', 'VOLUME', 'HEADLOSS'); + create table _node ( id varchar(32) primary key @@ -17,6 +19,7 @@ create table _link create table _curve ( id varchar(32) primary key +, type _curve_type not null ); create table _pattern diff --git a/script/sql/create/15.energy.sql b/script/sql/create/15.energy.sql index 822a706..93c5481 100644 --- a/script/sql/create/15.energy.sql +++ b/script/sql/create/15.energy.sql @@ -1,33 +1,31 @@ -- [ENERGY] -create type energy_param as enum ('PRICE', 'PATTERN', 'EFFIC'); - --- GLOBAL PRICE / PATTERN / EFFIC value create table energy_global ( - param energy_param not null -, value numeric not null + _no integer primary key +, price numeric not null +, pattern varchar(32) references _pattern(id) +, effic numeric not null +, demand_charge numeric not null ); --- PUMP pumpID PRICE / PATTERN / EFFIC value -create table energy_pump +insert into energy_global (_no, price, pattern, effic, demand_charge) + values (0, 0.0, null, 75, 0.0); + +create table energy_pump_price ( - id varchar(32) references pumps(id) not null -, param energy_param not null -, value numeric not null + pump varchar(32) primary key references pumps(id) not null +, price numeric not null ); --- DEMAND CHARGE value -create table energy_demand_charge +create table energy_pump_pattern ( - value numeric not null + pump varchar(32) primary key references pumps(id) not null +, pattern varchar(32) references _pattern(id) not null ); -insert into energy_global (param, value) values - ('PRICE', 0.0) -, ('EFFIC', 75) -; - -insert into energy_demand_charge values - (0.0) -; +create table energy_pump_effic +( + pump varchar(32) primary key references pumps(id) not null +, effic varchar(32) references _curve(id) not null +); diff --git a/script/sql/create/25.vertices.sql b/script/sql/create/25.vertices.sql index c4e2ec0..4e924f3 100644 --- a/script/sql/create/25.vertices.sql +++ b/script/sql/create/25.vertices.sql @@ -2,7 +2,8 @@ create table vertices ( - link varchar(32) references _link(id) not null + _order serial primary key +, link varchar(32) references _link(id) not null , x numeric not null , y numeric not null ); diff --git a/script/sql/create/26.labels.sql b/script/sql/create/26.labels.sql index 5e240a5..5d68062 100644 --- a/script/sql/create/26.labels.sql +++ b/script/sql/create/26.labels.sql @@ -5,5 +5,6 @@ create table labels x numeric not null , y numeric not null , label text not null -, anchornode varchar(32) references _node(id) +, node varchar(32) references _node(id) +, primary key (x, y) ); diff --git a/script/sql/create/27.backdrop.sql b/script/sql/create/27.backdrop.sql index d664e97..8cd174b 100644 --- a/script/sql/create/27.backdrop.sql +++ b/script/sql/create/27.backdrop.sql @@ -4,3 +4,5 @@ create table backdrop ( content text primary key ); + +insert into backdrop (content) values (''); diff --git a/script/sql/drop/0.base.sql b/script/sql/drop/0.base.sql index adf7030..e76a8ad 100644 --- a/script/sql/drop/0.base.sql +++ b/script/sql/drop/0.base.sql @@ -6,6 +6,8 @@ drop table if exists _link; drop table if exists _node; +drop type if exists _curve_type; + drop type if exists _link_type; drop type if exists _node_type; diff --git a/script/sql/drop/15.energy.sql b/script/sql/drop/15.energy.sql index cf524bd..cbf857d 100644 --- a/script/sql/drop/15.energy.sql +++ b/script/sql/drop/15.energy.sql @@ -1,9 +1,7 @@ -- [ENERGY] -drop table if exists energy_demand_charge; - -drop table if exists energy_pump; +drop table if exists energy_pump_effic; +drop table if exists energy_pump_pattern; +drop table if exists energy_pump_price; drop table if exists energy_global; - -drop type if exists energy_param; diff --git a/test_tjnetwork.py b/test_tjnetwork.py index 5ca0e1a..402b8f5 100644 --- a/test_tjnetwork.py +++ b/test_tjnetwork.py @@ -18,6 +18,9 @@ class TestApi: delete_project(p) + # project + + def test_project(self): p = 'test_project' @@ -62,6 +65,121 @@ class TestApi: assert get_project_open_count(p) == 0 + # operation + + + def test_snapshot(self): + p = "test_snapshot" + 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})) + add_junction(p, ChangeSet({'id': 'j3', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + add_junction(p, ChangeSet({'id': 'j4', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + + client_op = get_current_operation(p) + assert client_op == 4 + assert take_snapshot(p, 'x') == 4 + + execute_undo(p) + execute_undo(p) + add_junction(p, ChangeSet({'id': 'j5', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + add_junction(p, ChangeSet({'id': 'j6', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + + assert take_snapshot(p, 'xx') == 6 + + cs = sync_with_server(p, client_op).operations + cs[0]['operation'] = API_DELETE + cs[0]['id'] = 'j4' + cs[1]['operation'] = API_DELETE + cs[1]['id'] = 'j3' + cs[2]['operation'] = API_ADD + cs[2]['id'] = 'j5' + cs[3]['operation'] = API_ADD + cs[3]['id'] = 'j6' + + cs = pick_snapshot(p, 'x').operations + cs[0]['operation'] = 'delete' + cs[0]['id'] = 'j6' + cs[1]['operation'] = 'delete' + cs[1]['id'] = 'j5' + cs[2]['operation'] = 'add' + cs[2]['id'] = 'j3' + cs[3]['operation'] = 'add' + cs[3]['id'] = 'j4' + + assert get_nodes(p) == ['j1', 'j2', 'j3', 'j4'] + + self.leave(p) + + + def test_batch_commands(self): + p = 'test_batch_commands' + self.enter(p) + + cs = ChangeSet() + cs.add({'type': JUNCTION, 'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) + cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) + cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) # fail + + cs = execute_batch_commands(p, cs) + assert len(cs.operations) == 2 + + cs = ChangeSet() + cs.delete({'type': JUNCTION, 'id': 'j1'}) + cs.delete({'type': JUNCTION, 'id': 'j2'}) + + cs = execute_batch_commands(p, cs) + assert len(cs.operations) == 2 + + cs = execute_undo(p) + assert len(cs.operations) == 1 + + self.leave(p) + + + def test_batch_command(self): + p = 'test_batch_command' + self.enter(p) + + cs = ChangeSet() + cs.add({'type': JUNCTION, 'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) + cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) + cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) # fail + + cs = execute_batch_command(p, cs) + assert len(cs.operations) == 0 + + assert get_current_operation(p) == 0 + + cs = ChangeSet() + cs.add({'type': JUNCTION, 'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) + cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) + + cs = execute_batch_command(p, cs) + + assert get_current_operation(p) == 1 + + cs = ChangeSet() + cs.delete({'type': JUNCTION, 'id': 'j1'}) + cs.delete({'type': JUNCTION, 'id': 'j2'}) + + cs = execute_batch_command(p, cs) + + assert get_current_operation(p) == 2 + + cs = execute_undo(p) + assert get_current_operation(p) == 1 + + cs = execute_undo(p) + assert get_current_operation(p) == 0 + + self.leave(p) + + + # 1 title + + def test_title(self): p = 'test_title' self.enter(p) @@ -116,6 +234,9 @@ class TestApi: self.leave(p) + # 2 junction + + def test_junction(self): p = 'test_junction' self.enter(p) @@ -278,6 +399,9 @@ class TestApi: self.leave(p) + # 3 reservoir + + def test_reservoir(self): p = 'test_reservoir' self.enter(p) @@ -429,6 +553,9 @@ class TestApi: self.leave(p) + # 4 tank + + def test_tank(self): p = 'test_tank' self.enter(p) @@ -640,6 +767,9 @@ class TestApi: self.leave(p) + # 5 pipe + + def test_pipe(self): p = 'test_pipe' self.enter(p) @@ -833,6 +963,9 @@ class TestApi: self.leave(p) + # 6 pump + + def test_pump(self): p = 'test_pump' self.enter(p) @@ -992,6 +1125,9 @@ class TestApi: self.leave(p) + # 7 valve + + def test_valve(self): p = 'test_valve' self.enter(p) @@ -1174,6 +1310,9 @@ class TestApi: self.leave(p) + # 8 tag + + def test_tag(self): p = 'test_tag' self.enter(p) @@ -1264,38 +1403,7 @@ class TestApi: self.leave(p) - def test_rule(self): - p = 'test_rule' - self.enter(p) - - assert get_rule(p)['rule'] == '' - - set_rule(p, ChangeSet({'rule': 'x'})) - assert get_rule(p)['rule'] == 'x' - - self.leave(p) - - - def test_rule_op(self): - p = 'test_rule_op' - self.enter(p) - - cs = set_rule(p, ChangeSet({'rule': 'x'})).operations[0] - assert cs['operation'] == API_UPDATE - assert cs['type'] == 'rule' - assert cs['rule'] == 'x' - - cs = execute_undo(p).operations[0] - assert cs['operation'] == API_UPDATE - assert cs['type'] == 'rule' - assert cs['rule'] == '' - - cs = execute_redo(p).operations[0] - assert cs['operation'] == API_UPDATE - assert cs['type'] == 'rule' - assert cs['rule'] == 'x' - - self.leave(p) + # 9 demand def test_demand(self): @@ -1397,6 +1505,9 @@ class TestApi: self.leave(p) + # 10 status + + def test_status(self): p = 'test_status' self.enter(p) @@ -1475,29 +1586,39 @@ class TestApi: self.leave(p) + # 11 pattern + + def test_pattern(self): p = 'test_pattern' self.enter(p) assert is_pattern(p, 'p0') == False - p0 = get_pattern(p, 'p0') - assert p0['id'] == 'p0' - assert p0['factors'] == [] - set_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})) + add_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})) assert is_pattern(p, 'p0') p0 = get_pattern(p, 'p0') assert p0['id'] == 'p0' assert p0['factors'] == [1.0, 2.0, 3.0] + set_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0]})) + + assert is_pattern(p, 'p0') + p0 = get_pattern(p, 'p0') + assert p0['id'] == 'p0' + assert p0['factors'] == [1.0, 2.0] + set_pattern(p, ChangeSet({'id' : 'p0', 'factors': []})) - assert is_pattern(p, 'p0') == False + assert is_pattern(p, 'p0') p0 = get_pattern(p, 'p0') assert p0['id'] == 'p0' assert p0['factors'] == [] + delete_pattern(p, ChangeSet({'id' : 'p0'})) + assert is_pattern(p, 'p0') == False + self.leave(p) @@ -1505,41 +1626,105 @@ class TestApi: p = 'test_pattern_op' self.enter(p) - cs = set_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})).operations[0] - assert cs['operation'] == API_UPDATE + cs = add_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})).operations[0] + assert cs['operation'] == API_ADD assert cs['type'] == PATTERN assert cs['id'] == 'p0' assert cs['factors'] == [1.0, 2.0, 3.0] cs = execute_undo(p).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == PATTERN + assert cs['id'] == 'p0' + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == PATTERN + assert cs['id'] == 'p0' + assert cs['factors'] == [1.0, 2.0, 3.0] + + cs = set_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0]})).operations[0] assert cs['operation'] == API_UPDATE assert cs['type'] == PATTERN assert cs['id'] == 'p0' - assert cs['factors'] == [] + assert cs['factors'] == [1.0, 2.0] - cs = execute_redo(p).operations[0] + cs = execute_undo(p).operations[0] assert cs['operation'] == API_UPDATE assert cs['type'] == PATTERN assert cs['id'] == 'p0' assert cs['factors'] == [1.0, 2.0, 3.0] + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == PATTERN + assert cs['id'] == 'p0' + assert cs['factors'] == [1.0, 2.0] + + cs = set_pattern(p, ChangeSet({'id' : 'p0', 'factors': []})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == PATTERN + assert cs['id'] == 'p0' + assert cs['factors'] == [] + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == PATTERN + assert cs['id'] == 'p0' + assert cs['factors'] == [1.0, 2.0] + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == PATTERN + assert cs['id'] == 'p0' + assert cs['factors'] == [] + + cs = delete_pattern(p, ChangeSet({'id' : 'p0'})).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == PATTERN + assert cs['id'] == 'p0' + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == PATTERN + assert cs['id'] == 'p0' + assert cs['factors'] == [] + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == PATTERN + assert cs['id'] == 'p0' + self.leave(p) + # 12 curve + + def test_curve(self): p = 'test_curve' self.enter(p) assert is_curve(p, 'c0') == False - c0 = get_curve(p, 'c0') - assert c0['id'] == 'c0' - assert c0['coords'] == [] - set_curve(p, ChangeSet({'id' : 'c0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})) + add_curve(p, ChangeSet({'id' : 'c0', 'c_type' : CURVE_TYPE_PUMP, 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})) assert is_curve(p, 'c0') c0 = get_curve(p, 'c0') assert c0['id'] == 'c0' + assert c0['c_type'] == CURVE_TYPE_PUMP + xys = c0['coords'] + assert len(xys) == 2 + assert xys[0]['x'] == 1.0 + assert xys[0]['y'] == 2.0 + assert xys[1]['x'] == 2.0 + assert xys[1]['y'] == 1.0 + + set_curve(p, ChangeSet({'id' : 'c0', 'c_type': CURVE_TYPE_EFFICIENCY})) + + c0 = get_curve(p, 'c0') + assert c0['id'] == 'c0' + assert c0['c_type'] == CURVE_TYPE_EFFICIENCY xys = c0['coords'] assert len(xys) == 2 assert xys[0]['x'] == 1.0 @@ -1549,11 +1734,15 @@ class TestApi: set_curve(p, ChangeSet({'id' : 'c0', 'coords': []})) - assert is_curve(p, 'c0') == False c0 = get_curve(p, 'c0') assert c0['id'] == 'c0' + assert c0['c_type'] == CURVE_TYPE_EFFICIENCY assert c0['coords'] == [] + delete_curve(p, ChangeSet({'id' : 'c0'})) + + assert is_curve(p, 'c0') == False + self.leave(p) @@ -1561,10 +1750,40 @@ class TestApi: p = 'test_curve_op' self.enter(p) - cs = set_curve(p, ChangeSet({'id' : 'c0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})).operations[0] + cs = add_curve(p, ChangeSet({'id' : 'c0', 'c_type' : CURVE_TYPE_PUMP, 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == CURVE + assert cs['id'] == 'c0' + assert cs['c_type'] == CURVE_TYPE_PUMP + xys = cs['coords'] + assert len(xys) == 2 + assert xys[0]['x'] == 1.0 + assert xys[0]['y'] == 2.0 + assert xys[1]['x'] == 2.0 + assert xys[1]['y'] == 1.0 + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == CURVE + assert cs['id'] == 'c0' + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == CURVE + assert cs['id'] == 'c0' + assert cs['c_type'] == CURVE_TYPE_PUMP + xys = cs['coords'] + assert len(xys) == 2 + assert xys[0]['x'] == 1.0 + assert xys[0]['y'] == 2.0 + assert xys[1]['x'] == 2.0 + assert xys[1]['y'] == 1.0 + + cs = set_curve(p, ChangeSet({'id' : 'c0', 'c_type': CURVE_TYPE_EFFICIENCY})).operations[0] assert cs['operation'] == API_UPDATE assert cs['type'] == CURVE assert cs['id'] == 'c0' + assert cs['c_type'] == CURVE_TYPE_EFFICIENCY xys = cs['coords'] assert len(xys) == 2 assert xys[0]['x'] == 1.0 @@ -1576,12 +1795,7 @@ class TestApi: assert cs['operation'] == API_UPDATE assert cs['type'] == CURVE assert cs['id'] == 'c0' - assert cs['coords'] == [] - - cs = execute_redo(p).operations[0] - assert cs['operation'] == API_UPDATE - assert cs['type'] == CURVE - assert cs['id'] == 'c0' + assert cs['c_type'] == CURVE_TYPE_PUMP xys = cs['coords'] assert len(xys) == 2 assert xys[0]['x'] == 1.0 @@ -1589,9 +1803,502 @@ class TestApi: assert xys[1]['x'] == 2.0 assert xys[1]['y'] == 1.0 + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == CURVE + assert cs['id'] == 'c0' + assert cs['c_type'] == CURVE_TYPE_EFFICIENCY + xys = cs['coords'] + assert len(xys) == 2 + assert xys[0]['x'] == 1.0 + assert xys[0]['y'] == 2.0 + assert xys[1]['x'] == 2.0 + assert xys[1]['y'] == 1.0 + + cs = set_curve(p, ChangeSet({'id' : 'c0', 'coords': []})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == CURVE + assert cs['id'] == 'c0' + assert cs['c_type'] == CURVE_TYPE_EFFICIENCY + assert cs['coords'] == [] + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == CURVE + assert cs['id'] == 'c0' + assert cs['c_type'] == CURVE_TYPE_EFFICIENCY + xys = cs['coords'] + assert len(xys) == 2 + assert xys[0]['x'] == 1.0 + assert xys[0]['y'] == 2.0 + assert xys[1]['x'] == 2.0 + assert xys[1]['y'] == 1.0 + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == CURVE + assert cs['id'] == 'c0' + assert cs['c_type'] == CURVE_TYPE_EFFICIENCY + assert cs['coords'] == [] + self.leave(p) + # 13 control + + + def test_control(self): + p = 'test_control' + self.enter(p) + + assert get_control(p)['control'] == '' + + set_control(p, ChangeSet({'control': 'x'})) + assert get_control(p)['control'] == 'x' + + self.leave(p) + + + def test_control_op(self): + p = 'test_control_op' + self.enter(p) + + cs = set_control(p, ChangeSet({'control': 'x'})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'control' + assert cs['control'] == 'x' + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'control' + assert cs['control'] == '' + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'control' + assert cs['control'] == 'x' + + self.leave(p) + + + # 14 rule + + + def test_rule(self): + p = 'test_rule' + self.enter(p) + + assert get_rule(p)['rule'] == '' + + set_rule(p, ChangeSet({'rule': 'x'})) + assert get_rule(p)['rule'] == 'x' + + self.leave(p) + + + def test_rule_op(self): + p = 'test_rule_op' + self.enter(p) + + cs = set_rule(p, ChangeSet({'rule': 'x'})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'rule' + assert cs['rule'] == 'x' + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'rule' + assert cs['rule'] == '' + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'rule' + assert cs['rule'] == 'x' + + self.leave(p) + + + # 15 energy + + + def test_global_energy(self): + p = 'test_global_energy' + self.enter(p) + + ge = get_global_energy(p) + assert ge['price'] == 0.0 + assert ge['pattern'] == None + assert ge['effic'] == float(75) + assert ge['demand_charge'] == 0.0 + + set_global_energy(p, ChangeSet({ 'price' : 10.0 })) + ge = get_global_energy(p) + assert ge['price'] == 10.0 + assert ge['pattern'] == None + assert ge['effic'] == float(75) + assert ge['demand_charge'] == 0.0 + + add_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})) + set_global_energy(p, ChangeSet({ 'pattern' : 'p0' })) + ge = get_global_energy(p) + assert ge['price'] == 10.0 + assert ge['pattern'] == 'p0' + assert ge['effic'] == float(75) + assert ge['demand_charge'] == 0.0 + + set_global_energy(p, ChangeSet({ 'effic' : 0.0 })) + ge = get_global_energy(p) + assert ge['price'] == 10.0 + assert ge['pattern'] == 'p0' + assert ge['effic'] == 0.0 + assert ge['demand_charge'] == 0.0 + + set_global_energy(p, ChangeSet({ 'demand_charge' : 10.0 })) + ge = get_global_energy(p) + assert ge['price'] == 10.0 + assert ge['pattern'] == 'p0' + assert ge['effic'] == 0.0 + assert ge['demand_charge'] == 10.0 + + self.leave(p) + + + def test_global_energy_op(self): + p = 'test_global_energy_op' + self.enter(p) + + add_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})) + + cs = set_global_energy(p, ChangeSet({ 'price' : 10.0 })).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == None + assert cs['effic'] == float(75) + assert cs['demand_charge'] == 0.0 + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 0.0 + assert cs['pattern'] == None + assert cs['effic'] == float(75) + assert cs['demand_charge'] == 0.0 + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == None + assert cs['effic'] == float(75) + assert cs['demand_charge'] == 0.0 + + cs = set_global_energy(p, ChangeSet({ 'pattern' : 'p0' })).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == 'p0' + assert cs['effic'] == float(75) + assert cs['demand_charge'] == 0.0 + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == None + assert cs['effic'] == float(75) + assert cs['demand_charge'] == 0.0 + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == 'p0' + assert cs['effic'] == float(75) + assert cs['demand_charge'] == 0.0 + + cs = set_global_energy(p, ChangeSet({ 'effic' : 0.0 })).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == 'p0' + assert cs['effic'] == 0.0 + assert cs['demand_charge'] == 0.0 + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == 'p0' + assert cs['effic'] == float(75) + assert cs['demand_charge'] == 0.0 + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == 'p0' + assert cs['effic'] == 0.0 + assert cs['demand_charge'] == 0.0 + + cs = set_global_energy(p, ChangeSet({ 'demand_charge' : 10.0 })).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == 'p0' + assert cs['effic'] == 0.0 + assert cs['demand_charge'] == 10.0 + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == 'p0' + assert cs['effic'] == 0.0 + assert cs['demand_charge'] == 0.0 + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == 'p0' + assert cs['effic'] == 0.0 + assert cs['demand_charge'] == 10.0 + + cs = set_global_energy(p, ChangeSet({ 'price' : 0.0, 'pattern' : None, 'effic' : float(75), 'demand_charge' : 0.0 })).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 0.0 + assert cs['pattern'] == None + assert cs['effic'] == float(75) + assert cs['demand_charge'] == 0.0 + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 10.0 + assert cs['pattern'] == 'p0' + assert cs['effic'] == 0.0 + assert cs['demand_charge'] == 10.0 + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'global_energy' + assert cs['price'] == 0.0 + assert cs['pattern'] == None + assert cs['effic'] == float(75) + assert cs['demand_charge'] == 0.0 + + self.leave(p) + + + def test_pump_energy(self): + p = 'test_pump_energy' + self.enter(p) + + ge = get_pump_energy(p, 'p0') + assert ge['pump'] == 'p0' + assert ge['price'] == None + assert ge['pattern'] == None + assert ge['effic'] == None + + 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})) + add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'power': 0.0})) + + set_pump_energy(p, ChangeSet({'pump' : 'p0'})) + ge = get_pump_energy(p, 'p0') + assert ge['pump'] == 'p0' + assert ge['price'] == None + assert ge['pattern'] == None + assert ge['effic'] == None + + set_pump_energy(p, ChangeSet({'pump' : 'p0', 'price': 0.0})) + ge = get_pump_energy(p, 'p0') + assert ge['pump'] == 'p0' + assert ge['price'] == 0.0 + assert ge['pattern'] == None + assert ge['effic'] == None + + add_pattern(p, ChangeSet({'id' : 'pa0', 'factors': [1.0, 2.0, 3.0]})) + set_pump_energy(p, ChangeSet({'pump' : 'p0', 'pattern': 'pa0'})) + ge = get_pump_energy(p, 'p0') + assert ge['pump'] == 'p0' + assert ge['price'] == 0.0 + assert ge['pattern'] == 'pa0' + assert ge['effic'] == None + + add_curve(p, ChangeSet({'id' : 'c0', 'c_type' : CURVE_TYPE_PUMP, 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})) + set_pump_energy(p, ChangeSet({'pump' : 'p0', 'effic': 'c0'})) + ge = get_pump_energy(p, 'p0') + assert ge['pump'] == 'p0' + assert ge['price'] == 0.0 + assert ge['pattern'] == 'pa0' + assert ge['effic'] == 'c0' + + self.leave(p) + + + def test_pump_energy_op(self): + p = 'test_pump_energy_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})) + add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'power': 0.0})) + add_pattern(p, ChangeSet({'id' : 'pa0', 'factors': [1.0, 2.0, 3.0]})) + add_curve(p, ChangeSet({'id' : 'c0', 'c_type' : CURVE_TYPE_PUMP, 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})) + + cs = set_pump_energy(p, ChangeSet({'pump' : 'p0'})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == None + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == None + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == None + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = set_pump_energy(p, ChangeSet({'pump' : 'p0', 'price': 0.0})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == None + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = set_pump_energy(p, ChangeSet({'pump' : 'p0', 'pattern': 'pa0'})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == 'pa0' + assert cs['effic'] == None + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == 'pa0' + assert cs['effic'] == None + + cs = set_pump_energy(p, ChangeSet({'pump' : 'p0', 'effic': 'c0'})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == 'pa0' + assert cs['effic'] == 'c0' + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == 'pa0' + assert cs['effic'] == None + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == 'pa0' + assert cs['effic'] == 'c0' + + cs = set_pump_energy(p, ChangeSet({'pump' : 'p0', 'price': None, 'pattern': None, 'effic': None})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == None + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == 'pa0' + assert cs['effic'] == 'c0' + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == None + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = set_pump_energy(p, ChangeSet({'pump' : 'p0', 'price': 0.0, 'pattern': 'pa0', 'effic': 'c0'})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == 'pa0' + assert cs['effic'] == 'c0' + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == None + assert cs['pattern'] == None + assert cs['effic'] == None + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'pump_energy' + assert cs['pump'] == 'p0' + assert cs['price'] == 0.0 + assert cs['pattern'] == 'pa0' + assert cs['effic'] == 'c0' + + self.leave(p) + + + # 16 emitter + + def test_emitter(self): p = 'test_emitter' self.enter(p) @@ -1646,6 +2353,9 @@ class TestApi: self.leave(p) + # 21 time + + def test_time(self): p = 'test_time' self.enter(p) @@ -1742,6 +2452,9 @@ class TestApi: self.leave(p) + # 22 option + + def test_option(self): p = 'test_option' self.enter(p) @@ -1910,111 +2623,227 @@ class TestApi: self.leave(p) - def test_snapshot(self): - p = "test_snapshot" + # 25 vertex + + + def test_vertex(self): + p = 'test_vertex' 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})) - add_junction(p, ChangeSet({'id': 'j3', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) - add_junction(p, ChangeSet({'id': 'j4', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + 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 })) - client_op = get_current_operation(p) - assert client_op == 4 - assert take_snapshot(p, 'x') == 4 + v = get_vertex(p, 'p0') + assert v['link'] == 'p0' + assert v['coords'] == [] - execute_undo(p) - execute_undo(p) - add_junction(p, ChangeSet({'id': 'j5', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) - add_junction(p, ChangeSet({'id': 'j6', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + set_vertex(p, ChangeSet({'link' : 'p0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})) - assert take_snapshot(p, 'xx') == 6 + v = get_vertex(p, 'p0') + xys = v['coords'] + assert len(xys) == 2 + assert xys[0]['x'] == 1.0 + assert xys[0]['y'] == 2.0 + assert xys[1]['x'] == 2.0 + assert xys[1]['y'] == 1.0 - cs = sync_with_server(p, client_op).operations - cs[0]['operation'] = API_DELETE - cs[0]['id'] = 'j4' - cs[1]['operation'] = API_DELETE - cs[1]['id'] = 'j3' - cs[2]['operation'] = API_ADD - cs[2]['id'] = 'j5' - cs[3]['operation'] = API_ADD - cs[3]['id'] = 'j6' + set_vertex(p, ChangeSet({'link' : 'p0', 'coords': []})) - cs = pick_snapshot(p, 'x').operations - cs[0]['operation'] = 'delete' - cs[0]['id'] = 'j6' - cs[1]['operation'] = 'delete' - cs[1]['id'] = 'j5' - cs[2]['operation'] = 'add' - cs[2]['id'] = 'j3' - cs[3]['operation'] = 'add' - cs[3]['id'] = 'j4' - - assert get_nodes(p) == ['j1', 'j2', 'j3', 'j4'] + v = get_vertex(p, 'p0') + assert v['link'] == 'p0' + assert v['coords'] == [] self.leave(p) - def test_batch_commands(self): - p = 'test_batch_commands' + def test_vertex_op(self): + p = 'test_vertex_op' self.enter(p) - cs = ChangeSet() - cs.add({'type': JUNCTION, 'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) - cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) - cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) # fail + 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})) + 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 })) - cs = execute_batch_commands(p, cs) - assert len(cs.operations) == 2 + cs = set_vertex(p, ChangeSet({'link' : 'p0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'vertex' + assert cs['link'] == 'p0' + xys = cs['coords'] + assert len(xys) == 2 + assert xys[0]['x'] == 1.0 + assert xys[0]['y'] == 2.0 + assert xys[1]['x'] == 2.0 + assert xys[1]['y'] == 1.0 - cs = ChangeSet() - cs.delete({'type': JUNCTION, 'id': 'j1'}) - cs.delete({'type': JUNCTION, 'id': 'j2'}) + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'vertex' + assert cs['link'] == 'p0' + assert cs['coords'] == [] - cs = execute_batch_commands(p, cs) - assert len(cs.operations) == 2 - - cs = execute_undo(p) - assert len(cs.operations) == 1 + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'vertex' + assert cs['link'] == 'p0' + xys = cs['coords'] + assert len(xys) == 2 + assert xys[0]['x'] == 1.0 + assert xys[0]['y'] == 2.0 + assert xys[1]['x'] == 2.0 + assert xys[1]['y'] == 1.0 self.leave(p) - def test_batch_command(self): - p = 'test_batch_command' + # 26 label + + + def test_label(self): + p = 'test_label' self.enter(p) - cs = ChangeSet() - cs.add({'type': JUNCTION, 'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) - cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) - cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) # fail + l = get_label(p, 0.0, 0.0) + assert l['x'] == 0.0 + assert l['y'] == 0.0 + assert l['label'] == None + assert l['node'] == None - cs = execute_batch_command(p, cs) - assert len(cs.operations) == 0 + add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + add_label(p, ChangeSet({'x': 0.0, 'y': 0.0, 'label': 'x', 'node': 'j0'})) + l = get_label(p, 0.0, 0.0) + assert l['x'] == 0.0 + assert l['y'] == 0.0 + assert l['label'] == 'x' + assert l['node'] == 'j0' - assert get_current_operation(p) == 0 + add_junction(p, ChangeSet({'id': 'j1', 'x': 1.0, 'y': 20.0, 'elevation': 20.0})) + set_label(p, ChangeSet({'x': 0.0, 'y': 0.0, 'label': 'xxx', 'node': 'j1'})) + l = get_label(p, 0.0, 0.0) + assert l['x'] == 0.0 + assert l['y'] == 0.0 + assert l['label'] == 'xxx' + assert l['node'] == 'j1' - cs = ChangeSet() - cs.add({'type': JUNCTION, 'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) - cs.add({'type': JUNCTION, 'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}) + delete_label(p, ChangeSet({'x': 0.0, 'y': 0.0})) + l = get_label(p, 0.0, 0.0) + assert l['x'] == 0.0 + assert l['y'] == 0.0 + assert l['label'] == None + assert l['node'] == None - cs = execute_batch_command(p, cs) + self.leave(p) - assert get_current_operation(p) == 1 - cs = ChangeSet() - cs.delete({'type': JUNCTION, 'id': 'j1'}) - cs.delete({'type': JUNCTION, 'id': 'j2'}) + def test_label_op(self): + p = 'test_label_op' + self.enter(p) - cs = execute_batch_command(p, cs) + add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + add_junction(p, ChangeSet({'id': 'j1', 'x': 1.0, 'y': 20.0, 'elevation': 20.0})) - assert get_current_operation(p) == 2 + cs = add_label(p, ChangeSet({'x': 0.0, 'y': 0.0, 'label': 'x', 'node': 'j0'})).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == 'label' + assert cs['x'] == 0.0 + assert cs['y'] == 0.0 + assert cs['label'] == 'x' + assert cs['node'] == 'j0' - cs = execute_undo(p) - assert get_current_operation(p) == 1 + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == 'label' + assert cs['x'] == 0.0 + assert cs['y'] == 0.0 - cs = execute_undo(p) - assert get_current_operation(p) == 0 + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == 'label' + assert cs['x'] == 0.0 + assert cs['y'] == 0.0 + assert cs['label'] == 'x' + assert cs['node'] == 'j0' + + cs = set_label(p, ChangeSet({'x': 0.0, 'y': 0.0, 'label': 'xxx', 'node': 'j1'})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'label' + assert cs['x'] == 0.0 + assert cs['y'] == 0.0 + assert cs['label'] == 'xxx' + assert cs['node'] == 'j1' + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'label' + assert cs['x'] == 0.0 + assert cs['y'] == 0.0 + assert cs['label'] == 'x' + assert cs['node'] == 'j0' + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'label' + assert cs['x'] == 0.0 + assert cs['y'] == 0.0 + assert cs['label'] == 'xxx' + assert cs['node'] == 'j1' + + cs = delete_label(p, ChangeSet({'x': 0.0, 'y': 0.0})).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == 'label' + assert cs['x'] == 0.0 + assert cs['y'] == 0.0 + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == 'label' + assert cs['x'] == 0.0 + assert cs['y'] == 0.0 + assert cs['label'] == 'xxx' + assert cs['node'] == 'j1' + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == 'label' + assert cs['x'] == 0.0 + assert cs['y'] == 0.0 + + self.leave(p) + + + # 27 backdrop + + + def test_backdrop(self): + p = 'test_backdrop' + self.enter(p) + + assert get_backdrop(p)['content'] == '' + + set_backdrop(p, ChangeSet({'content': 'x'})) + assert get_backdrop(p)['content'] == 'x' + + self.leave(p) + + + def test_backdrop_op(self): + p = 'test_backdrop_op' + self.enter(p) + + cs = set_backdrop(p, ChangeSet({'content': 'x'})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'backdrop' + assert cs['content'] == 'x' + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'backdrop' + assert cs['content'] == '' + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'backdrop' + assert cs['content'] == 'x' self.leave(p) diff --git a/tjnetwork.py b/tjnetwork.py index f927a05..a0e2244 100644 --- a/tjnetwork.py +++ b/tjnetwork.py @@ -47,6 +47,11 @@ LINK_STATUS_OPEN = api.LINK_STATUS_OPEN LINK_STATUS_CLOSED = api.LINK_STATUS_CLOSED LINK_STATUS_ACTIVE = api.LINK_STATUS_ACTIVE +CURVE_TYPE_PUMP = api.CURVE_TYPE_PUMP +CURVE_TYPE_EFFICIENCY = api.CURVE_TYPE_EFFICIENCY +CURVE_TYPE_VOLUME = api.CURVE_TYPE_VOLUME +CURVE_TYPE_HEADLOSS = api.CURVE_TYPE_HEADLOSS + TIME_STATISTIC_NONE = api.TIME_STATISTIC_NONE TIME_STATISTIC_AVERAGED = api.TIME_STATISTIC_AVERAGED TIME_STATISTIC_MINIMUM = api.TIME_STATISTIC_MINIMUM @@ -397,10 +402,10 @@ def get_pattern_schema(name: str) -> dict[str, dict[str, Any]]: def get_pattern(name: str, id: str) -> dict[str, Any]: return api.get_pattern(name, id) -# example: set_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})) def set_pattern(name: str, cs: ChangeSet) -> ChangeSet: return api.set_pattern(name, cs) +# example: add_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})) def add_pattern(name: str, cs: ChangeSet) -> ChangeSet: return api.add_pattern(name, cs) @@ -418,10 +423,10 @@ def get_curve_schema(name: str) -> dict[str, dict[str, Any]]: def get_curve(name: str, id: str) -> dict[str, Any]: return api.get_curve(name, id) -# example: set_curve(p, ChangeSet({'id' : 'c0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})) def set_curve(name: str, cs: ChangeSet) -> ChangeSet: return api.set_curve(name, cs) +# example: add_curve(p, ChangeSet({'id' : 'c0', 'c_type' : CURVE_TYPE_PUMP, 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})) def add_curve(name: str, cs: ChangeSet) -> ChangeSet: return api.add_curve(name, cs) @@ -459,6 +464,28 @@ def set_rule(name: str, cs: ChangeSet) -> ChangeSet: return api.set_rule(name, cs) +############################################################ +# energy 16.[ENERGY] +############################################################ + +def get_global_energy_schema(name: str) -> dict[str, dict[str, Any]]: + return api.get_global_energy_schema(name) + +def get_global_energy(name: str) -> dict[str, Any]: + return api.get_global_energy(name) + +def set_global_energy(name: str, cs: ChangeSet) -> ChangeSet: + return api.set_global_energy(name, cs) + +def get_pump_energy_schema(name: str) -> dict[str, dict[str, Any]]: + return api.get_pump_energy_schema(name) + +def get_pump_energy(name: str, pump: str) -> dict[str, Any]: + return api.get_pump_energy(name, pump) + +def set_pump_energy(name: str, cs: ChangeSet) -> ChangeSet: + return api.set_pump_energy(name, cs) + ############################################################ # emitter 16.[EMITTERS] ############################################################ @@ -508,3 +535,62 @@ def set_option(name: str, cs: ChangeSet) -> ChangeSet: def get_node_coord(name: str, node_id: str) -> dict[str, float] | None: return api.get_node_coord(name, node_id) + + +############################################################ +# vertex 25.[VERTICES] +############################################################ + +def get_vertex_schema(name: str) -> dict[str, dict[str, Any]]: + return api.get_vertex_schema(name) + +def get_vertex(name: str, link: str) -> dict[str, Any]: + return api.get_vertex(name, link) + +def set_vertex(name: str, cs: ChangeSet) -> ChangeSet: + return api.set_vertex(name, cs) + +def add_vertex(name: str, cs: ChangeSet) -> ChangeSet: + return api.add_vertex(name, cs) + +def delete_vertex(name: str, cs: ChangeSet) -> ChangeSet: + return api.delete_vertex(name, cs) + + +############################################################ +# label 26.[LABELS] +############################################################ + +def get_label_schema(name: str) -> dict[str, dict[str, Any]]: + return api.get_label_schema(name) + +def get_label(name: str, x: float, y: float) -> dict[str, Any]: + return api.get_label(name, x, y) + +def set_label(name: str, cs: ChangeSet) -> ChangeSet: + return api.set_label(name, cs) + +def add_label(name: str, cs: ChangeSet) -> ChangeSet: + return api.add_label(name, cs) + +def delete_label(name: str, cs: ChangeSet) -> ChangeSet: + return api.delete_label(name, cs) + + +############################################################ +# backdrop 27.[BACKDROP] +############################################################ + +def get_backdrop_schema(name: str) -> dict[str, dict[str, Any]]: + return api.get_backdrop_schema(name) + +def get_backdrop(name: str) -> dict[str, Any]: + return api.get_backdrop(name) + +def set_backdrop(name: str, cs: ChangeSet) -> ChangeSet: + return api.set_backdrop(name, cs) + + +############################################################ +# end 28.[END] +############################################################