feat(clients): add nim-allographer client with BaraDB driver support
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

- Pure Nim wire protocol client (async + sync, no C FFI)
- Query Builder: fluent API, SQL generator, execution, transactions
- Schema Builder: create/alter/drop tables, column operations
- Connection pool with aging and timeout handling
- ORM integration via compile-time DB_BARADB switch
- Tests: test_open, test_query
- Documentation: README.md, PLAN_BARADB.md
This commit is contained in:
2026-05-21 15:49:11 +03:00
parent 2d310a33a1
commit 6bfc5b3a3c
654 changed files with 109419 additions and 0 deletions
@@ -0,0 +1,565 @@
discard """
cmd: "nim c -d:reset -d:ssl -r $file"
"""
# nim c -d:reset -d:ssl -r tests/mysql/test_query.nim
import std/unittest
import std/asyncdispatch
import std/httpclient
import std/json
import std/options
import std/streams
import std/strformat
import ../../src/allographer/schema_builder
import ../../src/allographer/query_builder
import ./connections
import ../clear_tables
let rdb = mysql
proc setup(rdb:MysqlConnections) =
rdb.create([
table("auth",[
Column.increments("id"),
Column.string("auth")
]),
table("user",[
Column.increments("id"),
Column.string("name").nullable(),
Column.string("email").nullable(),
Column.string("address").nullable(),
Column.date("submit_on").nullable(),
Column.datetime("submit_at").nullable(),
Column.foreign("auth_id").reference("id").onTable("auth").onDelete(SET_NULL).nullable()
])
])
# seeder
seeder(rdb, "auth"):
rdb.table("auth").insert(@[
%*{"auth": "admin"},
%*{"auth": "user"}
])
.waitFor
seeder(rdb, "user"):
var users: seq[JsonNode]
for i in 1..10:
let authId = if i mod 2 == 0: 2 else: 1
let month = if i > 9: $i else: &"0{i}"
users.add(
%*{
"name": &"user{i}",
"email": &"user{i}@example.com",
"auth_id": authId,
"submit_on": &"2020-{month}-01",
"submit_at": &"2020-{month}-01 00:00:00",
}
)
rdb.table("user").insert(users).waitFor
setup(rdb)
suite($rdb & " get"):
test("get"):
let t = rdb.table("user").get().waitFor
let expect = %*{"id":1,"name":"user1","email":"user1@example.com","address":newJNull(),"submit_on":"2020-01-01","submit_at":"2020-01-01 00:00:00","auth_id":1}
echo t[0]
echo expect
check t[0] == expect
test("getPlain"):
let t = rdb.table("user").getPlain().waitFor
check t[0] == @["1", "user1", "user1@example.com", "", "2020-01-01", "2020-01-01 00:00:00", "1"]
test("first"):
var t = rdb.table("user").where("name", "=", "user1").first().waitFor().get
check t == %*{"id": 1, "name": "user1", "email": "user1@example.com", "address":newJNull(), "submit_on":"2020-01-01","submit_at":"2020-01-01 00:00:00", "auth_id": 1}
test("firstPlain"):
var t = rdb.table("user").firstPlain().waitFor
check t == @["1", "user1", "user1@example.com", "", "2020-01-01", "2020-01-01 00:00:00", "1"]
test("find"):
var t = rdb.table("user").find(1).waitFor.get
check t == %*{"id": 1, "name": "user1", "email": "user1@example.com", "address":newJNull(), "submit_on":"2020-01-01","submit_at":"2020-01-01 00:00:00", "auth_id": 1}
test("findString"):
var t = rdb.table("user").find("1").waitFor.get
check t == %*{"id": 1, "name": "user1", "email": "user1@example.com", "address":newJNull(), "submit_on":"2020-01-01","submit_at":"2020-01-01 00:00:00", "auth_id": 1}
test("findPlain"):
var t = rdb.table("user").findPlain(1).waitFor
check t == @["1", "user1", "user1@example.com", "", "2020-01-01", "2020-01-01 00:00:00", "1"]
test("columns"):
let columns = rdb.table("user").columns().waitFor
check columns == @["id", "name", "email", "address", "submit_on", "submit_at", "auth_id"]
test("select"):
var t = rdb.select("name", "email").table("user").get().waitFor
check t[0] == %*{"name": "user1", "email": "user1@example.com"}
test("selectAs"):
var t = rdb.select("name as user_name", "email").table("user").get().waitFor
check t[0] == %*{"user_name": "user1", "email": "user1@example.com"}
test("selectLike"):
var t = rdb.select("email").table("user").where("email", "LIKE", "%10%").get().waitFor
check t == @[%*{"email":"user10@example.com"}]
t = rdb.select("email").table("user").where("email", "LIKE", "user10%").get().waitFor
check t == @[%*{"email":"user10@example.com"}]
t = rdb.select("email").table("user").where("email", "LIKE", "%10@example.com%").get().waitFor
check t == @[%*{"email":"user10@example.com"}]
test("select count"):
var t = rdb.select("COUNT(id) as count").table("user").get().waitFor
check t[0]["count"].getInt() == 10
test("select max"):
var t = rdb.select("MAX(id) as max").table("user").get().waitFor
check t[0]["max"].getInt() == 10
test("where"):
var t = rdb.table("user").where("auth_id", "=", "1").get().waitFor
check t == @[
%*{"id":1,"name":"user1","email":"user1@example.com","address":newJNull(),"submit_on":"2020-01-01","submit_at":"2020-01-01 00:00:00","auth_id":1},
%*{"id":3,"name":"user3","email":"user3@example.com","address":newJNull(),"submit_on":"2020-03-01","submit_at":"2020-03-01 00:00:00","auth_id":1},
%*{"id":5,"name":"user5","email":"user5@example.com","address":newJNull(),"submit_on":"2020-05-01","submit_at":"2020-05-01 00:00:00","auth_id":1},
%*{"id":7,"name":"user7","email":"user7@example.com","address":newJNull(),"submit_on":"2020-07-01","submit_at":"2020-07-01 00:00:00","auth_id":1},
%*{"id":9,"name":"user9","email":"user9@example.com","address":newJNull(),"submit_on":"2020-09-01","submit_at":"2020-09-01 00:00:00","auth_id":1}
]
test("orWhere"):
var t = rdb.table("user").where("auth_id", "=", "1").orWhere("name", "=", "user2").get().waitFor
check t == @[
%*{"id":1,"name":"user1","email":"user1@example.com","address":newJNull(),"submit_on":"2020-01-01","submit_at":"2020-01-01 00:00:00","auth_id":1},
%*{"id":2,"name":"user2","email":"user2@example.com","address":newJNull(),"submit_on":"2020-02-01","submit_at":"2020-02-01 00:00:00","auth_id":2},
%*{"id":3,"name":"user3","email":"user3@example.com","address":newJNull(),"submit_on":"2020-03-01","submit_at":"2020-03-01 00:00:00","auth_id":1},
%*{"id":5,"name":"user5","email":"user5@example.com","address":newJNull(),"submit_on":"2020-05-01","submit_at":"2020-05-01 00:00:00","auth_id":1},
%*{"id":7,"name":"user7","email":"user7@example.com","address":newJNull(),"submit_on":"2020-07-01","submit_at":"2020-07-01 00:00:00","auth_id":1},
%*{"id":9,"name":"user9","email":"user9@example.com","address":newJNull(),"submit_on":"2020-09-01","submit_at":"2020-09-01 00:00:00","auth_id":1}
]
test("whereBetween"):
var t = rdb
.select("id", "name")
.table("user")
.where("auth_id", "=", 1)
.whereBetween("id", [6, 9])
.get()
.waitFor
echo t
check t[0]["name"].getStr() == "user7"
test("whereBetweenString"):
var t = rdb
.table("user")
.whereBetween("submit_at", ["2020-01-01 00:00:00", "2020-01-31 00:00:00"])
.get()
.waitFor
check t[0]["name"].getStr == "user1"
t = rdb
.table("user")
.whereBetween("submit_on", ["2020-01-01", "2020-01-31"])
.get()
.waitFor
check t[0]["name"].getStr == "user1"
test("whereNotBetween"):
var t = rdb
.select("id", "name")
.table("user")
.where("auth_id", "=", 1)
.whereNotBetween("id", [1, 4])
.get()
.waitFor
check t[0]["name"].getStr() == "user5"
test("whereNotBetweenString"):
var t = rdb
.table("user")
.whereNotBetween("submit_at", ["2020-2-1 00:00:00", "2020-12-31 00:00:00"])
.get()
.waitFor
check t[0]["name"].getStr == "user1"
t = rdb
.table("user")
.whereNotBetween("submit_on", ["2020-2-1", "2020-12-31"])
.get()
.waitFor
check t[0]["name"].getStr == "user1"
test("whereIn"):
var t = rdb
.select("id", "name")
.table("user")
.whereBetween("id", [4, 10])
.whereIn("id", @[5, 6, 7])
.get()
.waitFor
echo t
check t[0]["name"].getStr() == "user5"
t = rdb
.select("id", "name")
.table("user")
.whereBetween("id", [4, 10])
.whereIn("name", @["user5", "user6", "user7"])
.get()
.waitFor
check t[0]["name"].getStr() == "user5"
test("whereNotIn"):
var t = rdb
.select("id", "name")
.table("user")
.whereBetween("id", [4, 10])
.whereNotIn("id", @[5, 6, 7])
.get()
.waitFor
echo t
check t == @[
%*{"id":4, "name": "user4"},
%*{"id":8, "name": "user8"},
%*{"id":9, "name": "user9"},
%*{"id":10, "name": "user10"},
]
t = rdb
.select("id", "name")
.table("user")
.whereBetween("id", [4, 10])
.whereNotIn("name", @["user5", "user6", "user7"])
.get()
.waitFor
echo t
check t == @[
%*{"id":4, "name": "user4"},
%*{"id":8, "name": "user8"},
%*{"id":9, "name": "user9"},
%*{"id":10, "name": "user10"},
]
test("whereNull"):
setUp(rdb)
rdb.table("user").insert(%*{"email": "user11@example.com"}).waitFor
var t = rdb
.select("id", "name", "email")
.table("user")
.whereNull("name")
.get()
.waitFor
echo t
check t[0]["id"].getInt() == 11
test("groupBy"):
var t = rdb
.table("user")
.where("auth_id", "=", 1)
.groupBy("auth_id")
.max("id")
.waitFor()
.get()
echo t
check t == "9"
test("having"):
var t = rdb
.select("id", "name")
.table("user")
.groupBy("auth_id")
.groupBy("id")
.having("auth_id", "=", 1)
.get()
.waitFor
echo t
check t[0]["id"].getInt() == 1
test("orderBy"):
var t = rdb.table("user")
.where("auth_id", "is not", nil)
.orderBy("auth_id", Asc)
.orderBy("id", Desc)
.get()
.waitFor
echo t
check t[0]["id"].getInt() == 9
test("join"):
var t = rdb
.select("user.id", "user.name")
.table("user")
.join("auth", "auth.id", "=", "user.auth_id")
.where("auth.id", "=", "2")
.get()
.waitFor
echo t
check t[0]["name"].getStr() == "user2"
test("leftJoin"):
rdb.table("user").insert(%*{
"name": "user11"
})
.waitFor
var t = rdb
.select("user.id", "user.name", "user.auth_id")
.table("user")
.leftJoin("auth", "auth.id", "=", "user.auth_id")
.orderBy("user.id", Desc)
.get()
.waitFor
echo t
check t[0]["name"].getStr() == "user11"
check t[0]["auth_id"] == newJNull()
test("resultIsNull"):
check rdb.table("user").find(50).waitFor().isSome == false
check newSeq[JsonNode](0) == rdb.table("user").where("id", "=", 50).get().waitFor
suite($rdb & " insert"):
setup:
setup(rdb)
test("insert row"):
rdb.table("user").insert(%*{"name": "Alice"}).waitFor
let t = rdb.table("user").orderBy("id", Desc).first().waitFor().get()
check t["name"].getStr() == "Alice"
test("insert rows"):
rdb.table("user").insert(@[
%*{"name": "Alice"},
%*{"name": "Bob"},
]).waitFor
let t = rdb.table("user").orderBy("id", Desc).limit(2).get().waitFor()
check t[0]["name"].getStr() == "Bob"
check t[1]["name"].getStr() == "Alice"
test("insertId row"):
var id = rdb.table("user").insertId(%*{"name": "Alice"}).waitFor
echo id
let t = rdb.table("user").find(id).waitFor().get()
check t["name"].getStr() == "Alice"
test("insertId rows"):
let ids = rdb.table("user").insertId(@[
%*{"name": "Alice"},
%*{"name": "Bob"},
]).waitFor
var t = rdb.table("user").find(ids[0]).waitFor().get()
check t["name"].getStr == "Alice"
t = rdb.table("user").find(ids[1]).waitFor().get()
check t["name"].getStr == "Bob"
test("insertNil"):
var id = rdb.table("user").insertId(%*{
"name": "Alice",
"email": nil,
"address": ""
})
.waitFor
var res = rdb.table("user").find(id).waitFor
echo res.get
check res.get["email"] == newJNull()
res = rdb.table("user").where("email", "is", nil).first().waitFor
echo res.get
check res.get["email"] == newJNull()
test("insert [T]"):
type User = object
name:string
let user = User(name: "Alice")
rdb.table("user").insert(user).waitFor
let row = rdb.table("user").orderBy("id", Desc).first().waitFor().get()
check row["name"].getStr() == "Alice"
test("insert seq[T]"):
type User = object
name:string
let users = @[
User(name: "Alice"),
User(name: "Bob"),
]
rdb.table("user").insert(users).waitFor
let t = rdb.table("user").orderBy("id", Desc).limit(2).get().waitFor()
check t[0]["name"].getStr() == "Bob"
check t[1]["name"].getStr() == "Alice"
suite($rdb & " update"):
setup:
setup(rdb)
test("update"):
rdb.table("user").where("id", "=", 1).update(%*{"name": "Alice"}).waitFor
var t = rdb.table("user").find(1).waitFor().get()
check t["name"].getStr() == "Alice"
test("update [T]"):
type User = object
name:string
let user = User(name: "Alice")
rdb.table("user").where("id", "=", 1).update(user).waitFor
var t = rdb.table("user").find(1).waitFor().get()
check t["name"].getStr() == "Alice"
suite($rdb & " delete"):
setup(rdb)
test("delete"):
rdb.table("user").delete(1).waitFor
check rdb.table("user").find(1).waitFor.isSome == false
test("delete where"):
rdb.table("user").where("name", "=", "user1").delete().waitFor
check rdb.table("user").find(1).waitFor.isSome == false
suite($rdb & " rawQuery"):
setup(rdb)
test("get"):
echo rdb.table("user").get().waitFor
let sql = &"SELECT * FROM `user` WHERE `id` = ?"
let res = rdb.raw(sql, %*[1]).get().waitFor
echo res
check res[0]["name"].getStr == "user1"
test("getPlain"):
let sql = &"SELECT * FROM `user` WHERE `id` = ?"
let res = rdb.raw(sql, %*[1]).getPlain().waitFor
echo res
check res[0][1] == "user1"
test("first"):
echo rdb.table("user").get().waitFor
let sql = &"SELECT * FROM `user` WHERE `id` = ?"
let res = rdb.raw(sql, %*[1]).first().waitFor().get()
echo res
check res["name"].getStr == "user1"
test("firstPlain"):
echo rdb.table("user").get().waitFor
let sql = &"SELECT name FROM `user` WHERE `id` = ?"
let res = rdb.raw(sql, %*[1]).firstPlain().waitFor()
echo res
check res[0] == "user1"
test("exec"):
var sql = "UPDATE `user` SET `name` = ? WHERE `id` = ?"
rdb.raw(sql, %*["updated user1", 1]).exec().waitFor
sql = &"SELECT * FROM `user` WHERE `id` = ?"
let res = rdb.raw(sql, %[1]).get().waitFor
echo res
check res[0]["name"].getStr == "updated user1"
setup(rdb)
suite($rdb & " aggregates"):
test("count"):
var t = rdb.table("user").count().waitFor
check t == 10
test("max"):
var t = rdb.table("user").max("name").waitFor.get
check t == "user9"
var t2 = rdb.table("user").max("id").waitFor.get
check t2 == "10"
test("min"):
var t = rdb.table("user").min("name").waitFor.get
check t == "user1"
var t2 = rdb.table("user").min("id").waitFor.get
check t2 == "1"
test("avg"):
var t = rdb.table("user").avg("id").waitFor.get
check t == 5.5
test("sum"):
var t = rdb.table("user").sum("id").waitFor.get
check t == 55.0
suite($rdb & " insert binary"):
test("should success"):
rdb.create(
table("test", [
Column.increments("id"),
Column.binary("pic"),
])
)
let client = newAsyncHttpClient()
let response = client.getContent("https://nim-lang.org/assets/img/twitter_banner.png").waitFor()
let imageStream = newStringStream(response)
let binaryImage = imageStream.readAll()
let id = rdb.table("test").insertId(%*{"pic": binaryImage}).waitFor()
var res = rdb.table("test").find(id).waitFor().get()
check res["pic"].getStr().len > 0
rdb.table("test").where("id","=", id).update(%*{"pic": binaryImage}).waitFor()
res = rdb.table("test").find(id).waitFor().get()
check res["pic"].getStr().len > 0
clearTables(rdb).waitFor()