6bfc5b3a3c
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
249 lines
6.2 KiB
Markdown
249 lines
6.2 KiB
Markdown
Example: Schema Builder
|
|
===
|
|
[back](../README.md)
|
|
|
|
## index
|
|
<!--ts-->
|
|
- [Example: Schema Builder](#example-schema-builder)
|
|
- [index](#index)
|
|
- [Create table](#create-table)
|
|
- [Alter Table](#alter-table)
|
|
- [add column](#add-column)
|
|
- [change column](#change-column)
|
|
- [drop column](#drop-column)
|
|
- [rename table](#rename-table)
|
|
- [drop table](#drop-table)
|
|
- [Migration history](#migration-history)
|
|
- [seeder template](#seeder-template)
|
|
- [integer](#integer)
|
|
- [float](#float)
|
|
- [char](#char)
|
|
- [date](#date)
|
|
- [others](#others)
|
|
- [options](#options)
|
|
- [Foreign Key Constraints](#foreign-key-constraints)
|
|
|
|
<!-- Created by https://github.com/ekalinin/github-markdown-toc -->
|
|
<!-- Added by: root, at: Mon Jul 17 07:46:21 UTC 2023 -->
|
|
|
|
<!--te-->
|
|
---
|
|
|
|
## Create table
|
|
```nim
|
|
import allographer/schema_builder
|
|
import connections # or define rdb here
|
|
|
|
rdb.create(
|
|
table("auth", [
|
|
Column.increments("id"),
|
|
Column.uuid("uuid"),
|
|
Column.string("name"),
|
|
Column.timestamps()
|
|
]),
|
|
table("users", [
|
|
Column.increments("id"),
|
|
Column.string("name"),
|
|
Column.foreign("auth_id").reference("id").onTable("auth").onDelete(SET_NULL),
|
|
Column.strForeign("uuid").reference("uuid").onTable("auth").onDelete(SET_NULL)
|
|
])
|
|
)
|
|
```
|
|
|
|
## Alter Table
|
|
### add column
|
|
```nim
|
|
rdb.alter(
|
|
table("auth", [
|
|
Column.string("email").add(),
|
|
]),
|
|
table("users", [
|
|
Column.string("email").unique().default("").add(),
|
|
Column.foreign("auth_id").reference("id").onTable("auth").onDelete(SET_NULL).add()
|
|
])
|
|
)
|
|
```
|
|
`>> ALTER TABLE "users" ADD COLUMN 'email' VARCHAR UNIQUE DEFAULT '' CHECK (length("email") <= 255)`
|
|
|
|
|
|
### change column
|
|
```nim
|
|
rdb.alter(
|
|
table("users", [
|
|
Column.renameColumn("name", "new_name"),
|
|
Column.char("name", 20).unique().default("").change()
|
|
])
|
|
)
|
|
```
|
|
- Create new table with new column definition
|
|
- Rename table which you want to change column
|
|
- Copy table data from old table to new table
|
|
- Drop old table
|
|
|
|
|
|
### drop column
|
|
```nim
|
|
rdb.alter(
|
|
table("users", [
|
|
Column.dropColumn("name")
|
|
])
|
|
)
|
|
```
|
|
|
|
### rename table
|
|
```nim
|
|
rdb.alter(
|
|
table("users").renameTo("new_users")
|
|
)
|
|
```
|
|
`>> ALTER TABLE users RENAME TO new_users`
|
|
|
|
### drop table
|
|
```nim
|
|
rdb.drop(
|
|
table("users")
|
|
)
|
|
```
|
|
`>> DROP TABLE users`
|
|
|
|
## Migration history
|
|
allographer generate `_allographer_migrations` table in your database. It has migration history data which have hash key generated a query.
|
|
|
|
|
|
```nim
|
|
# migrate.nim
|
|
import std/asyncdispatch
|
|
import std/json
|
|
import allographer/schema_builder
|
|
import connections
|
|
|
|
rdb.create(
|
|
table("auth", [
|
|
Column.increments("id"),
|
|
Column.string("name")
|
|
]),
|
|
table("users", [
|
|
Column.increments("id"),
|
|
Column.string("name"),
|
|
Column.foreign("auth_id").reference("id").onTable("auth").onDelete(SET_NULL)
|
|
])
|
|
)
|
|
|
|
seeder rdb, "auth":
|
|
rdb.table("auth").insert(@[
|
|
%*{"name": "admin"},
|
|
%*{"name": "member"}
|
|
])
|
|
.waitFor
|
|
|
|
seeder rdb, "users":
|
|
var data: seq[JsonNode]
|
|
for i in 1..10:
|
|
data.add(%*{
|
|
"name": &"user{i}",
|
|
"auth_id": if i mod 2 == 0: 1 else: 2
|
|
})
|
|
rdb.table("users").insert(data).waitFor
|
|
```
|
|
|
|
```sh
|
|
# first time
|
|
nim c -r migrate
|
|
>> run query and generate `_allographer_migrations` table
|
|
# secound time
|
|
nim c -r migrate
|
|
>> nothing to do
|
|
# reset existsing table and run migration again
|
|
nim c -r migrate --reset
|
|
or
|
|
nim c -d:reset -r migrate
|
|
>> drop table and create table
|
|
```
|
|
|
|
### seeder template
|
|
The `seeder` block allows the code in the block to work only when the table or specified column is empty.
|
|
|
|
```nim
|
|
template seeder*(rdb:Rdb, tableName:string, body:untyped):untyped
|
|
|
|
template seeder*(rdb:Rdb, tableName, column:string, body:untyped):untyped
|
|
```
|
|
|
|
|
|
## integer
|
|
|Command|Description|
|
|
|---|---|
|
|
|`increments("id")`|Auto-incrementing UNSIGNED INTEGER (primary key) equivalent column.|
|
|
|`integer("votes")`|INTEGER equivalent column.|
|
|
|`smallInteger("votes")`|SMALLINT equivalent column|
|
|
|`mediumInteger("votes")`|MEDIUMINT equivalent column|
|
|
|`bigInteger("votes")`|UNSIGNED BIGINT equivalent column.|
|
|
|
|
## float
|
|
|Command|Description|
|
|
|---|---|
|
|
|`decimal("amount", 8, 2)`|DECIMAL equivalent column with a precision (total digits) and scale (decimal digits).|
|
|
|`double("amount", 8, 2)`|DOUBLE equivalent column with a precision (total digits) and scale (decimal digits).|
|
|
|`float("float")`|FLOAT equivalent column with a implicit precision (total digits) and scale (decimal digits).|
|
|
|
|
## char
|
|
|Command|Description|
|
|
|---|---|
|
|
|`uuid("name")`|VARCHAR indexed and unique column.|
|
|
|`char("name", 100)`|CHAR equivalent column with an optional length.|
|
|
|`string("name")`|VARCHAR equivalent column.|
|
|
|`string("name", 100)`|VARCHAR equivalent column with a optional length.|
|
|
|`text("description")`|TEXT equivalent column.|
|
|
|`mediumText("description")`|MEDIUMTEXT equivalent column.|
|
|
|`longText("description")`|LONGTEXT equivalent column.|
|
|
|
|
## date
|
|
|Command|Description|
|
|
|---|---|
|
|
|`date("created_at")`|DATE equivalent column.|
|
|
|`datetime("created_at")`|DATETIME equivalent column.|
|
|
|`time("sunrise")`|TIME equivalent column.|
|
|
|`timestamp("added_on")`|TIMESTAMP equivalent column.|
|
|
|`timestamps()`|Adds nullable `created_at` and `updated_at` TIMESTAMP equivalent columns.|
|
|
|`softDelete()`|Adds a nullable `deleted_at` TIMESTAMP equivalent column for soft deletes.|
|
|
|
|
## others
|
|
|Command|Description|
|
|
|---|---|
|
|
|`binary("data")`|BLOB equivalent column.|
|
|
|`boolean("confirmed")`|BOOLEAN equivalent column.|
|
|
|`enumField("level", ["easy", "hard"])`|ENUM equivalent column.|
|
|
|`json("options")`|JSON equivalent column.|
|
|
|
|
## options
|
|
|Command|Description|
|
|
|---|---|
|
|
|`.nullable()`|Designate that the column allows NULL values|
|
|
|`.default(value)`|Declare a default value for a column|
|
|
|`.unsigned()`|Set INTEGER to UNSIGNED|
|
|
|`.unique()`|Adding an unique index|
|
|
|`.index()`|Adding an index|
|
|
|`.comment("value")`|Adding a comment to a column. Only for Postgres, Mariadb and Mysql|
|
|
|
|
## Foreign Key Constraints
|
|
For example, let's define a `user_id` column on the table that references the `id` column on a `users` table:
|
|
```nim
|
|
Column.foreign("user_id")
|
|
.reference("id")
|
|
.onTable("users")
|
|
.onDelete(SET_NULL)
|
|
|
|
Column.strForeign("uuid")
|
|
.reference("uuid")
|
|
.onTable("users")
|
|
.onDelete(SET_NULL)
|
|
|
|
# use `onTable("users")`
|
|
```
|
|
|
|
arg of `onDelete` is enum
|
|
- RESTRICT
|
|
- CASCADE
|
|
- SET_NULL
|
|
- NO_ACTION
|