Skip to content

Commit

Permalink
Add line breaks to the generated SQL
Browse files Browse the repository at this point in the history
It's more readable this way.
  • Loading branch information
mwiencek committed Mar 30, 2024
1 parent 1aca05a commit acfd822
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 80 deletions.
121 changes: 67 additions & 54 deletions generate_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
'del': 'DELETE',
}

indent_level = 1
def indent():
global indent_level
return ' ' * 4 * indent_level

handlers_source = dedent('''\
# Automatically generated, do not edit.
Expand Down Expand Up @@ -59,6 +64,7 @@

extra_functions_source = ''
extra_triggers_source = ''
indent_level = 1

for im in project['indexed_metadata']:
im_schema = im['schema']
Expand All @@ -70,7 +76,6 @@
extra_functions_source += 'BEGIN\n'

tg_rowvar = 'OLD' if tg_op == 'del' else 'NEW'
indent = ' '

col_comparisons = []
if tg_op == 'upd':
Expand All @@ -83,15 +88,15 @@

if col_comparisons:
col_comparisons_source = ' OR '.join(col_comparisons)
extra_functions_source += f'{indent}IF ({col_comparisons_source}) THEN\n'
indent += ' '
extra_functions_source += f'{indent()}IF ({col_comparisons_source}) THEN\n'
indent_level += 1

extra_functions_source += f'{indent}INSERT INTO artwork_indexer.event_queue (entity_type, action, message)'
extra_functions_source += f'{indent()}INSERT INTO artwork_indexer.event_queue (entity_type, action, message)'

indent += ' '
indent_level += 1
extra_functions_source += ' (\n'
extra_functions_source += f"{indent}SELECT '{entity_type}', 'index', jsonb_build_object('gid', {q_entity_table}.gid)\n"
extra_functions_source += f'{indent}FROM {q_entity_table}\n'
extra_functions_source += f"{indent()}SELECT '{entity_type}', 'index', jsonb_build_object('gid', {q_entity_table}.gid)\n"
extra_functions_source += f'{indent()}FROM {q_entity_table}\n'

for join in im.get('joins', ()):
(lhs_schema, lhs_table, lhs_col) = join['lhs']
Expand All @@ -100,31 +105,31 @@
q_lhs_table = f'{lhs_schema}.{lhs_table}'
q_rhs_table = f'{rhs_schema}.{rhs_table}'

extra_functions_source += f'{indent}JOIN {q_lhs_table} ON {q_lhs_table}.{lhs_col} = {q_rhs_table}.{rhs_col}\n'
extra_functions_source += f'{indent()}JOIN {q_lhs_table} ON {q_lhs_table}.{lhs_col} = {q_rhs_table}.{rhs_col}\n'

extra_functions_source += f'{indent}WHERE EXISTS (\n'
indent += ' '
extra_functions_source += f'{indent}SELECT 1 FROM {q_art_table}\n'
extra_functions_source += f'{indent}WHERE {q_art_table}.{entity_type} = {q_entity_table}.id\n'
indent = indent[:-4]
extra_functions_source += f'{indent})\n'
extra_functions_source += f'{indent()}WHERE EXISTS (\n'
indent_level += 1
extra_functions_source += f'{indent()}SELECT 1 FROM {q_art_table}\n'
extra_functions_source += f'{indent()}WHERE {q_art_table}.{entity_type} = {q_entity_table}.id\n'
indent_level -= 1
extra_functions_source += f'{indent()})\n'

if q_im_table == q_entity_table:
extra_functions_source += f"{indent}AND {q_entity_table}.gid = {tg_rowvar}.gid\n"
extra_functions_source += f"{indent()}AND {q_entity_table}.gid = {tg_rowvar}.gid\n"

im_condition = im.get('condition')
if im_condition:
extra_functions_source += f'{indent}AND {im_condition.format(tg_rowvar=tg_rowvar)}\n'
extra_functions_source += f'{indent()}AND {im_condition.format(tg_rowvar=tg_rowvar)}\n'

indent = indent[:-4]
extra_functions_source += f'{indent})\n'
indent_level -= 1
extra_functions_source += f'{indent()})\n'

extra_functions_source += f'{indent}ON CONFLICT DO NOTHING;\n'
extra_functions_source += f'{indent()}ON CONFLICT DO NOTHING;\n'
if col_comparisons:
indent = indent[:-4]
extra_functions_source += f'{indent}END IF;\n'
indent_level -= 1
extra_functions_source += f'{indent()}END IF;\n'

extra_functions_source += f'\n{indent}RETURN {tg_rowvar};\n'
extra_functions_source += f'\n{indent()}RETURN {tg_rowvar};\n'
extra_functions_source += 'END;\n'
extra_functions_source += '$$ LANGUAGE plpgsql;\n'

Expand All @@ -139,54 +144,59 @@
EXECUTE PROCEDURE artwork_indexer.{tg_fn_name}();
''')

