135 lines
4.4 KiB
Plaintext
135 lines
4.4 KiB
Plaintext
import 'package:weblibre/data/database/converters/uri.dart';
|
|
import 'package:weblibre/features/web_feed/data/models/feed_article_query_result.dart';
|
|
import 'package:weblibre/features/web_feed/data/database/converters/feed_authors.dart';
|
|
import 'package:weblibre/features/web_feed/data/database/converters/feed_categories.dart';
|
|
import 'package:weblibre/features/web_feed/data/database/converters/feed_links.dart';
|
|
import 'package:weblibre/features/web_feed/data/models/feed_article.dart';
|
|
|
|
CREATE TABLE feed (
|
|
url TEXT PRIMARY KEY NOT NULL MAPPED BY `const UriConverter()`,
|
|
title TEXT,
|
|
description TEXT,
|
|
icon TEXT MAPPED BY `const UriConverter()`,
|
|
site_link TEXT MAPPED BY `const UriConverter()`,
|
|
authors TEXT MAPPED BY `const FeedAuthorsConverter()`,
|
|
tags TEXT MAPPED BY `const FeedCategoriesConverter()`,
|
|
last_fetched DATETIME
|
|
);
|
|
|
|
CREATE TABLE article (
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
feed_id TEXT NOT NULL MAPPED BY `const UriConverter()` REFERENCES feed ("url") ON DELETE CASCADE,
|
|
fetched DATETIME NOT NULL,
|
|
created DATETIME,
|
|
updated DATETIME,
|
|
last_read DATETIME,
|
|
title TEXT,
|
|
authors TEXT MAPPED BY `const FeedAuthorsConverter()`,
|
|
tags TEXT MAPPED BY `const FeedCategoriesConverter()`,
|
|
links TEXT MAPPED BY `const FeedLinksConverter()`,
|
|
summaryHtml TEXT,
|
|
summaryMarkdown TEXT,
|
|
summaryPlain TEXT,
|
|
contentHtml TEXT,
|
|
contentMarkdown TEXT,
|
|
contentPlain TEXT
|
|
) WITH FeedArticle;
|
|
|
|
CREATE VIEW article_view WITH FeedArticle AS
|
|
SELECT
|
|
a.*,
|
|
f.icon,
|
|
f.site_link
|
|
FROM
|
|
article a
|
|
INNER JOIN
|
|
feed f on f.url = a.feed_id;
|
|
|
|
CREATE INDEX article_feed_id ON article (feed_id);
|
|
|
|
CREATE VIRTUAL TABLE article_fts
|
|
USING fts5(
|
|
title,
|
|
summaryPlain,
|
|
contentPlain,
|
|
content=article,
|
|
tokenize="trigram"
|
|
);
|
|
|
|
-- Triggers to keep the FTS index up to date.
|
|
CREATE TRIGGER article_after_insert AFTER INSERT ON article BEGIN
|
|
INSERT INTO
|
|
article_fts(rowid, title, summaryPlain, contentPlain)
|
|
VALUES (new.rowid, new.title, new.summaryPlain, new.contentPlain);
|
|
END;
|
|
CREATE TRIGGER article_after_delete AFTER DELETE ON article BEGIN
|
|
INSERT INTO
|
|
article_fts(article_fts, rowid, title, summaryPlain, contentPlain)
|
|
VALUES('delete', old.rowid, old.title, old.summaryPlain, old.contentPlain);
|
|
END;
|
|
CREATE TRIGGER article_after_update AFTER UPDATE ON article BEGIN
|
|
INSERT INTO
|
|
article_fts(article_fts, rowid, title, summaryPlain, contentPlain)
|
|
VALUES('delete', old.rowid, old.title, old.summaryPlain, old.contentPlain);
|
|
INSERT INTO
|
|
article_fts(rowid, title, summaryPlain, contentPlain)
|
|
VALUES (new.rowid, new.title, new.summaryPlain, new.contentPlain);
|
|
END;
|
|
|
|
optimizeFtsIndex:
|
|
INSERT INTO article_fts(article_fts) VALUES ('optimize');
|
|
|
|
queryArticlesBasic(:feed_id AS TEXT OR NULL) WITH FeedArticleQueryResult:
|
|
WITH weights AS (
|
|
SELECT
|
|
-- Customize these weights (higher = more important)
|
|
1.0 as title_weight -- Title matches are most important
|
|
)
|
|
SELECT
|
|
a.*,
|
|
f.icon,
|
|
(
|
|
bm25(article_fts, weights.title_weight)
|
|
) AS weighted_rank
|
|
FROM article_fts fts
|
|
INNER JOIN
|
|
article a ON a.rowid = fts.rowid
|
|
INNER JOIN
|
|
feed f ON f.url = a.feed_id
|
|
CROSS JOIN weights
|
|
WHERE
|
|
fts.title LIKE :query AND
|
|
(:feed_id IS NULL OR a.feed_id = :feed_id)
|
|
ORDER BY
|
|
weighted_rank ASC,
|
|
a.created DESC NULLS LAST;
|
|
|
|
queryArticlesFullContent(:feed_id AS TEXT OR NULL) WITH FeedArticleQueryResult:
|
|
WITH weights AS (
|
|
SELECT
|
|
-- Customize these weights (higher = more important)
|
|
10.0 as title_weight, -- Title matches are most important
|
|
3.0 as summary_weight, -- Summary matches are quite important
|
|
1.0 as content_weight -- Content matches are basic
|
|
)
|
|
SELECT
|
|
a.*,
|
|
f.icon,
|
|
highlight(article_fts, 0, :beforeMatch, :afterMatch) AS title_highlight,
|
|
snippet(article_fts, 1, :beforeMatch, :afterMatch, :ellipsis, :snippetLength) AS summary_snippet,
|
|
snippet(article_fts, 2, :beforeMatch, :afterMatch, :ellipsis, :snippetLength) AS content_snippet,
|
|
(
|
|
bm25(article_fts, weights.title_weight, weights.summary_weight,
|
|
weights.content_weight)
|
|
) AS weighted_rank
|
|
FROM article_fts(:query) fts
|
|
INNER JOIN
|
|
article a ON a.rowid = fts.rowid
|
|
INNER JOIN
|
|
feed f ON f.url = a.feed_id
|
|
CROSS JOIN weights
|
|
WHERE
|
|
:feed_id IS NULL OR a.feed_id = :feed_id
|
|
ORDER BY
|
|
weighted_rank ASC,
|
|
a.created DESC NULLS LAST; |