Powoli moje przygotowania backendu się kończą, co pewnie oznacza, że niebawem wrzucę jego kod gdzieś do sieci.
Docelowo wyobrażam sobie to w taki sposób, że tworzę społeczność dedykowaną na taki serwis do krótkich treści dla każdego języka jaki będzie wpierany przez stronę. Początkowo zanim nie wyjdzie z etapu testowego będzie to pewnie tylko język polski, ale z czasem pojawią się na pewno kolejne.
Serwis taki wyobrażam sobie w podobny spoósb jak np. mikroblog na wykopie. Jest jakaś główna tablica, która zawiera wszystkie wpisy - co akurat nie jest trudne bo takie działanie zapewnia standardowy RPC. Można też zobaczyć wpisy dla podanego tagu - tutaj już jest pewien problem, bo RPC pozwala na filtrowanie tylko globalnie, a nie wewnątrz społeczności - właśnie tutaj pojawił się pomysł aby spróbować zrobić własny BE, aby taką funkcjonalność umożliwić.
Dodatkowo powinniśmy mieć możliwość obserwowania tagów, dzięki czemu gdy ktoś zada jakieś pytanie do społeczności to będziemy mogli udzielić odpowiedzi. Nad tą częścią się jeszcze zastanawiam jak najlepiej ją zrealizować.
Użytkownicy powinni mieć też możliwość podglądania popularnych tagów. Zauważyłem, że gdy pojawiają się popularne tematy to jest to pewna mobilizacja dla innych aby zainteresować się tematem. Czasem jest to #mecz czasem jest to #bitcoin albo #polityka stworzyłem więc dodatkowo możliwość pobierania popularnych tagów w społeczności. Czy to powinny być 24h czy może klika dni to czas pokaże. Co istotne tagi są wyciągane z tekstu, a nie z parametru tagów, który w mojej opinni powinien kiedyś zmienić działanie, ale to inny temat.
Teraz pokażę Wam konfigurację mojego serwisu. Na początku tworzę kilka tabelek oraz pewien trigger, który pozwala mi w sqlite rozbić tagi do osobnej tabeli. Jest to przydatne właśnie do statystyk. Potem JSONata, który odpowiada za wyciądanie danych transakcyjnych, a na końcu endpointy.
startBlock: 37820000
dbfile: db.sqlite
process:
data:
creation:
- >
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT DEFAULT "",
author TEXT DEFAULT "",
permlink TEXT DEFAULT "",
title TEXT DEFAULT "",
community TEXT DEFAULT "",
tags TEXT DEFAULT "",
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
);
- >
CREATE TABLE IF NOT EXISTS tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tag_name TEXT NOT NULL UNIQUE
);
- >
CREATE TABLE IF NOT EXISTS post_tags (
post_id INTEGER,
tag_id INTEGER,
PRIMARY KEY (post_id, tag_id),
FOREIGN KEY (post_id) REFERENCES posts (id),
FOREIGN KEY (tag_id) REFERENCES tags (id)
);
- >
CREATE TRIGGER IF NOT EXISTS after_insert_post
AFTER INSERT ON posts
BEGIN
INSERT OR IGNORE INTO tags (tag_name)
WITH RECURSIVE split(tags, tag, rest) AS (
SELECT tags, '', tags || '#' FROM posts WHERE id = NEW.id
UNION ALL
SELECT
tags,
lower(SUBSTR(rest, 1, INSTR(rest, '#') - 1)),
SUBSTR(rest, INSTR(rest, '#') + 1)
FROM split
WHERE rest != ''
)
SELECT DISTINCT trim(tag) AS tag_name FROM split WHERE tag != '';
INSERT INTO post_tags (post_id, tag_id)
SELECT NEW.id, tags.id
FROM (
SELECT id, tags
FROM posts
ORDER BY id DESC
LIMIT 1
) AS NEW
JOIN tags ON lower(NEW.tags) || '#' LIKE '%#' || tags.tag_name || '#%';
END;
jsonata: >
$$.{
"community": parent_permlink,
"author": author,
"permlink": permlink,
"title": title,
"tags": $replace($join($match(body,/(?:^|\s)(#[a-zA-Z0-9]+)/).match, ''), ' ', '')
}[$contains(community, "blurt")]
insert_globals:
timestamp: true
insert: >
INSERT INTO posts (community, author, permlink, title, tags, timestamp) VALUES (:community, :author, :permlink, :title, :tags, :Gtimestamp);
api:
posts:
stats/:community/tag:
params:
community: string
projection: >
SELECT * FROM (SELECT COUNT(posts.id) as count, tag_name FROM posts, post_tags, tags
WHERE
community LIKE :community AND
posts.timestamp > (SELECT DATETIME('now', '-7 day')) AND
tag_id = tags.id AND
post_id = posts.id
GROUP BY tag_id, tag_name) ORDER BY count DESC LIMIT 10 OFFSET 0
posts/:community/tag/:name/:offset:
params:
community: string
name: string
offset: number
projection: >
SELECT * FROM posts WHERE community = :community AND id IN (
SELECT post_id FROM post_tags WHERE tag_id IN (
SELECT id FROM tags WHERE tag_name = :name COLLATE NOCASE
)
) LIMIT 10 OFFSET :offset
posts/:community/user/:name/:offset:
params:
community: string
name: string
offset: number
projection: >
SELECT * FROM posts WHERE community = :community AND author LIKE :name LIMIT 10 OFFSET :offset
posts/:community/:offset:
params:
community: string
offset: number
projection: >
SELECT * FROM posts WHERE community = :community LIMIT 10 OFFSET :offset
No i tak to wygląda na końcu:
Czuję, że jest jeszcze wiele rzeczy do przemyślenia, jak np. odpowiedzi na posty, które obecnie będą całkowicie ignorowane ze względu, że parent_permlink będzie wskazywać na post, a nie na społeczność. Wymaga to dodatkowej logiki sprawdzania co powinno trafić do bazy.
Ale to są rzeczy, które będą wychodzić już później. Myślę, że to na jakiś czas mój ostatni wpis zwizany z BE, i kolejne będą już o FE.
A tak to teraz wygląda w tej społeczności ;-)