def index_artwork_stmt(gids, parent):
def index_artwork_stmt(gids, parent, starting_indent_level):
global indent_level
indent_level = starting_indent_level
stmt = 'INSERT INTO artwork_indexer.event_queue ('
stmt += 'entity_type, action, message'
if parent:
stmt += ', depends_on'
stmt += ') VALUES '
stmt += ')\n'
stmt += f'{indent()}VALUES '
stmt += ', '.join([
(
f"('{entity_type}', 'index', jsonb_build_object('gid', {gid})" +
(f", array[{parent}])" if parent else ')')
) for gid in gids
])
stmt += ' ON CONFLICT ';
stmt += '\n'
stmt += f'{indent()}ON CONFLICT ';
if parent:
stmt += "(entity_type, action, message) WHERE state = 'queued' "
stmt += f"DO UPDATE SET depends_on = (coalesce(artwork_indexer.event_queue.depends_on, '{{}}') || {parent});"
stmt += "(entity_type, action, message) WHERE state = 'queued'\n"
stmt += f"{indent()}DO UPDATE SET depends_on = (coalesce(artwork_indexer.event_queue.depends_on, '{{}}') || {parent});"
else:
stmt += 'DO NOTHING;'
return stmt

def delete_artwork_stmt(artwork_id, gid, suffix, parent, return_var):
def delete_artwork_stmt(artwork_id, gid, suffix, parent, return_var, starting_indent_level):
global indent_level
indent_level = starting_indent_level
stmt = 'INSERT INTO artwork_indexer.event_queue ('
stmt += 'entity_type, action, message'
if parent:
stmt += ', depends_on'
stmt += ') VALUES ('
stmt += f"'{entity_type}', 'delete_image', "
stmt += 'jsonb_build_object('
stmt += f"'artwork_id', {artwork_id}, "
stmt += f"'gid', {gid}, "
stmt += f"'suffix', {suffix}"
stmt += ')'
stmt += ')\n'
stmt += f"{indent()}VALUES ('{entity_type}', 'delete_image', "
stmt += f"jsonb_build_object('artwork_id', {artwork_id}, 'gid', {gid}, 'suffix', {suffix})"
if parent:
stmt += f", array[{parent}]"
stmt += f') RETURNING id INTO STRICT {return_var};'
stmt += ')\n'
stmt += f'{indent()}RETURNING id INTO STRICT {return_var};'
return stmt

def deindex_artwork_stmt(gid, parent, indent):
stmt = 'INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on) '
stmt += f"VALUES ('{entity_type}', 'deindex', jsonb_build_object('gid', {gid}), {parent}) "
stmt += 'ON CONFLICT DO NOTHING;\n'
def deindex_artwork_stmt(gid, parent, starting_indent_level):
global indent_level
indent_level = starting_indent_level
stmt = 'INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on)\n'
stmt += f"{indent()}VALUES ('{entity_type}', 'deindex', jsonb_build_object('gid', {gid}), {parent})\n"
stmt += f'{indent()}ON CONFLICT DO NOTHING;\n\n'
# Delete any previous 'index' events that were queued; it's unlikely
# these exist, but if they do we can avoid having them run and fail.
stmt += f'{" " * 4 * indent}DELETE FROM artwork_indexer.event_queue '
stmt += "WHERE state = 'queued' "
stmt += f"AND entity_type = '{entity_type}' "
stmt += "AND action = 'index' "
stmt += f"AND message = jsonb_build_object('gid', {gid});"
stmt += f'{indent()}DELETE FROM artwork_indexer.event_queue\n'
stmt += f"{indent()}WHERE state = 'queued'\n"
stmt += f"{indent()}AND entity_type = '{entity_type}'\n"
stmt += f"{indent()}AND action = 'index'\n"
stmt += f"{indent()}AND message = jsonb_build_object('gid', {gid});"
return stmt

