Syncronization Routine
Overview
The sync_master_replica
function is a PostgreSQL user-defined function designed to synchronize records between a master dataset and its replica. The function performs three main tasks:
- Insertion: Inserts records into the replica that are present in the master but not in the replica.
- Update: Updates records in the replica that are present in both the master and replica.
- Deletion: Deletes records from the replica that are no longer present in the master.
Parameters
The function accepts five parameters:
- mastersql (text): A SQL query string that retrieves the records from the master dataset.
- replica_table_name (text): The name of the replica table where the synchronization will occur.
- insert_function_name (text): The name of the function that will handle inserting new records into the replica.
- update_function_name (text): The name of the function that will handle updating existing records in the replica.
- delete_function_name (text): The name of the function that will handle deleting records from the replica.
Return Value
The function returns a table with the following columns:
inserted_count (int)
: The number of records inserted into the replica.updated_count (int)
: The number of records updated in the replica.deleted_count (int)
: The number of records deleted from the replica.
Function Logic
-
Initialization:
- The counts for inserted, updated, and deleted records are initialized to zero.
-
Query Construction:
- A
replicasql
query is dynamically generated to select records from the replica table.
- A
-
Insert and Update Records:
- The function loops through each record returned by the
mastersql
query. - Each master record is converted to a JSONB object (
values_json
). - The function checks if a corresponding record exists in the replica using the
koksmat_masterdata_id
. - If a matching record exists, the
update_function_name
is called to update the record. - If no matching record is found, the
insert_function_name
is called to insert a new record.
- The function loops through each record returned by the
-
Delete Records:
- The function loops through each record in the replica table.
- It checks if the corresponding record exists in the master table.
- If the record does not exist in the master, the
delete_function_name
is called to delete the record from the replica.
-
Return the Results:
- The function returns the counts of inserted, updated, and deleted records.
Example Usage
SELECT * FROM sync_master_replica(
'SELECT id, field1, field2 FROM master_table',
'replica_table',
'insert_replica_record',
'update_replica_record',
'delete_replica_record'
);
Notes
- The function relies on dynamic SQL execution (
EXECUTE
) to handle varying table and function names. - The
koksmat_sync
JSONB object is constructed to track synchronization metadata, such as themaster_id
. - The function assumes that both the master and replica tables share a common identifier (
id
) and that the replica has a field namedkoksmat_masterdata_id
which links to the master record.
This function is particularly useful in scenarios where data from a source system (master) needs to be synchronized with a replica system, ensuring that both datasets remain consistent.
CREATE OR REPLACE FUNCTION sync_master_replica(
mastersql text,
replica_table_name text,
insert_function_name text,
update_function_name text,
delete_function_name text
)
RETURNS TABLE(inserted_count int, updated_count int, deleted_count int) AS $$
DECLARE
master_record record;
replica_record record;
values_json jsonb;
koksmat_sync jsonb;
replicasql text;
BEGIN
-- Initialize the counts
inserted_count := 0;
updated_count := 0;
deleted_count := 0;
-- Generate the replicasql query dynamically
replicasql := format('SELECT id,koksmat_masterdata_id FROM %I', replica_table_name);
-- Step 1: Handle updates and inserts
FOR master_record IN EXECUTE mastersql LOOP
-- Convert the entire master_record into a JSONB object
values_json := to_jsonb(master_record);
-- Create the koksmat_sync JSONB object with the master id
koksmat_sync := jsonb_build_object('master_id', master_record.id);
RAISE NOTICE 'Calling match: % WHERE koksmat_masterdata_id = ''%''', replicasql, master_record.id;
-- Find the corresponding replica record
EXECUTE format('%s WHERE koksmat_masterdata_id = ''%s''', replicasql, master_record.id) INTO replica_record;
RAISE NOTICE 'Found %', to_jsonb(replica_record);
IF replica_record is not null THEN
values_json := values_json || jsonb_build_object('id', replica_record.id);
-- If the replica record exists, call the update function
RAISE NOTICE 'Calling update function: % with id: %, actor: %, values: %, koksmat_sync: %',
update_function_name, replica_record.id, 'koksmat-sync', values_json, koksmat_sync;
EXECUTE format('SELECT %I($1::text, $2::jsonb, $3::jsonb)',
update_function_name)
USING 'koksmat-sync'::text, values_json::jsonb, koksmat_sync::jsonb;
updated_count := updated_count + 1;
ELSE
-- If the replica record does not exist, call the insert function
RAISE NOTICE 'Calling insert function: % with actor: %, values: %, koksmat_sync: %',
insert_function_name, 'koksmat-sync', values_json, koksmat_sync;
EXECUTE format('SELECT %I($1::text, $2::jsonb, $3::jsonb)',
insert_function_name)
USING 'koksmat-sync'::text, values_json::jsonb, koksmat_sync::jsonb;
inserted_count := inserted_count + 1;
END IF;
END LOOP;
-- Step 2: Handle deletions
FOR replica_record IN EXECUTE replicasql LOOP
-- Check if the corresponding master record exists
EXECUTE format('select id from (%s) as s WHERE id = ''%s''', mastersql, replica_record.koksmat_masterdata_id) INTO master_record;
-- If the master record does not exist, call the delete function
IF NOT FOUND THEN
values_json :=jsonb_build_object('id', replica_record.id,'hard',false);
RAISE NOTICE 'Calling delete function: % with id: %, actor: %, koksmat_sync: %',
delete_function_name, replica_record.koksmat_masterdata_id, 'koksmat-sync', koksmat_sync;
EXECUTE format('SELECT %I($1::text, $2::jsonb, $3::jsonb)',
delete_function_name)
USING 'koksmat-sync'::text, values_json::jsonb, koksmat_sync::jsonb;
deleted_count := deleted_count + 1;
END IF;
END LOOP;
-- Return the counts of inserted, updated, and deleted records
RETURN QUERY SELECT inserted_count, updated_count, deleted_count;
END $$ LANGUAGE plpgsql;