Balbuti #4: Konfiguracja BE (blurt)

in blurt-179874 •  9 months ago 

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:

image.png

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.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE BLURT!
Sort Order:  
  ·  9 months ago  ·  

A tak to teraz wygląda w tej społeczności ;-)

[
  {
    "count": 1,
    "tag_name": "mecz"
  },
  {
    "count": 1,
    "tag_name": "bitcoin"
  },
  {
    "count": 1,
    "tag_name": "polityka"
  }
]