Add Ormin ORM support for BaraDB (Nim client)
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled

This commit is contained in:
2026-05-15 21:49:08 +03:00
parent 2e945c1dcb
commit 4e54075078
63 changed files with 9764 additions and 0 deletions
@@ -0,0 +1,117 @@
body {
background-color: #f1f9ea;
margin: 0;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
}
div#main {
width: 80%;
margin-left: auto;
margin-right: auto;
}
div#user {
background-color: #66ac32;
width: 100%;
color: #c7f0aa;
padding: 5pt;
}
div#user > h1 {
color: #ffffff;
}
h1 {
margin: 0;
display: inline;
padding-left: 10pt;
padding-right: 10pt;
}
div#user > form {
float: right;
margin-right: 10pt;
}
div#user > form > input[type="submit"] {
border: 0px none;
padding: 5pt;
font-size: 108%;
color: #ffffff;
background-color: #515d47;
border-radius: 5px;
cursor: pointer;
}
div#user > form > input[type="submit"]:hover {
background-color: #538c29;
}
div#messages {
background-color: #a2dc78;
width: 90%;
margin-left: auto;
margin-right: auto;
color: #1a1a1a;
}
div#messages > div {
border-left: 1px solid #869979;
border-right: 1px solid #869979;
border-bottom: 1px solid #869979;
padding: 5pt;
}
div#messages > div > a, div#messages > div > span {
color: #475340;
}
div#messages > div > a:hover {
text-decoration: none;
color: #c13746;
}
h3 {
margin-bottom: 0;
font-weight: normal;
}
div#login {
width: 200px;
margin-left: auto;
margin-right: auto;
margin-top: 20%;
font-size: 130%;
}
div#login span.small {
display: block;
font-size: 56%;
}
div#newMessage {
background-color: #538c29;
width: 90%;
margin-left: auto;
margin-right: auto;
color: #ffffff;
padding: 5pt;
}
div#newMessage span {
padding-right: 5pt;
}
div#newMessage form {
display: inline;
}
div#newMessage > form > input[type="text"] {
width: 80%;
}
div#newMessage > form > input[type="submit"] {
font-size: 80%;
}
@@ -0,0 +1,3 @@
# Tweeter example
Modified from [tweeter example](https://github.com/dom96/nim-in-action-code/tree/master/Chapter7/Tweeter) in the "nim in action" book, replace the database layer with ormin.
@@ -0,0 +1,2 @@
--define: ssl
--path:"$projectDir/../../../../ormin"
@@ -0,0 +1,11 @@
import db_sqlite, os, strutils
let db {.global.} = open("tweeter.db", "", "", "")
let sqlFile = readFile(currentSourcePath.parentDir() / "tweeter_model.sql")
for t in sqlFile.split(';'):
if t.strip() != "":
db.exec(sql(t))
echo("Database created successfully!")
db.close()
@@ -0,0 +1,51 @@
import times, strutils, strformat, sequtils
from db_connector/db_sqlite import instantRows, `[]`
import ../../../ormin
import model
importModel(DbBackend.sqlite, "tweeter_model")
var db {.global.} = open("tweeter.db", "", "", "")
proc findUser*(username: string, user: var User): bool =
let res = query:
select user(username)
where username == ?username
echo res
if res.len == 0: return false
else: user.username = res[0]
let following = query:
select following(followed_user)
where follower == ?username
user.following = following.filterIt(it.len != 0)
return true
proc create*(user: User) =
query:
insert user(username = ?user.username)
proc post*(message: Message) =
if message.msg.len > 140:
raise newException(ValueError, "Message has to be less than 140 characters.")
query:
insert message(username = ?message.username,
time = ?message.time,
msg = ?message.msg)
proc follow*(follower, user: User) =
query:
insert following(follower = ?follower.username, followed_user = ?user.username)
proc findMessage*(usernames: openArray[string], limit = 10): seq[Message] =
result = @[]
if usernames.len == 0: return
var whereClause = "WHERE "
for i in 0 ..< usernames.len:
whereClause.add("trim(username) = ?")
if i < usernames.len - 1:
whereClause.add(" or ")
let s = &"SELECT username, time, msg FROM Message {whereClause} ORDER BY time DESC LIMIT {limit}"
for row in db.instantRows(sql(s), usernames):
result.add((username: row[0], time: row[1].parseInt, msg: row[2]))
@@ -0,0 +1,11 @@
type
User* = tuple[
username: string,
following: seq[string]
]
Message* = tuple[
username: string,
time: int,
msg: string
]
@@ -0,0 +1,59 @@
import asyncdispatch, times
import jester
import database, model, views/[user, general]
proc userLogin(request: Request, user: var User): bool =
if request.cookies.hasKey("username"):
let username = request.cookies["username"]
if not findUser(username, user):
user = (username: username, following: @[])
create(user)
return true
else:
return false
routes:
get "/":
var user: User
if userLogin(request, user):
let messages = findMessage(user.following & user.username)
resp renderMain(renderTimeline(user.username, messages))
else:
resp renderMain(renderLogin())
get "/@name":
cond '.' notin @"name"
var user: User
if not findUser(@"name", user):
halt "User not found"
let messages = findMessage([user.username])
var currentUser: User
if userLogin(request, currentUser):
resp renderMain(renderUser(user, currentUser) & renderMessages(messages))
else:
resp renderMain(renderUser(user) & renderMessages(messages))
post "/follow":
var follower, target: User
if not findUser(@"follower", follower):
halt "Follower not found"
if not findUser(@"target", target):
halt "Follow target not found"
follow(follower, target)
redirect uri("/" & @"target")
post "/login":
setCookie("username", @"username", getTime().utc() + 2.hours)
redirect "/"
post "/createMessage":
let message = (
username: @"username",
time: getTime().toUnix().int,
msg: @"message"
)
post(message)
redirect "/"
runForever()
@@ -0,0 +1,24 @@
# Generated by ormin_importer. DO NOT EDIT.
type
Attr = object
name: string
tabIndex: int
typ: DbTypekind
key: int # 0 nothing special,
# +1 -- primary key
# -N -- references attribute N
const tableNames = [
"user",
"following",
"message"
]
const attributes = [
Attr(name: "username", tabIndex: 0, typ: dbVarchar, key: 1),
Attr(name: "follower", tabIndex: 1, typ: dbVarchar, key: -1),
Attr(name: "followed_user", tabIndex: 1, typ: dbVarchar, key: -1),
Attr(name: "username", tabIndex: 2, typ: dbVarchar, key: -1),
Attr(name: "time", tabIndex: 2, typ: dbInt, key: 0),
Attr(name: "msg", tabIndex: 2, typ: dbVarchar, key: 0)
]
@@ -0,0 +1,18 @@
CREATE TABLE IF NOT EXISTS User(
username text PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS Following(
follower text,
followed_user text,
PRIMARY KEY (follower, followed_user),
FOREIGN KEY (follower) REFERENCES User(username),
FOREIGN KEY (followed_user) REFERENCES User(username)
);
CREATE TABLE IF NOT EXISTS Message(
username text,
time integer,
msg text NOT NULL,
FOREIGN KEY (username) REFERENCES User(username)
);
@@ -0,0 +1,51 @@
#? stdtmpl(subsChar = '$', metaChar = '#')
#import xmltree
#import ../model
#import user
#
#proc `$!`(text: string): string = escape(text)
#end proc
#
#proc renderMain*(body: string): string =
# result = ""
<!DOCTYPE html>
<html>
<head>
<title>Tweeter written in Nim</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
${body}
</body>
</html>
#end proc
#
#proc renderLogin*(): string =
# result = ""
<div id="login">
<span>Login</span>
<span class="small">Please type in your username...</span>
<form action="login" method="post">
<input type="text" name="username">
<input type="submit" value="Login">
</form>
</div>
#end proc
#
#proc renderTimeline*(username: string, messages: openArray[Message]): string =
# result = ""
<div id="user">
<h1>${$!username} timeline</h1>
</div>
<div id="newMessage">
<span>New message</span>
<form action="createMessage" method="post">
<input type="text" name="message">
<input type="hidden" name="username" value="${$!username}">
<input type="submit" value="Tweet">
</form>
</div>
${renderMessages(messages)}
#end proc
@@ -0,0 +1,41 @@
#? stdtmpl(subsChar = '$', metaChar = '#', toString = "xmltree.escape")
#import xmltree
#import times
#import "../model"
#
#proc renderUser*(user: User): string =
# result = ""
<div id="user">
<h1>${user.username}</h1>
<span>Following: ${$user.following.len}</span>
</div>
#end proc
#
#proc renderUser*(user, currentUser: User): string =
# result = ""
<div id="user">
<h1>${user.username}</h1>
<span>Following: ${$user.following.len}</span>
#if user.username notin currentUser.following and user.username != currentUser.username:
<form action="follow" method="post">
<input type="hidden" name="follower" value="${currentUser.username}">
<input type="hidden" name="target" value="${user.username}">
<input type="submit" value="Follow">
</form>
#end if
</div>
#
#end proc
#
#proc renderMessages*(messages: openArray[Message]): string =
# result = ""
<div id="messages">
#for message in messages:
<div>
<a href="/${message.username}">${message.username}</a>
<span>${message.time.fromUnix().format("HH:mm MMMM d',' yyyy")}</span>
<h3>${message.msg}</h3>
</div>
#end for
</div>
#end proc