From bf5ce42b188ffad3dfa05ce2a1cd3d0e3c169fb9 Mon Sep 17 00:00:00 2001 From: Wesley Kerfoot Date: Sun, 16 Feb 2020 14:39:57 -0500 Subject: [PATCH] normalize db schema a bit, change layout --- src/tweetlogpkg/server.nim | 76 ++++++++++++++++++++++++++--------- src/tweetlogpkg/templates.nim | 19 +++++---- 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/tweetlogpkg/server.nim b/src/tweetlogpkg/server.nim index 91c806f..35b6dc3 100644 --- a/src/tweetlogpkg/server.nim +++ b/src/tweetlogpkg/server.nim @@ -3,21 +3,25 @@ import twitter import templates import jester +type Author = object + name: string + authorID : int + type ThreadRequest = object tweetID: string - author: string + author: Author type TwitterThread = ref object of RootObj tweetID: string - author: string tweets: string + author: Author proc parseTweetUrl(url : string) : Option[ThreadRequest] = let path = url.parseUri.path var author : string var tweetID : int if scanf(path, "/$w/status/$i$.", author, tweetID): - some(ThreadRequest(tweetID : $tweetID, author: author)) + some(ThreadRequest(tweetID : $tweetID, author: Author(name: author))) else: none(ThreadRequest) @@ -30,38 +34,70 @@ chan.open(20) let db = open("tweetlog.db", "", "", "") -proc createTweetTable() = +proc createTweetTables() = db.exec(sql"""CREATE TABLE IF NOT EXISTS threads ( id INTEGER PRIMARY KEY, tid TEXT, - author TEXT, - tweets TEXT + tweets TEXT, + authorID INTEGER + )""") + + db.exec(sql"""CREATE TABLE IF NOT EXISTS authors ( + id INTEGER PRIMARY KEY, + name TEXT, + UNIQUE(name, id) )""") -proc threadExists(threadID : string, author : string) : Option[TwitterThread] = - let row = db.getRow(sql"SELECT * FROM threads WHERE tid=? AND author=?", threadID, author) +proc authorExists(authorName : string) : Option[Author] = + let authorID = db.getRow(sql"SELECT * from authors where name=?", authorName) + + if authorID.all(col => col == ""): + return none(Author) + + return some(Author(name: authorName, authorID: authorID[0].parseInt)) + +proc threadExists(threadID : string, authorName : string) : Option[TwitterThread] = + let author = authorName.authorExists + + if not author.isSome: + return none(TwitterThread) + + let row = db.getRow(sql"SELECT * FROM threads WHERE tid=? AND authorID=?", threadID, author.get.authorID) if row.all(col => col == ""): return none(TwitterThread) + some( TwitterThread(tweetID: row[1], - author: row[2], - tweets: row[3]) + author: author.get, + tweets: row[2]) ) iterator allAuthors() : string = - for author in db.getAllRows(sql"SELECT DISTINCT author FROM threads"): + for author in db.getAllRows(sql"SELECT DISTINCT name FROM authors"): yield author[0] iterator threadIDs(author : string) : string = - for threadID in db.getAllRows(sql"SELECT tid from threads WHERE author=?", author): - yield threadID[0] + let authorID = db.getRow(sql"SELECT * from authors where name=?", author) + + if authorID.all(col => col == ""): + yield "" + else: + for threadID in db.getAllRows(sql"SELECT tid from threads WHERE authorID=?", authorID): + yield threadID[0] proc insertThread(thread : TwitterThread) = - db.exec(sql"INSERT INTO threads (tid, author, tweets) VALUES (?, ?, ?)", + db.exec(sql"INSERT OR IGNORE INTO authors (name) VALUES (?)", thread.author.name) + + let author = thread.author.name.authorExists + + if not author.isSome: + return + + db.exec(sql"INSERT INTO threads (tid, tweets, authorID) VALUES (?, ?, ?)", thread.tweetID, - thread.author, - thread.tweets) + thread.tweets, + author.get.authorID) # Routes @@ -96,7 +132,7 @@ router twitblog: else: # Send it off to the rendering thread for processing # Let them know to check back later - chan.send(ThreadRequest(tweetID: tweetID, author: author)) + chan.send(ThreadRequest(tweetID: tweetID, author: Author(name: author))) resp checkBack() get "/author/@author/threads": @@ -108,7 +144,7 @@ router twitblog: # Entry points proc startServer* = - createTweetTable() + createTweetTables() defer: db.close() let port = 8080.Port let settings = newSettings(port=port) @@ -120,10 +156,10 @@ proc handleRenders* = while true: let t : ThreadRequest = chan.recv() - if threadExists(t.tweetID, t.author).isSome: + if threadExists(t.tweetID, t.author.name).isSome: continue - let tweets = t.tweetID.renderThread(t.author) + let tweets = t.tweetID.renderThread(t.author.name) if tweets.isSome: insertThread( diff --git a/src/tweetlogpkg/templates.nim b/src/tweetlogpkg/templates.nim index 3087fec..49ee3b5 100644 --- a/src/tweetlogpkg/templates.nim +++ b/src/tweetlogpkg/templates.nim @@ -1,12 +1,13 @@ import strformat import karax / [karaxdsl, vdom] -proc layout(inner : VNode) : string = +proc layout(inner : VNode, title : string) : string = let vnode = buildHtml(html): head: meta(charset="utf-8") link(href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css", rel="stylesheet") body: + h1(class="text-center"): text title tdiv(class="text-center appearance-none"): inner "\n" & $vnode @@ -23,12 +24,12 @@ proc tweetThread*(author : string, ul(class="m-auto max-w-md list-decimal text-left"): for tweet in tweets: li: text tweet - result = $vnode.layout + result = $vnode.layout("Threads") proc checkBack*() : string = let vnode = buildHtml(tdiv): h4: text "Check back later please" - result = $vnode.layout + result = $vnode.layout("Check back") proc listThreads*(author : string, threads : seq[string]) : string = @@ -39,7 +40,7 @@ proc listThreads*(author : string, ul: for thread in threads: li: a(href=fmt"/thread/{author}/status/{thread}"): text thread - result = $vnode.layout + result = $vnode.layout("Threads") # Main page @@ -64,7 +65,9 @@ proc submitThread() : VNode = result = vnode proc mainPage*(authors : seq[string]) : string = - let vnode = buildHtml(tdiv): - listAuthors(authors) - submitThread() - result = $vnode.layout + let vnode = buildHtml(tdiv(class="grid grid-cols-2 gap-4")): + tdiv: + listAuthors(authors) + tdiv: + submitThread() + result = $vnode.layout("Tweetlog")