Big change to operation!
This commit is contained in:
@@ -5,10 +5,8 @@ from .project import copy_project
|
||||
from .change_set import ChangeSet
|
||||
|
||||
from .operation import get_current_operation
|
||||
from .operation import execute_undo as undo
|
||||
from .operation import execute_redo as redo
|
||||
from .operation import have_snapshot, take_snapshot, pick_snapshot
|
||||
from .operation import have_transaction, start_transaction, commit_transaction, abort_transaction
|
||||
from .operation import execute_undo, execute_redo
|
||||
from .operation import have_snapshot, take_snapshot, pick_snapshot, sync_with_server
|
||||
|
||||
from .s0_base import JUNCTION, RESERVOIR, TANK, PIPE, PUMP, VALVE
|
||||
from .s0_base import is_node, is_junction, is_reservoir, is_tank
|
||||
@@ -20,9 +18,7 @@ from .s0_base import get_node_links
|
||||
|
||||
from .s1_title import set_title, get_title
|
||||
|
||||
from .s2_junctions import add_junction, delete_junction
|
||||
from .s2_junctions import set_junction_elevation, set_junction_demand, set_junction_pattern, set_junction_coord
|
||||
from .s2_junctions import get_junction_property_names, get_junction_properties
|
||||
from .s2_junctions import get_junction_schema, add_junction, delete_junction, get_junction, set_junction
|
||||
|
||||
from .s3_reservoirs import add_reservoir, delete_reservoir
|
||||
from .s3_reservoirs import set_reservoir_head, set_reservoir_pattern, set_reservoir_coord
|
||||
|
||||
320
api/operation.py
320
api/operation.py
@@ -1,111 +1,130 @@
|
||||
from psycopg.rows import dict_row, Row
|
||||
from .connection import g_conn_dict as conn
|
||||
from .utility import *
|
||||
from .change_set import *
|
||||
|
||||
def _get_current_transaction(name: str) -> Row | None:
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
cur.execute(f"select * from transaction_operation")
|
||||
return cur.fetchone()
|
||||
|
||||
def _get_current_transaction_id(name: str) -> int:
|
||||
row = _get_current_transaction(name)
|
||||
return int(row['id'])
|
||||
API_ADD = 'add'
|
||||
API_DELETE = 'delete'
|
||||
API_UPDATE = 'update'
|
||||
|
||||
def _remove_transaction(name: str) -> None:
|
||||
with conn[name].cursor() as cur:
|
||||
cur.execute(f"delete from transaction_operation")
|
||||
|
||||
def _remove_operation(name: str, id: int) -> None:
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
# can not be >= to cascade delete since there is a tree !
|
||||
cur.execute(f"delete from transaction_operation where id = {id}") # this should not happen
|
||||
cur.execute(f"delete from snapshot_operation where id = {id}") # this may happen
|
||||
cur.execute(f"delete from operation where id = {id}")
|
||||
row = read(name, f'select * from operation where parent = {id}')
|
||||
if row != None:
|
||||
raise Exception('Disallow to remove parent operation !')
|
||||
|
||||
sql += f'delete from snapshot_operation where id = {id};'
|
||||
sql += f'delete from operation where id = {id}'
|
||||
write(name, sql)
|
||||
|
||||
|
||||
def _get_parents(name: str, id: int) -> list[int]:
|
||||
ids = [id]
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
while ids[-1] != 0:
|
||||
cur.execute(f"select parent from operation where id = {ids[-1]}")
|
||||
ids.append(int(cur.fetchone()['parent']))
|
||||
while ids[-1] != 0:
|
||||
row = read(name, f'select parent from operation where id = {ids[-1]}')
|
||||
ids.append(int(row['parent']))
|
||||
return ids
|
||||
|
||||
|
||||
def get_current_operation(name: str) -> int:
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
cur.execute(f"select id from current_operation")
|
||||
return int(cur.fetchone()['id'])
|
||||
row = read(name, f'select id from current_operation')
|
||||
return int(row['id'])
|
||||
|
||||
|
||||
def _update_current_operation(name: str, old_id: int, id: int) -> None:
|
||||
with conn[name].cursor() as cur:
|
||||
cur.execute(f"update current_operation set id = {id} where id = {old_id}")
|
||||
return write(name, f'update current_operation set id = {id} where id = {old_id}')
|
||||
|
||||
def _add_redo_undo(name: str, redo: str, undo: str) -> int:
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
parent = get_current_operation(name)
|
||||
cur.execute(f"insert into operation (id, redo, undo, parent) values (default, '{redo}', '{undo}', {parent})")
|
||||
cur.execute("select max(id) from operation")
|
||||
return int(cur.fetchone()['max'])
|
||||
|
||||
# execute curr undo
|
||||
def _query_undo(name: str, id: str) -> dict[str, str]:
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
cur.execute(f"select undo, parent from operation where id = {id}")
|
||||
return cur.fetchone()
|
||||
def _add_redo_undo(name: str, redo: str, undo: str, api_id: str, api_op: str, api_object_type: str, api_object_id: str, api_object_properties: list[str]) -> int:
|
||||
parent = get_current_operation(name)
|
||||
ps = []
|
||||
for p in api_object_properties:
|
||||
ps.append(f'"{p}"')
|
||||
if len(ps) > 0:
|
||||
ps = ','.join(ps)
|
||||
ps = '{' + ps + '}'
|
||||
sql = f"insert into operation (id, redo, undo, parent, api_id, api_op, api_object_type, api_object_id, api_object_properties) values (default, '{redo}', '{undo}', {parent}, '{api_id}', '{api_op}', '{api_object_type}', '{api_object_id}', '{ps}')"
|
||||
else:
|
||||
sql = f"insert into operation (id, redo, undo, parent, api_id, api_op, api_object_type, api_object_id) values (default, '{redo}', '{undo}', {parent}, '{api_id}', '{api_op}', '{api_object_type}', '{api_object_id}')"
|
||||
write(name, sql)
|
||||
|
||||
return int(read(name, 'select max(id) from operation')['max'])
|
||||
|
||||
|
||||
def _query_operation(name: str, id: str) -> dict[str, str]:
|
||||
return read(name, f'select * from operation where id = {id}')
|
||||
|
||||
|
||||
# execute next redo
|
||||
def _query_redo_child(name: str, id: str) -> str:
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
cur.execute(f"select redo_child from operation where id = {id}")
|
||||
return cur.fetchone()['redo_child']
|
||||
row = read(name, f'select redo_child from operation where id = {id}')
|
||||
return row['redo_child']
|
||||
|
||||
def _query_redo(name: str, id: str) -> dict[str, str]:
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
cur.execute(f"select redo from operation where id = {id}")
|
||||
return cur.fetchone()['redo']
|
||||
|
||||
def _set_redo_child(name: str, id: int, child: int | str) -> None:
|
||||
with conn[name].cursor() as cur:
|
||||
cur.execute(f"update operation set redo_child = {child} where id = {id}")
|
||||
return write(name, f'update operation set redo_child = {child} where id = {id}')
|
||||
|
||||
def _execute(name: str, sql: str) -> None:
|
||||
with conn[name].cursor() as cur:
|
||||
sql = sql.replace("\"", "\'")
|
||||
cur.execute(sql)
|
||||
|
||||
def add_operation(name: str, redo: str, undo: str) -> None:
|
||||
curr = _add_redo_undo(name, redo, undo)
|
||||
def add_operation(name: str, redo: str, undo: str, api_id: str, api_op: str, api_object_type: str, api_object_id: str, api_object_properties: list[str] = []) -> None:
|
||||
curr = _add_redo_undo(name, redo, undo, api_id, api_op, api_object_type, api_object_id, api_object_properties)
|
||||
old = get_current_operation(name)
|
||||
_update_current_operation(name, old, curr)
|
||||
|
||||
def execute_undo(name: str, discard: bool = False) -> None:
|
||||
|
||||
def _reverser_op(op: str) -> str:
|
||||
if op == API_ADD:
|
||||
return API_DELETE
|
||||
elif op == API_DELETE:
|
||||
return API_ADD
|
||||
else:
|
||||
return op
|
||||
|
||||
|
||||
def _get_change_set(row: dict[str, str], undo: bool) -> ChangeSet:
|
||||
op = row['api_op']
|
||||
if undo:
|
||||
op = _reverser_op(op)
|
||||
|
||||
type = row['api_object_type']
|
||||
id = row['api_object_id']
|
||||
|
||||
change = ChangeSet()
|
||||
|
||||
if op == API_ADD:
|
||||
change.add(type, id)
|
||||
elif op == API_DELETE:
|
||||
change.delete(type, id)
|
||||
elif op == API_UPDATE:
|
||||
ps = row['api_object_properties'].removeprefix('{').removesuffix('}').split(',')
|
||||
change.update(type, id, ps)
|
||||
|
||||
return change
|
||||
|
||||
|
||||
def execute_undo(name: str, discard: bool) -> ChangeSet:
|
||||
curr = get_current_operation(name)
|
||||
|
||||
# transaction control
|
||||
if have_transaction(name):
|
||||
tran = _get_current_transaction(name)
|
||||
if tran != None and int(tran['id']) >= 0:
|
||||
if bool(tran['strict']): # strict mode disallow undo
|
||||
print("Do not allow to undo in strict transaction mode!")
|
||||
return
|
||||
elif int(tran['id']) >= curr: # normal mode disallow undo start point, and there is foreign key constraint
|
||||
print("Do not allow to undo transaction start point!")
|
||||
return
|
||||
|
||||
row = _query_undo(name, curr)
|
||||
row = _query_operation(name, curr)
|
||||
undo = row['undo']
|
||||
if undo == '':
|
||||
print("nothing to undo!")
|
||||
return
|
||||
|
||||
parent = int(row['parent'])
|
||||
_set_redo_child(name, parent, 'NULL' if discard else curr)
|
||||
change = _get_change_set(row, True)
|
||||
|
||||
_execute(name, undo)
|
||||
parent = int(row['parent'])
|
||||
_set_redo_child(name, parent, 'null' if discard else curr)
|
||||
|
||||
write(name, undo)
|
||||
_update_current_operation(name, curr, parent)
|
||||
|
||||
if discard:
|
||||
_remove_operation(name, curr)
|
||||
|
||||
def execute_redo(name: str) -> None:
|
||||
return change
|
||||
|
||||
|
||||
def execute_redo(name: str) -> ChangeSet:
|
||||
curr = get_current_operation(name)
|
||||
redoChild = _query_redo_child(name, curr)
|
||||
if redoChild == None:
|
||||
@@ -113,108 +132,127 @@ def execute_redo(name: str) -> None:
|
||||
return
|
||||
|
||||
child = int(redoChild)
|
||||
redo = _query_redo(name, child)
|
||||
row = _query_operation(name, child)
|
||||
redo = row['redo']
|
||||
|
||||
_execute(name, redo)
|
||||
change = _get_change_set(row, False)
|
||||
|
||||
write(name, redo)
|
||||
_update_current_operation(name, curr, child)
|
||||
|
||||
# snapshot support to checkout between different version of database
|
||||
# snapshot is persistent
|
||||
# since redo always remember the recently undo path
|
||||
return change
|
||||
|
||||
|
||||
def _get_operation_by_tag(name: str, tag: str) -> int | None:
|
||||
row = read(name, f"select id from snapshot_operation where tag = '{tag}'")
|
||||
return int(row['id']) if row != None else None
|
||||
|
||||
|
||||
def have_snapshot(name: str, tag: str) -> bool:
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
cur.execute(f"select id from snapshot_operation where tag = '{tag}'")
|
||||
return cur.rowcount > 0
|
||||
return _get_operation_by_tag(name, tag) != None
|
||||
|
||||
def take_snapshot(name: str, tag: str) -> None:
|
||||
|
||||
def take_snapshot(name: str, tag: str) -> int | None:
|
||||
if tag == None or tag == '':
|
||||
print('Non empty tag is expected!')
|
||||
return
|
||||
return None
|
||||
|
||||
curr = get_current_operation(name)
|
||||
write(name, f"insert into snapshot_operation (id, tag) values ({curr}, '{tag}')")
|
||||
return curr
|
||||
|
||||
with conn[name].cursor() as cur:
|
||||
cur.execute(f"insert into snapshot_operation (id, tag) values ({curr}, '{tag}')")
|
||||
|
||||
def pick_snapshot(name: str, tag: str) -> None:
|
||||
def pick_snapshot(name: str, tag: str, discard: bool) -> ChangeSet:
|
||||
if tag == None or tag == '':
|
||||
print('Non empty tag is expected!')
|
||||
return
|
||||
return ChangeSet()
|
||||
|
||||
if not have_snapshot(name, tag):
|
||||
target = _get_operation_by_tag(name, tag)
|
||||
if target == None:
|
||||
print('No such snapshot!')
|
||||
return
|
||||
return ChangeSet()
|
||||
|
||||
curr = get_current_operation(name)
|
||||
|
||||
curr_parents = _get_parents(name, curr)
|
||||
target_parents = _get_parents(name, target)
|
||||
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
cur.execute(f"select id from snapshot_operation where tag = '{tag}'")
|
||||
target = int(cur.fetchone()['id'])
|
||||
if target in curr_parents: # target -> curr
|
||||
for i in range(curr_parents.index(target)):
|
||||
execute_undo(name)
|
||||
else:
|
||||
target_parents = _get_parents(name, target)
|
||||
if curr in target_parents: # curr -> target
|
||||
for i in range(target_parents.index(curr)):
|
||||
execute_redo(name)
|
||||
else:
|
||||
ancestor_index = -1
|
||||
while curr_parents[ancestor_index] == target_parents[ancestor_index]:
|
||||
ancestor_index -= 1
|
||||
change = ChangeSet()
|
||||
|
||||
# ancestor -> curr
|
||||
ancestor = curr_parents[ancestor_index + 1] # ancestor_index + 1 is common parent
|
||||
for i in range(curr_parents.index(ancestor)):
|
||||
execute_undo(name)
|
||||
# ancestor -> redo, need assign redo_child
|
||||
while target_parents[ancestor_index] != target:
|
||||
cur.execute(f"update operation set redo_child = '{target_parents[ancestor_index]}' where id = '{target_parents[ancestor_index + 1]}'")
|
||||
execute_redo(name)
|
||||
ancestor_index -= 1
|
||||
cur.execute(f"update operation set redo_child = '{target}' where id = '{target_parents[1]}'")
|
||||
execute_redo(name)
|
||||
if target in curr_parents:
|
||||
for _ in range(curr_parents.index(target)):
|
||||
change.append(execute_undo(name, discard))
|
||||
|
||||
# transaction is volatile, commit/abort will destroy transaction.
|
||||
# can not redo an aborted transaction.
|
||||
# but can undo a committed transaction... inconsistent...
|
||||
# it may remove snapshot if it is in aborted transaction
|
||||
elif curr in target_parents:
|
||||
target_parents.reverse()
|
||||
curr_index = target_parents.index(curr)
|
||||
for i in range(curr_index, len(target_parents) - 1):
|
||||
write(name, f"update operation set redo_child = '{target_parents[i + 1]}' where id = '{target_parents[i]}'")
|
||||
change.append(execute_redo(name))
|
||||
|
||||
def have_transaction(name: str) -> bool:
|
||||
with conn[name].cursor(row_factory=dict_row) as cur:
|
||||
cur.execute(f"select * from transaction_operation")
|
||||
return cur.rowcount > 0
|
||||
else:
|
||||
ancestor_index = -1
|
||||
while curr_parents[ancestor_index] == target_parents[ancestor_index]:
|
||||
ancestor_index -= 1
|
||||
ancestor = curr_parents[ancestor_index + 1]
|
||||
|
||||
def start_transaction(name: str, strict: bool = False) -> None:
|
||||
if have_transaction(name):
|
||||
print("Only support single transaction now, please commit/abort current transaction!")
|
||||
return
|
||||
for _ in range(curr_parents.index(ancestor)):
|
||||
change.append(execute_undo(name, discard))
|
||||
|
||||
curr = get_current_operation(name)
|
||||
target_parents.reverse()
|
||||
curr_index = target_parents.index(ancestor)
|
||||
for i in range(curr_index, len(target_parents) - 1):
|
||||
write(name, f"update operation set redo_child = '{target_parents[i + 1]}' where id = '{target_parents[i]}'")
|
||||
change.append(execute_redo(name))
|
||||
|
||||
with conn[name].cursor() as cur:
|
||||
cur.execute(f"insert into transaction_operation (id, strict) values ({curr}, {strict});")
|
||||
return change.compress()
|
||||
|
||||
def commit_transaction(name: str) -> None:
|
||||
if not have_transaction(name):
|
||||
print("No active transaction!")
|
||||
return
|
||||
|
||||
_remove_transaction(name)
|
||||
def get_change_set(name: str, operation: int, undo: bool) -> ChangeSet:
|
||||
row = read(name, f'select api_id, api_op, api_object_type, api_object_id, api_object_properties from operation where id = {operation}')
|
||||
return _get_change_set(row, undo)
|
||||
|
||||
def abort_transaction(name: str) -> None:
|
||||
if not have_transaction(name):
|
||||
print("No active transaction!")
|
||||
return
|
||||
|
||||
tran = _get_current_transaction_id(name)
|
||||
def get_current_change_set(name: str) -> ChangeSet:
|
||||
return get_change_set(name, get_current_operation(name), False)
|
||||
|
||||
curr = get_current_operation(name)
|
||||
curr_parents = _get_parents(name, curr)
|
||||
|
||||
for i in range(curr_parents.index(tran)):
|
||||
execute_undo(name, True)
|
||||
|
||||
_remove_transaction(name)
|
||||
def sync_with_server(name: str, operation: int) -> ChangeSet:
|
||||
fr = operation
|
||||
to = get_current_operation(name)
|
||||
|
||||
fr_parents = _get_parents(name, fr)
|
||||
to_parents = _get_parents(name, to)
|
||||
|
||||
change = ChangeSet()
|
||||
|
||||
if fr in to_parents:
|
||||
index = to_parents.index(fr) - 1
|
||||
while index >= 0:
|
||||
change.append(get_change_set(name, to_parents[index], False))
|
||||
index -= 1
|
||||
|
||||
elif to in fr_parents:
|
||||
index = 0
|
||||
while index <= fr_parents.index(to) - 1:
|
||||
change.append(get_change_set(name, fr_parents[index], True))
|
||||
index += 1
|
||||
|
||||
else:
|
||||
ancestor_index = -1
|
||||
while fr_parents[ancestor_index] == to_parents[ancestor_index]:
|
||||
ancestor_index -= 1
|
||||
|
||||
ancestor = fr_parents[ancestor_index + 1]
|
||||
|
||||
index = 0
|
||||
while index <= fr_parents.index(ancestor) - 1:
|
||||
change.append(get_change_set(name, fr_parents[index], True))
|
||||
index += 1
|
||||
|
||||
index = to_parents.index(ancestor) - 1
|
||||
while index >= 0:
|
||||
change.append(get_change_set(name, to_parents[index], False))
|
||||
index -= 1
|
||||
|
||||
return change.compress()
|
||||
|
||||
@@ -99,15 +99,15 @@ def add_node(name: str, node_type: str, id: str, x: float, y: float, table_sql:
|
||||
return ChangeSet()
|
||||
|
||||
with conn[name].cursor() as cur:
|
||||
sql = f"insert into _node (id, type) values ('{id}', '{node_type}'); "
|
||||
sql = f"insert into _node (id, type) values ('{id}', '{node_type}');"
|
||||
sql += table_sql
|
||||
sql += f" insert into coordinates (node, coord) values ('{id}', '({x}, {y})');"
|
||||
sql += f"insert into coordinates (node, coord) values ('{id}', '({x}, {y})');"
|
||||
cur.execute(sql)
|
||||
|
||||
redo = sql.replace("'", '"')
|
||||
undo = f'delete from coordinates where node = "{id}"; '
|
||||
undo = f'delete from coordinates where node = "{id}";'
|
||||
undo += table_undo_sql
|
||||
undo += f' delete from _node where id = "{id}";'
|
||||
undo += f'delete from _node where id = "{id}";'
|
||||
add_operation(name, redo, undo)
|
||||
|
||||
change = ChangeSet()
|
||||
@@ -133,9 +133,9 @@ def delete_node(name: str, node_type: str, id: str, table_sql: str, table_undo_s
|
||||
cur.execute(sql)
|
||||
|
||||
redo = sql.replace("'", '"')
|
||||
undo = f'insert into _node (id, type) values ("{id}", "{node_type}"); '
|
||||
undo = f'insert into _node (id, type) values ("{id}", "{node_type}");'
|
||||
undo += table_undo_sql
|
||||
undo += f' insert into coordinates (node, coord) values ("{id}", "{coord}");'
|
||||
undo += f'insert into coordinates (node, coord) values ("{id}", "{coord}");'
|
||||
add_operation(name, redo, undo)
|
||||
|
||||
change = ChangeSet()
|
||||
@@ -148,13 +148,13 @@ def add_link(name: str, link_type: str, id: str, table_sql: str, table_undo_sql:
|
||||
return ChangeSet()
|
||||
|
||||
with conn[name].cursor() as cur:
|
||||
sql = f"insert into _link (id, type) values ('{id}', '{link_type}'); "
|
||||
sql = f"insert into _link (id, type) values ('{id}', '{link_type}');"
|
||||
sql += table_sql
|
||||
cur.execute(sql)
|
||||
|
||||
redo = sql.replace("'", '"')
|
||||
undo = table_undo_sql
|
||||
undo += f' delete from _link where id = "{id}";'
|
||||
undo += f'delete from _link where id = "{id}";'
|
||||
add_operation(name, redo, undo)
|
||||
|
||||
change = ChangeSet()
|
||||
|
||||
@@ -5,10 +5,8 @@ from .operation import *
|
||||
from .change_set import ChangeSet
|
||||
|
||||
|
||||
def _to_point(coord: str) -> dict[str, float]:
|
||||
coord = coord.removeprefix('(')
|
||||
coord = coord.removesuffix(')')
|
||||
coord = coord.split(',')
|
||||
def _to_client_point(coord: str) -> dict[str, float]:
|
||||
coord = coord.removeprefix('(').removesuffix(')').split(',')
|
||||
return { 'x': float(coord[0]), 'y': float(coord[1]) }
|
||||
|
||||
|
||||
@@ -20,7 +18,7 @@ def get_node_coord(name: str, id: str) -> dict[str, float] | None:
|
||||
return None
|
||||
|
||||
coord = str(row['coord'])
|
||||
return _to_point(coord)
|
||||
return _to_client_point(coord)
|
||||
|
||||
|
||||
def set_node_coord(name: str, node_type: str, id: str, x: float, y: float) -> ChangeSet:
|
||||
|
||||
@@ -4,82 +4,98 @@ from .s0_base import *
|
||||
from .change_set import ChangeSet
|
||||
from .s24_coordinates import *
|
||||
from .utility import *
|
||||
from .schema import *
|
||||
|
||||
|
||||
schema: dict[str, dict[str, Any]] = { \
|
||||
'id' : define_property(str_type, False, True), \
|
||||
'elevation' : define_property(float_type), \
|
||||
'demand' : define_property(float_type, True), \
|
||||
'pattern' : define_property(str_type, True), \
|
||||
'coord' : define_property(client_point_type), \
|
||||
'links' : define_property(str_list_type, False, True)}
|
||||
|
||||
|
||||
def get_junction_schema(name: str) -> dict[str, str]:
|
||||
return schema
|
||||
|
||||
|
||||
def _query_junction(name: str, id: str) -> Row | None:
|
||||
return read(name, f"select id, elevation, demand, pattern from junctions where id = '{id}'")
|
||||
|
||||
|
||||
def add_junction(name: str, id: str, x: float, y: float, elevation: float) -> ChangeSet:
|
||||
sql = f"insert into junctions (id, elevation) values ('{id}', {elevation});"
|
||||
undo_sql = f'delete from junctions where id = "{id}";'
|
||||
return add_node(name, JUNCTION, id, x, y, sql, undo_sql)
|
||||
|
||||
|
||||
def _get_junction(name: str, id: str) -> Row | None:
|
||||
return query(name, f"select elevation, demand, pattern from junctions where id = '{id}'")
|
||||
|
||||
|
||||
def delete_junction(name: str, id: str) -> ChangeSet:
|
||||
if not is_junction(name, id):
|
||||
if is_junction(name, id):
|
||||
return ChangeSet()
|
||||
|
||||
row = _get_junction(name, id)
|
||||
if row == None:
|
||||
return ChangeSet()
|
||||
sql = f"insert into _node (id, type) values ('{id}', '{JUNCTION}');"
|
||||
sql += f"\ninsert into junctions (id, elevation) values ('{id}', {elevation});"
|
||||
sql += f"\ninsert into coordinates (node, coord) values ('{id}', '({x}, {y})');"
|
||||
|
||||
elevation = row['elevation']
|
||||
demand = decorate(row['demand'], 'float', True)
|
||||
pattern = decorate(row['pattern'], 'str', True)
|
||||
undo = f"delete from coordinates where node = ''{id}'';"
|
||||
undo += f"\ndelete from junctions where id = ''{id}'';"
|
||||
undo += f"\ndelete from _node where id = ''{id}'';"
|
||||
|
||||
sql = f"delete from junctions where id = '{id}';"
|
||||
undo_sql = f'insert into junctions (id, elevation, demand, pattern) values ("{id}", {elevation}, {demand}, {pattern});'
|
||||
|
||||
return delete_node(name, JUNCTION, id, sql, undo_sql)
|
||||
write(name, sql)
|
||||
add_operation(name, sql.replace("'", "''"), undo, 'add_junction', API_ADD, JUNCTION, id)
|
||||
return get_current_change_set(name)
|
||||
|
||||
|
||||
def _set_junction(name: str, id: str, key: str, key_type: str, value: str, optional: bool = False) -> ChangeSet:
|
||||
if not is_junction(name, id):
|
||||
return ChangeSet()
|
||||
|
||||
row = _get_junction(name, id)
|
||||
if row == None:
|
||||
return ChangeSet()
|
||||
|
||||
return update(name, JUNCTION, 'junctions', 'id', id, key, key_type, row[key], value, optional)
|
||||
|
||||
|
||||
def set_junction_elevation(name: str, id: str, elevation: float) -> ChangeSet:
|
||||
return _set_junction(name, id, 'elevation', 'float', str(elevation))
|
||||
|
||||
|
||||
def set_junction_demand(name: str, id: str, demand: float) -> ChangeSet:
|
||||
return _set_junction(name, id, 'demand', 'float', str(demand), True)
|
||||
|
||||
|
||||
def set_junction_pattern(name: str, id: str, pattern: str) -> ChangeSet:
|
||||
if not is_pattern(name, pattern):
|
||||
return ChangeSet()
|
||||
|
||||
return _set_junction(name, id, 'pattern', 'str', pattern, True)
|
||||
|
||||
|
||||
def set_junction_coord(name: str, id: str, x: float, y: float) -> ChangeSet:
|
||||
if not is_junction(name, id):
|
||||
return ChangeSet()
|
||||
|
||||
return set_node_coord(name, JUNCTION, id, x, y)
|
||||
|
||||
|
||||
def get_junction_property_names(name: str) -> list[str]:
|
||||
return ['elevation', 'demand', 'pattern', 'coord', 'links']
|
||||
|
||||
|
||||
def get_junction_properties(name: str, id: str) -> dict[str, Any] | None:
|
||||
row = _get_junction(name, id)
|
||||
def get_junction(name: str, id: str) -> dict[str, Any] | None:
|
||||
row = _query_junction(name, id)
|
||||
if row == None:
|
||||
return None
|
||||
|
||||
ps: dict[str, str] = {}
|
||||
ps['elevation'] = float(row['elevation'])
|
||||
ps['demand'] = float(row['demand']) if row != None and row['demand'] != None else None
|
||||
ps['pattern'] = row['pattern'] if row != None and row['pattern'] != None else None
|
||||
ps['demand'] = float(row['demand']) if row['demand'] != None else None
|
||||
ps['pattern'] = row['pattern']
|
||||
ps['coord'] = get_node_coord(name, id)
|
||||
ps['links'] = get_node_links(name, id)
|
||||
return ps
|
||||
|
||||
|
||||
def delete_junction(name: str, id: str) -> ChangeSet:
|
||||
row = get_junction(name, id)
|
||||
if row == None:
|
||||
return ChangeSet()
|
||||
|
||||
old = Serialize(get_junction(name, id), schema).to_storage()
|
||||
|
||||
sql = f"delete from coordinates where node = '{id}';"
|
||||
sql += f"\ndelete from junctions where id = '{id}';"
|
||||
sql += f"\ndelete from _node where id = '{id}';"
|
||||
|
||||
undo = f"insert into _node (id, type) values (''{id}'', ''{JUNCTION}'');"
|
||||
undo += f"\ninsert into junctions (id, elevation, demand, pattern) values (''{id}'', {old['elevation']}, {old['demand']}, {old['pattern']});"
|
||||
undo += f"\ninsert into coordinates (node, coord) values (''{id}'', {old['coord']});"
|
||||
|
||||
write(name, sql)
|
||||
add_operation(name, sql.replace("'", "''"), undo, 'delete_junction', API_DELETE, JUNCTION, id)
|
||||
return get_current_change_set(name)
|
||||
|
||||
|
||||
def set_junction(name: str, id: str, properties: dict[str, Any]) -> ChangeSet:
|
||||
if not is_junction(name, id):
|
||||
return ChangeSet()
|
||||
|
||||
old = Serialize(get_junction(name, id), schema).to_storage()
|
||||
|
||||
new = get_junction(name, id)
|
||||
ps: list[str] = []
|
||||
for key in properties:
|
||||
if key in schema and schema[key]['readonly'] == False:
|
||||
new[key] = properties[key]
|
||||
ps.append(key)
|
||||
new = Serialize(new, schema).to_execution()
|
||||
|
||||
sql = f"update junctions set elevation = {new['elevation']}, demand = {new['demand']}, pattern = {new['pattern']} where id = '{id}';"
|
||||
undo = ""
|
||||
if 'coord' in ps:
|
||||
sql += f"\nupdate coordinates set coord = {new['coord']} where node = '{id}';"
|
||||
undo = f"update coordinates set coord = {old['coord']} where node = ''{id}'';"
|
||||
undo += f"\nupdate junctions set elevation = {old['elevation']}, demand = {old['demand']}, pattern = {old['pattern']} where id = ''{id}'';"
|
||||
|
||||
write(name, sql)
|
||||
add_operation(name, sql.replace("'", "''"), undo, 'set_junction', API_UPDATE, JUNCTION, id, ps)
|
||||
return get_current_change_set(name)
|
||||
|
||||
48
tjnetwork.py
48
tjnetwork.py
@@ -71,32 +71,23 @@ def copy_project(source: str, new: str) -> None:
|
||||
def get_current_operation(name: str) -> int:
|
||||
return api.get_current_operation(name)
|
||||
|
||||
def undo(name: str) -> None:
|
||||
return api.undo(name)
|
||||
def execute_undo(name: str, discard: bool = False) -> ChangeSet:
|
||||
return api.execute_undo(name, discard)
|
||||
|
||||
def redo(name: str) -> None:
|
||||
return api.redo(name)
|
||||
def execute_redo(name: str) -> ChangeSet:
|
||||
return api.execute_redo(name)
|
||||
|
||||
def have_snapshot(name: str, tag: str) -> bool:
|
||||
return api.have_snapshot(name, tag)
|
||||
|
||||
def take_snapshot(name: str, tag: str) -> None:
|
||||
def take_snapshot(name: str, tag: str) -> int:
|
||||
return api.take_snapshot(name, tag)
|
||||
|
||||
def pick_snapshot(name: str, tag: str) -> None:
|
||||
return api.pick_snapshot(name, tag)
|
||||
def pick_snapshot(name: str, tag: str, discard: bool = False) -> ChangeSet:
|
||||
return api.pick_snapshot(name, tag, discard)
|
||||
|
||||
def have_transaction(name: str) -> bool:
|
||||
return api.have_transaction(name)
|
||||
|
||||
def start_transaction(name: str, strict: bool = False) -> None:
|
||||
return api.start_transaction(name, strict)
|
||||
|
||||
def commit_transaction(name: str) -> None:
|
||||
return api.commit_transaction(name)
|
||||
|
||||
def abort_transaction(name: str) -> None:
|
||||
return api.abort_transaction(name)
|
||||
def sync_with_server(name: str, operation: int) -> ChangeSet:
|
||||
return api.sync_with_server(name, operation)
|
||||
|
||||
|
||||
############################################################
|
||||
@@ -161,8 +152,8 @@ def get_title(name: str) -> str:
|
||||
# junction 2.[JUNCTIONS]
|
||||
############################################################
|
||||
|
||||
def get_junction_property_names(name: str) -> list[str]:
|
||||
return api.get_junction_property_names(name)
|
||||
def get_junction_schema(name: str) -> dict[str, str]:
|
||||
return api.get_junction_schema(name)
|
||||
|
||||
def add_junction(name: str, junction_id: str, x: float, y: float, elevation: float) -> ChangeSet:
|
||||
return api.add_junction(name, junction_id, x, y, elevation)
|
||||
@@ -170,20 +161,11 @@ def add_junction(name: str, junction_id: str, x: float, y: float, elevation: flo
|
||||
def delete_junction(name: str, junction_id: str) -> ChangeSet:
|
||||
return api.delete_junction(name, junction_id)
|
||||
|
||||
def set_junction_elevation(name: str, junction_id: str, elevation: float) -> ChangeSet:
|
||||
return api.set_junction_elevation(name, junction_id, elevation)
|
||||
def get_junction(name: str, junction_id: str) -> dict[str, Any] | None:
|
||||
return api.get_junction(name, junction_id)
|
||||
|
||||
def set_junction_demand(name: str, junction_id: str, demand: float) -> ChangeSet:
|
||||
return api.set_junction_demand(name, junction_id, demand)
|
||||
|
||||
def set_junction_pattern(name: str, junction_id: str, pattern: str) -> ChangeSet:
|
||||
return api.set_junction_pattern(name, junction_id, pattern)
|
||||
|
||||
def set_junction_coord(name: str, junction_id: str, x: float, y: float) -> ChangeSet:
|
||||
return api.set_junction_coord(name, junction_id, x, y)
|
||||
|
||||
def get_junction_properties(name: str, junction_id: str) -> dict[str, Any] | None:
|
||||
return api.get_junction_properties(name, junction_id)
|
||||
def set_junction(name: str, junction_id: str, properties: dict[str, Any]) -> ChangeSet:
|
||||
return api.set_junction(name, junction_id, properties)
|
||||
|
||||
|
||||
############################################################
|
||||
|
||||
Reference in New Issue
Block a user