-- -- This function adds a story to a container at the specified position, or moves an existing story to a new -- position. It also ensures that the story appears in only a single container, although that is a convenience -- of this function, rather than a requirement of the design. -- -- container.items is an array of container items (which might be stories, other containers, or other things) -- -- The result is similar to creating a many-many table and indexing it, but is much faster in a large, -- shared table with sparse data, because it requires much less I/O to find the list of contained items, -- since we don't need to look up an index on, or update, the many-many table, at the cost of only a little -- more complexity (ie, this function). -- -- _tid team ID -- _container container ID to add story to -- _story story ID to add -- _position position to add story (1-based) -- create or replace function backlog.container_add_story(_tid int, _container int, _story int, _position int) returns void language plpgsql as $$ declare _backlog backlog.backlog_t; _new_container backlog.container_t; _new_item backlog.container_item_t; _items backlog.container_item_t[]; _items_left backlog.container_item_t[]; _items_right backlog.container_item_t[]; begin _new_item = ('STORY', _story)::backlog.container_item_t; -- Referential integrity check select backlog into _backlog from backlog.story where tid = _tid and story = _story; if not found then raise exception 'story not found: %', _story; end if; -- -- Remove the story from any existing container(s). This is an intentional feature of this -- function, but a decision that might be revisited in the future; being able to add a story -- to multiple containers might later become a feature. -- update backlog.container set items = array_remove(items, _new_item) where tid=_tid and backlog=_backlog and _new_item = any (items); -- -- Now, add the story to the specific, identified container. The story was already removed, if it -- existed, by the previous update. -- select container, items into _new_container, _items from backlog.container where tid = _tid and container = _container; if not found then raise exception 'container not found: %', _container; end if; -- -- Compute the slice to the left and right of the position in which the story is to be -- added. (This could be done directly in the `select` statement, but it seems a bit clearer to do it -- explicity) -- _items_left = _items[:_position - 1]; _items_right = _items[_position:]; update backlog.container set items = _items_left || _new_item || _items_right where tid = _tid and backlog=_backlog and container = _container; end; $$;