from typing import Any from psycopg import sql from ..core.database import ( ChangeSet, DatabaseCommand, execute_command, g_add_prefix, g_delete_prefix, g_update_prefix, read_all, sql_literal, try_read, ) PATTERN_V3_TYPE_FIXED = 'FIXED' PATTERN_V3_TYPE_VARIABLE = 'VARIABLE' pattern_v3_types = [PATTERN_V3_TYPE_FIXED, PATTERN_V3_TYPE_VARIABLE] def get_pattern_schema(name: str) -> dict[str, dict[str, Any]]: return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, 'factors' : {'type': 'float_list' , 'optional': False , 'readonly': False } } def get_pattern(name: str, id: str) -> dict[str, Any]: p_one = try_read(name, "select id from network.patterns where id = %s", (id,)) if p_one == None: return {} pas = read_all(name, "select factor from network.pattern_values where pattern_id = %s order by sequence_no", (id,)) ps = [] for r in pas: ps.append(float(r['factor'])) return { 'id': id, 'factors': ps } def _set_pattern(name: str, cs: ChangeSet) -> DatabaseCommand: id = cs.operations[0]['id'] f_id = sql_literal(id) old = get_pattern(name, id) new = { 'id': id } if 'factors' in cs.operations[0]: new['factors'] = cs.operations[0]['factors'] else: new['factors'] = old['factors'] statement = f"delete from network.pattern_values where pattern_id = {f_id};" for sequence_no, factor in enumerate(new['factors']): f_factor = sql_literal(factor) statement += f"\ninsert into network.pattern_values (pattern_id, sequence_no, factor) values ({f_id}, {sequence_no}, {f_factor});" change = g_update_prefix | { 'type': 'pattern' } | new return DatabaseCommand(statement, [change]) def set_pattern(name: str, cs: ChangeSet) -> ChangeSet: if 'id' not in cs.operations[0]: return ChangeSet() if get_pattern(name, cs.operations[0]['id']) == {}: return ChangeSet() return execute_command(name, _set_pattern(name, cs)) def _add_pattern(name: str, cs: ChangeSet) -> DatabaseCommand: id = cs.operations[0]['id'] f_id = sql_literal(id) new = { 'id': id, 'factors': cs.operations[0]['factors'] } statement = f"insert into network.patterns (id) values ({f_id});" for sequence_no, factor in enumerate(new['factors']): f_factor = sql_literal(factor) statement += f"\ninsert into network.pattern_values (pattern_id, sequence_no, factor) values ({f_id}, {sequence_no}, {f_factor});" change = g_add_prefix | { 'type': 'pattern' } | new return DatabaseCommand(statement, [change]) def add_pattern(name: str, cs: ChangeSet) -> ChangeSet: if 'id' not in cs.operations[0]: return ChangeSet() if get_pattern(name, cs.operations[0]['id']) != {}: return ChangeSet() return execute_command(name, _add_pattern(name, cs)) def _delete_pattern(name: str, cs: ChangeSet) -> DatabaseCommand: id = cs.operations[0]['id'] f_id = sql_literal(id) statement = ( f"update network.demands set pattern_id = null where pattern_id = {f_id};" f"\ndelete from network.patterns where id = {f_id};" ) change = g_delete_prefix | { 'type': 'pattern' } | { 'id': id } return DatabaseCommand(statement, [change]) def delete_pattern(name: str, cs: ChangeSet) -> ChangeSet: if 'id' not in cs.operations[0]: return ChangeSet() if get_pattern(name, cs.operations[0]['id']) == {}: return ChangeSet() return execute_command(name, _delete_pattern(name, cs)) #-------------------------------------------------------------- # [EPA2][IN][OUT] # ;desc # id mult1 mult2 ..... #-------------------------------------------------------------- #-------------------------------------------------------------- # [EPA3][IN][OUT] # id FIXED (interval) # id factor1 factor2 ... # id VARIABLE # id time1 factor1 time2 factor2 ... #-------------------------------------------------------------- def inp_in_pattern(line: str, fixed: bool = True) -> str: tokens = line.split() sql = '' pattern_id = sql_literal(tokens[0]) if fixed: for token in tokens[1:]: factor = sql_literal(float(token)) sql += f"insert into network.pattern_values (pattern_id, sequence_no, factor) values ({pattern_id}, (select coalesce(max(sequence_no) + 1, 0) from network.pattern_values where pattern_id = {pattern_id}), {factor});" else: for token in tokens[1::2]: factor = sql_literal(float(token)) sql += f"insert into network.pattern_values (pattern_id, sequence_no, factor) values ({pattern_id}, (select coalesce(max(sequence_no) + 1, 0) from network.pattern_values where pattern_id = {pattern_id}), {factor});" return sql def inp_out_pattern(name: str) -> list[str]: lines = [] objs = read_all(name, "select pattern_id as id, factor from network.pattern_values order by pattern_id, sequence_no") for obj in objs: id = obj['id'] factor = obj['factor'] lines.append(f'{id} {factor}') return lines def inp_out_pattern_v3(name: str) -> list[str]: lines = [] objs = read_all(name, "select pattern_id as id, factor from network.pattern_values order by pattern_id, sequence_no") ids = [] for obj in objs: id = obj['id'] if id not in ids: # for EPA3, ignore time of variable pattern... lines.append(f'{id} FIXED') ids.append(id) factor = obj['factor'] lines.append(f'{id} {factor}') return lines