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
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:
@@ -0,0 +1,22 @@
|
||||
DB_SQLITE=true
|
||||
DB_POSTGRES=true
|
||||
DB_MARIADB=true
|
||||
DB_SURREAL=true
|
||||
|
||||
SQLITE_HOST="/root/project/example/db.sqlite3"
|
||||
# SQLITE_HOST=":memory:"
|
||||
MY_HOST=mysql
|
||||
MARIA_HOST=mariadb
|
||||
MY_PORT=3306
|
||||
PG_HOST=postgres
|
||||
PG_PORT=5432
|
||||
DB_USER=user
|
||||
DB_PASSWORD=pass
|
||||
DB_DATABASE=database
|
||||
DB_MAX_CONNECTION=95
|
||||
DB_TIMEOUT=30
|
||||
|
||||
# Logging
|
||||
LOG_IS_DISPLAY=true
|
||||
LOG_IS_FILE=false
|
||||
LOG_DIR="/root/project/example/logs"
|
||||
@@ -0,0 +1,58 @@
|
||||
# nim c -r -d:reset example/columnType.nim
|
||||
import std/json
|
||||
import std/asyncdispatch
|
||||
import ../src/allographer/query_builder
|
||||
import ../src/allographer/schema_builder
|
||||
import ./connections
|
||||
|
||||
asyncBlock:
|
||||
rdb.create([
|
||||
table("auth",[
|
||||
Column.increments("id"),
|
||||
Column.string("auth")
|
||||
]),
|
||||
table("users",[
|
||||
Column.increments("id"),
|
||||
Column.string("name").nullable(),
|
||||
Column.string("email").nullable(),
|
||||
Column.string("password").nullable(),
|
||||
Column.string("address").nullable(),
|
||||
Column.date("birth_date").nullable(),
|
||||
Column.foreign("auth_id").reference("id").onTable("auth").onDelete(SET_NULL)
|
||||
]),
|
||||
table("sample", [
|
||||
Column.increments("id"),
|
||||
Column.float("float"),
|
||||
Column.string("string"),
|
||||
Column.datetime("datetime"),
|
||||
Column.string("null").nullable(),
|
||||
Column.boolean("is_admin")
|
||||
])
|
||||
])
|
||||
|
||||
echo await rdb.select("id", "name", "address").table("users")
|
||||
.limit(2)
|
||||
.get()
|
||||
|
||||
echo await rdb.select("id", "name", "address").table("users").first()
|
||||
|
||||
echo await rdb.select("id", "name", "address").table("users").find(3)
|
||||
|
||||
await rdb.table("sample").insert(%*{
|
||||
"id": 1,
|
||||
"float": 3.14,
|
||||
"string": "string",
|
||||
"datetime": "2019-01-01 12:00:00.1234",
|
||||
"is_admin": true
|
||||
})
|
||||
|
||||
echo await rdb.select("id", "float", "string", "datetime", "null", "is_admin").table("sample").get()
|
||||
|
||||
echo await rdb.select("id", "float", "string", "datetime", "null", "is_admin").table("sample").get()
|
||||
|
||||
|
||||
var sql = "update users set name='John' where id = 1"
|
||||
await rdb.raw(sql).exec()
|
||||
|
||||
sql = "select * from users where id = 1"
|
||||
echo await rdb.raw(sql).get()
|
||||
@@ -0,0 +1,21 @@
|
||||
import std/strutils
|
||||
import ../src/allographer/connection
|
||||
|
||||
let
|
||||
maxConnections = 95
|
||||
timeout = 30
|
||||
mysqlUrl = "mysql://user:pass@mysql:3306/database"
|
||||
mariadbUrl = "mariadb://user:pass@mariadb:3306/database"
|
||||
pgUrl = "postgresql://user:pass@postgres:5432/database"
|
||||
|
||||
# rdb* = dbOpen(SQLite3, sqliteHost, maxConnections=maxConnections, shouldDisplayLog=false)
|
||||
rdb* = dbOpen(SQLite3, ":memory:", maxConnections=maxConnections, shouldDisplayLog=false)
|
||||
# rdb* = dbOpen(MySQL, mysqlUrl, maxConnections, timeout, shouldDisplayLog=true)
|
||||
# rdb* = dbOpen(MariaDB, mariadbUrl, maxConnections, timeout, shouldDisplayLog=true)
|
||||
# rdb* = dbOpen(PostgreSQL, pgUrl, maxConnections, timeout, shouldDisplayLog=true)
|
||||
|
||||
template asyncBlock*(body:untyped) =
|
||||
(proc(){.async.}=
|
||||
body
|
||||
)()
|
||||
.waitFor()
|
||||
@@ -0,0 +1,12 @@
|
||||
SQLITE_HOST="/root/project/example/db.sqlite3"
|
||||
# SQLITE_HOST=":memory:"
|
||||
PG_URL="postgresql://user:pass@postgres:5432/database"
|
||||
MYSQL_URL="mysql://user:pass@mysql:3306/database"
|
||||
MARIA_URL="mariadb://user:pass@mariadb:3306/database"
|
||||
DB_MAX_CONNECTION=95
|
||||
DB_TIMEOUT=30
|
||||
|
||||
# Logging
|
||||
LOG_IS_DISPLAY=true
|
||||
LOG_IS_FILE=false
|
||||
LOG_DIR="/root/project/example/logs"
|
||||
@@ -0,0 +1,17 @@
|
||||
import std/asyncdispatch
|
||||
import std/os
|
||||
import std/strutils
|
||||
import ../../src/allographer/connection
|
||||
|
||||
let
|
||||
pgUrl = getEnv("PG_URL")
|
||||
mariaUrl = getEnv("MARIA_URL")
|
||||
mysqlUrl = getEnv("MYSQL_URL")
|
||||
maxConnections = getEnv("DB_MAX_CONNECTION").parseInt
|
||||
timeout = getEnv("DB_TIMEOUT").parseInt
|
||||
|
||||
# let rdb* = dbOpen(SQLite3, "./db.sqlite3", shouldDisplayLog=true)
|
||||
let rdb* = dbOpen(PostgreSQL, pgUrl, maxConnections, timeout, shouldDisplayLog=true)
|
||||
# let rdb* = dbOpen(Mariadb, mariaUrl, maxConnections, timeout, shouldDisplayLog=true)
|
||||
# let rdb* = dbOpen(MySQL, mysqlUrl, maxConnections, timeout, shouldDisplayLog=true)
|
||||
# let rdb* = dbOpen(SurrealDB, "test", "test", "user", "pass", "http://surreal", 8000, 5, 30, shouldDisplayLog=true).waitFor()
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
nim c -d:reset --threads:off ./migrations/migrate.nim
|
||||
nim c --threads:off ./seeder/develop
|
||||
|
||||
./migrations/migrate
|
||||
./seeder/develop
|
||||
@@ -0,0 +1,42 @@
|
||||
import std/json
|
||||
import ../../../src/allographer/schema_builder
|
||||
import ../connection
|
||||
|
||||
proc createAllTypeTable*() =
|
||||
## 0002
|
||||
rdb.create([
|
||||
table("IntRelation", [
|
||||
Column.increments("id")
|
||||
]),
|
||||
table("StrRelation", [
|
||||
Column.uuid("uuid")
|
||||
]),
|
||||
table("Types", [
|
||||
Column.increments("id"),
|
||||
Column.integer("integer"),
|
||||
Column.smallInteger("smallInteger"),
|
||||
Column.mediumInteger("mediumInteger"),
|
||||
Column.bigInteger("bigInteger"),
|
||||
Column.decimal("decimal", 10, 3),
|
||||
Column.double("double", 10, 3),
|
||||
Column.float("float"),
|
||||
Column.uuid("uuid"),
|
||||
Column.char("char", 255),
|
||||
Column.string("string"),
|
||||
Column.text("text"),
|
||||
Column.mediumText("mediumText"),
|
||||
Column.longText("longText"),
|
||||
Column.date("date"),
|
||||
Column.datetime("datetime"),
|
||||
Column.time("time"),
|
||||
Column.timestamp("timestamp"),
|
||||
Column.timestamps(),
|
||||
Column.softDelete(),
|
||||
Column.binary("binary"),
|
||||
Column.boolean("boolean"),
|
||||
Column.enumField("enumField", ["A", "B", "C"]),
|
||||
Column.json("json"),
|
||||
Column.foreign("int_relation_id").reference("id").onTable("IntRelation").onDelete(SET_NULL),
|
||||
Column.strForeign("str_relation_id").reference("uuid").onTable("StrRelation").onDelete(SET_NULL)
|
||||
]),
|
||||
])
|
||||
@@ -0,0 +1,23 @@
|
||||
import ../../../src/allographer/schema_builder
|
||||
import ../connection
|
||||
|
||||
proc initDatabaase*() =
|
||||
## 0001
|
||||
rdb.create([
|
||||
table("user", [
|
||||
Column.uuid("id").index().comment("User ID"),
|
||||
Column.string("name").comment("User name"),
|
||||
Column.string("email").comment("User email address"),
|
||||
Column.string("password").comment("User password"),
|
||||
Column.integer("created_at").index().comment("Created at"),
|
||||
Column.integer("updated_at").index().comment("Updated at"),
|
||||
], "User table"),
|
||||
table("post", [
|
||||
Column.uuid("id").index().comment("Post ID"),
|
||||
Column.string("title").comment("Post title"),
|
||||
Column.string("content").comment("Post content"),
|
||||
Column.strForeign("user_id").reference("id").onTable("user").comment("User ID"),
|
||||
Column.integer("created_at").index().comment("Created at"),
|
||||
Column.integer("updated_at").index().comment("Updated at"),
|
||||
], "Post table"),
|
||||
])
|
||||
@@ -0,0 +1,12 @@
|
||||
import std/asyncdispatch
|
||||
import ../../../src/allographer/schema_builder
|
||||
import ../connection
|
||||
import ./init_databaase
|
||||
import ./create_all_type_table
|
||||
|
||||
proc migrate*() =
|
||||
initDatabaase()
|
||||
createAllTypeTable()
|
||||
|
||||
migrate()
|
||||
createSchema(rdb).waitFor()
|
||||
@@ -0,0 +1,5 @@
|
||||
nim c --threads:off ./migrations/migrate.nim
|
||||
nim c --threads:off database/seeder/production
|
||||
|
||||
./migrations/migrate
|
||||
APP_ENV=production ./database/seeder/production
|
||||
@@ -0,0 +1,67 @@
|
||||
import std/json
|
||||
|
||||
type IntRelationTable* = object
|
||||
## IntRelation
|
||||
id*: int
|
||||
|
||||
|
||||
type StrRelationTable* = object
|
||||
## StrRelation
|
||||
uuid*: string
|
||||
|
||||
|
||||
type UserTable* = object
|
||||
## user
|
||||
id*: string
|
||||
name*: string
|
||||
email*: string
|
||||
password*: string
|
||||
created_at*: int
|
||||
updated_at*: int
|
||||
|
||||
|
||||
type AuthTable* = object
|
||||
## Auth
|
||||
id*: int
|
||||
auth*: string
|
||||
|
||||
|
||||
type TypesTable* = object
|
||||
## Types
|
||||
id*: int
|
||||
integer*: int
|
||||
smallInteger*: int
|
||||
mediumInteger*: int
|
||||
bigInteger*: int
|
||||
decimal*: float
|
||||
double*: float
|
||||
float*: float
|
||||
uuid*: string
|
||||
char*: string
|
||||
string*: string
|
||||
text*: string
|
||||
mediumText*: string
|
||||
longText*: string
|
||||
date*: string
|
||||
datetime*: string
|
||||
time*: string
|
||||
timestamp*: string
|
||||
created_at*: string
|
||||
updated_at*: string
|
||||
deleted_at*: string
|
||||
binary*: string
|
||||
boolean*: bool
|
||||
enumField*: string
|
||||
json*: JsonNode
|
||||
int_relation_id*: int
|
||||
str_relation_id*: string
|
||||
|
||||
|
||||
type PostTable* = object
|
||||
## post
|
||||
id*: string
|
||||
title*: string
|
||||
content*: string
|
||||
user_id*: string
|
||||
created_at*: int
|
||||
updated_at*: int
|
||||
@@ -0,0 +1,32 @@
|
||||
import std/json
|
||||
import std/strformat
|
||||
import std/asyncdispatch
|
||||
import std/oids
|
||||
import std/times
|
||||
import ../../../../src/allographer/query_builder
|
||||
import ../../connection
|
||||
import ../../schema
|
||||
|
||||
proc postSeeder*() {.async.} =
|
||||
seeder(rdb, "post"):
|
||||
let postCount = rdb.table("post").count().await
|
||||
if postCount > 0:
|
||||
return
|
||||
|
||||
let users = rdb.table("user").get().orm(UserTable).await
|
||||
if users.len == 0:
|
||||
raise newException(ValueError, "No users found in database")
|
||||
|
||||
var postList: seq[JsonNode]
|
||||
for i in 1..users.len:
|
||||
let row = PostTable(
|
||||
id: $genOid(),
|
||||
title: &"post {i}",
|
||||
content: &"content {i}",
|
||||
user_id: users[i-1].id,
|
||||
created_at: now().toTime().toUnix().int,
|
||||
updated_at: now().toTime().toUnix().int
|
||||
)
|
||||
postList.add(%row)
|
||||
|
||||
rdb.table("post").insert(postList).await
|
||||
@@ -0,0 +1,24 @@
|
||||
import std/json
|
||||
import std/strformat
|
||||
import std/asyncdispatch
|
||||
import std/oids
|
||||
import std/times
|
||||
import ../../../../src/allographer/query_builder
|
||||
import ../../connection
|
||||
import ../../schema
|
||||
|
||||
proc userSeeder*() {.async.} =
|
||||
seeder(rdb, "user"):
|
||||
var userList: seq[JsonNode]
|
||||
for i in 1..10:
|
||||
let row = UserTable(
|
||||
id: $genOid(),
|
||||
name: &"user {i}",
|
||||
email: &"user{i}@example.com",
|
||||
password: &"password{i}",
|
||||
created_at: now().toTime().toUnix().int,
|
||||
updated_at: now().toTime().toUnix().int,
|
||||
)
|
||||
userList.add(%row)
|
||||
|
||||
rdb.table("user").insert(userList).await
|
||||
@@ -0,0 +1,16 @@
|
||||
import std/asyncdispatch
|
||||
import std/os
|
||||
import ./data/user_seeder
|
||||
import ./data/post_seeder
|
||||
|
||||
|
||||
proc seed() {.async.} =
|
||||
let env = getEnv("APP_ENV")
|
||||
if env != "develop":
|
||||
raise newException(CatchableError, "This command is only available in the develop environment")
|
||||
|
||||
userSeeder().await
|
||||
postSeeder().await
|
||||
|
||||
|
||||
seed().waitFor()
|
||||
@@ -0,0 +1,14 @@
|
||||
import std/asyncdispatch
|
||||
import std/os
|
||||
import ./data/user_seeder
|
||||
import ./data/post_seeder
|
||||
|
||||
proc seed() =
|
||||
let env = getEnv("APP_ENV")
|
||||
if env != "production":
|
||||
raise newException(Exception, "This command is only available in the production environment")
|
||||
|
||||
userSeeder().waitFor()
|
||||
postSeeder().waitFor()
|
||||
|
||||
seed()
|
||||
@@ -0,0 +1,14 @@
|
||||
import std/asyncdispatch
|
||||
import std/os
|
||||
import ./data/user_seeder
|
||||
import ./data/post_seeder
|
||||
|
||||
proc seed() =
|
||||
let env = getEnv("APP_ENV")
|
||||
if env != "staging":
|
||||
raise newException(Exception, "This command is only available in the staging environment")
|
||||
|
||||
userSeeder().waitFor()
|
||||
postSeeder().waitFor()
|
||||
|
||||
seed()
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
nim c -d:reset --threads:off./migrations/migrate.nim
|
||||
nim c --threads:off database/seeder/staging
|
||||
|
||||
./migrations/migrate
|
||||
APP_ENV=staging ./database/seeder/staging
|
||||
@@ -0,0 +1,17 @@
|
||||
import json
|
||||
import std/asyncdispatch
|
||||
import std/options
|
||||
import ../../src/allographer/query_builder
|
||||
import ../connections
|
||||
|
||||
type Repository* = ref object
|
||||
rdb*: SqliteConnections
|
||||
|
||||
proc newRepository*(): Repository =
|
||||
Repository(rdb: rdb)
|
||||
|
||||
proc getUsers*(this: Repository): seq[JsonNode] =
|
||||
this.rdb.table("users").get().waitFor()
|
||||
|
||||
proc getUser*(this: Repository, id: int): Option[JsonNode] =
|
||||
this.rdb.table("users").find(id).waitFor()
|
||||
@@ -0,0 +1,18 @@
|
||||
import json
|
||||
import std/options
|
||||
import ../../src/allographer/query_builder
|
||||
import repository
|
||||
|
||||
type Service = ref object
|
||||
repository:Repository
|
||||
|
||||
proc newService*():Service =
|
||||
return Service(
|
||||
repository: newRepository()
|
||||
)
|
||||
|
||||
proc getUsers*(this:Service):seq[JsonNode] =
|
||||
return this.repository.getUsers()
|
||||
|
||||
proc getUser*(this:Service, id:int):Option[JsonNode] =
|
||||
return this.repository.getUser(id)
|
||||
@@ -0,0 +1,126 @@
|
||||
# nim c -r --threads:off -d:reset example/mariadb/benchmark.nim
|
||||
|
||||
import std/asyncdispatch
|
||||
import std/json
|
||||
import std/os
|
||||
import std/random
|
||||
import std/strutils
|
||||
import std/monotimes
|
||||
import std/times
|
||||
import ../../src/allographer/connection
|
||||
import ../../src/allographer/query_builder
|
||||
import ../../src/allographer/schema_builder
|
||||
|
||||
|
||||
randomize()
|
||||
|
||||
const
|
||||
range1_10000 = 1..10000
|
||||
countNum = 500
|
||||
shouldDisplayLog = false
|
||||
selectSql = "SELECT `index` as id, `randomNumber` FROM `World` WHERE `index` = ?"
|
||||
updateSql = "UPDATE `World` SET `randomNumber` = ? WHERE `index` = ?"
|
||||
|
||||
|
||||
let
|
||||
maxConnections = getEnv("DB_MAX_CONNECTION", "95").parseInt
|
||||
timeout = getEnv("DB_TIMEOUT", "30").parseInt
|
||||
|
||||
mariaUrl = getEnv("MARIA_URL")
|
||||
|
||||
|
||||
proc timeProcess(name: string, cb: proc(): Future[void]) {.async.} =
|
||||
var eachTime = 0.0
|
||||
var sumTime = 0.0
|
||||
const repeatCount = 5
|
||||
var resultStr = ""
|
||||
|
||||
for i in 1..repeatCount:
|
||||
sleep(100)
|
||||
let start = getMonoTime()
|
||||
await cb()
|
||||
eachTime = float64((getMonoTime() - start).inMilliseconds) / 1000.0
|
||||
sumTime += eachTime
|
||||
if i > 1: resultStr.add("\n")
|
||||
resultStr.add("|" & $i & "|" & $eachTime & "|")
|
||||
|
||||
echo name
|
||||
echo "|num|time|"
|
||||
echo "|---|---|"
|
||||
echo resultStr
|
||||
echo "|Avg|" & $(sumTime / repeatCount) & "|"
|
||||
echo ""
|
||||
|
||||
|
||||
proc mariaBenchmarkScenario(rdb: MariadbConnections) {.async.} =
|
||||
rdb.create(
|
||||
table("World", [
|
||||
Column.increments("index"),
|
||||
Column.integer("randomNumber").default(0)
|
||||
])
|
||||
)
|
||||
seeder(rdb, "World"):
|
||||
var data = newSeq[JsonNode]()
|
||||
for i in range1_10000:
|
||||
data.add(
|
||||
%*{"randomNumber": rand(range1_10000)}
|
||||
)
|
||||
await rdb.table("World").insert(data)
|
||||
|
||||
proc benchUpdate() {.async.} =
|
||||
var futures = newSeq[Future[void]](countNum)
|
||||
for i in 1..countNum:
|
||||
let index = rand(range1_10000)
|
||||
let number = rand(range1_10000)
|
||||
futures[i - 1] = (proc(): Future[void] {.async.} =
|
||||
discard rdb.select("index as id", "randomNumber").table("World").where("index", "=", index).first().await
|
||||
rdb.table("World").where("index", "=", index).update(%*{"randomNumber": number}).await
|
||||
)()
|
||||
await all(futures)
|
||||
|
||||
proc benchUpdatePreparedCold() {.async.} =
|
||||
let selectStmt = rdb.prepare(selectSql)
|
||||
let updateStmt = rdb.prepare(updateSql)
|
||||
defer:
|
||||
selectStmt.close().await
|
||||
updateStmt.close().await
|
||||
var futures = newSeq[Future[void]](countNum)
|
||||
for i in 1..countNum:
|
||||
let index = rand(range1_10000)
|
||||
let number = rand(range1_10000)
|
||||
futures[i - 1] = (proc(): Future[void] {.async.} =
|
||||
rdb.withConn(
|
||||
proc(ctx: MariadbPreparedContext): Future[void] {.async.} =
|
||||
discard await selectStmt.first(ctx, @[$index])
|
||||
await updateStmt.exec(ctx, @[$number, $index])
|
||||
)
|
||||
)()
|
||||
await all(futures)
|
||||
|
||||
let selectStmtWarm = rdb.prepare(selectSql)
|
||||
let updateStmtWarm = rdb.prepare(updateSql)
|
||||
|
||||
proc benchUpdatePreparedWarm() {.async.} =
|
||||
var futures = newSeq[Future[void]](countNum)
|
||||
for i in 1..countNum:
|
||||
let index = rand(range1_10000)
|
||||
let number = rand(range1_10000)
|
||||
futures[i - 1] = (proc(): Future[void] {.async.} =
|
||||
rdb.withConn(
|
||||
proc(ctx: MariadbPreparedContext): Future[void] {.async.} =
|
||||
discard await selectStmtWarm.first(ctx, @[$index])
|
||||
await updateStmtWarm.exec(ctx, @[$number, $index])
|
||||
)
|
||||
)()
|
||||
await all(futures)
|
||||
|
||||
await timeProcess("mariadb benchmark", benchUpdate)
|
||||
await timeProcess("mariadb benchmark prepared cold", benchUpdatePreparedCold)
|
||||
await timeProcess("mariadb benchmark prepared warm", benchUpdatePreparedWarm)
|
||||
|
||||
|
||||
proc main() =
|
||||
let rdb = dbOpen(MariaDB, mariaUrl, maxConnections, timeout, shouldDisplayLog=shouldDisplayLog)
|
||||
mariaBenchmarkScenario(rdb).waitFor
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,164 @@
|
||||
// apt install -y libcurl4-openssl-dev
|
||||
// gcc test.c -o test -lmariadb -lcurl && ./test
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <mariadb/mysql.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
struct MemoryStruct {
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
|
||||
size_t realsize = size * nmemb;
|
||||
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
|
||||
|
||||
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
|
||||
if (mem->memory == NULL) {
|
||||
fprintf(stderr, "Not enough memory (realloc returned NULL)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
||||
mem->size += realsize;
|
||||
mem->memory[mem->size] = 0;
|
||||
|
||||
return realsize;
|
||||
}
|
||||
|
||||
int main() {
|
||||
MYSQL *conn;
|
||||
MYSQL_STMT *stmt;
|
||||
MYSQL_BIND bind[5];
|
||||
my_bool is_null[5] = {0};
|
||||
unsigned long length[5];
|
||||
|
||||
// MariaDBに接続するための設定
|
||||
const char *host = "mariadb";
|
||||
const char *user = "user";
|
||||
const char *password = "pass";
|
||||
const char *database = "database";
|
||||
|
||||
conn = mysql_init(NULL);
|
||||
if (conn == NULL) {
|
||||
fprintf(stderr, "mysql_init() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (mysql_real_connect(conn, host, user, password, database, 0, NULL, 0) == NULL) {
|
||||
fprintf(stderr, "mysql_real_connect() failed\n");
|
||||
mysql_close(conn);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// テーブルを削除
|
||||
if (mysql_query(conn, "DROP TABLE IF EXISTS `test`")) {
|
||||
fprintf(stderr, "DROP TABLE failed. Error: %s\n", mysql_error(conn));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// テーブルを作成
|
||||
if (mysql_query(conn, "CREATE TABLE IF NOT EXISTS `test` ("
|
||||
"`bool` BOOLEAN,"
|
||||
"`int` INT,"
|
||||
"`float` DOUBLE,"
|
||||
"`str` VARCHAR(255),"
|
||||
"`data` BLOB)")) {
|
||||
fprintf(stderr, "CREATE TABLE failed. Error: %s\n", mysql_error(conn));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
struct MemoryStruct chunk;
|
||||
chunk.memory = malloc(1);
|
||||
chunk.size = 0;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "https://nim-lang.org/assets/img/twitter_banner.png");
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
curl_global_cleanup();
|
||||
|
||||
// データを挿入
|
||||
stmt = mysql_stmt_init(conn);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, "mysql_stmt_init() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char *insert_query = "INSERT INTO `test` (`bool`, `int`, `float`, `str`, `data`) VALUES (?, ?, ?, ?, ?)";
|
||||
if (mysql_stmt_prepare(stmt, insert_query, strlen(insert_query))) {
|
||||
fprintf(stderr, "mysql_stmt_prepare() failed. Error: %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(bind, 0, sizeof(bind));
|
||||
|
||||
my_bool bool_value = 1;
|
||||
int int_value = 1;
|
||||
double float_value = 1.1;
|
||||
char str_value[255] = "alice";
|
||||
length[0] = sizeof(bool_value);
|
||||
length[1] = sizeof(int_value);
|
||||
length[2] = sizeof(float_value);
|
||||
length[3] = strlen(str_value);
|
||||
length[4] = chunk.size;
|
||||
|
||||
bind[0].buffer_type = MYSQL_TYPE_TINY;
|
||||
bind[0].buffer = (char *)&bool_value;
|
||||
bind[0].is_null = &is_null[0];
|
||||
bind[0].length = &length[0];
|
||||
|
||||
bind[1].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[1].buffer = (char *)&int_value;
|
||||
bind[1].is_null = &is_null[1];
|
||||
bind[1].length = &length[1];
|
||||
|
||||
bind[2].buffer_type = MYSQL_TYPE_DOUBLE;
|
||||
bind[2].buffer = (char *)&float_value;
|
||||
bind[2].is_null = &is_null[2];
|
||||
bind[2].length = &length[2];
|
||||
|
||||
bind[3].buffer_type = MYSQL_TYPE_STRING;
|
||||
bind[3].buffer = (char *)str_value;
|
||||
bind[3].buffer_length = sizeof(str_value);
|
||||
bind[3].is_null = &is_null[3];
|
||||
bind[3].length = &length[3];
|
||||
|
||||
bind[4].buffer_type = MYSQL_TYPE_BLOB;
|
||||
bind[4].buffer = (char *)chunk.memory;
|
||||
bind[4].buffer_length = chunk.size;
|
||||
bind[4].is_null = &is_null[4];
|
||||
bind[4].length = &length[4];
|
||||
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, "mysql_stmt_bind_param() failed. Error: %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, "mysql_stmt_execute() failed. Error: %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
mysql_close(conn);
|
||||
free(chunk.memory);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import json
|
||||
import ../src/allographer/schema_builder
|
||||
import connections
|
||||
|
||||
|
||||
# migration
|
||||
rdb.create([
|
||||
table("Auth",[
|
||||
Column.increments("id"),
|
||||
Column.string("auth")
|
||||
]),
|
||||
table("Users",[
|
||||
Column.increments("id"),
|
||||
Column.uuid("uuid"),
|
||||
Column.string("oid").index().nullable(),
|
||||
Column.string("oid2").index().nullable(),
|
||||
Column.string("Name").nullable(),
|
||||
Column.date("birth_date").nullable(),
|
||||
Column.foreign("auth_id").reference("id").onTable("Auth").onDelete(SET_NULL).default(1)
|
||||
]),
|
||||
])
|
||||
|
||||
rdb.alter([
|
||||
table("Users", [
|
||||
# add column
|
||||
Column.string("aaa").default("").add(),
|
||||
Column.foreign("bbb").reference("id").onTable("Auth").onDelete(SET_NULL).add(),
|
||||
# change column definition
|
||||
Column.string("aaa").nullable().change(),
|
||||
# change column name
|
||||
Column.renameColumn("aaa", "ccc"),
|
||||
# delete column
|
||||
Column.dropColumn("ccc"),
|
||||
Column.dropColumn("bbb"),
|
||||
]),
|
||||
# change table name
|
||||
table("Users").renameTo("members"),
|
||||
])
|
||||
|
||||
# drop table
|
||||
rdb.drop(table("members"))
|
||||
@@ -0,0 +1,164 @@
|
||||
// apt install -y libcurl4-openssl-dev
|
||||
// gcc test.c -o test -lmariadb -lcurl && ./test
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <mariadb/mysql.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
struct MemoryStruct {
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
|
||||
size_t realsize = size * nmemb;
|
||||
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
|
||||
|
||||
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
|
||||
if (mem->memory == NULL) {
|
||||
fprintf(stderr, "Not enough memory (realloc returned NULL)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
||||
mem->size += realsize;
|
||||
mem->memory[mem->size] = 0;
|
||||
|
||||
return realsize;
|
||||
}
|
||||
|
||||
int main() {
|
||||
MYSQL *conn;
|
||||
MYSQL_STMT *stmt;
|
||||
MYSQL_BIND bind[5];
|
||||
my_bool is_null[5] = {0};
|
||||
unsigned long length[5];
|
||||
|
||||
// MariaDBに接続するための設定
|
||||
const char *host = "mariadb";
|
||||
const char *user = "user";
|
||||
const char *password = "pass";
|
||||
const char *database = "database";
|
||||
|
||||
conn = mysql_init(NULL);
|
||||
if (conn == NULL) {
|
||||
fprintf(stderr, "mysql_init() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (mysql_real_connect(conn, host, user, password, database, 0, NULL, 0) == NULL) {
|
||||
fprintf(stderr, "mysql_real_connect() failed\n");
|
||||
mysql_close(conn);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// テーブルを削除
|
||||
if (mysql_query(conn, "DROP TABLE IF EXISTS `test`")) {
|
||||
fprintf(stderr, "DROP TABLE failed. Error: %s\n", mysql_error(conn));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// テーブルを作成
|
||||
if (mysql_query(conn, "CREATE TABLE IF NOT EXISTS `test` ("
|
||||
"`bool` BOOLEAN,"
|
||||
"`int` INT,"
|
||||
"`float` DOUBLE,"
|
||||
"`str` VARCHAR(255),"
|
||||
"`data` BLOB)")) {
|
||||
fprintf(stderr, "CREATE TABLE failed. Error: %s\n", mysql_error(conn));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
struct MemoryStruct chunk;
|
||||
chunk.memory = malloc(1);
|
||||
chunk.size = 0;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "https://nim-lang.org/assets/img/twitter_banner.png");
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
curl_global_cleanup();
|
||||
|
||||
// データを挿入
|
||||
stmt = mysql_stmt_init(conn);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, "mysql_stmt_init() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char *insert_query = "INSERT INTO `test` (`bool`, `int`, `float`, `str`, `data`) VALUES (?, ?, ?, ?, ?)";
|
||||
if (mysql_stmt_prepare(stmt, insert_query, strlen(insert_query))) {
|
||||
fprintf(stderr, "mysql_stmt_prepare() failed. Error: %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(bind, 0, sizeof(bind));
|
||||
|
||||
my_bool bool_value = 1;
|
||||
int int_value = 1;
|
||||
double float_value = 1.1;
|
||||
char str_value[255] = "alice";
|
||||
length[0] = sizeof(bool_value);
|
||||
length[1] = sizeof(int_value);
|
||||
length[2] = sizeof(float_value);
|
||||
length[3] = strlen(str_value);
|
||||
length[4] = chunk.size;
|
||||
|
||||
bind[0].buffer_type = MYSQL_TYPE_TINY;
|
||||
bind[0].buffer = (char *)&bool_value;
|
||||
bind[0].is_null = &is_null[0];
|
||||
bind[0].length = &length[0];
|
||||
|
||||
bind[1].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[1].buffer = (char *)&int_value;
|
||||
bind[1].is_null = &is_null[1];
|
||||
bind[1].length = &length[1];
|
||||
|
||||
bind[2].buffer_type = MYSQL_TYPE_DOUBLE;
|
||||
bind[2].buffer = (char *)&float_value;
|
||||
bind[2].is_null = &is_null[2];
|
||||
bind[2].length = &length[2];
|
||||
|
||||
bind[3].buffer_type = MYSQL_TYPE_STRING;
|
||||
bind[3].buffer = (char *)str_value;
|
||||
bind[3].buffer_length = sizeof(str_value);
|
||||
bind[3].is_null = &is_null[3];
|
||||
bind[3].length = &length[3];
|
||||
|
||||
bind[4].buffer_type = MYSQL_TYPE_BLOB;
|
||||
bind[4].buffer = (char *)chunk.memory;
|
||||
bind[4].buffer_length = chunk.size;
|
||||
bind[4].is_null = &is_null[4];
|
||||
bind[4].length = &length[4];
|
||||
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, "mysql_stmt_bind_param() failed. Error: %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, "mysql_stmt_execute() failed. Error: %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
mysql_close(conn);
|
||||
free(chunk.memory);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
# nim c -r --threads:off -d:reset example/postgres/benchmark.nim
|
||||
|
||||
import std/asyncdispatch
|
||||
import std/json
|
||||
import std/os
|
||||
import std/random
|
||||
import std/strutils
|
||||
import std/monotimes
|
||||
import std/times
|
||||
import ../../src/allographer/connection
|
||||
import ../../src/allographer/query_builder
|
||||
import ../../src/allographer/schema_builder
|
||||
|
||||
|
||||
randomize()
|
||||
|
||||
const
|
||||
range1_10000 = 1..10000
|
||||
countNum = 500
|
||||
shouldDisplayLog = false
|
||||
pgUrl = "postgresql://user:pass@postgres:5432/database"
|
||||
selectSql = """SELECT "index" as id, "randomNumber" FROM "World" WHERE "index" = ?"""
|
||||
updateSql = """UPDATE "World" SET "randomNumber" = ? WHERE "index" = ?"""
|
||||
maxConnections = 95
|
||||
timeout = 30
|
||||
|
||||
let rdb = dbOpen(PostgreSQL, pgUrl, maxConnections, timeout, shouldDisplayLog=shouldDisplayLog)
|
||||
|
||||
|
||||
proc timeProcess(name: string, cb: proc(): Future[void]) {.async.} =
|
||||
var eachTime = 0.0
|
||||
var sumTime = 0.0
|
||||
const repeatCount = 5
|
||||
var resultStr = ""
|
||||
|
||||
for i in 1..repeatCount:
|
||||
sleep(100)
|
||||
let start = getMonoTime()
|
||||
await cb()
|
||||
eachTime = float64((getMonoTime() - start).inMilliseconds) / 1000.0
|
||||
sumTime += eachTime
|
||||
if i > 1: resultStr.add("\n")
|
||||
resultStr.add("|" & $i & "|" & $eachTime & "|")
|
||||
|
||||
echo name
|
||||
echo "|num|time|"
|
||||
echo "|---|---|"
|
||||
echo resultStr
|
||||
echo "|Avg|" & $(sumTime / repeatCount) & "|"
|
||||
echo ""
|
||||
|
||||
|
||||
rdb.create(
|
||||
table("World", [
|
||||
Column.increments("index"),
|
||||
Column.integer("randomNumber").default(0)
|
||||
])
|
||||
)
|
||||
seeder(rdb, "World"):
|
||||
var data = newSeq[JsonNode]()
|
||||
for i in range1_10000:
|
||||
data.add(
|
||||
%*{"randomNumber": rand(range1_10000)}
|
||||
)
|
||||
rdb.table("World").insert(data).waitFor
|
||||
|
||||
|
||||
proc benchUpdate() {.async.} =
|
||||
var futures = newSeq[Future[void]](countNum)
|
||||
for i in 1..countNum:
|
||||
let index = rand(range1_10000)
|
||||
let number = rand(range1_10000)
|
||||
futures[i - 1] = (proc(): Future[void] {.async.} =
|
||||
discard rdb.select("index as id", "randomNumber").table("World").where("index", "=", index).first().await
|
||||
rdb.table("World").where("index", "=", index).update(%*{"randomNumber": number}).await
|
||||
)()
|
||||
await all(futures)
|
||||
|
||||
|
||||
proc benchUpdatePreparedCold() {.async.} =
|
||||
let selectStmt = rdb.prepare(selectSql)
|
||||
let updateStmt = rdb.prepare(updateSql)
|
||||
defer:
|
||||
selectStmt.close().await
|
||||
updateStmt.close().await
|
||||
var futures = newSeq[Future[void]](countNum)
|
||||
for i in 1..countNum:
|
||||
let index = rand(range1_10000)
|
||||
let number = rand(range1_10000)
|
||||
futures[i - 1] = (proc(): Future[void] {.async.} =
|
||||
rdb.withConn(
|
||||
proc(ctx: PostgresPreparedContext): Future[void] {.async.} =
|
||||
discard await selectStmt.first(ctx, @[$index])
|
||||
await updateStmt.exec(ctx, @[$number, $index])
|
||||
)
|
||||
)()
|
||||
await all(futures)
|
||||
|
||||
|
||||
let selectStmtWarm = rdb.prepare(selectSql)
|
||||
let updateStmtWarm = rdb.prepare(updateSql)
|
||||
|
||||
proc benchUpdatePreparedWarm() {.async.} =
|
||||
var futures = newSeq[Future[void]](countNum)
|
||||
for i in 1..countNum:
|
||||
let index = rand(range1_10000)
|
||||
let number = rand(range1_10000)
|
||||
futures[i - 1] = (proc(): Future[void] {.async.} =
|
||||
rdb.withConn(
|
||||
proc(ctx: PostgresPreparedContext): Future[void] {.async.} =
|
||||
discard await selectStmtWarm.first(ctx, @[$index])
|
||||
await updateStmtWarm.exec(ctx, @[$number, $index])
|
||||
)
|
||||
)()
|
||||
await all(futures)
|
||||
|
||||
|
||||
proc main(){.async.} =
|
||||
await timeProcess("postgres benchmark", benchUpdate)
|
||||
await timeProcess("postgres benchmark prepared cold", benchUpdatePreparedCold)
|
||||
await timeProcess("postgres benchmark prepared warm", benchUpdatePreparedWarm)
|
||||
|
||||
main().waitFor
|
||||
@@ -0,0 +1,147 @@
|
||||
// gcc -I/usr/include/postgresql -I/usr/local/include/curl -o test test.c -lpq -lcurl && ./test
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <libpq-fe.h>
|
||||
#include <string.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
struct MemoryStruct
|
||||
{
|
||||
unsigned char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
size_t realsize = size * nmemb;
|
||||
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
|
||||
|
||||
mem->memory = realloc(mem->memory, mem->size + realsize);
|
||||
if (mem->memory == NULL)
|
||||
{
|
||||
/* out of memory! */
|
||||
printf("not enough memory (realloc returned NULL)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
||||
mem->size += realsize;
|
||||
|
||||
return realsize;
|
||||
}
|
||||
|
||||
void exit_nicely(PGconn *conn)
|
||||
{
|
||||
PQfinish(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
// ##################################################
|
||||
// # Binary image
|
||||
// ##################################################
|
||||
|
||||
CURL *curl_handle;
|
||||
CURLcode curlRes;
|
||||
|
||||
struct MemoryStruct chunk;
|
||||
|
||||
chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
|
||||
chunk.size = 0; /* no data at this point */
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
/* init the curl session */
|
||||
curl_handle = curl_easy_init();
|
||||
|
||||
/* specify URL to get */
|
||||
curl_easy_setopt(curl_handle, CURLOPT_URL, "https://nim-lang.org/assets/img/twitter_banner.png");
|
||||
|
||||
/* send all data to this function */
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
||||
|
||||
/* we pass our 'chunk' struct to the callback function */
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
|
||||
|
||||
/* some servers don't like requests that are made without a user-agent
|
||||
field, so we provide one */
|
||||
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
||||
|
||||
/* get it! */
|
||||
curlRes = curl_easy_perform(curl_handle);
|
||||
|
||||
/* check for errors */
|
||||
if (curlRes != CURLE_OK)
|
||||
{
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(curlRes));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%lu bytes retrieved\n", (long)chunk.size);
|
||||
}
|
||||
|
||||
/* cleanup curl stuff */
|
||||
curl_easy_cleanup(curl_handle);
|
||||
|
||||
/* we're done with libcurl, so clean it up */
|
||||
curl_global_cleanup();
|
||||
|
||||
// ##################################################
|
||||
// # Postgres
|
||||
// ##################################################
|
||||
const char *conninfo;
|
||||
PGconn *conn;
|
||||
PGresult *res;
|
||||
|
||||
// Specify your connection info
|
||||
conninfo = "dbname=database user=user password=pass hostaddr=postgres port=5432";
|
||||
|
||||
// Make a connection to the database
|
||||
// conn = PQconnectdb(conninfo);
|
||||
conn = PQsetdbLogin("postgres", "5432", NULL, NULL, "database", "user", "pass");
|
||||
|
||||
// Check to see that the backend connection was successfully made
|
||||
if (PQstatus(conn) != CONNECTION_OK)
|
||||
{
|
||||
fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
|
||||
exit_nicely(conn);
|
||||
}
|
||||
|
||||
// Your binary data
|
||||
// unsigned char binary_data[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21};
|
||||
unsigned char binary_data[chunk.size];
|
||||
memcpy(binary_data, chunk.memory, chunk.size);
|
||||
int binary_data_size = sizeof(binary_data) / sizeof(binary_data[0]);
|
||||
|
||||
// INSERT query
|
||||
const char *query = "INSERT INTO image (data) VALUES ($1)";
|
||||
|
||||
const char *paramValues[1];
|
||||
int paramLengths[1];
|
||||
int paramFormats[1];
|
||||
|
||||
paramValues[0] = (char *)binary_data;
|
||||
paramLengths[0] = binary_data_size;
|
||||
paramFormats[0] = 1; // binary
|
||||
|
||||
// Execute the INSERT statement
|
||||
res = PQexecParams(conn, query, 1, NULL, paramValues, paramLengths, paramFormats, 1);
|
||||
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||
{
|
||||
fprintf(stderr, "INSERT command failed: %s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
exit_nicely(conn);
|
||||
}
|
||||
|
||||
// Clear result
|
||||
PQclear(res);
|
||||
|
||||
// Close connection
|
||||
PQfinish(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import std/asyncdispatch
|
||||
import std/json
|
||||
import std/random
|
||||
import std/times
|
||||
import ../src/allographer/query_builder
|
||||
import ../src/allographer/schema_builder
|
||||
import ../src/allographer/query_builder/libs/sqlite/sqlite_impl
|
||||
from connections import rdb
|
||||
|
||||
randomize()
|
||||
|
||||
rdb.create(
|
||||
table("num_table", [
|
||||
Column.integer("id"),
|
||||
Column.integer("randomnumber")
|
||||
])
|
||||
)
|
||||
|
||||
seeder rdb, "num_table":
|
||||
var data = newSeq[JsonNode]()
|
||||
for i in 1..10000:
|
||||
data.add(%*{"id": i, "randomnumber": rand(10000)})
|
||||
rdb.table("num_table").insert(data).waitFor
|
||||
|
||||
let start = cpuTime()
|
||||
(proc(){.async.}=
|
||||
let conn = rdb.pools.conns[0].conn
|
||||
let stmt = await conn.prepare("select * from num_table where id = ?", 30)
|
||||
let resultSet = await conn.preparedQuery(@["1"], stmt)
|
||||
echo resultSet[0]
|
||||
)()
|
||||
.waitFor
|
||||
echo cpuTime() - start
|
||||
@@ -0,0 +1,48 @@
|
||||
import std/asyncdispatch
|
||||
import std/json
|
||||
import std/httpclient
|
||||
import std/streams
|
||||
import std/options
|
||||
import ../src/allographer/connection
|
||||
import ../src/allographer/query_builder
|
||||
|
||||
|
||||
proc main() {.async.} =
|
||||
let client = newAsyncHttpClient()
|
||||
let response = client.getContent("https://nim-lang.org/assets/img/twitter_banner.png").await
|
||||
let imageStream = newStringStream(response)
|
||||
let binaryImage = imageStream.readAll()
|
||||
|
||||
|
||||
let rdb = dbOpen(SQLite3, "/root/project/db.sqlite3", shouldDisplayLog=true)
|
||||
echo rdb.type
|
||||
|
||||
rdb.raw("DROP TABLE IF EXISTS \"test\"").exec().await
|
||||
|
||||
rdb.raw("""
|
||||
CREATE TABLE IF NOT EXISTS "test" (
|
||||
'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
'blob' BLOB,
|
||||
'int' INTEGER,
|
||||
'float' NUMERIC,
|
||||
'str' VARCHAR
|
||||
)"""
|
||||
).exec().await
|
||||
|
||||
rdb.table("test").insert(%*{"blob":binaryImage, "int": 1, "float": 1.1, "str": "alice"}).await
|
||||
|
||||
let res = rdb.select("id", "int", "float", "str").table("test").get().await
|
||||
for row in res:
|
||||
echo row
|
||||
|
||||
var row = rdb.select("id", "int", "float", "str").table("test").first().await
|
||||
if row.isSome:
|
||||
echo row.get
|
||||
|
||||
rdb.table("test").where("id", "=", 1).update(%*{"str": "bob"}).await
|
||||
|
||||
row = rdb.select("id", "int", "float", "str").table("test").find(1).await
|
||||
if row.isSome:
|
||||
echo row.get
|
||||
|
||||
main().waitFor
|
||||
@@ -0,0 +1,131 @@
|
||||
import strformat, json, asyncdispatch
|
||||
|
||||
import ../src/allographer/query_builder
|
||||
import ../src/allographer/schema_builder
|
||||
|
||||
from connections import rdb
|
||||
|
||||
rdb.create([
|
||||
table("auth",[
|
||||
Column.increments("id"),
|
||||
Column.string("auth")
|
||||
]),
|
||||
table("users",[
|
||||
Column.increments("id"),
|
||||
Column.string("name").nullable(),
|
||||
Column.string("email").nullable(),
|
||||
Column.string("password").nullable(),
|
||||
Column.string("address").nullable(),
|
||||
Column.date("birth_date").nullable(),
|
||||
Column.foreign("auth_id").reference("id").onTable("auth").onDelete(SET_NULL)
|
||||
])
|
||||
])
|
||||
|
||||
# シーダー
|
||||
seeder rdb, "auth":
|
||||
rdb.table("auth").insert(@[
|
||||
%*{"auth": "admin"},
|
||||
%*{"auth": "user"}
|
||||
])
|
||||
.waitFor()
|
||||
|
||||
seeder rdb, "users":
|
||||
let total = 20
|
||||
var insertData: seq[JsonNode]
|
||||
for i in 1..total:
|
||||
let authId = if i mod 2 == 0: 1 else: 2
|
||||
insertData.add(
|
||||
%*{
|
||||
"name": &"user{i}",
|
||||
"email": &"user{i}@gmail.com",
|
||||
"password": &"password{i}",
|
||||
"auth_id": authId
|
||||
}
|
||||
)
|
||||
|
||||
rdb.table("users").insert(insertData).waitFor()
|
||||
|
||||
echo rdb.table("users").get().waitFor()
|
||||
|
||||
echo rdb
|
||||
.select("users.id", "users.email")
|
||||
.table("users")
|
||||
.where("name", "=", "user3")
|
||||
.orWhere("name", "=", "user4")
|
||||
.orWhere("users.id", "=", 5)
|
||||
.join("auth", "auth.id", "=", "users.auth_id")
|
||||
.limit(10)
|
||||
.get()
|
||||
.waitFor()
|
||||
|
||||
echo rdb.select("id", "email").table("users").limit(5).get().waitFor()
|
||||
echo rdb.select("id", "email").table("users").limit(5).first().waitFor()
|
||||
echo rdb.table("users").find(4).waitFor()
|
||||
echo rdb.select("id", "email").table("users").limit(5).find(3).waitFor()
|
||||
|
||||
echo ""
|
||||
|
||||
rdb.table("users").insert(%*{"name": "John", "email": "John@gmail.com"}).waitFor()
|
||||
echo rdb.table("users").insertId(%*{"name": "John", "email": "John@gmail.com"}).waitFor()
|
||||
|
||||
|
||||
rdb.table("users").insert(
|
||||
@[
|
||||
%*{"name": "John", "email": "John@gmail.com"},
|
||||
%*{"name": "Paul", "email": "Paul@gmail.com"}
|
||||
]
|
||||
)
|
||||
.waitFor()
|
||||
|
||||
rdb.table("users").insert(
|
||||
@[
|
||||
%*{"name": "Mick", "email": "Mick@gmail.com"},
|
||||
%*{"name": "Keith", "password": "KeithPass"}
|
||||
]
|
||||
)
|
||||
.waitFor()
|
||||
|
||||
|
||||
rdb.table("users").where("id", "=", 2).update(%*{"name": "David"}).waitFor()
|
||||
rdb.table("users").where("id", "=", 2).update(%*{"name": "David"}).waitFor()
|
||||
echo rdb.select().table("users").where("name", "=", "David").get().waitFor()
|
||||
echo rdb.table("users").find(2).waitFor()
|
||||
|
||||
rdb.table("users").where("name", "=", "David").delete().waitFor()
|
||||
rdb.table("users").delete(3).waitFor()
|
||||
echo rdb.table("users").find(3).waitFor()
|
||||
echo rdb.table("users").limit(5).get().waitFor()
|
||||
echo rdb.select("name").table("users").where("address", "is", nil).get().waitFor()
|
||||
|
||||
# sql check
|
||||
let r = rdb
|
||||
.select("users.id", "users.email")
|
||||
.table("users")
|
||||
.where("name", "=", "user3")
|
||||
.where("name", "=", "user4")
|
||||
.where("users.id", "=", 5)
|
||||
.orWhere("name", "=", "user6")
|
||||
.orWhere("users.id", "=", 7)
|
||||
.join("auth", "auth.id", "=", "users.auth_id")
|
||||
.limit(10)
|
||||
.get()
|
||||
.waitFor()
|
||||
echo r[0]["id"]
|
||||
echo r[0]["id"].type
|
||||
echo r[0]["email"]
|
||||
echo r[0]["email"].type
|
||||
|
||||
type User = ref object
|
||||
id:int
|
||||
name:string
|
||||
email:string
|
||||
password:string
|
||||
address:string
|
||||
birth_date:string
|
||||
auth_id:int
|
||||
let users = rdb.table("users").limit(5).get().orm(User).waitFor()
|
||||
for user in users:
|
||||
echo user.name
|
||||
|
||||
waitFor rdb.raw("DROP TABLE users").exec()
|
||||
waitFor rdb.raw("DROP TABLE auth").exec()
|
||||
@@ -0,0 +1,55 @@
|
||||
import std/asyncdispatch
|
||||
import std/strformat
|
||||
import std/json
|
||||
import ../src/allographer/query_builder
|
||||
import ../src/allographer/schema_builder
|
||||
from ./connections import rdb
|
||||
|
||||
|
||||
rdb.create([
|
||||
table("auth",[
|
||||
Column.increments("id"),
|
||||
Column.string("name")
|
||||
]),
|
||||
table("users",[
|
||||
Column.increments("user_id"),
|
||||
Column.string("name").nullable(),
|
||||
Column.string("email").nullable(),
|
||||
Column.string("password").nullable(),
|
||||
Column.string("address").nullable(),
|
||||
Column.date("birth_date").nullable(),
|
||||
Column.foreign("auth_id").reference("id").onTable("auth").onDelete(SET_NULL)
|
||||
])
|
||||
])
|
||||
|
||||
# シーダー
|
||||
seeder rdb, "auth":
|
||||
rdb.table("auth").insert(@[
|
||||
%*{"name": "admin"},
|
||||
%*{"name": "user"}
|
||||
])
|
||||
.waitFor
|
||||
|
||||
let total = 20
|
||||
var insertData: seq[JsonNode]
|
||||
for i in 1..total:
|
||||
let authId = if i mod 2 == 0: 1 else: 2
|
||||
insertData.add(
|
||||
%*{
|
||||
"name": &"user{i}",
|
||||
"email": &"user{i}@gmail.com",
|
||||
"password": &"password{i}",
|
||||
"auth_id": authId
|
||||
}
|
||||
)
|
||||
|
||||
rdb.table("users").insert(insertData).waitFor()
|
||||
echo rdb.table("users").get().waitFor()
|
||||
|
||||
echo rdb.table("users").find(2, key="user_id").waitFor()
|
||||
echo rdb.table("auth").find(1).waitFor()
|
||||
|
||||
rdb.table("users").delete(2, key="user_id").waitFor()
|
||||
rdb.table("auth").delete(2).waitFor()
|
||||
echo rdb.table("users").limit(3).get().waitFor()
|
||||
echo rdb.table("auth").limit(3).get().waitFor()
|
||||
@@ -0,0 +1,51 @@
|
||||
import
|
||||
std/strformat,
|
||||
std/json,
|
||||
std/asyncdispatch,
|
||||
../src/allographer/query_builder,
|
||||
../src/allographer/schema_builder
|
||||
|
||||
from ./connections import rdb
|
||||
|
||||
template bench*(msg, body) =
|
||||
block:
|
||||
echo "=== " & msg
|
||||
let start = cpuTime()
|
||||
body
|
||||
echo cpuTime() - start
|
||||
|
||||
proc setup*() =
|
||||
rdb.create(
|
||||
table("auth",[
|
||||
Column.increments("id"),
|
||||
Column.string("auth")
|
||||
]),
|
||||
table("user",[
|
||||
Column.increments("id"),
|
||||
Column.string("name").nullable(),
|
||||
Column.string("email").nullable(),
|
||||
Column.foreign("auth_id").reference("id").onTable("auth").onDelete(SET_NULL)
|
||||
])
|
||||
)
|
||||
|
||||
# seeder
|
||||
seeder(rdb, "auth"):
|
||||
rdb.table("auth").insert(@[
|
||||
%*{"auth": "admin"},
|
||||
%*{"auth": "user"}
|
||||
])
|
||||
.waitFor
|
||||
|
||||
seeder(rdb, "user"):
|
||||
var user: seq[JsonNode]
|
||||
for i in 1..10:
|
||||
let authId = if i mod 2 == 0: 2 else: 1
|
||||
user.add(
|
||||
%*{
|
||||
"name": &"user{i}",
|
||||
"email": &"user{i}@mail.com",
|
||||
"auth_id": authId
|
||||
}
|
||||
)
|
||||
|
||||
rdb.table("user").insert(user).waitFor
|
||||
@@ -0,0 +1,126 @@
|
||||
# nim c -r --threads:off -d:reset example/sqlite/benchmark.nim
|
||||
|
||||
import std/asyncdispatch
|
||||
import std/json
|
||||
import std/os
|
||||
import std/random
|
||||
import std/strutils
|
||||
import std/monotimes
|
||||
import std/times
|
||||
import ../../src/allographer/connection
|
||||
import ../../src/allographer/query_builder
|
||||
import ../../src/allographer/schema_builder
|
||||
|
||||
|
||||
randomize()
|
||||
|
||||
const
|
||||
range1_10000 = 1..10000
|
||||
countNum = 500
|
||||
shouldDisplayLog = false
|
||||
selectSql = "SELECT index as id, randomNumber FROM World WHERE index = ?"
|
||||
updateSql = "UPDATE World SET randomNumber = ? WHERE index = ?"
|
||||
|
||||
|
||||
let
|
||||
maxConnections = getEnv("DB_MAX_CONNECTION", "95").parseInt
|
||||
timeout = getEnv("DB_TIMEOUT", "30").parseInt
|
||||
|
||||
sqlitePath = getEnv("SQLITE_PATH", "db.sqlite3")
|
||||
|
||||
|
||||
proc timeProcess(name: string, cb: proc(): Future[void]) {.async.} =
|
||||
var eachTime = 0.0
|
||||
var sumTime = 0.0
|
||||
const repeatCount = 5
|
||||
var resultStr = ""
|
||||
|
||||
for i in 1..repeatCount:
|
||||
sleep(100)
|
||||
let start = getMonoTime()
|
||||
await cb()
|
||||
eachTime = float64((getMonoTime() - start).inMilliseconds) / 1000.0
|
||||
sumTime += eachTime
|
||||
if i > 1: resultStr.add("\n")
|
||||
resultStr.add("|" & $i & "|" & $eachTime & "|")
|
||||
|
||||
echo name
|
||||
echo "|num|time|"
|
||||
echo "|---|---|"
|
||||
echo resultStr
|
||||
echo "|Avg|" & $(sumTime / repeatCount) & "|"
|
||||
echo ""
|
||||
|
||||
|
||||
proc sqliteBenchmarkScenario(rdb: SqliteConnections) {.async.} =
|
||||
rdb.create(
|
||||
table("World", [
|
||||
Column.increments("index"),
|
||||
Column.integer("randomNumber").default(0)
|
||||
])
|
||||
)
|
||||
seeder(rdb, "World"):
|
||||
var data = newSeq[JsonNode]()
|
||||
for i in range1_10000:
|
||||
data.add(
|
||||
%*{"randomNumber": rand(range1_10000)}
|
||||
)
|
||||
await rdb.table("World").insert(data)
|
||||
|
||||
proc benchUpdate() {.async.} =
|
||||
var futures = newSeq[Future[void]](countNum)
|
||||
for i in 1..countNum:
|
||||
let index = rand(range1_10000)
|
||||
let number = rand(range1_10000)
|
||||
futures[i - 1] = (proc(): Future[void] {.async.} =
|
||||
discard rdb.select("index as id", "randomNumber").table("World").where("index", "=", index).first().await
|
||||
rdb.table("World").where("index", "=", index).update(%*{"randomNumber": number}).await
|
||||
)()
|
||||
await all(futures)
|
||||
|
||||
proc benchUpdatePreparedCold() {.async.} =
|
||||
let selectStmt = rdb.prepare(selectSql)
|
||||
let updateStmt = rdb.prepare(updateSql)
|
||||
defer:
|
||||
selectStmt.close().await
|
||||
updateStmt.close().await
|
||||
var futures = newSeq[Future[void]](countNum)
|
||||
for i in 1..countNum:
|
||||
let index = rand(range1_10000)
|
||||
let number = rand(range1_10000)
|
||||
futures[i - 1] = (proc(): Future[void] {.async.} =
|
||||
rdb.withConn(
|
||||
proc(ctx: SqlitePreparedContext): Future[void] {.async.} =
|
||||
discard await selectStmt.first(ctx, @[$index])
|
||||
await updateStmt.exec(ctx, @[$number, $index])
|
||||
)
|
||||
)()
|
||||
await all(futures)
|
||||
|
||||
let selectStmtWarm = rdb.prepare(selectSql)
|
||||
let updateStmtWarm = rdb.prepare(updateSql)
|
||||
|
||||
proc benchUpdatePreparedWarm() {.async.} =
|
||||
var futures = newSeq[Future[void]](countNum)
|
||||
for i in 1..countNum:
|
||||
let index = rand(range1_10000)
|
||||
let number = rand(range1_10000)
|
||||
futures[i - 1] = (proc(): Future[void] {.async.} =
|
||||
rdb.withConn(
|
||||
proc(ctx: SqlitePreparedContext): Future[void] {.async.} =
|
||||
discard await selectStmtWarm.first(ctx, @[$index])
|
||||
await updateStmtWarm.exec(ctx, @[$number, $index])
|
||||
)
|
||||
)()
|
||||
await all(futures)
|
||||
|
||||
await timeProcess("sqlite benchmark", benchUpdate)
|
||||
await timeProcess("sqlite benchmark prepared cold", benchUpdatePreparedCold)
|
||||
await timeProcess("sqlite benchmark prepared warm", benchUpdatePreparedWarm)
|
||||
|
||||
|
||||
proc main() =
|
||||
let rdb = dbOpen(SQLite3, sqlitePath, maxConnections, timeout, shouldDisplayLog=shouldDisplayLog)
|
||||
sqliteBenchmarkScenario(rdb).waitFor
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,209 @@
|
||||
import std/asyncdispatch
|
||||
import std/times
|
||||
import std/json
|
||||
import std/options
|
||||
import ../src/allographer/connection
|
||||
import ../src/allographer/query_builder
|
||||
|
||||
proc main() {.async.} =
|
||||
let surreal = await dbOpen(SurrealDb, "test", "test", "user", "pass", "http://surreal", 8000, 10, 30, true, false)
|
||||
surreal.raw("DELETE type").exec().await
|
||||
|
||||
surreal.table("type").insert(%*[
|
||||
{
|
||||
"bool":true,
|
||||
"string": "alice",
|
||||
"int": 1,
|
||||
"float": 3.14,
|
||||
"datetime": now().format("yyyy-MM-dd'T'HH:mm:sszzz")
|
||||
},
|
||||
{
|
||||
"bool":false,
|
||||
"string": "bob",
|
||||
"int": 2,
|
||||
"float": 1.11,
|
||||
"datetime": (now() + initDuration(days=1)).format("yyyy-MM-dd'T'HH:mm:sszzz")
|
||||
}
|
||||
])
|
||||
.await
|
||||
|
||||
block :
|
||||
echo "=== get"
|
||||
echo surreal.table("type").get().await
|
||||
|
||||
block:
|
||||
echo "=== first"
|
||||
let res = surreal.table("type").first().await
|
||||
if res.isSome():
|
||||
echo res.get()
|
||||
|
||||
block:
|
||||
echo "=== find"
|
||||
let id = SurrealId.new("type:64t0w6gpnye7tdf083ch")
|
||||
let res = surreal.table("type").find(id).await
|
||||
if res.isSome():
|
||||
echo res.get()
|
||||
|
||||
block:
|
||||
echo "=== where"
|
||||
surreal.raw("DELETE auth").exec().await
|
||||
surreal.raw("DELETE user").exec().await
|
||||
|
||||
let adminId = surreal.table("auth").insertId(%*{"name": "admin"}).await
|
||||
surreal.table("auth").insert(%*{"name": "editor"}).await
|
||||
echo surreal.table("auth").get().await
|
||||
surreal.table("user").insert(%*{"name":"alice", "email":"alice@example.com", "auth": adminId}).await
|
||||
|
||||
let res = surreal.table("user").where("name", "=", "alice").first().await
|
||||
if res.isSome():
|
||||
echo res.get().pretty()
|
||||
|
||||
block:
|
||||
echo "=== fetch"
|
||||
let alice = surreal.table("user").where("auth.name", "=", "admin").fetch("auth").first().await
|
||||
if alice.isSome():
|
||||
echo alice.get().pretty()
|
||||
|
||||
block:
|
||||
echo "=== update"
|
||||
surreal.raw("DELETE type").exec().await
|
||||
|
||||
let id = surreal.table("type").insertId(%*{
|
||||
"bool":true,
|
||||
"string": "alice",
|
||||
"int": 1,
|
||||
"float": 3.14,
|
||||
"datetime": now().format("yyyy-MM-dd'T'HH:mm:sszzz")
|
||||
})
|
||||
.await
|
||||
echo id.rawId()
|
||||
|
||||
surreal.table("type").where("id", "=", id).update(%*{"string": "bob"}).await
|
||||
echo surreal.table("type").find(id).await
|
||||
|
||||
block:
|
||||
echo "=== delete all"
|
||||
surreal.raw("DELETE type").exec().await
|
||||
|
||||
let id = surreal.table("type").insertId(%*{
|
||||
"bool":true,
|
||||
"string": "alice",
|
||||
"int": 1,
|
||||
"float": 3.14,
|
||||
"datetime": now().format("yyyy-MM-dd'T'HH:mm:sszzz")
|
||||
})
|
||||
.await
|
||||
|
||||
surreal.table("type").delete().await
|
||||
echo surreal.table("type").get().await
|
||||
|
||||
block:
|
||||
echo "=== delete row"
|
||||
surreal.raw("DELETE type").exec().await
|
||||
|
||||
surreal.table("type").insert(%*[
|
||||
{
|
||||
"bool":true,
|
||||
"string": "alice",
|
||||
"int": 1,
|
||||
"float": 3.14,
|
||||
"datetime": now().format("yyyy-MM-dd'T'HH:mm:sszzz")
|
||||
},
|
||||
{
|
||||
"bool":false,
|
||||
"string": "bob",
|
||||
"int": 2,
|
||||
"float": 1.11,
|
||||
"datetime": (now() + initDuration(days=1)).format("yyyy-MM-dd'T'HH:mm:sszzz")
|
||||
}])
|
||||
.await
|
||||
|
||||
let row = surreal.table("type").where("string", "=", "alice").first().await.get()
|
||||
let rowId = SurrealId.new(row["id"].getStr())
|
||||
|
||||
surreal.table("type").where("id", "=", rowId).delete().await
|
||||
echo surreal.table("type").get().await
|
||||
|
||||
block:
|
||||
echo "=== raw"
|
||||
surreal.table("type").delete().await
|
||||
|
||||
let define = """
|
||||
REMOVE TABLE type;
|
||||
DEFINE TABLE type SCHEMAFULL;
|
||||
DEFINE FIELD index ON TABLE type TYPE int;
|
||||
DEFINE INDEX types_index ON TABLE type COLUMNS index UNIQUE;
|
||||
DEFINE FIELD bool ON TABLE type TYPE bool;
|
||||
DEFINE FIELD datetime ON TABLE type TYPE datetime;
|
||||
DEFINE FIELD float ON TABLE type TYPE float;
|
||||
DEFINE FIELD int ON TABLE type TYPE int;
|
||||
DEFINE FIELD string ON TABLE type TYPE string;
|
||||
"""
|
||||
surreal.raw(define).exec().await
|
||||
|
||||
echo surreal.raw("INFO FOR TABLE type").info().await
|
||||
|
||||
var rows = surreal.raw("SELECT * FROM type").get().await
|
||||
let max = rows.len + 1
|
||||
|
||||
surreal.raw("""
|
||||
CREATE type CONTENT {
|
||||
index: ?,
|
||||
bool: true,
|
||||
datetime: ?,
|
||||
float: 1.11,
|
||||
int: 1,
|
||||
string: "aaa"
|
||||
}
|
||||
""",
|
||||
%*[$max, now().format("yyyy-MM-dd'T'HH:mm:sszzz")])
|
||||
.exec()
|
||||
.await
|
||||
|
||||
rows = surreal.raw("SELECT * FROM type").get().await
|
||||
echo rows
|
||||
|
||||
block:
|
||||
echo "=== count"
|
||||
surreal.table("user").delete().await
|
||||
|
||||
surreal.table("user").insert(%*[
|
||||
{"name": "alice", "email": "alice@example.com"},
|
||||
{"name": "bob", "email": "bob@example.com"},
|
||||
{"name": "charlie", "email": "charlie@example.com"},
|
||||
])
|
||||
.await
|
||||
|
||||
let count = surreal.table("user").count().await
|
||||
echo count
|
||||
|
||||
block:
|
||||
echo "=== max"
|
||||
surreal.table("user").delete().await
|
||||
|
||||
surreal.table("user").insert(%*[
|
||||
{"name": "alice", "email": "alice@example.com", "index": 1},
|
||||
{"name": "bob", "email": "bob@example.com", "index": 2},
|
||||
{"name": "charlie", "email": "charlie@example.com", "index": 3},
|
||||
])
|
||||
.await
|
||||
|
||||
let max = surreal.table("user").max("index").await
|
||||
echo max
|
||||
|
||||
block:
|
||||
echo "=== min"
|
||||
surreal.table("user").delete().await
|
||||
|
||||
surreal.table("user").insert(%*[
|
||||
{"name": "alice", "email": "alice@example.com", "index": 1},
|
||||
{"name": "bob", "email": "bob@example.com", "index": 2},
|
||||
{"name": "charlie", "email": "charlie@example.com", "index": 3},
|
||||
])
|
||||
.await
|
||||
|
||||
let min = surreal.table("user").min("index").await
|
||||
echo min
|
||||
|
||||
|
||||
main().waitFor
|
||||
@@ -0,0 +1,62 @@
|
||||
import std/asyncdispatch
|
||||
import std/json
|
||||
import ../../src/allographer/query_builder
|
||||
import ../../src/allographer/schema_builder
|
||||
import ../../src/allographer/connection
|
||||
|
||||
|
||||
let rdb = dbOpen(SurrealDB, "ns", "database", "user", "pass", "http://surreal", 8000, shouldDisplayLog=true).waitFor()
|
||||
|
||||
rdb.raw("""
|
||||
REMOVE TABLE `_sequences`;
|
||||
REMOVE EVENT `set_user_index` ON TABLE `user`;
|
||||
REMOVE TABLE `user`;
|
||||
REMOVE TABLE `auth`;
|
||||
""").exec().waitFor()
|
||||
|
||||
rdb.raw("""
|
||||
DEFINE TABLE `_sequences`;
|
||||
DEFINE FIELD `table_name` ON TABLE `_sequences` TYPE string;
|
||||
DEFINE FIELD `max_index` ON TABLE `_sequences` TYPE int;
|
||||
DEFINE INDEX `_sequences_table_name_unique` ON TABLE `_sequences` COLUMNS `table_name` UNIQUE;
|
||||
""").exec().waitFor()
|
||||
|
||||
rdb.raw("""
|
||||
DEFINE TABLE `user`;
|
||||
INSERT INTO `_sequences` {table_name: "user", max_index: 0};
|
||||
DEFINE FIELD `index` ON TABLE `user` TYPE int;
|
||||
DEFINE FIELD `name` ON TABLE `user` TYPE string;
|
||||
""").exec().waitFor()
|
||||
|
||||
rdb.raw("""
|
||||
DEFINE EVENT `set_user_index` ON TABLE `user` WHEN $event = "CREATE" THEN {
|
||||
LET $val = (SELECT `max_index` FROM `_sequences` WHERE `table_name` = "user" LIMIT 1)[0].max_index + 1;
|
||||
UPDATE `user` MERGE {index: $val} WHERE id = $after.id;
|
||||
UPDATE `_sequences` MERGE {max_index: $val} WHERE table_name = "user";
|
||||
};
|
||||
""").exec().waitFor()
|
||||
|
||||
echo rdb.raw("""
|
||||
INSERT INTO `user` {name: "user1"};
|
||||
SELECT * FROM `user`;
|
||||
SELECT * FROM `_sequences`;
|
||||
""").info().waitFor()
|
||||
|
||||
echo rdb.raw("""
|
||||
UPDATE `user` MERGE {name: "updated"} WHERE `name` = "user1";
|
||||
SELECT * FROM `user`;
|
||||
SELECT * FROM `_sequences`;
|
||||
""").info().waitFor()
|
||||
|
||||
|
||||
echo rdb.raw("""
|
||||
INSERT INTO `user` {name: "user2"};
|
||||
SELECT * FROM `user`;
|
||||
SELECT * FROM `_sequences`;
|
||||
""").info().waitFor()
|
||||
|
||||
echo rdb.raw("""
|
||||
UPDATE `user` MERGE {name: "updated2"} WHERE `name` = "user2";
|
||||
SELECT * FROM `user`;
|
||||
SELECT * FROM `_sequences`;
|
||||
""").info().waitFor()
|
||||
@@ -0,0 +1,49 @@
|
||||
import std/asyncdispatch
|
||||
import std/httpclient
|
||||
import std/streams
|
||||
import std/json
|
||||
import ../../src/allographer/connection
|
||||
import ../../src/allographer/query_builder
|
||||
import ../../src/allographer/schema_builder
|
||||
|
||||
proc main() {.async.} =
|
||||
let rdb = dbOpen(SurrealDB, "ns", "database", "user", "pass", "http://surreal", 8000, shouldDisplayLog=true).await
|
||||
|
||||
rdb.raw("""
|
||||
REMOVE TABLE `test`
|
||||
""").exec().await
|
||||
|
||||
rdb.raw("""
|
||||
DEFINE TABLE `test` SCHEMAFULL;
|
||||
DEFINE FIELD `bool` ON TABLE `test` TYPE bool;
|
||||
DEFINE FIELD `int` ON TABLE `test` TYPE int;
|
||||
DEFINE FIELD `float` ON TABLE `test` TYPE decimal;
|
||||
DEFINE FIELD `str` ON TABLE `test` TYPE string;
|
||||
DEFINE FIELD `data` ON TABLE `test` TYPE string | NONE;
|
||||
DEFINE FIELD `object` ON TABLE `test` TYPE object | NONE FLEXIBLE;
|
||||
""").exec().waitFor
|
||||
|
||||
echo rdb.table("test").columns().waitFor
|
||||
|
||||
rdb.raw("""
|
||||
INSERT INTO `test` {bool:?, int:?, float:?, str:?, object:?}
|
||||
""", %*[true, 1, 1.1, "alice", {"bool": false, "int": 2, "float": 2.1, "str": "two"}]).exec().waitFor
|
||||
|
||||
echo rdb.raw("""
|
||||
SELECT * FROM `test`
|
||||
""").get().waitFor
|
||||
|
||||
let client = newAsyncHttpClient()
|
||||
var veryLongText = ""
|
||||
var response = client.getContent("https://bible-api.com/genesis+1:1-31").await.parseJson
|
||||
veryLongText.add(response["text"].getStr)
|
||||
response = client.getContent("https://bible-api.com/genesis+2:1-25").await.parseJson
|
||||
veryLongText.add(response["text"].getStr)
|
||||
response = client.getContent("https://bible-api.com/genesis+3:1-24").await.parseJson
|
||||
veryLongText.add(response["text"].getStr)
|
||||
|
||||
rdb.table("test").insert(%*{"bool":false, "int":2, "float":2.1, "str": veryLongText}).waitFor
|
||||
|
||||
echo rdb.select("bool", "int", "float", "str").table("test").get().waitFor
|
||||
|
||||
main().waitFor
|
||||
@@ -0,0 +1,17 @@
|
||||
import std/asyncdispatch
|
||||
import std/json
|
||||
import ../src/allographer/connection
|
||||
import ../src/allographer/query_builder
|
||||
|
||||
|
||||
let db = dbOpen(SurrealDB, "test", "test", "user", "pass", "http://surreal", 8000, 10, 30, true, true).waitFor()
|
||||
db.raw("DELETE FROM account").exec().waitFor
|
||||
echo db.raw("INFO FOR DB").get().waitFor
|
||||
|
||||
for _ in 0..3:
|
||||
db.raw("CREATE account SET name = 'ACME Inc', created_at = time::now()").exec().waitFor
|
||||
|
||||
let resp = db.raw("SELECT * from account").get().waitFor
|
||||
for row in resp:
|
||||
echo row
|
||||
echo row["id"].getStr
|
||||
@@ -0,0 +1,56 @@
|
||||
import json, asyncdispatch, strformat
|
||||
import ../src/allographer/schema_builder
|
||||
import ../src/allographer/query_builder
|
||||
import ./connections
|
||||
import ./setup
|
||||
|
||||
|
||||
proc main(){.async.} =
|
||||
rdb.create(
|
||||
table("auth",[
|
||||
Column.increments("id"),
|
||||
Column.string("auth")
|
||||
]),
|
||||
table("users",[
|
||||
Column.increments("id"),
|
||||
Column.string("name").nullable(),
|
||||
Column.string("email").nullable(),
|
||||
Column.string("address").nullable(),
|
||||
Column.foreign("auth_id").reference("id").onTable("auth").onDelete(SET_NULL)
|
||||
])
|
||||
)
|
||||
|
||||
# seeder
|
||||
seeder(rdb, "auth"):
|
||||
rdb.table("auth").insert(@[
|
||||
%*{"auth": "admin"},
|
||||
%*{"auth": "user"}
|
||||
]).waitFor
|
||||
|
||||
seeder(rdb, "users"):
|
||||
var users: seq[JsonNode]
|
||||
for i in 1..10:
|
||||
let authId = if i mod 2 == 0: 2 else: 1
|
||||
users.add(
|
||||
%*{
|
||||
"name": &"user{i}",
|
||||
"email": &"user{i}@gmail.com",
|
||||
"auth_id": authId
|
||||
}
|
||||
)
|
||||
rdb.table("users").insert(users).waitFor
|
||||
|
||||
echo "====="
|
||||
transaction(rdb):
|
||||
assert rdb.isInTransaction == true
|
||||
echo rdb.select("name", "email").table("users").where("id", "=", 2).get().await
|
||||
|
||||
echo "====="
|
||||
transaction(rdb):
|
||||
assert rdb.isInTransaction == true
|
||||
rdb.table("table").insert(%*{"aaa": "bbb"}).await
|
||||
echo rdb.table("aaa").get().await
|
||||
|
||||
assert rdb.isInTransaction == false
|
||||
|
||||
main().waitFor
|
||||
@@ -0,0 +1,35 @@
|
||||
import times, json, macros
|
||||
|
||||
# type Type = ref object
|
||||
# id: int
|
||||
# name: string
|
||||
# birth_date: DateTime
|
||||
|
||||
# let response = Type(id:1, name:"John", birth_date: "1990-01-01".parse("yyyy-MM-dd"))
|
||||
var typ: tuple[id:int, name:string, birth_date:DateTime]
|
||||
var response = @[
|
||||
%*{"id": 1, "name":"user1", "birth_date":"1990-01-01"},
|
||||
%*{"id": 2, "name":"user2", "birth_date":"1990-01-02"}
|
||||
]
|
||||
|
||||
macro orm(head, body: untyped) =
|
||||
echo repr(head)
|
||||
echo repr(body)
|
||||
|
||||
orm typ:
|
||||
response
|
||||
# for v in typ.fields:
|
||||
# echo v
|
||||
|
||||
#[
|
||||
|
||||
proc orm(response_arg:openArray[JsonNode], typ:var tuple):seq[typ.type] =
|
||||
var response: seq[typ.type]
|
||||
for row in response_arg:
|
||||
typ.id = row["id"].getInt()
|
||||
typ.name = row["name"].getStr()
|
||||
typ.birth_date = row["birth_date"].getStr().parse("yyyy-MM-dd")
|
||||
response.add(typ)
|
||||
return response
|
||||
|
||||
]#
|
||||
@@ -0,0 +1,10 @@
|
||||
import json
|
||||
import ../src/allographer/connection
|
||||
import ../src/allographer/query_builder
|
||||
|
||||
let rdb = dbOpen(SQLite3, ":memory:", shouldDisplayLog=false)
|
||||
|
||||
discard rdb.table("world").where("id", "=", 1).update(%*{"randomnumber": 2})
|
||||
discard rdb.table("World").where("Id", "=", 1).update(%*{"randomNumber": 2})
|
||||
discard rdb.select("id", "randomnumber").table("world").where("id", "=", 1).get()
|
||||
discard rdb.select("id", "randomNumber").table("World").where("Id", "=", 1).get()
|
||||
Reference in New Issue
Block a user