-- Some cleanup of old columns not used anymore. DROP INDEX public.node_history_client_idx; ALTER TABLE public.node_history DROP COLUMN client_sequence; ALTER TABLE public.node DROP COLUMN markdown; DROP INDEX public.node_history_idx; ALTER TABLE public.node DROP COLUMN history; ALTER TABLE public.node DROP COLUMN client_sequence; CREATE OR REPLACE PROCEDURE public.add_nodes(IN p_user_id integer, IN p_client_uuid uuid, IN p_nodes jsonb) LANGUAGE plpgsql AS $procedure$ DECLARE node_data jsonb; node_updated timestamptz; db_updated timestamptz; db_uuid uuid; db_client uuid; db_history_uuid uuid; node_uuid uuid; node_parent_uuid uuid; node_history_uuid uuid; BEGIN FOR node_data IN SELECT * FROM jsonb_array_elements(p_nodes) LOOP node_uuid = (node_data->>'UUID')::uuid; node_history_uuid = (node_data->>'HistoryUUID')::uuid; node_updated = (node_data->>'Updated')::timestamptz; -- Frontend is using an all-zero UUID to define the root node. -- Database is using NULL. IF node_data->>'ParentUUID' = '00000000-0000-0000-0000-000000000000' OR node_data->>'ParentUUID' = '' THEN node_parent_uuid = NULL; ELSE node_parent_uuid = (node_data->>'ParentUUID')::uuid; END IF; -- Every jode has a new history UUID to keep the history entry uniquely identifiable -- across clients. A history entry could potentially be sent again, but should be -- safe to ignore as every change to a node should have a new history UUID. -- -- The current node is also stored as history. INSERT INTO node_history( user_id, "uuid", "history_uuid", parents, created, updated, "name", "content", "content_encrypted", client ) VALUES( p_user_id, -- combined key node_uuid, -- combined key node_history_uuid, -- combined key (jsonb_populate_record(null::json_ancestor_array, node_data))."Ancestors", COALESCE((node_data->>'Created')::timestamptz, NOW()), COALESCE((node_data->>'Updated')::timestamptz, NOW()), (node_data->>'Name')::varchar, (node_data->>'Content')::text, '', /* content_encrypted */ p_client_uuid ) ON CONFLICT ("user_id", "uuid", "history_uuid") DO NOTHING; -- Retrieve the current modified timestamp for this node from the database. SELECT uuid, updated, client INTO db_uuid, db_updated, db_client FROM public."node" WHERE user_id = p_user_id AND uuid::uuid = node_uuid::uuid; -- Is the node not in database? It needs to be created. IF db_uuid IS NULL THEN RAISE NOTICE '01 New node %', node_uuid; INSERT INTO public."node" ( user_id, "uuid", parent_uuid, created, updated, "name", "content", "content_encrypted", client ) VALUES( p_user_id, node_uuid, node_parent_uuid, COALESCE((node_data->>'Created')::timestamptz, NOW()), COALESCE((node_data->>'Updated')::timestamptz, NOW()), (node_data->>'Name')::varchar, (node_data->>'Content')::text, '', /* content_encrypted */ p_client_uuid ); CONTINUE; END IF; -- Update the public node as well if it was older than incoming node. IF node_updated > db_updated THEN UPDATE public."node" SET updated = (node_data->>'Updated')::timestamptz, updated_seq = nextval('node_updates'), name = (node_data->>'Name')::varchar, content = (node_data->>'Content')::text, client = p_client_uuid WHERE user_id = p_user_id AND uuid::uuid = node_uuid::uuid; END IF; END LOOP; END $procedure$ ;