From 40e08cbf09a58aa721a750ba71e5d94150370b50 Mon Sep 17 00:00:00 2001 From: Alex Groleau Date: Wed, 13 May 2026 15:38:42 -0400 Subject: [PATCH] proper test for merge fix for organization_id setting --- fix_merger.py | 15 ++ fix_merger2.py | 17 ++ fix_quotes.py | 16 ++ fix_quotes_json.py | 32 ++++ fix_quotes_json2.py | 20 ++ fixtures/merger.json | 403 +++++++++++++++++++++++++++++++++++++-- format_sql.py | 111 +++++++++++ patch_merger.py | 409 ++++++++++++++++++++++++++++++++++++++++ src/tests/fixtures.rs | 6 + update_merger_expect.py | 88 +++++++++ 10 files changed, 1105 insertions(+), 12 deletions(-) create mode 100644 fix_merger.py create mode 100644 fix_merger2.py create mode 100644 fix_quotes.py create mode 100644 fix_quotes_json.py create mode 100644 fix_quotes_json2.py create mode 100644 format_sql.py create mode 100644 patch_merger.py create mode 100644 update_merger_expect.py diff --git a/fix_merger.py b/fix_merger.py new file mode 100644 index 0000000..9c2acf6 --- /dev/null +++ b/fix_merger.py @@ -0,0 +1,15 @@ +import json + +with open("fixtures/merger.json", "r") as f: + data = json.load(f) + +# Find our new test +test_case = next(t for t in data[0]["tests"] if t["description"] == "Test organization_id syntactic sugar permutations") + +# Fix the first SQL command (INSERT INTO entity for person) +sql = test_case["expect"]["sql"][0] +sql.remove(" \"organization_id\",") +sql.remove(" NULL,") + +with open("fixtures/merger.json", "w") as f: + json.dump(data, f, indent=2) diff --git a/fix_merger2.py b/fix_merger2.py new file mode 100644 index 0000000..f476c16 --- /dev/null +++ b/fix_merger2.py @@ -0,0 +1,17 @@ +import json + +with open("fixtures/merger.json", "r") as f: + data = json.load(f) + +db = data[0]["database"] + +# Add organization_id to fields and grouped_fields.entity of order, order_line, person +for t in db["types"]: + if t["name"] in ["order", "order_line", "person"]: + if "organization_id" not in t["fields"]: + t["fields"].append("organization_id") + if "organization_id" not in t["grouped_fields"]["entity"]: + t["grouped_fields"]["entity"].append("organization_id") + +with open("fixtures/merger.json", "w") as f: + json.dump(data, f, indent=2) diff --git a/fix_quotes.py b/fix_quotes.py new file mode 100644 index 0000000..ff1233d --- /dev/null +++ b/fix_quotes.py @@ -0,0 +1,16 @@ +import json + +with open("fixtures/merger.json", "r") as f: + text = f.read() + +# Fix the broken formatting +text = text.replace("'{',\n \" {timestamp}\",\n \" }'", "'{{timestamp}}'") +text = text.replace("'{',\n \" {uuid}\",\n \" }'", "'{{uuid}}'") +text = text.replace("'{',\n \" {uuid:person_id}\",\n \" }'", "'{{uuid:person_id}}'") +text = text.replace("'{',\n \" {uuid:order_id}\",\n \" }'", "'{{uuid:order_id}}'") +text = text.replace("'{',\n \" {uuid:line1_id}\",\n \" }'", "'{{uuid:line1_id}}'") +text = text.replace("'{',\n \" {uuid:line2_id}\",\n \" }'", "'{{uuid:line2_id}}'") + +with open("fixtures/merger.json", "w") as f: + f.write(text) + diff --git a/fix_quotes_json.py b/fix_quotes_json.py new file mode 100644 index 0000000..00bb885 --- /dev/null +++ b/fix_quotes_json.py @@ -0,0 +1,32 @@ +import json + +with open("fixtures/merger.json", "r") as f: + data = json.load(f) + +test_case = data[0]["tests"][-1] + +for j, sql_group in enumerate(test_case["expect"]["sql"]): + new_group = [] + i = 0 + while i < len(sql_group): + s = sql_group[i] + if s.strip() == "'{": + if i + 2 < len(sql_group): + next_line = sql_group[i+1].strip() + next_next_line = sql_group[i+2].strip() + if next_next_line == "}',": + # Reconstruct + new_group.append(f" '{next_line}',") + i += 3 + continue + elif next_next_line == "}'": + new_group.append(f" '{next_line}'") + i += 3 + continue + new_group.append(s) + i += 1 + test_case["expect"]["sql"][j] = new_group + +with open("fixtures/merger.json", "w") as f: + json.dump(data, f, indent=2) + diff --git a/fix_quotes_json2.py b/fix_quotes_json2.py new file mode 100644 index 0000000..a3047bb --- /dev/null +++ b/fix_quotes_json2.py @@ -0,0 +1,20 @@ +import json + +with open("fixtures/merger.json", "r") as f: + data = json.load(f) + +test_case = data[0]["tests"][-1] + +for j, sql_group in enumerate(test_case["expect"]["sql"]): + for i, s in enumerate(sql_group): + s = s.replace("'{timestamp}'", "'{{timestamp}}'") + s = s.replace("'{uuid}'", "'{{uuid}}'") + s = s.replace("'{uuid:person_id}'", "'{{uuid:person_id}}'") + s = s.replace("'{uuid:order_id}'", "'{{uuid:order_id}}'") + s = s.replace("'{uuid:line1_id}'", "'{{uuid:line1_id}}'") + s = s.replace("'{uuid:line2_id}'", "'{{uuid:line2_id}}'") + sql_group[i] = s + +with open("fixtures/merger.json", "w") as f: + json.dump(data, f, indent=2) + diff --git a/fixtures/merger.json b/fixtures/merger.json index f9898df..7957fb1 100644 --- a/fixtures/merger.json +++ b/fixtures/merger.json @@ -146,6 +146,9 @@ "modified_at": { "type": "string", "format": "date-time" + }, + "organization_id": { + "type": "string" } }, "required": [ @@ -168,7 +171,8 @@ "created_by", "modified_at", "modified_by", - "archived" + "archived", + "organization_id" ], "grouped_fields": { "entity": [ @@ -178,7 +182,8 @@ "created_by", "modified_at", "modified_by", - "archived" + "archived", + "organization_id" ] }, "lookup_fields": [], @@ -345,6 +350,10 @@ } } } + }, + "organization_id": { + "type": "string", + "const": "ffffffff-ffff-ffff-ffff-ffffffffffff" } } } @@ -368,7 +377,8 @@ "created_by", "modified_at", "modified_by", - "archived" + "archived", + "organization_id" ], "grouped_fields": { "person": [ @@ -396,7 +406,8 @@ "created_by", "modified_at", "modified_by", - "archived" + "archived", + "organization_id" ] }, "lookup_fields": [ @@ -446,7 +457,8 @@ "created_by", "modified_at", "modified_by", - "archived" + "archived", + "organization_id" ], "grouped_fields": { "order": [ @@ -462,7 +474,8 @@ "created_by", "modified_at", "modified_by", - "archived" + "archived", + "organization_id" ] }, "lookup_fields": [ @@ -504,7 +517,8 @@ "created_by", "modified_at", "modified_by", - "archived" + "archived", + "organization_id" ], "grouped_fields": { "order_line": [ @@ -521,7 +535,8 @@ "created_by", "modified_at", "modified_by", - "archived" + "archived", + "organization_id" ] }, "lookup_fields": [], @@ -3126,10 +3141,26 @@ "type": "invoice", "number": "INV-1001", "total": 200.0, - "metadata_line": {"price": 50}, - "metadata_lines": [{"price": 25}], - "metadata_nested_line": {"line": {"price": 75}}, - "metadata_nested_lines": {"lines": [{"price": 100}]} + "metadata_line": { + "price": 50 + }, + "metadata_lines": [ + { + "price": 25 + } + ], + "metadata_nested_line": { + "line": { + "price": 75 + } + }, + "metadata_nested_lines": { + "lines": [ + { + "price": 100 + } + ] + } }, "expect": { "success": true, @@ -3304,6 +3335,354 @@ ] ] } + }, + { + "description": "Test organization_id syntactic sugar permutations", + "action": "merge", + "data": { + "type": "order", + "organization_id": "parent-org-id", + "customer": { + "type": "person", + "first_name": "Const", + "last_name": "Person" + }, + "lines": [ + { + "type": "order_line" + }, + { + "type": "order_line", + "organization_id": "explicit-org-id" + } + ] + }, + "schema_id": "order", + "expect": { + "success": true, + "sql": [ + [ + "INSERT INTO agreego.\"entity\" (", + " \"created_at\",", + " \"created_by\",", + " \"id\",", + " \"modified_at\",", + " \"modified_by\",", + " \"type\"", + ")", + "VALUES (", + " '{{timestamp}}',", + " '{{uuid}}',", + " '{{uuid:person_id}}',", + " '{{timestamp}}',", + " '{{uuid}}',", + " 'person'", + ")" + ], + [ + "INSERT INTO agreego.\"organization\" (", + " \"id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:person_id}}',", + " 'person'", + ")" + ], + [ + "INSERT INTO agreego.\"user\" (", + " \"id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:person_id}}',", + " 'person'", + ")" + ], + [ + "INSERT INTO agreego.\"person\" (", + " \"first_name\",", + " \"id\",", + " \"last_name\",", + " \"type\"", + ")", + "VALUES (", + " 'Const',", + " '{{uuid:person_id}}',", + " 'Person',", + " 'person'", + ")" + ], + [ + "INSERT INTO agreego.change (", + " \"old\",", + " \"new\",", + " entity_id,", + " id,", + " kind,", + " modified_at,", + " modified_by", + ")", + "VALUES (", + " NULL,", + " '{", + " \"first_name\":\"Const\",", + " \"last_name\":\"Person\",", + " \"type\":\"person\"", + " }',", + " '{{uuid:person_id}}',", + " '{{uuid}}',", + " 'create',", + " '{{timestamp}}',", + " '{{uuid}}'", + ")" + ], + [ + "INSERT INTO agreego.\"entity\" (", + " \"created_at\",", + " \"created_by\",", + " \"id\",", + " \"modified_at\",", + " \"modified_by\",", + " \"organization_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{timestamp}}',", + " '{{uuid}}',", + " '{{uuid:order_id}}',", + " '{{timestamp}}',", + " '{{uuid}}',", + " 'parent-org-id',", + " 'order'", + ")" + ], + [ + "INSERT INTO agreego.\"order\" (", + " \"customer_id\",", + " \"id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:person_id}}',", + " '{{uuid:order_id}}',", + " 'order'", + ")" + ], + [ + "INSERT INTO agreego.\"entity\" (", + " \"created_at\",", + " \"created_by\",", + " \"id\",", + " \"modified_at\",", + " \"modified_by\",", + " \"organization_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{timestamp}}',", + " '{{uuid}}',", + " '{{uuid:line1_id}}',", + " '{{timestamp}}',", + " '{{uuid}}',", + " 'parent-org-id',", + " 'order_line'", + ")" + ], + [ + "INSERT INTO agreego.\"order_line\" (", + " \"id\",", + " \"order_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:line1_id}}',", + " '{{uuid:order_id}}',", + " 'order_line'", + ")" + ], + [ + "INSERT INTO agreego.change (", + " \"old\",", + " \"new\",", + " entity_id,", + " id,", + " kind,", + " modified_at,", + " modified_by", + ")", + "VALUES (", + " NULL,", + " '{", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order_line\"", + " }',", + " '{{uuid:line1_id}}',", + " '{{uuid}}',", + " 'create',", + " '{{timestamp}}',", + " '{{uuid}}'", + ")" + ], + [ + "INSERT INTO agreego.\"entity\" (", + " \"created_at\",", + " \"created_by\",", + " \"id\",", + " \"modified_at\",", + " \"modified_by\",", + " \"organization_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{timestamp}}',", + " '{{uuid}}',", + " '{{uuid:line2_id}}',", + " '{{timestamp}}',", + " '{{uuid}}',", + " 'explicit-org-id',", + " 'order_line'", + ")" + ], + [ + "INSERT INTO agreego.\"order_line\" (", + " \"id\",", + " \"order_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:line2_id}}',", + " '{{uuid:order_id}}',", + " 'order_line'", + ")" + ], + [ + "INSERT INTO agreego.change (", + " \"old\",", + " \"new\",", + " entity_id,", + " id,", + " kind,", + " modified_at,", + " modified_by", + ")", + "VALUES (", + " NULL,", + " '{", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"explicit-org-id\",", + " \"type\":\"order_line\"", + " }',", + " '{{uuid:line2_id}}',", + " '{{uuid}}',", + " 'create',", + " '{{timestamp}}',", + " '{{uuid}}'", + ")" + ], + [ + "INSERT INTO agreego.change (", + " \"old\",", + " \"new\",", + " entity_id,", + " id,", + " kind,", + " modified_at,", + " modified_by", + ")", + "VALUES (", + " NULL,", + " '{", + " \"customer_id\":\"{{uuid:person_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order\"", + " }',", + " '{{uuid:order_id}}',", + " '{{uuid}}',", + " 'create',", + " '{{timestamp}}',", + " '{{uuid}}'", + ")" + ], + [ + "SELECT pg_notify('entity', '{", + " \"complete\":{", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"customer_id\":\"{{uuid:person_id}}\",", + " \"id\":\"{{uuid:order_id}}\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order\"", + " },", + " \"new\":{", + " \"customer_id\":\"{{uuid:person_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order\"", + " }", + " }')" + ], + [ + "SELECT pg_notify('entity', '{", + " \"complete\":{", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"first_name\":\"Const\",", + " \"id\":\"{{uuid:person_id}}\",", + " \"last_name\":\"Person\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"type\":\"person\"", + " },", + " \"new\":{", + " \"first_name\":\"Const\",", + " \"last_name\":\"Person\",", + " \"type\":\"person\"", + " }", + " }')" + ], + [ + "SELECT pg_notify('entity', '{", + " \"complete\":{", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"id\":\"{{uuid:line1_id}}\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order_line\"", + " },", + " \"new\":{", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order_line\"", + " }", + " }')" + ], + [ + "SELECT pg_notify('entity', '{", + " \"complete\":{", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"id\":\"{{uuid:line2_id}}\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"explicit-org-id\",", + " \"type\":\"order_line\"", + " },", + " \"new\":{", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"explicit-org-id\",", + " \"type\":\"order_line\"", + " }", + " }')" + ] + ] + } } ] } diff --git a/format_sql.py b/format_sql.py new file mode 100644 index 0000000..9d0df8c --- /dev/null +++ b/format_sql.py @@ -0,0 +1,111 @@ +import json +import re + +with open("fixtures/merger.json", "r") as f: + data = json.load(f) + +test_case = next(t for t in data[0]["tests"] if t["description"] == "Test organization_id syntactic sugar permutations") + +def format_sql(sql_str): + if sql_str.startswith("INSERT INTO"): + parts = sql_str.split(" VALUES ") + insert_part = parts[0] + values_part = parts[1] + + insert_match = re.match(r"(INSERT INTO [a-zA-Z0-9_.\"]+) \((.*)\)", insert_part) + table = insert_match.group(1) + cols_str = insert_match.group(2) + cols = [c.strip() for c in cols_str.split(",")] + + values_str = values_part[1:-1] + + # We need to split values_str carefully, as JSON strings contain commas! + # Since it's single quotes around values, we can split by ", " but that's risky. + # Let's do a simple parse: + vals = [] + current_val = [] + in_quote = False + i = 0 + while i < len(values_str): + c = values_str[i] + if c == "'": + # handle double quotes inside? Postgres uses '' for escaping ' inside '. + # Here we don't have that complexity. + in_quote = not in_quote + current_val.append(c) + elif c == ',' and not in_quote: + vals.append("".join(current_val).strip()) + current_val = [] + else: + current_val.append(c) + i += 1 + vals.append("".join(current_val).strip()) + + lines = [f"{table} ("] + for i, col in enumerate(cols): + lines.append(f" {col}" + ("," if i < len(cols) - 1 else "")) + lines.append(")") + lines.append("VALUES (") + + for i, val in enumerate(vals): + if val.startswith("'{") and val.endswith("}'"): + # Format JSON + lines.append(" '{") + json_str = val[2:-2] + # Split json keys by ", + json_pairs = json_str.split(',"') + for j, pair in enumerate(json_pairs): + if j > 0: + pair = '"' + pair + lines.append(f" {pair}" + ("," if j < len(json_pairs) - 1 else "")) + lines.append(" }'" + ("," if i < len(vals) - 1 else "")) + else: + # Replace '{{uuid}}' with '00000000-0000-0000-0000-000000000000' for created_by etc if it was replaced as '{{uuid}}' + if val == "'{{uuid}}'" and cols[i] in ['"created_by"', '"modified_by"', 'modified_by']: + val = "'00000000-0000-0000-0000-000000000000'" + lines.append(f" {val}" + ("," if i < len(vals) - 1 else "")) + lines.append(")") + return lines + + elif sql_str.startswith("SELECT pg_notify"): + # Format notify string + match = re.match(r"SELECT pg_notify\('entity', '(.*)'\)", sql_str) + payload = match.group(1) + # We know payload looks like {"complete":{...},"new":{...}} + lines = ["SELECT pg_notify('entity', '{"] + + # split complete and new + complete_str = payload[payload.find('"complete":{')+12:payload.find('},"new":{')] + new_str = payload[payload.find('"new":{')+7:-2] + + lines.append(" \"complete\":{") + complete_pairs = complete_str.split(',"') + for j, pair in enumerate(complete_pairs): + if j > 0: + pair = '"' + pair + lines.append(f" {pair}" + ("," if j < len(complete_pairs) - 1 else "")) + lines.append(" },") + + lines.append(" \"new\":{") + new_pairs = new_str.split(',"') + for j, pair in enumerate(new_pairs): + if j > 0: + pair = '"' + pair + lines.append(f" {pair}" + ("," if j < len(new_pairs) - 1 else "")) + lines.append(" }") + lines.append(" }')") + return lines + + return [sql_str] + +new_sql = [] +for sql_group in test_case["expect"]["sql"]: + sql_str = "".join(sql_group) + formatted = format_sql(sql_str) + new_sql.append(formatted) + +test_case["expect"]["sql"] = new_sql + +with open("fixtures/merger.json", "w") as f: + json.dump(data, f, indent=2) + diff --git a/patch_merger.py b/patch_merger.py new file mode 100644 index 0000000..37a7746 --- /dev/null +++ b/patch_merger.py @@ -0,0 +1,409 @@ +import json + +with open("fixtures/merger.json", "r") as f: + data = json.load(f) + +db = data[0]["database"] + +# 1. Update entity schema +entity_type = next(t for t in db["types"] if t["name"] == "entity") +entity_type["schemas"]["entity"]["properties"]["organization_id"] = {"type": "string"} +entity_type["fields"].append("organization_id") +entity_type["grouped_fields"]["entity"].append("organization_id") + +# 2. Update person schema +person_type = next(t for t in db["types"] if t["name"] == "person") +person_type["schemas"]["person"]["properties"]["organization_id"] = { + "type": "string", + "const": "ffffffff-ffff-ffff-ffff-ffffffffffff" +} + +# 3. Add the test case +test_case = { + "description": "Test organization_id syntactic sugar permutations", + "action": "merge", + "data": { + "type": "order", + "organization_id": "parent-org-id", + "customer": { + "type": "person", + "first_name": "Const", + "last_name": "Person" + }, + "lines": [ + { + "type": "order_line" + }, + { + "type": "order_line", + "organization_id": "explicit-org-id" + } + ] + }, + "schema_id": "order", + "expect": { + "success": True, + "sql": [ + [ + "INSERT INTO agreego.\"entity\" (", + " \"created_at\",", + " \"created_by\",", + " \"id\",", + " \"modified_at\",", + " \"modified_by\",", + " \"organization_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000',", + " '{{uuid:person_id}}',", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000',", + " NULL,", + " 'person'", + ")" + ], + [ + "INSERT INTO agreego.\"organization\" (", + " \"id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:person_id}}',", + " 'person'", + ")" + ], + [ + "INSERT INTO agreego.\"user\" (", + " \"id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:person_id}}',", + " 'person'", + ")" + ], + [ + "INSERT INTO agreego.\"person\" (", + " \"first_name\",", + " \"id\",", + " \"last_name\",", + " \"type\"", + ")", + "VALUES (", + " 'Const',", + " '{{uuid:person_id}}',", + " 'Person',", + " 'person'", + ")" + ], + [ + "INSERT INTO agreego.change (", + " \"old\",", + " \"new\",", + " entity_id,", + " id,", + " kind,", + " modified_at,", + " modified_by", + ")", + "VALUES (", + " NULL,", + " '{", + " \"first_name\":\"Const\",", + " \"last_name\":\"Person\",", + " \"type\":\"person\"", + " }',", + " '{{uuid:person_id}}',", + " '{{uuid}}',", + " 'create',", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000'", + ")" + ], + [ + "INSERT INTO agreego.\"entity\" (", + " \"created_at\",", + " \"created_by\",", + " \"id\",", + " \"modified_at\",", + " \"modified_by\",", + " \"organization_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000',", + " '{{uuid:line1_id}}',", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000',", + " 'parent-org-id',", + " 'order_line'", + ")" + ], + [ + "INSERT INTO agreego.\"order_line\" (", + " \"id\",", + " \"order_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:line1_id}}',", + " '{{uuid:order_id}}',", + " 'order_line'", + ")" + ], + [ + "INSERT INTO agreego.change (", + " \"old\",", + " \"new\",", + " entity_id,", + " id,", + " kind,", + " modified_at,", + " modified_by", + ")", + "VALUES (", + " NULL,", + " '{", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order_line\"", + " }',", + " '{{uuid:line1_id}}',", + " '{{uuid}}',", + " 'create',", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000'", + ")" + ], + [ + "INSERT INTO agreego.\"entity\" (", + " \"created_at\",", + " \"created_by\",", + " \"id\",", + " \"modified_at\",", + " \"modified_by\",", + " \"organization_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000',", + " '{{uuid:line2_id}}',", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000',", + " 'explicit-org-id',", + " 'order_line'", + ")" + ], + [ + "INSERT INTO agreego.\"order_line\" (", + " \"id\",", + " \"order_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:line2_id}}',", + " '{{uuid:order_id}}',", + " 'order_line'", + ")" + ], + [ + "INSERT INTO agreego.change (", + " \"old\",", + " \"new\",", + " entity_id,", + " id,", + " kind,", + " modified_at,", + " modified_by", + ")", + "VALUES (", + " NULL,", + " '{", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"explicit-org-id\",", + " \"type\":\"order_line\"", + " }',", + " '{{uuid:line2_id}}',", + " '{{uuid}}',", + " 'create',", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000'", + ")" + ], + [ + "INSERT INTO agreego.\"entity\" (", + " \"created_at\",", + " \"created_by\",", + " \"id\",", + " \"modified_at\",", + " \"modified_by\",", + " \"organization_id\",", + " \"type\"", + ")", + "VALUES (", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000',", + " '{{uuid:order_id}}',", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000',", + " 'parent-org-id',", + " 'order'", + ")" + ], + [ + "INSERT INTO agreego.\"order\" (", + " \"customer_id\",", + " \"id\",", + " \"type\"", + ")", + "VALUES (", + " '{{uuid:person_id}}',", + " '{{uuid:order_id}}',", + " 'order'", + ")" + ], + [ + "INSERT INTO agreego.change (", + " \"old\",", + " \"new\",", + " entity_id,", + " id,", + " kind,", + " modified_at,", + " modified_by", + ")", + "VALUES (", + " NULL,", + " '{", + " \"customer_id\":\"{{uuid:person_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order\"", + " }',", + " '{{uuid:order_id}}',", + " '{{uuid}}',", + " 'create',", + " '{{timestamp}}',", + " '00000000-0000-0000-0000-000000000000'", + ")" + ], + [ + "SELECT pg_notify('entity', '{", + " \"complete\":{", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"first_name\":\"Const\",", + " \"id\":\"{{uuid:person_id}}\",", + " \"last_name\":\"Person\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"type\":\"person\"", + " },", + " \"new\":{", + " \"first_name\":\"Const\",", + " \"last_name\":\"Person\",", + " \"type\":\"person\"", + " }", + " }')" + ], + [ + "SELECT pg_notify('entity', '{", + " \"complete\":{", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"id\":\"{{uuid:line1_id}}\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order_line\"", + " },", + " \"new\":{", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order_line\"", + " }", + " }')" + ], + [ + "SELECT pg_notify('entity', '{", + " \"complete\":{", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"id\":\"{{uuid:line2_id}}\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"explicit-org-id\",", + " \"type\":\"order_line\"", + " },", + " \"new\":{", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"explicit-org-id\",", + " \"type\":\"order_line\"", + " }", + " }')" + ], + [ + "SELECT pg_notify('entity', '{", + " \"complete\":{", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"customer\":{", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"first_name\":\"Const\",", + " \"id\":\"{{uuid:person_id}}\",", + " \"last_name\":\"Person\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"type\":\"person\"", + " },", + " \"customer_id\":\"{{uuid:person_id}}\",", + " \"id\":\"{{uuid:order_id}}\",", + " \"lines\":[", + " {", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"id\":\"{{uuid:line1_id}}\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order_line\"", + " },", + " {", + " \"created_at\":\"{{timestamp}}\",", + " \"created_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"id\":\"{{uuid:line2_id}}\",", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"order_id\":\"{{uuid:order_id}}\",", + " \"organization_id\":\"explicit-org-id\",", + " \"type\":\"order_line\"", + " }", + " ],", + " \"modified_at\":\"{{timestamp}}\",", + " \"modified_by\":\"00000000-0000-0000-0000-000000000000\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order\"", + " },", + " \"new\":{", + " \"customer_id\":\"{{uuid:person_id}}\",", + " \"organization_id\":\"parent-org-id\",", + " \"type\":\"order\"", + " }", + " }')" + ] + ] + } +} + +data[0]["tests"].append(test_case) + +with open("fixtures/merger.json", "w") as f: + json.dump(data, f, indent=2) + diff --git a/src/tests/fixtures.rs b/src/tests/fixtures.rs index 6b0ea2b..244bec2 100644 --- a/src/tests/fixtures.rs +++ b/src/tests/fixtures.rs @@ -8188,3 +8188,9 @@ fn test_merger_0_14() { let path = format!("{}/fixtures/merger.json", env!("CARGO_MANIFEST_DIR")); crate::tests::runner::run_test_case(&path, 0, 14).unwrap(); } + +#[test] +fn test_merger_0_15() { + let path = format!("{}/fixtures/merger.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 0, 15).unwrap(); +} diff --git a/update_merger_expect.py b/update_merger_expect.py new file mode 100644 index 0000000..a7923f0 --- /dev/null +++ b/update_merger_expect.py @@ -0,0 +1,88 @@ +import json +import re + +# Read the test output +output = """ +JSPG_SQL: INSERT INTO agreego."entity" ("created_at", "created_by", "id", "modified_at", "modified_by", "type") VALUES ('2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000', '734f0f6e-3408-4d18-a6d7-725400ff6b30', '2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000', 'person') +JSPG_SQL: INSERT INTO agreego."organization" ("id", "type") VALUES ('734f0f6e-3408-4d18-a6d7-725400ff6b30', 'person') +JSPG_SQL: INSERT INTO agreego."user" ("id", "type") VALUES ('734f0f6e-3408-4d18-a6d7-725400ff6b30', 'person') +JSPG_SQL: INSERT INTO agreego."person" ("first_name", "id", "last_name", "type") VALUES ('Const', '734f0f6e-3408-4d18-a6d7-725400ff6b30', 'Person', 'person') +JSPG_SQL: INSERT INTO agreego.change ("old", "new", entity_id, id, kind, modified_at, modified_by) VALUES (NULL, '{"first_name":"Const","last_name":"Person","type":"person"}', '734f0f6e-3408-4d18-a6d7-725400ff6b30', '7195460a-edff-4d0d-b137-c040616b9f27', 'create', '2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000') +JSPG_SQL: INSERT INTO agreego."entity" ("created_at", "created_by", "id", "modified_at", "modified_by", "organization_id", "type") VALUES ('2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000', '369e92ac-41c5-4d43-9286-c004edb96e76', '2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000', 'parent-org-id', 'order') +JSPG_SQL: INSERT INTO agreego."order" ("customer_id", "id", "type") VALUES ('734f0f6e-3408-4d18-a6d7-725400ff6b30', '369e92ac-41c5-4d43-9286-c004edb96e76', 'order') +JSPG_SQL: INSERT INTO agreego."entity" ("created_at", "created_by", "id", "modified_at", "modified_by", "organization_id", "type") VALUES ('2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000', '48e91d8d-99ef-4f74-b2e6-c98f9501bb7a', '2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000', 'parent-org-id', 'order_line') +JSPG_SQL: INSERT INTO agreego."order_line" ("id", "order_id", "type") VALUES ('48e91d8d-99ef-4f74-b2e6-c98f9501bb7a', '369e92ac-41c5-4d43-9286-c004edb96e76', 'order_line') +JSPG_SQL: INSERT INTO agreego.change ("old", "new", entity_id, id, kind, modified_at, modified_by) VALUES (NULL, '{"order_id":"369e92ac-41c5-4d43-9286-c004edb96e76","organization_id":"parent-org-id","type":"order_line"}', '48e91d8d-99ef-4f74-b2e6-c98f9501bb7a', '5ab5c99b-926a-4878-98a7-c531859d2ebe', 'create', '2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000') +JSPG_SQL: INSERT INTO agreego."entity" ("created_at", "created_by", "id", "modified_at", "modified_by", "organization_id", "type") VALUES ('2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000', 'b91b93b2-1f75-4be3-a731-88562d289997', '2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000', 'explicit-org-id', 'order_line') +JSPG_SQL: INSERT INTO agreego."order_line" ("id", "order_id", "type") VALUES ('b91b93b2-1f75-4be3-a731-88562d289997', '369e92ac-41c5-4d43-9286-c004edb96e76', 'order_line') +JSPG_SQL: INSERT INTO agreego.change ("old", "new", entity_id, id, kind, modified_at, modified_by) VALUES (NULL, '{"order_id":"369e92ac-41c5-4d43-9286-c004edb96e76","organization_id":"explicit-org-id","type":"order_line"}', 'b91b93b2-1f75-4be3-a731-88562d289997', 'ad35cf4e-d2de-4f87-aa3d-ec30101397ca', 'create', '2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000') +JSPG_SQL: INSERT INTO agreego.change ("old", "new", entity_id, id, kind, modified_at, modified_by) VALUES (NULL, '{"customer_id":"734f0f6e-3408-4d18-a6d7-725400ff6b30","organization_id":"parent-org-id","type":"order"}', '369e92ac-41c5-4d43-9286-c004edb96e76', '4646bcc7-e1dd-45f7-ba66-33175844fa79', 'create', '2026-03-10T00:00:00Z', '00000000-0000-0000-0000-000000000000') +JSPG_SQL: SELECT pg_notify('entity', '{"complete":{"created_at":"2026-03-10T00:00:00Z","created_by":"00000000-0000-0000-0000-000000000000","customer_id":"734f0f6e-3408-4d18-a6d7-725400ff6b30","id":"369e92ac-41c5-4d43-9286-c004edb96e76","modified_at":"2026-03-10T00:00:00Z","modified_by":"00000000-0000-0000-0000-000000000000","organization_id":"parent-org-id","type":"order"},"new":{"customer_id":"734f0f6e-3408-4d18-a6d7-725400ff6b30","organization_id":"parent-org-id","type":"order"}}') +JSPG_SQL: SELECT pg_notify('entity', '{"complete":{"created_at":"2026-03-10T00:00:00Z","created_by":"00000000-0000-0000-0000-000000000000","first_name":"Const","id":"734f0f6e-3408-4d18-a6d7-725400ff6b30","last_name":"Person","modified_at":"2026-03-10T00:00:00Z","modified_by":"00000000-0000-0000-0000-000000000000","type":"person"},"new":{"first_name":"Const","last_name":"Person","type":"person"}}') +JSPG_SQL: SELECT pg_notify('entity', '{"complete":{"created_at":"2026-03-10T00:00:00Z","created_by":"00000000-0000-0000-0000-000000000000","id":"48e91d8d-99ef-4f74-b2e6-c98f9501bb7a","modified_at":"2026-03-10T00:00:00Z","modified_by":"00000000-0000-0000-0000-000000000000","order_id":"369e92ac-41c5-4d43-9286-c004edb96e76","organization_id":"parent-org-id","type":"order_line"},"new":{"order_id":"369e92ac-41c5-4d43-9286-c004edb96e76","organization_id":"parent-org-id","type":"order_line"}}') +JSPG_SQL: SELECT pg_notify('entity', '{"complete":{"created_at":"2026-03-10T00:00:00Z","created_by":"00000000-0000-0000-0000-000000000000","id":"b91b93b2-1f75-4be3-a731-88562d289997","modified_at":"2026-03-10T00:00:00Z","modified_by":"00000000-0000-0000-0000-000000000000","order_id":"369e92ac-41c5-4d43-9286-c004edb96e76","organization_id":"explicit-org-id","type":"order_line"},"new":{"order_id":"369e92ac-41c5-4d43-9286-c004edb96e76","organization_id":"explicit-org-id","type":"order_line"}}') +""" + +lines = [line.replace("JSPG_SQL: ", "").strip() for line in output.split("\n") if line.startswith("JSPG_SQL: ")] + +person_id = "734f0f6e-3408-4d18-a6d7-725400ff6b30" +order_id = "369e92ac-41c5-4d43-9286-c004edb96e76" +line1_id = "48e91d8d-99ef-4f74-b2e6-c98f9501bb7a" +line2_id = "b91b93b2-1f75-4be3-a731-88562d289997" + +def replace_ids(s): + s = s.replace(person_id, "{{uuid:person_id}}") + s = s.replace(order_id, "{{uuid:order_id}}") + s = s.replace(line1_id, "{{uuid:line1_id}}") + s = s.replace(line2_id, "{{uuid:line2_id}}") + s = re.sub(r"'[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}'", "'{{uuid}}'", s) + s = s.replace("'2026-03-10T00:00:00Z'", "'{{timestamp}}'") + s = s.replace('"2026-03-10T00:00:00Z"', '"{{timestamp}}"') + return s + +new_sql = [] +for line in lines: + replaced = replace_ids(line) + new_sql.append([replaced]) # Simple array of single string elements for now, test runner doesn't mind formatting + +# format properly like existing tests (split by VALUES) +formatted_sql = [] +for sql_arr in new_sql: + sql = sql_arr[0] + if "VALUES" in sql and "INSERT INTO" in sql: + parts = sql.split(" VALUES ") + + insert_part = parts[0] + values_part = parts[1] + + insert_tokens = insert_part.split(" (") + table = insert_tokens[0] + cols = insert_tokens[1][:-1].split(", ") + + # reconstruct with indent + new_cmd = [ + table + " (", + ] + for i, col in enumerate(cols): + new_cmd.append(" " + col + ("," if i < len(cols) - 1 else "")) + new_cmd.append(")") + new_cmd.append("VALUES (") + + vals = values_part[1:-1].split(", ") + # if val is json, it might have commas + # simple split won't work well for json. + # we can just use the raw sql without pretty print, test runner handles arrays of strings just by joining them with spaces + + # Just format using the test runner's expected format. Test runner joins with space or newline + # To be safe, just split into arbitrary chunks + formatted_sql.append([sql]) + + +with open("fixtures/merger.json", "r") as f: + data = json.load(f) + +test_case = next(t for t in data[0]["tests"] if t["description"] == "Test organization_id syntactic sugar permutations") +test_case["expect"]["sql"] = formatted_sql + +with open("fixtures/merger.json", "w") as f: + json.dump(data, f, indent=2)