bb843b9a03
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
315 lines
8.9 KiB
Markdown
315 lines
8.9 KiB
Markdown
# BaraDB Migration System — Ръководство
|
||
|
||
## Общ преглед
|
||
|
||
BaraDB има вградена миграционна система чрез BaraQL. Миграциите се управляват
|
||
изцяло от сървъра — checksums, locking, rollback, status tracking. Клиентът
|
||
(nim-allographer) изпраща BaraQL команди и не поддържа собствена миграционна
|
||
таблица.
|
||
|
||
## BaraQL миграционен синтаксис
|
||
|
||
```sql
|
||
-- Създаване на миграция с UP и DOWN скриптове
|
||
CREATE MIGRATION add_users_table {
|
||
UP: CREATE TABLE users (
|
||
id SERIAL PRIMARY KEY,
|
||
name VARCHAR(255) NOT NULL,
|
||
email VARCHAR(255) UNIQUE,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
DOWN: DROP TABLE IF EXISTS users;
|
||
}
|
||
|
||
-- Прилагане на конкретна миграция
|
||
APPLY MIGRATION add_users_table
|
||
|
||
-- Прилагане на всички неприложени миграции
|
||
MIGRATION UP
|
||
|
||
-- Прилагане на следващите N миграции
|
||
MIGRATION UP 3
|
||
|
||
-- Отмяна на последната миграция (rollback)
|
||
MIGRATION DOWN
|
||
|
||
-- Отмяна на последните N миграции
|
||
MIGRATION DOWN 2
|
||
|
||
-- Преглед на статуса на всички миграции
|
||
MIGRATION STATUS
|
||
|
||
-- Dry run — проверка без изпълнение
|
||
MIGRATION DRY RUN add_users_table
|
||
```
|
||
|
||
## Nim API (nim-allographer)
|
||
|
||
### Свързване
|
||
|
||
```nim
|
||
import allographer/connection
|
||
import allographer/query_builder
|
||
|
||
# Стандартно свързване
|
||
let rdb = dbOpen(Baradb, "mydb", "admin", "", "127.0.0.1", 9472)
|
||
|
||
# Или чрез URL
|
||
let rdb = dbOpen(Baradb, asDatabaseUrl("baradb://admin@127.0.0.1:9472/mydb"))
|
||
```
|
||
|
||
### Управление на миграции
|
||
|
||
```nim
|
||
import allographer/query_builder/models/baradb/baradb_exec
|
||
|
||
# Създаване на миграция
|
||
let upSql = """
|
||
CREATE TABLE products (
|
||
id SERIAL PRIMARY KEY,
|
||
name VARCHAR(255) NOT NULL,
|
||
price DECIMAL(10,2)
|
||
)
|
||
"""
|
||
let downSql = "DROP TABLE IF EXISTS products"
|
||
let qr = waitFor rdb.createMigration("add_products", upSql, downSql)
|
||
|
||
# Прилагане на миграция
|
||
let qr = waitFor rdb.applyMigration("add_products")
|
||
|
||
# Прилагане на всички неприложени
|
||
let qr = waitFor rdb.migrateUp()
|
||
|
||
# Rollback
|
||
let qr = waitFor rdb.migrateDown(1)
|
||
|
||
# Проверка на статус
|
||
let status = waitFor rdb.migrationStatus()
|
||
for row in status:
|
||
echo row["name"].getStr, " → ", row["status"].getStr
|
||
|
||
# Проверка дали миграция е приложена
|
||
if waitFor rdb.isMigrationApplied("add_products"):
|
||
echo "Migration already applied"
|
||
|
||
# Dry run
|
||
let qr = waitFor rdb.migrationDryRun("add_products")
|
||
echo $qr
|
||
```
|
||
|
||
### Schema Builder (автоматични миграции)
|
||
|
||
```nim
|
||
import allographer/schema_builder
|
||
import allographer/query_builder
|
||
|
||
let rdb = dbOpen(Baradb, "mydb", "admin", "", "127.0.0.1", 9472)
|
||
|
||
# Дефиниране на таблица
|
||
let usersTable = table("users", [
|
||
Column.increments("id"),
|
||
Column.string("name"),
|
||
Column.string("email").unique(),
|
||
Column.integer("age").nullable(),
|
||
Column.timestamps()
|
||
])
|
||
|
||
# Създаване (автоматично генерира CREATE MIGRATION)
|
||
rdb.create(usersTable)
|
||
|
||
# Промяна
|
||
let alteredTable = table("users", [
|
||
Column.string("phone").nullable().add() # добавяне на колона
|
||
])
|
||
rdb.alter(alteredTable)
|
||
|
||
# Изтриване
|
||
rdb.drop(usersTable)
|
||
```
|
||
|
||
### Prepared Statements
|
||
|
||
```nim
|
||
import allographer/query_builder/models/baradb/baradb_exec
|
||
|
||
# Подготовка на statement (кешира се)
|
||
let stmt = waitFor rdb.prepare(
|
||
"SELECT * FROM users WHERE age > ? AND status = ?", nArgs = 2
|
||
)
|
||
|
||
# Изпълнение с параметри
|
||
let youngAdmins = waitFor stmt.preparedGet(@[
|
||
WireValue(kind: fkInt32, int32Val: 18),
|
||
WireValue(kind: fkString, strVal: "active")
|
||
])
|
||
|
||
# Execute (INSERT/UPDATE/DELETE)
|
||
let affected = waitFor stmt.preparedExec(@[
|
||
WireValue(kind: fkInt32, int32Val: 21),
|
||
WireValue(kind: fkString, strVal: "pending")
|
||
])
|
||
|
||
# Освобождаване
|
||
stmt.flushStmt()
|
||
|
||
# Изчистване на целия кеш
|
||
rdb.clearStmtCache()
|
||
```
|
||
|
||
### Pagination
|
||
|
||
```nim
|
||
# Offset-based
|
||
let page1 = waitFor rdb.table("users")
|
||
.orderBy("id", Asc)
|
||
.paginate(page = 1, perPage = 20)
|
||
echo page1.rows.len # 20
|
||
echo page1.total # 150
|
||
echo page1.hasMore # true
|
||
|
||
# Cursor-based (по-бързо за големи таблици)
|
||
let batch = waitFor rdb.table("users")
|
||
.fastPaginate("id", perPage = 100, afterId = "42")
|
||
echo batch.hasMore
|
||
```
|
||
|
||
---
|
||
|
||
## Cross-DB Migration Engine
|
||
|
||
Мигриране на данни от PostgreSQL, MySQL, MariaDB, SQLite или SurrealDB към BaraDB.
|
||
|
||
### Поддържани source бази
|
||
|
||
| База | Статус | Schema extraction |
|
||
|------|--------|-------------------|
|
||
| PostgreSQL | ✅ | `information_schema` |
|
||
| MySQL | ✅ | `information_schema` |
|
||
| MariaDB | ✅ | `information_schema` |
|
||
| SQLite | ✅ | `sqlite_master` + `PRAGMA` |
|
||
| SurrealDB | ✅ | `INFO FOR DB` / `INFO FOR TABLE` |
|
||
|
||
### API
|
||
|
||
```nim
|
||
import allographer/migrate_data
|
||
|
||
# Свързване към source и target
|
||
let pg = dbOpen(PostgreSQL, "sourcedb", "user", "pass", "localhost", 5432)
|
||
let bdb = dbOpen(Baradb, "targetdb", "admin", "", "127.0.0.1", 9472)
|
||
|
||
# Мигриране на всички таблици
|
||
let report = waitFor migrate(pg, bdb, batchSize = 5000)
|
||
echo report
|
||
# Migration: PostgreSQL → BaraDB
|
||
# Tables: 12/12
|
||
# Rows: 45230
|
||
# Time: 3.2s
|
||
|
||
# Мигриране само на конкретни таблици
|
||
let report = waitFor migrate(pg, bdb, tables = @["users", "orders", "products"])
|
||
```
|
||
|
||
### Как работи
|
||
|
||
1. **Schema extraction** — чете структурата на таблиците от source базата
|
||
2. **Type mapping** — мапва типовете към BaraDB еквиваленти:
|
||
- `SERIAL` → `SERIAL`
|
||
- `VARCHAR(n)` → `VARCHAR(n)`
|
||
- `TEXT` → `TEXT`
|
||
- `JSONB` → `JSON`
|
||
- `BOOLEAN` → `BOOLEAN`
|
||
- и още 50+ типа
|
||
3. **DDL генерация** — създава `CREATE MIGRATION` с UP/DOWN скриптове
|
||
4. **Data transfer** — чете данни на batch-ове и ги вмъква в BaraDB
|
||
5. **Progress tracking** — връща `MigrationReport` с детайли
|
||
|
||
---
|
||
|
||
## IMPORT FROM / EXPORT TO (BaraQL)
|
||
|
||
```sql
|
||
-- Импорт от CSV
|
||
IMPORT FROM '/data/users.csv' INTO users
|
||
FORMAT CSV
|
||
DELIMITER ','
|
||
HEADER true
|
||
BATCH 1000
|
||
|
||
-- Импорт от JSON
|
||
IMPORT FROM '/data/users.json' INTO users
|
||
FORMAT JSON
|
||
|
||
-- Импорт от NDJSON (newline-delimited JSON)
|
||
IMPORT FROM '/data/users.ndjson' INTO users
|
||
FORMAT NDJSON
|
||
|
||
-- Експорт към CSV
|
||
EXPORT TO '/backup/users.csv' FROM users
|
||
FORMAT CSV
|
||
DELIMITER ','
|
||
HEADER true
|
||
|
||
-- Експорт към JSON
|
||
EXPORT TO '/backup/users.json' FROM users
|
||
FORMAT JSON
|
||
```
|
||
|
||
### Поддържани формати
|
||
|
||
| Формат | Import | Export | Опции |
|
||
|--------|--------|--------|-------|
|
||
| CSV | ✅ | ✅ | DELIMITER, HEADER, BATCH |
|
||
| JSON | ✅ | ✅ | — |
|
||
| NDJSON | ✅ | ✅ | — |
|
||
|
||
---
|
||
|
||
## Често задавани въпроси
|
||
|
||
### Мога ли да мигрирам от SQLite директно към BaraDB?
|
||
|
||
Да. Свържете се към SQLite файла и използвайте `migrate()`:
|
||
|
||
```nim
|
||
let sqlite = dbOpen(SQLite3, "mydb.sqlite")
|
||
let bdb = dbOpen(Baradb, "mydb", "admin", "", "127.0.0.1", 9472)
|
||
let report = waitFor migrate(sqlite, bdb)
|
||
```
|
||
|
||
### Какво става ако миграцията се прекъсне?
|
||
|
||
BaraDB сървърът поддържа transaction safety. Всяка миграция се изпълнява в
|
||
рамките на една транзакция. При грешка:
|
||
- DDL промените се отменят автоматично
|
||
- `MIGRATION STATUS` показва кои миграции са applied и кои не
|
||
- Може да продължите от последната успешна миграция
|
||
|
||
### Как да проверя какви миграции са приложени?
|
||
|
||
```nim
|
||
let status = waitFor rdb.migrationStatus()
|
||
for row in status:
|
||
echo &"{row[\"name\"]} → {row[\"status\"]} ({row[\"applied_at\"]})"
|
||
```
|
||
|
||
Или чрез BaraQL:
|
||
```sql
|
||
MIGRATION STATUS
|
||
```
|
||
|
||
### Поддържат ли се foreign key зависимости при cross-DB миграция?
|
||
|
||
Да. `migrate_data.nim` запазва foreign key дефинициите в генерирания DDL.
|
||
Препоръчва се таблиците без foreign key зависимости да се мигрират първи.
|
||
|
||
### Как се прави backup преди миграция?
|
||
|
||
```sql
|
||
-- Експортирайте данните преди миграция
|
||
EXPORT TO '/backup/before_migration.csv' FROM users FORMAT CSV
|
||
|
||
-- Или използвайте backup manager-а
|
||
-- (backup restore list verify cleanup)
|
||
```
|