mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 05:21:57 +00:00
127 lines
4.4 KiB
PL/PgSQL
127 lines
4.4 KiB
PL/PgSQL
CREATE OR REPLACE FUNCTION soft_delete_handle_fk() RETURNS TRIGGER AS $$
|
|
DECLARE
|
|
fk record;
|
|
child_column text;
|
|
parent_column text;
|
|
parent_value text;
|
|
child_has_deleted_at boolean;
|
|
ref_exists boolean;
|
|
sql text;
|
|
BEGIN
|
|
IF OLD.deleted_at IS NULL AND NEW.deleted_at IS NOT NULL THEN
|
|
FOR fk IN
|
|
SELECT conrelid::regclass AS child_table,
|
|
conkey AS child_cols,
|
|
confkey AS parent_cols,
|
|
confdeltype
|
|
FROM pg_constraint
|
|
WHERE contype = 'f'
|
|
AND confrelid = TG_RELID
|
|
LOOP
|
|
IF array_length(fk.child_cols, 1) IS DISTINCT FROM 1
|
|
OR array_length(fk.parent_cols, 1) IS DISTINCT FROM 1 THEN
|
|
RAISE NOTICE 'soft_delete_handle_fk skipped composite fk on %', fk.child_table;
|
|
CONTINUE;
|
|
END IF;
|
|
|
|
SELECT attname INTO child_column
|
|
FROM pg_attribute
|
|
WHERE attrelid = fk.child_table
|
|
AND attnum = fk.child_cols[1]
|
|
AND NOT attisdropped;
|
|
|
|
SELECT attname INTO parent_column
|
|
FROM pg_attribute
|
|
WHERE attrelid = TG_RELID
|
|
AND attnum = fk.parent_cols[1]
|
|
AND NOT attisdropped;
|
|
|
|
EXECUTE format('SELECT ($1).%I', parent_column)
|
|
INTO parent_value
|
|
USING OLD;
|
|
|
|
SELECT EXISTS (
|
|
SELECT 1
|
|
FROM pg_attribute
|
|
WHERE attrelid = fk.child_table
|
|
AND attname = 'deleted_at'
|
|
AND NOT attisdropped
|
|
) INTO child_has_deleted_at;
|
|
|
|
IF fk.confdeltype IN ('r', 'a') THEN
|
|
sql := format(
|
|
'SELECT EXISTS (SELECT 1 FROM %s WHERE %I = $1 %s)',
|
|
fk.child_table,
|
|
child_column,
|
|
CASE WHEN child_has_deleted_at THEN 'AND deleted_at IS NULL' ELSE '' END
|
|
);
|
|
EXECUTE sql INTO ref_exists USING parent_value;
|
|
IF ref_exists THEN
|
|
RAISE EXCEPTION 'Cannot soft delete %, still referenced by %',
|
|
TG_TABLE_NAME, fk.child_table;
|
|
END IF;
|
|
ELSIF fk.confdeltype = 'n' THEN
|
|
sql := format(
|
|
'UPDATE %s SET %I = NULL WHERE %I = $1 %s',
|
|
fk.child_table,
|
|
child_column,
|
|
child_column,
|
|
CASE WHEN child_has_deleted_at THEN 'AND deleted_at IS NULL' ELSE '' END
|
|
);
|
|
EXECUTE sql USING parent_value;
|
|
ELSIF fk.confdeltype = 'c' THEN
|
|
IF child_has_deleted_at THEN
|
|
sql := format(
|
|
'UPDATE %s SET deleted_at = NOW() WHERE %I = $1 AND deleted_at IS NULL',
|
|
fk.child_table,
|
|
child_column
|
|
);
|
|
EXECUTE sql USING parent_value;
|
|
ELSE
|
|
sql := format(
|
|
'DELETE FROM %s WHERE %I = $1',
|
|
fk.child_table,
|
|
child_column
|
|
);
|
|
EXECUTE sql USING parent_value;
|
|
END IF;
|
|
ELSIF fk.confdeltype = 'd' THEN
|
|
sql := format(
|
|
'UPDATE %s SET %I = DEFAULT WHERE %I = $1 %s',
|
|
fk.child_table,
|
|
child_column,
|
|
child_column,
|
|
CASE WHEN child_has_deleted_at THEN 'AND deleted_at IS NULL' ELSE '' END
|
|
);
|
|
EXECUTE sql USING parent_value;
|
|
END IF;
|
|
END LOOP;
|
|
END IF;
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DO $$
|
|
DECLARE
|
|
r record;
|
|
trigger_name text;
|
|
BEGIN
|
|
FOR r IN
|
|
SELECT table_schema, table_name
|
|
FROM information_schema.columns
|
|
WHERE column_name = 'deleted_at'
|
|
AND table_schema = 'public'
|
|
GROUP BY table_schema, table_name
|
|
LOOP
|
|
trigger_name := format('trg_soft_delete_fk_%s', r.table_name);
|
|
EXECUTE format('DROP TRIGGER IF EXISTS %I ON %I.%I', trigger_name, r.table_schema, r.table_name);
|
|
EXECUTE format(
|
|
'CREATE TRIGGER %I BEFORE UPDATE OF deleted_at ON %I.%I FOR EACH ROW EXECUTE FUNCTION soft_delete_handle_fk()',
|
|
trigger_name,
|
|
r.table_schema,
|
|
r.table_name
|
|
);
|
|
END LOOP;
|
|
END $$;
|