functions_source = dedent(f'''\
Expand All @@ -201,7 +211,7 @@ def deindex_artwork_stmt(gid, parent, indent):
FROM {q_entity_table}
WHERE {q_entity_table}.id = NEW.{entity_type};
{index_artwork_stmt((f'{entity_type}_gid',), None)}
{index_artwork_stmt((f'{entity_type}_gid',), None, 3)}
RETURN NEW;
END;
Expand Down Expand Up @@ -241,7 +251,7 @@ def deindex_artwork_stmt(gid, parent, indent):
))
RETURNING id INTO STRICT copy_event_id;
{delete_artwork_stmt('OLD.id', f'old_{entity_type}_gid', 'suffix', 'copy_event_id', 'delete_event_id')}
{delete_artwork_stmt('OLD.id', f'old_{entity_type}_gid', 'suffix', 'copy_event_id', 'delete_event_id', 4)}
-- Check if any images remain for the old {entity_type}. If not, deindex it.
PERFORM 1 FROM {q_art_table}
Expand All @@ -252,13 +262,14 @@ def deindex_artwork_stmt(gid, parent, indent):
IF FOUND THEN
-- If there's an existing, queued index event, reset its parent to our
-- deletion event (i.e. delay it until after the deletion executes).
{index_artwork_stmt((f'old_{entity_type}_gid', f'new_{entity_type}_gid'), 'delete_event_id')}
{index_artwork_stmt((f'old_{entity_type}_gid', f'new_{entity_type}_gid'), 'delete_event_id', 5)}
ELSE
{index_artwork_stmt((f'new_{entity_type}_gid',), 'delete_event_id')}
{index_artwork_stmt((f'new_{entity_type}_gid',), 'delete_event_id', 5)}
{deindex_artwork_stmt(f'old_{entity_type}_gid', 'array[delete_event_id]', 5)}
END IF;
ELSE
{index_artwork_stmt((f'old_{entity_type}_gid', f'new_{entity_type}_gid'), None)}
{index_artwork_stmt((f'old_{entity_type}_gid', f'new_{entity_type}_gid'), None, 4)}
END IF;
RETURN NEW;
Expand All @@ -281,8 +292,9 @@ def deindex_artwork_stmt(gid, parent, indent):
-- If no row is found, it's likely because the entity itself has been
-- deleted, which cascades to this table.
IF FOUND THEN
{delete_artwork_stmt('OLD.id', f'{entity_type}_gid', 'suffix', None, 'delete_event_id')}
{index_artwork_stmt((f'{entity_type}_gid',), 'delete_event_id')}
{delete_artwork_stmt('OLD.id', f'{entity_type}_gid', 'suffix', None, 'delete_event_id', 4)}
{index_artwork_stmt((f'{entity_type}_gid',), 'delete_event_id', 4)}
END IF;
RETURN OLD;
Expand All @@ -299,7 +311,7 @@ def deindex_artwork_stmt(gid, parent, indent):
JOIN {q_art_table} ON {q_entity_table}.id = {q_art_table}.{entity_type}
WHERE {q_art_table}.id = NEW.id;
{index_artwork_stmt((f'{entity_type}_gid',), None)}
{index_artwork_stmt((f'{entity_type}_gid',), None, 3)}
RETURN NEW;
END;
Expand All @@ -318,7 +330,7 @@ def deindex_artwork_stmt(gid, parent, indent):
-- If no row is found, it's likely because the artwork itself has been
-- deleted, which cascades to this table.
IF FOUND THEN
{index_artwork_stmt((f'{entity_type}_gid',), None)}
{index_artwork_stmt((f'{entity_type}_gid',), None, 4)}
END IF;
RETURN OLD;
Expand All @@ -344,6 +356,7 @@ def deindex_artwork_stmt(gid, parent, indent):
WHERE {q_art_table}.{entity_type} = OLD.id
)
ON CONFLICT DO NOTHING;
{deindex_artwork_stmt('OLD.gid', 'NULL', 4)}
END IF;
Expand Down
64 changes: 51 additions & 13 deletions sql/caa_functions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ BEGIN
FROM musicbrainz.release
WHERE musicbrainz.release.id = NEW.release;

INSERT INTO artwork_indexer.event_queue (entity_type, action, message) VALUES ('release', 'index', jsonb_build_object('gid', release_gid)) ON CONFLICT DO NOTHING;
INSERT INTO artwork_indexer.event_queue (entity_type, action, message)
VALUES ('release', 'index', jsonb_build_object('gid', release_gid))
ON CONFLICT DO NOTHING;

RETURN NEW;
END;
Expand Down Expand Up @@ -49,7 +51,9 @@ BEGIN
))
RETURNING id INTO STRICT copy_event_id;

INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on) VALUES ('release', 'delete_image', jsonb_build_object('artwork_id', OLD.id, 'gid', old_release_gid, 'suffix', suffix), array[copy_event_id]) RETURNING id INTO STRICT delete_event_id;
INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on)
VALUES ('release', 'delete_image', jsonb_build_object('artwork_id', OLD.id, 'gid', old_release_gid, 'suffix', suffix), array[copy_event_id])
RETURNING id INTO STRICT delete_event_id;

-- Check if any images remain for the old release. If not, deindex it.
PERFORM 1 FROM cover_art_archive.cover_art
Expand All @@ -60,14 +64,30 @@ BEGIN
IF FOUND THEN
-- If there's an existing, queued index event, reset its parent to our
-- deletion event (i.e. delay it until after the deletion executes).
INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on) VALUES ('release', 'index', jsonb_build_object('gid', old_release_gid), array[delete_event_id]), ('release', 'index', jsonb_build_object('gid', new_release_gid), array[delete_event_id]) ON CONFLICT (entity_type, action, message) WHERE state = 'queued' DO UPDATE SET depends_on = (coalesce(artwork_indexer.event_queue.depends_on, '{}') || delete_event_id);
INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on)
VALUES ('release', 'index', jsonb_build_object('gid', old_release_gid), array[delete_event_id]), ('release', 'index', jsonb_build_object('gid', new_release_gid), array[delete_event_id])
ON CONFLICT (entity_type, action, message) WHERE state = 'queued'
DO UPDATE SET depends_on = (coalesce(artwork_indexer.event_queue.depends_on, '{}') || delete_event_id);
ELSE
INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on) VALUES ('release', 'index', jsonb_build_object('gid', new_release_gid), array[delete_event_id]) ON CONFLICT (entity_type, action, message) WHERE state = 'queued' DO UPDATE SET depends_on = (coalesce(artwork_indexer.event_queue.depends_on, '{}') || delete_event_id);
INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on) VALUES ('release', 'deindex', jsonb_build_object('gid', old_release_gid), array[delete_event_id]) ON CONFLICT DO NOTHING;
DELETE FROM artwork_indexer.event_queue WHERE state = 'queued' AND entity_type = 'release' AND action = 'index' AND message = jsonb_build_object('gid', old_release_gid);
INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on)
VALUES ('release', 'index', jsonb_build_object('gid', new_release_gid), array[delete_event_id])
ON CONFLICT (entity_type, action, message) WHERE state = 'queued'
DO UPDATE SET depends_on = (coalesce(artwork_indexer.event_queue.depends_on, '{}') || delete_event_id);

INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on)
VALUES ('release', 'deindex', jsonb_build_object('gid', old_release_gid), array[delete_event_id])
ON CONFLICT DO NOTHING;

DELETE FROM artwork_indexer.event_queue
WHERE state = 'queued'
AND entity_type = 'release'
AND action = 'index'
AND message = jsonb_build_object('gid', old_release_gid);
END IF;
ELSE
INSERT INTO artwork_indexer.event_queue (entity_type, action, message) VALUES ('release', 'index', jsonb_build_object('gid', old_release_gid)), ('release', 'index', jsonb_build_object('gid', new_release_gid)) ON CONFLICT DO NOTHING;
INSERT INTO artwork_indexer.event_queue (entity_type, action, message)
VALUES ('release', 'index', jsonb_build_object('gid', old_release_gid)), ('release', 'index', jsonb_build_object('gid', new_release_gid))
ON CONFLICT DO NOTHING;
END IF;

RETURN NEW;
Expand All @@ -90,8 +110,14 @@ BEGIN
-- If no row is found, it's likely because the entity itself has been
-- deleted, which cascades to this table.
IF FOUND THEN
INSERT INTO artwork_indexer.event_queue (entity_type, action, message) VALUES ('release', 'delete_image', jsonb_build_object('artwork_id', OLD.id, 'gid', release_gid, 'suffix', suffix)) RETURNING id INTO STRICT delete_event_id;
INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on) VALUES ('release', 'index', jsonb_build_object('gid', release_gid), array[delete_event_id]) ON CONFLICT (entity_type, action, message) WHERE state = 'queued' DO UPDATE SET depends_on = (coalesce(artwork_indexer.event_queue.depends_on, '{}') || delete_event_id);
INSERT INTO artwork_indexer.event_queue (entity_type, action, message)
VALUES ('release', 'delete_image', jsonb_build_object('artwork_id', OLD.id, 'gid', release_gid, 'suffix', suffix))
RETURNING id INTO STRICT delete_event_id;

INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on)
VALUES ('release', 'index', jsonb_build_object('gid', release_gid), array[delete_event_id])
ON CONFLICT (entity_type, action, message) WHERE state = 'queued'
DO UPDATE SET depends_on = (coalesce(artwork_indexer.event_queue.depends_on, '{}') || delete_event_id);
END IF;

RETURN OLD;
Expand All @@ -108,7 +134,9 @@ BEGIN
JOIN cover_art_archive.cover_art ON musicbrainz.release.id = cover_art_archive.cover_art.release
WHERE cover_art_archive.cover_art.id = NEW.id;

INSERT INTO artwork_indexer.event_queue (entity_type, action, message) VALUES ('release', 'index', jsonb_build_object('gid', release_gid)) ON CONFLICT DO NOTHING;
INSERT INTO artwork_indexer.event_queue (entity_type, action, message)
VALUES ('release', 'index', jsonb_build_object('gid', release_gid))
ON CONFLICT DO NOTHING;

RETURN NEW;
END;
Expand All @@ -127,7 +155,9 @@ BEGIN
-- If no row is found, it's likely because the artwork itself has been
-- deleted, which cascades to this table.
IF FOUND THEN
INSERT INTO artwork_indexer.event_queue (entity_type, action, message) VALUES ('release', 'index', jsonb_build_object('gid', release_gid)) ON CONFLICT DO NOTHING;
INSERT INTO artwork_indexer.event_queue (entity_type, action, message)
VALUES ('release', 'index', jsonb_build_object('gid', release_gid))
ON CONFLICT DO NOTHING;
END IF;

RETURN OLD;
Expand All @@ -153,8 +183,16 @@ BEGIN
WHERE cover_art_archive.cover_art.release = OLD.id
)
ON CONFLICT DO NOTHING;
INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on) VALUES ('release', 'deindex', jsonb_build_object('gid', OLD.gid), NULL) ON CONFLICT DO NOTHING;
DELETE FROM artwork_indexer.event_queue WHERE state = 'queued' AND entity_type = 'release' AND action = 'index' AND message = jsonb_build_object('gid', OLD.gid);

INSERT INTO artwork_indexer.event_queue (entity_type, action, message, depends_on)
VALUES ('release', 'deindex', jsonb_build_object('gid', OLD.gid), NULL)
ON CONFLICT DO NOTHING;

DELETE FROM artwork_indexer.event_queue
WHERE state = 'queued'
AND entity_type = 'release'
AND action = 'index'
AND message = jsonb_build_object('gid', OLD.gid);
END IF;

RETURN OLD;
Expand Down
Loading

0 comments on commit acfd822

Please sign in to comment.