Skip to content

Commit 4c9182a

Browse files
committed
create edit enum function
1 parent d18320e commit 4c9182a

1 file changed

Lines changed: 123 additions & 0 deletions

File tree

openslides_backend/migrations/sql_diff_generator.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from argparse import ArgumentParser
44
from collections import defaultdict
55
from copy import deepcopy
6+
from textwrap import dedent
67
from typing import Any, cast
78

89
import simplejson as json
@@ -980,6 +981,24 @@ def handle_edit_tree(
980981
remove_empty(dc_edit_tree_dict, collection_name)
981982
return sql
982983

984+
@staticmethod
985+
def get_recreate_enum(
986+
enum_name: str, collection_name: str, field_name: str, values: list[str]
987+
) -> str:
988+
result = ""
989+
result += (
990+
AlterSchemaHelper.get_drop_enum_type_statement_from_collection_and_column(
991+
collection_name, field_name
992+
)
993+
)
994+
result += Helper.ENUM_DEFINITION_TEMPLATE.substitute(
995+
{
996+
"name": enum_name,
997+
"values": ", ".join([f"'{item}'" for item in values]),
998+
}
999+
)
1000+
return result
1001+
9831002
@staticmethod
9841003
def handle_edit_field_attributes(
9851004
table_name: str,
@@ -1037,6 +1056,13 @@ def handle_edit_field_attributes(
10371056
table_name, field_name
10381057
),
10391058
)
1059+
case "enum":
1060+
values_old = PREV_MODELS[collection_name]["fields"][field_name][
1061+
constraint
1062+
]
1063+
constraints_sql += EditHelper.edit_enum(
1064+
value, values_old, collection_name, field_name
1065+
)
10401066
case "sql":
10411067
alter_views.add(collection_name)
10421068
case "reference" | "to":
@@ -1066,10 +1092,107 @@ def handle_edit_field_attributes(
10661092
case value if value in FieldAttributes.skipped_in_schema:
10671093
pass
10681094
case _:
1095+
# Currently unhandled:
1096+
# "required" "unique" as they are only present with true and will be deleted if false.
1097+
# type changes are not yet supported
10691098
raise NotImplementedError(f"{constraint}: {value}")
10701099
del dc_field_def[0][constraint]
10711100
return constraints_sql
10721101

1102+
@classmethod
1103+
def edit_enum(
1104+
cls,
1105+
values_new: list[str],
1106+
values_old: list[str],
1107+
collection_name: str,
1108+
field_name: str,
1109+
) -> str:
1110+
# not_found_streak = None
1111+
recreate_enum = False
1112+
add_attributes: list[str] = []
1113+
rename_attributes = {} # old: new
1114+
concurrent_mismatches = {} # old: new
1115+
expected_idx = 0
1116+
alter_enum_sql = ""
1117+
# Finding the stretches that differ by identifying the position in the old array
1118+
for nmbr, v_new in enumerate(values_new):
1119+
if recreate_enum:
1120+
break
1121+
expected_idx = nmbr - len(add_attributes)
1122+
try:
1123+
if field_name == "state":
1124+
pass
1125+
idx_old = values_old.index(v_new)
1126+
except ValueError:
1127+
# value not in list
1128+
# edge up NOT_FOUND_STREAK
1129+
# collect for change detection
1130+
if expected_idx < len(values_old):
1131+
concurrent_mismatches[values_old[expected_idx]] = v_new
1132+
elif not concurrent_mismatches:
1133+
add_attributes.append(v_new)
1134+
else:
1135+
raise Exception(
1136+
"It seems you are trying to rename and add at the end of the list at the same time."
1137+
)
1138+
# not_found_streak = True
1139+
else:
1140+
# edge down for NOT_FOUND_STREAK
1141+
if idx_old == expected_idx:
1142+
# if gap matches rename attribute and give warning to check those lines in output
1143+
# else recreated enum
1144+
# if not_found_streak:
1145+
# not_found_streak = False
1146+
rename_attributes.update(concurrent_mismatches)
1147+
elif idx_old < expected_idx:
1148+
# Add inbetween of new entries.
1149+
add_attributes.extend(v for v in concurrent_mismatches.values())
1150+
elif idx_old > expected_idx:
1151+
# Add inbetween of old entries means remove in new.
1152+
# We can't delete but can tolerate it being unused. So nothing to do here.
1153+
# TODO decide whether to do nothing,
1154+
recreate_enum = True
1155+
# or change type to string?
1156+
if concurrent_mismatches:
1157+
concurrent_mismatches.clear()
1158+
# Clean up remaining
1159+
if len(values_new) > len(values_old) + len(add_attributes):
1160+
add_attributes.extend(v for v in concurrent_mismatches.values())
1161+
else:
1162+
rename_attributes.update(concurrent_mismatches)
1163+
if len(values_old) > len(values_new) - len(add_attributes):
1164+
recreate_enum = True
1165+
1166+
# Do the stuff
1167+
enum_name = HelperGetNames.get_enum_name_for_column(collection_name, field_name)
1168+
if recreate_enum:
1169+
# recreate enum
1170+
alter_enum_sql += EditHelper.get_recreate_enum(
1171+
enum_name, collection_name, field_name, values_new
1172+
)
1173+
else:
1174+
for attr in add_attributes:
1175+
alter_enum_sql += AlterSchemaHelper.get_add_value_to_enum(
1176+
enum_name, attr
1177+
)
1178+
if rename_attributes:
1179+
print(
1180+
dedent(f"""
1181+
Renaming entries for '{enum_name}'.
1182+
{rename_attributes}
1183+
Make sure that this is intended.
1184+
Alternatively recreate it by replacing with:
1185+
""")
1186+
+ EditHelper.get_recreate_enum(
1187+
enum_name, collection_name, field_name, values_new
1188+
)
1189+
)
1190+
for attr_old, attr_new in rename_attributes.items():
1191+
alter_enum_sql += AlterSchemaHelper.get_rename_value_in_enum(
1192+
enum_name, attr_old, attr_new
1193+
)
1194+
return alter_enum_sql
1195+
10731196

10741197
def handle_rename(renames: Renames, dc_rename_dict: Renames) -> str:
10751198
result = ""

0 commit comments

Comments
 (0)