Files
narl-workspace/migrations/0027_card_links.sql
T
nvrl b8b3641e6e cards: a document and its cards, seen from both ends
A document now lists the cards about it: the ones whose notes it is and
the ones whose description links to it. GET /nodes/{id}/cards answers
that, and the node itself carries it as `cards`. A line under the
document's meta line says what is still open and when it is first due;
it and `gc` open a new cards part of the info sheet, where j/k picks a
card, Space, H/L, D, a and `:` act on it, and Enter turns it over on its
board. `c` while reading a document makes a card about it.

Card verbs act on the card in focus wherever it is looked at: the
board's cursor, the card turned over, the agenda's highlight, the card
picked in the info sheet, or a document's only open card. patchCard,
sendCard and toggleDone take that card, so patchAgendaCard,
sendAgendaCard and finishCard are gone, and :due, :repeat, :label and
:done no longer refuse to run away from the board.

Migration 0027 adds card_links, links for a card's description: indexed
on every write, backfilled on start, followed and rewritten on a rename
or move like a document's, and claimed when a title they named appears.
It also adds cards_fts over title, description and checklist steps;
GET /cards?q= searches it, and / lists the cards found after the nodes,
Enter turning one over on its board.
2026-10-22 10:45:20 +02:00

50 lines
2.3 KiB
SQL

-- A document and its cards, seen from both ends. A card has always pointed at
-- one document, its notes, and the document could not see it back; a card's
-- summary could link to documents, and nothing kept those links.
--
-- `card_links` is `links` for a card's summary: what its `/n/` paths and
-- `[[title]]`s lead to, rebuilt whenever the summary is written. Read the
-- other way round, it is the cards that mention a document, and the summaries
-- a rename or a move rewrites along with the documents.
--
-- Nothing fills it for the cards already written; the server indexes them when
-- it starts and finds it empty (see `links::backfill`).
CREATE TABLE card_links (
card_id INTEGER NOT NULL REFERENCES cards (id) ON DELETE CASCADE,
kind TEXT NOT NULL CHECK (kind IN ('path', 'wiki')),
target TEXT NOT NULL,
to_id INTEGER NOT NULL REFERENCES nodes (id) ON DELETE CASCADE,
PRIMARY KEY (card_id, kind, target)
) WITHOUT ROWID;
CREATE INDEX idx_card_links_to ON card_links (to_id);
-- Search finds a card the way it finds a document: by its title, its summary,
-- or a step on its checklist. The steps are JSON on the card, so the index
-- keeps its own copy of their text rather than reading the card's columns.
CREATE VIRTUAL TABLE cards_fts USING fts5 (title, body, steps, tokenize = 'unicode61');
CREATE TRIGGER cards_ai AFTER INSERT ON cards BEGIN
INSERT INTO cards_fts (rowid, title, body, steps)
VALUES (new.id, new.title, new.body,
(SELECT COALESCE(group_concat(json_extract(value, '$.text'), ' '), '')
FROM json_each(new.checklist)));
END;
CREATE TRIGGER cards_ad AFTER DELETE ON cards BEGIN
DELETE FROM cards_fts WHERE rowid = old.id;
END;
CREATE TRIGGER cards_au AFTER UPDATE OF title, body, checklist ON cards BEGIN
DELETE FROM cards_fts WHERE rowid = old.id;
INSERT INTO cards_fts (rowid, title, body, steps)
VALUES (new.id, new.title, new.body,
(SELECT COALESCE(group_concat(json_extract(value, '$.text'), ' '), '')
FROM json_each(new.checklist)));
END;
-- The cards written before the triggers existed.
INSERT INTO cards_fts (rowid, title, body, steps)
SELECT id, title, body,
(SELECT COALESCE(group_concat(json_extract(value, '$.text'), ' '), '')
FROM json_each(cards.checklist))
FROM cards;