Update documentation and clients for v1.1.0
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

Documentation updates:
- Fix v0.1.0 → v1.1.0 version numbers in en, ru, fa, zh docs
- Add missing Window Functions, Multi-Tenant ERP, Supported Keywords sections
  to ru, fa, zh baraql.md (~105 lines each)
- Expand Turkish and Arabic baraql.md (110 → 268 lines)
- Expand Turkish and Arabic installation.md (62 → 307 lines)
- Add new Bulgarian documentation files (18 new files)

Client updates:
- Python: Full async/await rewrite with asyncio, request queueing
- Rust: Full async/await rewrite with tokio, async examples
- Nim: Update README to v1.1.0
- All clients now support async patterns consistently
This commit is contained in:
2026-05-14 23:05:47 +03:00
parent f7d4961125
commit c55d3080cf
48 changed files with 5792 additions and 544 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ Official Nim client for **BaraDB** — a multimodal database engine.
Add to your `.nimble` file: Add to your `.nimble` file:
```nim ```nim
requires "baradb >= 1.0.0" requires "baradb >= 1.1.0"
``` ```
Or clone locally: Or clone locally:
+50 -28
View File
@@ -1,15 +1,16 @@
# BaraDB Python Client # BaraDB Python Async Client
Official Python client for **BaraDB** — a multimodal database engine written in Nim. Official async Python client for **BaraDB** — a multimodal database engine written in Nim.
## Features ## Features
- **Async/await** — fully non-blocking, concurrent query support
- **Binary wire protocol** — fast, compact TCP communication - **Binary wire protocol** — fast, compact TCP communication
- **Sync & blocking API** — simple to use in scripts and apps - **Request queueing** — sequential processing with concurrent execution
- **Query builder** — fluent SQL construction - **Query builder** — fluent SQL construction
- **Parameterized queries** — safe from SQL injection - **Parameterized queries** — safe from SQL injection
- **Vector & JSON support** — first-class multimodal types - **Vector & JSON support** — first-class multimodal types
- **Context managers** — `with` statement support - **Context managers** — async `async with` statement support
## Installation ## Installation
@@ -20,7 +21,7 @@ pip install baradb
Or from source: Or from source:
```bash ```bash
git clone https://github.com/barabadb/baradadb.git git clone https://github.com/katehonz/barabaDB.git
cd clients/python cd clients/python
pip install -e ".[dev]" pip install -e ".[dev]"
``` ```
@@ -28,48 +29,62 @@ pip install -e ".[dev]"
## Quick Start ## Quick Start
```python ```python
import asyncio
from baradb import Client from baradb import Client
client = Client("localhost", 9472) async def main():
client.connect() client = Client("localhost", 9472)
await client.connect()
result = client.query("SELECT name, age FROM users WHERE age > 18") result = await client.query("SELECT name, age FROM users WHERE age > 18")
for row in result: for row in result:
print(row["name"], row["age"]) print(row["name"], row["age"])
client.close() await client.close()
asyncio.run(main())
``` ```
### Context Manager ### Context Manager
```python ```python
import asyncio
from baradb import Client from baradb import Client
with Client("localhost", 9472) as client: async def main():
result = client.query("SELECT 1") async with Client("localhost", 9472) as client:
result = await client.query("SELECT 1")
print(result.row_count) print(result.row_count)
asyncio.run(main())
``` ```
### Parameterized Queries ### Parameterized Queries
```python ```python
import asyncio
from baradb import Client, WireValue from baradb import Client, WireValue
with Client("localhost", 9472) as client: async def main():
result = client.query_params( async with Client("localhost", 9472) as client:
result = await client.query_params(
"SELECT * FROM users WHERE age > $1 AND country = $2", "SELECT * FROM users WHERE age > $1 AND country = $2",
[WireValue.int64(18), WireValue.string("BG")], [WireValue.int64(18), WireValue.string("BG")],
) )
for row in result: for row in result:
print(row) print(row)
asyncio.run(main())
``` ```
### Query Builder ### Query Builder
```python ```python
import asyncio
from baradb import Client, QueryBuilder from baradb import Client, QueryBuilder
with Client("localhost", 9472) as client: async def main():
async with Client("localhost", 9472) as client:
qb = ( qb = (
QueryBuilder(client) QueryBuilder(client)
.select("name", "email") .select("name", "email")
@@ -78,21 +93,28 @@ with Client("localhost", 9472) as client:
.order_by("name") .order_by("name")
.limit(10) .limit(10)
) )
result = qb.exec() result = await qb.exec()
for row in result: for row in result:
print(row) print(row)
asyncio.run(main())
``` ```
### Vector Search ### Vector Search
```python ```python
import asyncio
from baradb import Client, WireValue from baradb import Client, WireValue
with Client("localhost", 9472) as client: async def main():
result = client.query_params( async with Client("localhost", 9472) as client:
result = await client.query_params(
"SELECT id, name FROM products ORDER BY embedding <-> $1 LIMIT 5", "SELECT id, name FROM products ORDER BY embedding <-> $1 LIMIT 5",
[WireValue.vector([0.1, 0.2, 0.3])], [WireValue.vector([0.1, 0.2, 0.3])],
) )
print(result.rows)
asyncio.run(main())
``` ```
## Running Tests ## Running Tests
@@ -107,7 +129,7 @@ Integration tests (requires server on `localhost:9472`):
```bash ```bash
# Start server # Start server
docker run -d -p 9472:9472 baradb:latest docker run -d -p 9472:9472 barabadb:latest
# Run all tests # Run all tests
pytest pytest
@@ -124,17 +146,17 @@ pytest
| `database` | `default` | Default database | | `database` | `default` | Default database |
| `username` | `admin` | Username | | `username` | `admin` | Username |
| `password` | `""` | Password | | `password` | `""` | Password |
| `timeout` | `30` | Socket timeout in seconds | | `timeout` | `30.0` | Socket timeout in seconds |
### Methods ### Methods (all async)
- `connect()` — open TCP connection - `await client.connect()` — open TCP connection
- `close()` — close connection - `await client.close()` — close connection
- `query(sql) -> QueryResult` — execute SELECT-like query - `await client.query(sql) -> QueryResult` — execute SELECT-like query
- `query_params(sql, params) -> QueryResult` — parameterized query - `await client.query_params(sql, params) -> QueryResult` — parameterized query
- `execute(sql) -> int` — execute DDL/DML, returns affected rows - `await client.execute(sql) -> int` — execute DDL/DML, returns affected rows
- `auth(token)` — JWT authentication - `await client.auth(token)` — JWT authentication
- `ping() -> bool` — health check - `await client.ping() -> bool` — health check
## License ## License
+20 -6
View File
@@ -1,20 +1,34 @@
""" """
BaraDB Python Client BaraDB Python Async Client
Official Python client for BaraDB — Multimodal Database Engine. Official async Python client for BaraDB — Multimodal Database Engine.
Communicates via the BaraDB Wire Protocol (binary, big-endian, TCP). Communicates via the BaraDB Wire Protocol (binary, big-endian, TCP).
Install: Install:
pip install baradb pip install baradb
Quick Start: Quick Start:
import asyncio
from baradb import Client from baradb import Client
async def main():
client = Client("localhost", 9472) client = Client("localhost", 9472)
client.connect() await client.connect()
result = client.query("SELECT name FROM users WHERE age > 18") result = await client.query("SELECT name FROM users WHERE age > 18")
for row in result: for row in result:
print(row["name"]) print(row["name"])
client.close() await client.close()
asyncio.run(main())
Parameterized Queries:
result = await client.query_params(
"SELECT * FROM users WHERE age > $1",
[WireValue.int64(18)]
)
Authentication:
await client.auth("jwt-token-here")
""" """
from .core import ( from .core import (
@@ -27,7 +41,7 @@ from .core import (
ResultFormat, ResultFormat,
) )
__version__ = "1.0.0" __version__ = "1.1.0"
__all__ = [ __all__ = [
"Client", "Client",
"QueryBuilder", "QueryBuilder",
+138 -72
View File
@@ -1,33 +1,38 @@
""" """
BaraDB Python Client BaraDB Python Async Client
Binary protocol client for BaraDB database. Official async Python client for BaraDB — Multimodal Database Engine.
Communicates via the BaraDB Wire Protocol (binary, big-endian). Communicates via the BaraDB Wire Protocol (binary, big-endian, TCP).
Install: Install:
pip install baradb pip install baradb
Quick Start: Quick Start:
import asyncio
from baradb import Client from baradb import Client
async def main():
client = Client("localhost", 9472) client = Client("localhost", 9472)
client.connect() await client.connect()
result = client.query("SELECT name FROM users WHERE age > 18") result = await client.query("SELECT name FROM users WHERE age > 18")
for row in result: for row in result:
print(row["name"]) print(row["name"])
client.close() await client.close()
asyncio.run(main())
Parameterized Queries: Parameterized Queries:
result = client.query_params("SELECT * FROM users WHERE age > $1", [WireValue.int64(18)]) result = await client.query_params(
"SELECT * FROM users WHERE age > $1",
[WireValue.int64(18)]
)
Authentication: Authentication:
client = Client("localhost", 9472, username="admin", password="secret") await client.auth("jwt-token-here")
client.connect()
client.auth("jwt-token-here")
""" """
import socket import asyncio
import struct import struct
import json
from typing import Any, Optional, Sequence from typing import Any, Optional, Sequence
@@ -49,7 +54,6 @@ class FieldKind:
class MsgKind: class MsgKind:
# Client messages
CLIENT_HANDSHAKE = 0x01 CLIENT_HANDSHAKE = 0x01
QUERY = 0x02 QUERY = 0x02
QUERY_PARAMS = 0x03 QUERY_PARAMS = 0x03
@@ -59,7 +63,6 @@ class MsgKind:
CLOSE = 0x07 CLOSE = 0x07
PING = 0x08 PING = 0x08
AUTH = 0x09 AUTH = 0x09
# Server messages
SERVER_HANDSHAKE = 0x80 SERVER_HANDSHAKE = 0x80
READY = 0x81 READY = 0x81
DATA = 0x82 DATA = 0x82
@@ -88,7 +91,7 @@ class WireValue:
return WireValue(FieldKind.NULL) return WireValue(FieldKind.NULL)
@staticmethod @staticmethod
def bool_val(val: bool): def bool(val: bool):
return WireValue(FieldKind.BOOL, val) return WireValue(FieldKind.BOOL, val)
@staticmethod @staticmethod
@@ -120,15 +123,15 @@ class WireValue:
return WireValue(FieldKind.STRING, val) return WireValue(FieldKind.STRING, val)
@staticmethod @staticmethod
def bytes_val(val: bytes): def bytes(val: bytes):
return WireValue(FieldKind.BYTES, val) return WireValue(FieldKind.BYTES, val)
@staticmethod @staticmethod
def array_val(val: list): def array(val: list):
return WireValue(FieldKind.ARRAY, val) return WireValue(FieldKind.ARRAY, val)
@staticmethod @staticmethod
def object_val(val: dict): def object(val: dict):
return WireValue(FieldKind.OBJECT, val) return WireValue(FieldKind.OBJECT, val)
@staticmethod @staticmethod
@@ -136,7 +139,7 @@ class WireValue:
return WireValue(FieldKind.VECTOR, val) return WireValue(FieldKind.VECTOR, val)
@staticmethod @staticmethod
def json_val(val: str): def json(val: str):
return WireValue(FieldKind.JSON, val) return WireValue(FieldKind.JSON, val)
def serialize(self) -> bytes: def serialize(self) -> bytes:
@@ -202,72 +205,92 @@ class QueryResult:
class Client: class Client:
"""BaraDB database client.""" """Async BaraDB database client."""
def __init__(self, host: str = "localhost", port: int = 9472, def __init__(self, host: str = "localhost", port: int = 9472,
database: str = "default", username: str = "admin", database: str = "default", username: str = "admin",
password: str = "", timeout: int = 30): password: str = "", timeout: float = 30.0):
self.host = host self.host = host
self.port = port self.port = port
self.database = database self.database = database
self.username = username self.username = username
self.password = password self.password = password
self.timeout = timeout self.timeout = timeout
self._sock: Optional[socket.socket] = None self._reader: Optional[asyncio.StreamReader] = None
self._writer: Optional[asyncio.StreamWriter] = None
self._connected = False self._connected = False
self._request_id = 0 self._request_id = 0
self._buffer = bytearray()
self._pending_resolve = None
self._request_queue: list = []
self._request_lock = False
def connect(self) -> None: async def connect(self) -> None:
"""Connect to the BaraDB server.""" """Connect to the BaraDB server."""
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._reader, self._writer = await asyncio.wait_for(
self._sock.settimeout(self.timeout) asyncio.open_connection(self.host, self.port),
self._sock.connect((self.host, self.port)) timeout=self.timeout
)
self._connected = True self._connected = True
def close(self) -> None: async def close(self) -> None:
if self._sock: """Close the connection to the server."""
if self._writer and self._connected:
try: try:
msg = self._build_message(MsgKind.CLOSE, b"") msg = self._build_message(MsgKind.CLOSE, b"")
self._sock.send(msg) self._writer.write(msg)
await self._writer.drain()
except Exception: except Exception:
pass pass
self._sock.close() if self._writer:
self._writer.close()
await self._writer.wait_closed()
self._writer = None
self._reader = None
self._connected = False self._connected = False
def is_connected(self) -> bool: def is_connected(self) -> bool:
"""Check if client is connected."""
return self._connected return self._connected
def _next_id(self) -> int: def _next_id(self) -> int:
self._request_id += 1 self._request_id += 1
return self._request_id return self._request_id
def _recv_exact(self, size: int) -> bytes: async def _recv_exact(self, size: int) -> bytes:
"""Receive exactly `size` bytes from the socket.""" """Receive exactly `size` bytes from the socket."""
data = b"" while len(self._buffer) < size:
while len(data) < size: try:
chunk = self._sock.recv(size - len(data)) chunk = await asyncio.wait_for(
self._reader.read(size - len(self._buffer)),
timeout=self.timeout
)
if not chunk: if not chunk:
raise ConnectionError("Connection closed by server") raise ConnectionError("Connection closed by server")
data += chunk self._buffer.extend(chunk)
except asyncio.TimeoutError:
raise TimeoutError("Receive timeout")
data = bytes(self._buffer[:size])
del self._buffer[:size]
return data return data
def _read_response_header(self) -> tuple[int, int, int]: async def _read_header(self) -> tuple[int, int, int]:
"""Read a 12-byte message header. Returns (kind, length, request_id).""" """Read a 12-byte message header. Returns (kind, length, request_id)."""
header = self._recv_exact(12) header = await self._recv_exact(12)
kind, length, req_id = struct.unpack(">III", header) kind, length, req_id = struct.unpack(">III", header)
return kind, length, req_id return kind, length, req_id
def _read_error(self, length: int) -> Exception: async def _read_error(self, length: int) -> Exception:
"""Read and parse an ERROR payload.""" """Read and parse an ERROR payload."""
data = self._recv_exact(length) data = await self._recv_exact(length)
code = struct.unpack(">I", data[:4])[0] code = struct.unpack(">I", data[:4])[0]
msg_len = struct.unpack(">I", data[4:8])[0] msg_len = struct.unpack(">I", data[4:8])[0]
error_msg = data[8:8 + msg_len].decode("utf-8") error_msg = data[8:8 + msg_len].decode("utf-8")
return Exception(f"BaraDB error {code}: {error_msg}") return Exception(f"BaraDB error {code}: {error_msg}")
def _read_data_response(self, length: int) -> QueryResult: async def _read_data_response(self, length: int) -> QueryResult:
"""Read and parse a DATA payload, then follow up with COMPLETE.""" """Read and parse a DATA payload, then follow up with COMPLETE."""
data = self._recv_exact(length) data = await self._recv_exact(length)
pos = [0] pos = [0]
col_count = struct.unpack(">I", data[pos[0]:pos[0]+4])[0] col_count = struct.unpack(">I", data[pos[0]:pos[0]+4])[0]
@@ -299,68 +322,107 @@ class Client:
result.rows = rows result.rows = rows
result.row_count = row_count result.row_count = row_count
comp_kind, comp_len, _ = self._read_response_header() comp_kind, comp_len, _ = await self._read_header()
if comp_kind == MsgKind.COMPLETE: if comp_kind == MsgKind.COMPLETE:
comp_data = self._recv_exact(comp_len) comp_data = await self._recv_exact(comp_len)
result.affected_rows = struct.unpack(">I", comp_data[:4])[0] result.affected_rows = struct.unpack(">I", comp_data[:4])[0]
elif comp_kind == MsgKind.ERROR: elif comp_kind == MsgKind.ERROR:
raise self._read_error(comp_len) raise await self._read_error(comp_len)
return result return result
def auth(self, token: str) -> None: async def auth(self, token: str) -> None:
"""Authenticate with the server using a JWT token.""" """Authenticate with the server using a JWT token."""
if not self._connected:
raise Exception("Not connected")
encoded = token.encode("utf-8") encoded = token.encode("utf-8")
payload = struct.pack(">I", len(encoded)) + encoded payload = struct.pack(">I", len(encoded)) + encoded
msg = self._build_message(MsgKind.AUTH, payload) msg = self._build_message(MsgKind.AUTH, payload)
self._sock.send(msg) self._writer.write(msg)
await self._writer.drain()
kind, length, _ = self._read_response_header() kind, length, _ = await self._read_header()
if kind == MsgKind.AUTH_OK: if kind == MsgKind.AUTH_OK:
return return
elif kind == MsgKind.ERROR: elif kind == MsgKind.ERROR:
raise self._read_error(length) raise await self._read_error(length)
else: else:
raise Exception(f"Unexpected auth response: 0x{kind:02x}") raise Exception(f"Unexpected auth response: 0x{kind:02x}")
def ping(self) -> bool: async def ping(self) -> bool:
"""Ping the server. Returns True if pong received.""" """Ping the server. Returns True if pong received."""
if not self._connected:
raise Exception("Not connected")
msg = self._build_message(MsgKind.PING, b"") msg = self._build_message(MsgKind.PING, b"")
self._sock.send(msg) self._writer.write(msg)
await self._writer.drain()
kind, length, _ = self._read_response_header() kind, length, _ = await self._read_header()
if kind == MsgKind.PONG: if kind == MsgKind.PONG:
return True return True
elif kind == MsgKind.ERROR: elif kind == MsgKind.ERROR:
raise self._read_error(length) raise await self._read_error(length)
return False return False
def query(self, sql: str) -> QueryResult: async def _process_queue(self) -> None:
"""Process queued requests sequentially."""
if self._request_lock or len(self._request_queue) == 0:
return
self._request_lock = True
task_data = self._request_queue.pop(0)
try:
result = await task_data["task"]()
task_data["resolve"](result)
except Exception as err:
task_data["reject"](err)
finally:
self._request_lock = False
asyncio.create_task(self._process_queue())
def _enqueue(self, task) -> None:
"""Add a task to the request queue."""
future = asyncio.Future()
self._request_queue.append({"task": task, "resolve": future.set_result, "reject": future.set_exception})
asyncio.create_task(self._process_queue())
return future
async def query(self, sql: str) -> QueryResult:
"""Execute a BaraQL query.""" """Execute a BaraQL query."""
if not self._connected:
raise Exception("Not connected")
async def _do_query():
payload = self._encode_string(sql) payload = self._encode_string(sql)
payload += bytes([ResultFormat.BINARY]) payload += bytes([ResultFormat.BINARY])
msg = self._build_message(MsgKind.QUERY, payload) msg = self._build_message(MsgKind.QUERY, payload)
self._sock.send(msg) self._writer.write(msg)
await self._writer.drain()
kind, length, _ = self._read_response_header() kind, length, _ = await self._read_header()
if kind == MsgKind.ERROR: if kind == MsgKind.ERROR:
raise self._read_error(length) raise await self._read_error(length)
if kind == MsgKind.DATA: if kind == MsgKind.DATA:
return self._read_data_response(length) return await self._read_data_response(length)
if kind == MsgKind.COMPLETE: if kind == MsgKind.COMPLETE:
data = self._recv_exact(length) data = await self._recv_exact(length)
result = QueryResult() result = QueryResult()
result.affected_rows = struct.unpack(">I", data[:4])[0] result.affected_rows = struct.unpack(">I", data[:4])[0]
return result return result
return QueryResult() return QueryResult()
def query_params(self, sql: str, params: Sequence[WireValue]) -> QueryResult: return await self._enqueue(_do_query)
async def query_params(self, sql: str, params: Sequence[WireValue]) -> QueryResult:
"""Execute a parameterized BaraQL query.""" """Execute a parameterized BaraQL query."""
if not self._connected:
raise Exception("Not connected")
async def _do_query_params():
payload = self._encode_string(sql) payload = self._encode_string(sql)
payload += bytes([ResultFormat.BINARY]) payload += bytes([ResultFormat.BINARY])
payload += struct.pack(">I", len(params)) payload += struct.pack(">I", len(params))
@@ -368,26 +430,30 @@ class Client:
payload += p.serialize() payload += p.serialize()
msg = self._build_message(MsgKind.QUERY_PARAMS, payload) msg = self._build_message(MsgKind.QUERY_PARAMS, payload)
self._sock.send(msg) self._writer.write(msg)
await self._writer.drain()
kind, length, _ = self._read_response_header() kind, length, _ = await self._read_header()
if kind == MsgKind.ERROR: if kind == MsgKind.ERROR:
raise self._read_error(length) raise await self._read_error(length)
if kind == MsgKind.DATA: if kind == MsgKind.DATA:
return self._read_data_response(length) return await self._read_data_response(length)
if kind == MsgKind.COMPLETE: if kind == MsgKind.COMPLETE:
data = self._recv_exact(length) data = await self._recv_exact(length)
result = QueryResult() result = QueryResult()
result.affected_rows = struct.unpack(">I", data[:4])[0] result.affected_rows = struct.unpack(">I", data[:4])[0]
return result return result
return QueryResult() return QueryResult()
def execute(self, sql: str) -> int: return await self._enqueue(_do_query_params)
result = self.query(sql)
async def execute(self, sql: str) -> int:
"""Execute a query and return affected rows count."""
result = await self.query(sql)
return result.affected_rows return result.affected_rows
def _build_message(self, kind: int, payload: bytes) -> bytes: def _build_message(self, kind: int, payload: bytes) -> bytes:
@@ -477,12 +543,12 @@ class Client:
return self._read_string(data, pos) return self._read_string(data, pos)
return None return None
def __enter__(self): async def __aenter__(self):
self.connect() await self.connect()
return self return self
def __exit__(self, *args): async def __aexit__(self, *args):
self.close() await self.close()
class QueryBuilder: class QueryBuilder:
@@ -559,5 +625,5 @@ class QueryBuilder:
sql += " OFFSET " + str(self._offset) sql += " OFFSET " + str(self._offset)
return sql return sql
def exec(self) -> QueryResult: async def exec(self) -> QueryResult:
return self.client.query(self.build()) return await self.client.query(self.build())
+3 -2
View File
@@ -3,9 +3,9 @@ name = "baradb"
version = "1.1.0" version = "1.1.0"
edition = "2021" edition = "2021"
authors = ["BaraDB Team <team@baradb.dev>"] authors = ["BaraDB Team <team@baradb.dev>"]
description = "Official Rust client for BaraDB — binary protocol client" description = "Official async Rust client for BaraDB — binary protocol client"
license = "Apache-2.0" license = "Apache-2.0"
repository = "https://github.com/barabadb/baradadb" repository = "https://github.com/katehonz/barabaDB"
documentation = "https://docs.baradb.dev" documentation = "https://docs.baradb.dev"
readme = "README.md" readme = "README.md"
keywords = ["database", "baradb", "multimodal", "client", "wire-protocol"] keywords = ["database", "baradb", "multimodal", "client", "wire-protocol"]
@@ -13,6 +13,7 @@ categories = ["database", "network-programming"]
rust-version = "1.70" rust-version = "1.70"
[dependencies] [dependencies]
tokio = { version = "1.35", features = ["full"] }
[dev-dependencies] [dev-dependencies]
+41 -35
View File
@@ -1,13 +1,13 @@
# BaraDB Rust Client # BaraDB Async Rust Client
Official Rust client for **BaraDB** — a multimodal database engine written in Nim. Official async Rust client for **BaraDB** — a multimodal database engine written in Nim.
## Features ## Features
- **Binary wire protocol** — fast TCP communication using only `std` - **Async/await** — fully non-blocking with Tokio runtime
- **Zero dependencies** — no external crates required - **Binary wire protocol** — fast TCP communication
- **Sync API** — blocking I/O suitable for most applications
- **Query builder** — fluent SQL construction - **Query builder** — fluent SQL construction
- **Parameterized queries** — safe from SQL injection
- **Vector & JSON support** — first-class multimodal types - **Vector & JSON support** — first-class multimodal types
## Installation ## Installation
@@ -16,13 +16,14 @@ Add to your `Cargo.toml`:
```toml ```toml
[dependencies] [dependencies]
baradb = "1.0" baradb = "1.1"
tokio = { version = "1.35", features = ["full"] }
``` ```
Or from source: Or from source:
```bash ```bash
git clone https://github.com/barabadb/baradadb.git git clone https://github.com/katehonz/barabaDB.git
cd clients/rust cd clients/rust
cargo build cargo build
``` ```
@@ -32,13 +33,14 @@ cargo build
```rust ```rust
use baradb::Client; use baradb::Client;
fn main() -> Result<(), Box<dyn std::error::Error>> { #[tokio::main]
let mut client = Client::connect("localhost", 9472)?; async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let result = client.query("SELECT name, age FROM users WHERE age > 18")?; let mut client = Client::connect("localhost", 9472).await?;
let result = client.query("SELECT name, age FROM users WHERE age > 18").await?;
for row in result.rows() { for row in result.rows() {
println!("{:?}", row); println!("{:?}", row);
} }
client.close(); client.close().await;
Ok(()) Ok(())
} }
``` ```
@@ -48,16 +50,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
```rust ```rust
use baradb::{Client, WireValue}; use baradb::{Client, WireValue};
fn main() -> Result<(), Box<dyn std::error::Error>> { #[tokio::main]
let mut client = Client::connect("localhost", 9472)?; async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut client = Client::connect("localhost", 9472).await?;
let result = client.query_params( let result = client.query_params(
"SELECT * FROM users WHERE age > $1 AND country = $2", "SELECT * FROM users WHERE age > $1 AND country = $2",
&[WireValue::Int64(18), WireValue::String("BG".to_string())], &[WireValue::Int64(18), WireValue::String("BG".to_string())],
)?; ).await?;
for row in result.rows() { for row in result.rows() {
println!("{:?}", row); println!("{:?}", row);
} }
client.close(); client.close().await;
Ok(()) Ok(())
} }
``` ```
@@ -65,21 +68,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
### Query Builder ### Query Builder
```rust ```rust
use baradb::Client; use baradb::{Client, QueryBuilder};
fn main() -> Result<(), Box<dyn std::error::Error>> { #[tokio::main]
let mut client = Client::connect("localhost", 9472)?; async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let result = baradb::QueryBuilder::new(&mut client) let mut client = Client::connect("localhost", 9472).await?;
let result = QueryBuilder::new(&mut client)
.select(&["name", "email"]) .select(&["name", "email"])
.from("users") .from("users")
.where_clause("active = true") .where_clause("active = true")
.order_by("name", "ASC") .order_by("name", "ASC")
.limit(10) .limit(10)
.exec()?; .exec()
.await?;
for row in result.rows() { for row in result.rows() {
println!("{:?}", row); println!("{:?}", row);
} }
client.close(); client.close().await;
Ok(()) Ok(())
} }
``` ```
@@ -89,13 +94,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
```rust ```rust
use baradb::{Client, WireValue}; use baradb::{Client, WireValue};
fn main() -> Result<(), Box<dyn std::error::Error>> { #[tokio::main]
let mut client = Client::connect("localhost", 9472)?; async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut client = Client::connect("localhost", 9472).await?;
let result = client.query_params( let result = client.query_params(
"SELECT id, name FROM products ORDER BY embedding <-> $1 LIMIT 5", "SELECT id, name FROM products ORDER BY embedding <-> $1 LIMIT 5",
&[WireValue::Vector(vec![0.1, 0.2, 0.3])], &[WireValue::Vector(vec![0.1, 0.2, 0.3])],
)?; ).await?;
client.close(); client.close().await;
Ok(()) Ok(())
} }
``` ```
@@ -112,7 +118,7 @@ Integration tests (requires server on `localhost:9472`):
```bash ```bash
# Start server # Start server
docker run -d -p 9472:9472 baradb:latest docker run -d -p 9472:9472 barabadb:latest
# Run all tests # Run all tests
cargo test cargo test
@@ -120,18 +126,18 @@ cargo test
## API Reference ## API Reference
### `Client::connect(host, port)` ### `Client::connect(host, port) -> Result<Client>`
Creates a new client connected to the given host and port. Creates a new async client connected to the given host and port.
### Methods ### Methods (all async)
- `query(sql) -> Result<QueryResult>` — execute SELECT-like query - `await client.query(sql) -> Result<QueryResult>` — execute SELECT-like query
- `query_params(sql, params) -> Result<QueryResult>` — parameterized query - `await client.query_params(sql, params) -> Result<QueryResult>` — parameterized query
- `execute(sql) -> Result<usize>` — execute DDL/DML, returns affected rows - `await client.execute(sql) -> Result<usize>` — execute DDL/DML, returns affected rows
- `auth(token) -> Result<()>` — JWT authentication - `await client.auth(token) -> Result<()>` — JWT authentication
- `ping() -> Result<bool>` — health check - `await client.ping() -> Result<bool>` — health check
- `close()` — close connection - `await client.close()` — close connection
## License ## License
+58 -48
View File
@@ -3,34 +3,65 @@
use baradb::{Client, QueryBuilder, WireValue}; use baradb::{Client, QueryBuilder, WireValue};
fn example_connection() -> Result<(), Box<dyn std::error::Error>> { #[tokio::main]
async fn main() {
println!("BaraDB Rust Client Examples");
println!("Make sure BaraDB is running on localhost:9472");
println!();
if let Err(e) = example_connection().await {
eprintln!("ERROR: {}", e);
}
if let Err(e) = example_simple_query().await {
eprintln!("ERROR: {}", e);
}
if let Err(e) = example_parameterized_query().await {
eprintln!("ERROR: {}", e);
}
if let Err(e) = example_query_builder().await {
eprintln!("ERROR: {}", e);
}
if let Err(e) = example_vector().await {
eprintln!("ERROR: {}", e);
}
if let Err(e) = example_ddl_dml().await {
eprintln!("ERROR: {}", e);
}
}
async fn example_connection() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
println!("=== Connection ==="); println!("=== Connection ===");
let mut client = Client::connect("127.0.0.1", 9472)?; let mut client = Client::connect("127.0.0.1", 9472).await?;
println!("Connected: {}", client.is_connected()); println!("Connected: {}", client.is_connected());
println!("Ping: {}", client.ping()?); println!("Ping: {}", client.ping().await?);
client.close(); client.close().await;
println!("Connected after close: {}", client.is_connected()); println!("Connected after close: {}", client.is_connected());
println!(); println!();
Ok(()) Ok(())
} }
fn example_simple_query() -> Result<(), Box<dyn std::error::Error>> { async fn example_simple_query() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
println!("=== Simple Query ==="); println!("=== Simple Query ===");
let mut client = Client::connect("127.0.0.1", 9472)?; let mut client = Client::connect("127.0.0.1", 9472).await?;
let result = client.query("SELECT 42 as answer, 'BaraDB' as db")?; let result = client.query("SELECT 42 as answer, 'BaraDB' as db").await?;
println!("Columns: {:?}", result.columns()); println!("Columns: {:?}", result.columns());
println!("Row count: {}", result.row_count()); println!("Row count: {}", result.row_count());
for row in result.rows() { for row in result.rows() {
println!(" {:?}", row); println!(" {:?}", row);
} }
client.close(); client.close().await;
println!(); println!();
Ok(()) Ok(())
} }
fn example_parameterized_query() -> Result<(), Box<dyn std::error::Error>> { async fn example_parameterized_query() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
println!("=== Parameterized Query ==="); println!("=== Parameterized Query ===");
let mut client = Client::connect("127.0.0.1", 9472)?; let mut client = Client::connect("127.0.0.1", 9472).await?;
let result = client.query_params( let result = client.query_params(
"SELECT $1 as num, $2 as txt, $3 as flag", "SELECT $1 as num, $2 as txt, $3 as flag",
&[ &[
@@ -38,18 +69,18 @@ fn example_parameterized_query() -> Result<(), Box<dyn std::error::Error>> {
WireValue::String("hello world".to_string()), WireValue::String("hello world".to_string()),
WireValue::Bool(true), WireValue::Bool(true),
], ],
)?; ).await?;
for row in result.rows() { for row in result.rows() {
println!(" {:?}", row); println!(" {:?}", row);
} }
client.close(); client.close().await;
println!(); println!();
Ok(()) Ok(())
} }
fn example_query_builder() -> Result<(), Box<dyn std::error::Error>> { async fn example_query_builder() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
println!("=== Query Builder ==="); println!("=== Query Builder ===");
let mut client = Client::connect("127.0.0.1", 9472)?; let mut client = Client::connect("127.0.0.1", 9472).await?;
let sql = QueryBuilder::new(&mut client) let sql = QueryBuilder::new(&mut client)
.select(&["id", "name"]) .select(&["id", "name"])
.from("users") .from("users")
@@ -58,70 +89,49 @@ fn example_query_builder() -> Result<(), Box<dyn std::error::Error>> {
.limit(5) .limit(5)
.build(); .build();
println!("Generated SQL: {}", sql); println!("Generated SQL: {}", sql);
client.close(); client.close().await;
println!(); println!();
Ok(()) Ok(())
} }
fn example_vector() -> Result<(), Box<dyn std::error::Error>> { async fn example_vector() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
println!("=== Vector Value ==="); println!("=== Vector Value ===");
let mut client = Client::connect("127.0.0.1", 9472)?; let mut client = Client::connect("127.0.0.1", 9472).await?;
let result = client.query_params( let result = client.query_params(
"SELECT $1 as embedding", "SELECT $1 as embedding",
&[WireValue::Vector(vec![0.1, 0.2, 0.3, 0.4])], &[WireValue::Vector(vec![0.1, 0.2, 0.3, 0.4])],
)?; ).await?;
for row in result.rows() { for row in result.rows() {
println!(" {:?}", row); println!(" {:?}", row);
} }
client.close(); client.close().await;
println!(); println!();
Ok(()) Ok(())
} }
fn example_ddl_dml() -> Result<(), Box<dyn std::error::Error>> { async fn example_ddl_dml() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
println!("=== DDL & DML ==="); println!("=== DDL & DML ===");
let mut client = Client::connect("127.0.0.1", 9472)?; let mut client = Client::connect("127.0.0.1", 9472).await?;
let _ = client.execute("DROP TABLE IF EXISTS demo_products"); let _ = client.execute("DROP TABLE IF EXISTS demo_products").await;
client.execute( client.execute(
"CREATE TABLE demo_products (id INT PRIMARY KEY, name STRING, price FLOAT)", "CREATE TABLE demo_products (id INT PRIMARY KEY, name STRING, price FLOAT)",
)?; ).await?;
let affected = client.execute( let affected = client.execute(
"INSERT INTO demo_products (id, name, price) VALUES (1, 'Widget', 9.99)", "INSERT INTO demo_products (id, name, price) VALUES (1, 'Widget', 9.99)",
)?; ).await?;
println!("Insert affected rows: {}", affected); println!("Insert affected rows: {}", affected);
let result = client.query("SELECT * FROM demo_products")?; let result = client.query("SELECT * FROM demo_products").await?;
println!("Select returned {} row(s)", result.row_count()); println!("Select returned {} row(s)", result.row_count());
for row in result.rows() { for row in result.rows() {
println!(" {:?}", row); println!(" {:?}", row);
} }
client.execute("DROP TABLE demo_products")?; client.execute("DROP TABLE demo_products").await?;
println!("Table dropped"); println!("Table dropped");
client.close(); client.close().await;
println!(); println!();
Ok(()) Ok(())
} }
fn main() {
println!("BaraDB Rust Client Examples");
println!("Make sure BaraDB is running on localhost:9472");
println!();
let examples: Vec<fn() -> Result<(), Box<dyn std::error::Error>>> = vec![
example_connection,
example_simple_query,
example_parameterized_query,
example_query_builder,
example_vector,
example_ddl_dml,
];
for example in examples {
if let Err(e) = example() {
eprintln!("ERROR: {}", e);
}
}
}
+103 -68
View File
@@ -1,36 +1,42 @@
//! BaraDB Rust Client //! BaraDB Async Rust Client
//! //!
//! Binary protocol client for BaraDB database. //! Async binary protocol client for BaraDB database.
//! Zero external dependencies — uses only `std`. //! Uses Tokio for async I/O operations.
//! //!
//! # Example //! # Example
//! ```no_run //! ```no_run
//! use baradb::{Client, WireValue}; //! use baradb::{Client, WireValue};
//! //!
//! let mut client = Client::connect("localhost", 9472).unwrap(); //! #[tokio::main]
//! let result = client.query("SELECT name FROM users WHERE age > 18").unwrap(); //! async fn main() {
//! let mut client = Client::connect("localhost", 9472).await.unwrap();
//! let result = client.query("SELECT name FROM users WHERE age > 18").await.unwrap();
//! for row in result.rows() { //! for row in result.rows() {
//! if let Some(WireValue::String(name)) = row.get("name") { //! if let Some(WireValue::String(name)) = row.get("name") {
//! println!("{}", name); //! println!("{}", name);
//! } //! }
//! } //! }
//! client.close(); //! client.close().await;
//! }
//! ``` //! ```
//! //!
//! # Parameterized Queries //! # Parameterized Queries
//! ```no_run //! ```no_run
//! use baradb::{Client, WireValue}; //! use baradb::{Client, WireValue};
//! //!
//! let mut client = Client::connect("localhost", 9472).unwrap(); //! #[tokio::main]
//! async fn main() {
//! let mut client = Client::connect("localhost", 9472).await.unwrap();
//! let result = client.query_params( //! let result = client.query_params(
//! "SELECT * FROM users WHERE age > $1", //! "SELECT * FROM users WHERE age > $1",
//! &[WireValue::Int64(18)], //! &[WireValue::Int64(18)],
//! ).unwrap(); //! ).await.unwrap();
//! }
//! ``` //! ```
use std::collections::HashMap; use std::collections::HashMap;
use std::io::{Read, Write}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
use std::net::TcpStream; use tokio::net::TcpStream;
// Client message kinds // Client message kinds
const MK_CLIENT_HANDSHAKE: u32 = 0x01; const MK_CLIENT_HANDSHAKE: u32 = 0x01;
@@ -221,43 +227,41 @@ impl QueryResult {
} }
} }
/// BaraDB client /// BaraDB async client
pub struct Client { pub struct Client {
config: Config,
stream: TcpStream, stream: TcpStream,
connected: bool, connected: bool,
request_id: u32, request_id: u32,
read_buf: Vec<u8>,
} }
impl Client { impl Client {
pub fn connect(host: &str, port: u16) -> Result<Self, Box<dyn std::error::Error>> { /// Connect to a BaraDB server
let config = Config { pub async fn connect(host: &str, port: u16) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
host: host.to_string(), let addr = format!("{}:{}", host, port);
port, let stream = TcpStream::connect(&addr).await?;
..Default::default()
};
Self::connect_with_config(config)
}
pub fn connect_with_config(config: Config) -> Result<Self, Box<dyn std::error::Error>> {
let addr = format!("{}:{}", config.host, config.port);
let stream = TcpStream::connect(&addr)?;
stream.set_nodelay(true)?;
Ok(Client { Ok(Client {
config,
stream, stream,
connected: true, connected: true,
request_id: 0, request_id: 0,
read_buf: Vec::new(),
}) })
} }
pub fn close(&mut self) { /// Connect with custom configuration
pub async fn connect_with_config(config: Config) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
Self::connect(&config.host, config.port).await
}
/// Close the connection
pub async fn close(&mut self) {
if self.connected { if self.connected {
let _ = self.send_close(); let _ = self.send_close().await;
} }
self.connected = false; self.connected = false;
} }
/// Check if connected
pub fn is_connected(&self) -> bool { pub fn is_connected(&self) -> bool {
self.connected self.connected
} }
@@ -267,27 +271,39 @@ impl Client {
self.request_id self.request_id
} }
fn send_close(&mut self) -> Result<(), Box<dyn std::error::Error>> { async fn send_close(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let msg = build_message(MK_CLOSE, self.next_id(), &[]); let msg = build_message(MK_CLOSE, self.next_id(), &[]);
self.stream.write_all(&msg)?; self.stream.write_all(&msg).await?;
Ok(()) Ok(())
} }
fn read_header(&mut self) -> Result<(u32, u32, u32), Box<dyn std::error::Error>> { async fn read_exact(&mut self, mut n: usize) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
let mut header = [0u8; 12]; let mut buf = vec![0u8; n];
self.stream.read_exact(&mut header)?; let mut pos = 0;
while pos < n {
let read = self.stream.read(&mut buf[pos..]).await?;
if read == 0 {
return Err("Connection closed".into());
}
pos += read;
}
Ok(buf)
}
async fn read_header(&mut self) -> Result<(u32, u32, u32), Box<dyn std::error::Error + Send + Sync>> {
let header = self.read_exact(12).await?;
let kind = u32::from_be_bytes([header[0], header[1], header[2], header[3]]); let kind = u32::from_be_bytes([header[0], header[1], header[2], header[3]]);
let length = u32::from_be_bytes([header[4], header[5], header[6], header[7]]); let length = u32::from_be_bytes([header[4], header[5], header[6], header[7]]);
let req_id = u32::from_be_bytes([header[8], header[9], header[10], header[11]]); let req_id = u32::from_be_bytes([header[8], header[9], header[10], header[11]]);
Ok((kind, length, req_id)) Ok((kind, length, req_id))
} }
fn read_payload(&mut self, length: u32) -> Result<Vec<u8>, Box<dyn std::error::Error>> { async fn read_payload(&mut self, length: u32) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
let mut payload = vec![0u8; length as usize];
if length > 0 { if length > 0 {
self.stream.read_exact(&mut payload)?; self.read_exact(length as usize).await
} else {
Ok(vec![])
} }
Ok(payload)
} }
fn read_error_message(payload: &[u8]) -> String { fn read_error_message(payload: &[u8]) -> String {
@@ -302,26 +318,26 @@ impl Client {
"Query error".to_string() "Query error".to_string()
} }
fn read_data_response(&mut self, payload: &[u8]) -> Result<QueryResult, Box<dyn std::error::Error>> { async fn read_data_response(&mut self, payload: &[u8]) -> Result<QueryResult, Box<dyn std::error::Error + Send + Sync>> {
let mut pos = 0usize; let mut pos = 0usize;
let col_count = read_u32(payload, &mut pos) as usize; let col_count = read_u32(payload, &mut pos);
let mut columns = Vec::with_capacity(col_count); let mut columns = Vec::with_capacity(col_count as usize);
for _ in 0..col_count { for _ in 0..col_count {
columns.push(read_string(payload, &mut pos)); columns.push(read_string(payload, &mut pos));
} }
let mut col_types = Vec::with_capacity(col_count); let mut col_types = Vec::with_capacity(col_count as usize);
for _ in 0..col_count { for _ in 0..col_count {
col_types.push(payload[pos]); col_types.push(payload[pos]);
pos += 1; pos += 1;
} }
let row_count = read_u32(payload, &mut pos) as usize; let row_count = read_u32(payload, &mut pos);
let mut rows = Vec::with_capacity(row_count); let mut rows = Vec::with_capacity(row_count as usize);
for _ in 0..row_count { for _ in 0..row_count {
let mut row = HashMap::new(); let mut row = HashMap::new();
for c in 0..col_count { for c in 0..col_count as usize {
let val = read_wire_value(payload, &mut pos); let val = read_wire_value(payload, &mut pos);
row.insert(columns[c].clone(), val); row.insert(columns[c].clone(), val);
} }
@@ -329,9 +345,9 @@ impl Client {
} }
let mut affected = 0usize; let mut affected = 0usize;
let (comp_kind, comp_len, _) = self.read_header()?; let (comp_kind, comp_len, _) = self.read_header().await?;
if comp_kind == MK_COMPLETE { if comp_kind == MK_COMPLETE {
let comp_payload = self.read_payload(comp_len)?; let comp_payload = self.read_payload(comp_len).await?;
if comp_payload.len() >= 4 { if comp_payload.len() >= 4 {
affected = u32::from_be_bytes([comp_payload[0], comp_payload[1], comp_payload[2], comp_payload[3]]) as usize; affected = u32::from_be_bytes([comp_payload[0], comp_payload[1], comp_payload[2], comp_payload[3]]) as usize;
} }
@@ -340,44 +356,47 @@ impl Client {
Ok(QueryResult { columns, column_types: col_types, rows, affected_rows: affected }) Ok(QueryResult { columns, column_types: col_types, rows, affected_rows: affected })
} }
pub fn auth(&mut self, token: &str) -> Result<(), Box<dyn std::error::Error>> { /// Authenticate with JWT token
pub async fn auth(&mut self, token: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
if !self.connected { if !self.connected {
return Err("Not connected".into()); return Err("Not connected".into());
} }
let payload = encode_string(token); let payload = encode_string(token);
let msg = build_message(MK_AUTH, self.next_id(), &payload); let msg = build_message(MK_AUTH, self.next_id(), &payload);
self.stream.write_all(&msg)?; self.stream.write_all(&msg).await?;
let (kind, length, _) = self.read_header()?; let (kind, length, _) = self.read_header().await?;
match kind { match kind {
MK_AUTH_OK => Ok(()), MK_AUTH_OK => Ok(()),
MK_ERROR => { MK_ERROR => {
let p = self.read_payload(length)?; let p = self.read_payload(length).await?;
Err(Self::read_error_message(&p).into()) Err(Self::read_error_message(&p).into())
} }
_ => Err(format!("Unexpected auth response: 0x{:02x}", kind).into()), _ => Err(format!("Unexpected auth response: 0x{:02x}", kind).into()),
} }
} }
pub fn ping(&mut self) -> Result<bool, Box<dyn std::error::Error>> { /// Ping the server
pub async fn ping(&mut self) -> Result<bool, Box<dyn std::error::Error + Send + Sync>> {
if !self.connected { if !self.connected {
return Err("Not connected".into()); return Err("Not connected".into());
} }
let msg = build_message(MK_PING, self.next_id(), &[]); let msg = build_message(MK_PING, self.next_id(), &[]);
self.stream.write_all(&msg)?; self.stream.write_all(&msg).await?;
let (kind, length, _) = self.read_header()?; let (kind, length, _) = self.read_header().await?;
match kind { match kind {
MK_PONG => Ok(true), MK_PONG => Ok(true),
MK_ERROR => { MK_ERROR => {
let p = self.read_payload(length)?; let p = self.read_payload(length).await?;
Err(Self::read_error_message(&p).into()) Err(Self::read_error_message(&p).into())
} }
_ => Ok(false), _ => Ok(false),
} }
} }
pub fn query(&mut self, sql: &str) -> Result<QueryResult, Box<dyn std::error::Error>> { /// Execute a query
pub async fn query(&mut self, sql: &str) -> Result<QueryResult, Box<dyn std::error::Error + Send + Sync>> {
if !self.connected { if !self.connected {
return Err("Not connected".into()); return Err("Not connected".into());
} }
@@ -386,14 +405,14 @@ impl Client {
payload.push(0x00); // ResultFormat::BINARY payload.push(0x00); // ResultFormat::BINARY
let msg = build_message(MK_QUERY, self.next_id(), &payload); let msg = build_message(MK_QUERY, self.next_id(), &payload);
self.stream.write_all(&msg)?; self.stream.write_all(&msg).await?;
let (kind, length, _) = self.read_header()?; let (kind, length, _) = self.read_header().await?;
let resp_payload = self.read_payload(length)?; let resp_payload = self.read_payload(length).await?;
match kind { match kind {
MK_READY => Ok(QueryResult { columns: vec![], column_types: vec![], rows: vec![], affected_rows: 0 }), MK_READY => Ok(QueryResult { columns: vec![], column_types: vec![], rows: vec![], affected_rows: 0 }),
MK_DATA => self.read_data_response(&resp_payload), MK_DATA => self.read_data_response(&resp_payload).await,
MK_COMPLETE => { MK_COMPLETE => {
let affected = if resp_payload.len() >= 4 { let affected = if resp_payload.len() >= 4 {
u32::from_be_bytes([resp_payload[0], resp_payload[1], resp_payload[2], resp_payload[3]]) as usize u32::from_be_bytes([resp_payload[0], resp_payload[1], resp_payload[2], resp_payload[3]]) as usize
@@ -405,7 +424,8 @@ impl Client {
} }
} }
pub fn query_params(&mut self, sql: &str, params: &[WireValue]) -> Result<QueryResult, Box<dyn std::error::Error>> { /// Execute a parameterized query
pub async fn query_params(&mut self, sql: &str, params: &[WireValue]) -> Result<QueryResult, Box<dyn std::error::Error + Send + Sync>> {
if !self.connected { if !self.connected {
return Err("Not connected".into()); return Err("Not connected".into());
} }
@@ -418,14 +438,14 @@ impl Client {
} }
let msg = build_message(MK_QUERY_PARAMS, self.next_id(), &payload); let msg = build_message(MK_QUERY_PARAMS, self.next_id(), &payload);
self.stream.write_all(&msg)?; self.stream.write_all(&msg).await?;
let (kind, length, _) = self.read_header()?; let (kind, length, _) = self.read_header().await?;
let resp_payload = self.read_payload(length)?; let resp_payload = self.read_payload(length).await?;
match kind { match kind {
MK_READY => Ok(QueryResult { columns: vec![], column_types: vec![], rows: vec![], affected_rows: 0 }), MK_READY => Ok(QueryResult { columns: vec![], column_types: vec![], rows: vec![], affected_rows: 0 }),
MK_DATA => self.read_data_response(&resp_payload), MK_DATA => self.read_data_response(&resp_payload).await,
MK_COMPLETE => { MK_COMPLETE => {
let affected = if resp_payload.len() >= 4 { let affected = if resp_payload.len() >= 4 {
u32::from_be_bytes([resp_payload[0], resp_payload[1], resp_payload[2], resp_payload[3]]) as usize u32::from_be_bytes([resp_payload[0], resp_payload[1], resp_payload[2], resp_payload[3]]) as usize
@@ -437,12 +457,14 @@ impl Client {
} }
} }
pub fn execute(&mut self, sql: &str) -> Result<usize, Box<dyn std::error::Error>> { /// Execute and return affected rows
let result = self.query(sql)?; pub async fn execute(&mut self, sql: &str) -> Result<usize, Box<dyn std::error::Error + Send + Sync>> {
let result = self.query(sql).await?;
Ok(result.affected_rows()) Ok(result.affected_rows())
} }
} }
/// Query builder for fluent SQL construction
pub struct QueryBuilder<'a> { pub struct QueryBuilder<'a> {
client: &'a mut Client, client: &'a mut Client,
select_cols: Vec<String>, select_cols: Vec<String>,
@@ -457,6 +479,7 @@ pub struct QueryBuilder<'a> {
} }
impl<'a> QueryBuilder<'a> { impl<'a> QueryBuilder<'a> {
/// Create a new query builder
pub fn new(client: &'a mut Client) -> Self { pub fn new(client: &'a mut Client) -> Self {
QueryBuilder { QueryBuilder {
client, client,
@@ -472,56 +495,67 @@ impl<'a> QueryBuilder<'a> {
} }
} }
/// Add columns to SELECT
pub fn select(mut self, cols: &[&str]) -> Self { pub fn select(mut self, cols: &[&str]) -> Self {
self.select_cols.extend(cols.iter().map(|s| s.to_string())); self.select_cols.extend(cols.iter().map(|s| s.to_string()));
self self
} }
/// Set the FROM table
pub fn from(mut self, table: &str) -> Self { pub fn from(mut self, table: &str) -> Self {
self.from_table = table.to_string(); self.from_table = table.to_string();
self self
} }
/// Add a WHERE clause
pub fn where_clause(mut self, clause: &str) -> Self { pub fn where_clause(mut self, clause: &str) -> Self {
self.where_clauses.push(clause.to_string()); self.where_clauses.push(clause.to_string());
self self
} }
/// Add a JOIN clause
pub fn join(mut self, table: &str, on: &str) -> Self { pub fn join(mut self, table: &str, on: &str) -> Self {
self.joins.push(format!("JOIN {} ON {}", table, on)); self.joins.push(format!("JOIN {} ON {}", table, on));
self self
} }
/// Add a LEFT JOIN clause
pub fn left_join(mut self, table: &str, on: &str) -> Self { pub fn left_join(mut self, table: &str, on: &str) -> Self {
self.joins.push(format!("LEFT JOIN {} ON {}", table, on)); self.joins.push(format!("LEFT JOIN {} ON {}", table, on));
self self
} }
/// Add GROUP BY columns
pub fn group_by(mut self, cols: &[&str]) -> Self { pub fn group_by(mut self, cols: &[&str]) -> Self {
self.group_by.extend(cols.iter().map(|s| s.to_string())); self.group_by.extend(cols.iter().map(|s| s.to_string()));
self self
} }
/// Add HAVING clause
pub fn having(mut self, clause: &str) -> Self { pub fn having(mut self, clause: &str) -> Self {
self.having = clause.to_string(); self.having = clause.to_string();
self self
} }
/// Add ORDER BY column
pub fn order_by(mut self, col: &str, dir: &str) -> Self { pub fn order_by(mut self, col: &str, dir: &str) -> Self {
self.order_by.push(format!("{} {}", col, dir)); self.order_by.push(format!("{} {}", col, dir));
self self
} }
/// Set LIMIT
pub fn limit(mut self, n: usize) -> Self { pub fn limit(mut self, n: usize) -> Self {
self.limit = n; self.limit = n;
self self
} }
/// Set OFFSET
pub fn offset(mut self, n: usize) -> Self { pub fn offset(mut self, n: usize) -> Self {
self.offset = n; self.offset = n;
self self
} }
/// Build the SQL string
pub fn build(&self) -> String { pub fn build(&self) -> String {
let mut sql = String::from("SELECT "); let mut sql = String::from("SELECT ");
if self.select_cols.is_empty() { if self.select_cols.is_empty() {
@@ -555,9 +589,10 @@ impl<'a> QueryBuilder<'a> {
sql sql
} }
pub fn exec(self) -> Result<QueryResult, Box<dyn std::error::Error>> { /// Execute the query
pub async fn exec(self) -> Result<QueryResult, Box<dyn std::error::Error + Send + Sync>> {
let sql = self.build(); let sql = self.build();
self.client.query(&sql) self.client.query(&sql).await
} }
} }
+167
View File
@@ -97,5 +97,172 @@ RETURN friend.name;
```sql ```sql
BEGIN; BEGIN;
INSERT users { name := 'Alice', age := 30 }; INSERT users { name := 'Alice', age := 30 };
INSERT orders { user_id := last_insert_id(), total := 100 };
COMMIT;
-- مع نقطة حفظ
BEGIN;
INSERT users { name := 'Bob', age := 25 };
SAVEPOINT sp1;
INSERT orders { user_id := last_insert_id(), total := 200 };
-- خطأ، التراجع إلى نقطة الحفظ
ROLLBACK TO sp1;
COMMIT; COMMIT;
``` ```
## البحث النصي الكامل
```sql
-- بحث أساسي
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('database programming');
-- مع درجة الصلة
SELECT title, relevance()
FROM articles
WHERE MATCH(title, body) AGAINST('Nim language')
ORDER BY relevance() DESC;
-- الوضع المنطقي
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('+Nim -Python' IN BOOLEAN MODE);
-- البحث الضبابي
SELECT * FROM articles
WHERE MATCH(title) AGAINST('programing' WITH FUZZINESS 2);
```
## الدوال المحددة من المستخدم
```sql
-- تسجيل UDF
CREATE FUNCTION greet(name str) -> str {
RETURN 'Hello, ' || name || '!';
};
-- استخدامها
SELECT greet(name) FROM users;
-- الدوال المدمجة
SELECT abs(-5), sqrt(16), lower('HELLO'), len('test');
```
## تلميحات الاستعلام
```sql
-- فرض استخدام الفهرس
SELECT /*+ USE_INDEX(idx_users_age) */ * FROM users WHERE age > 18;
-- فرض البحث المتجهي التقريبي
SELECT /*+ APPROXIMATE */ * FROM vectors
ORDER BY cosine_distance(embedding, [...])
LIMIT 10;
-- التنفيذ المتوازي
SELECT /*+ PARALLEL(4) */ * FROM large_table;
```
## دوال النوافذ
```sql
-- دوال الترتيب
SELECT
name,
department,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS r,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dr
FROM employees;
-- دوال القيمة
SELECT
name,
salary,
LAG(salary, 1, 0) OVER (ORDER BY salary) AS prev_salary,
LEAD(salary, 1, 0) OVER (ORDER BY salary) AS next_salary,
FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS cheapest,
LAST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS most_expensive
FROM employees;
-- دوال التوزيع
SELECT name, NTILE(4) OVER (ORDER BY salary) AS quartile FROM employees;
```
### مواصفات الإطار
```sql
-- إطار ROWS
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
)
-- إطار RANGE
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
```
## ERP متعدد المستأجرين
يدعم BaraDB تشغيل عدة شركات (مستأجرين) في مثيل قاعدة بيانات واحد، باستخدام **أمان مستوى الصف (RLS)** مع **متغيرات الجلسة**.
### متغيرات الجلسة
```sql
SET app.tenant_id = 'company-123';
SELECT current_setting('app.tenant_id') AS tenant;
```
### المستخدم / الدور الحالي
```sql
SELECT current_user AS me, current_role AS my_role;
```
### عزل المستأجر عبر RLS
```sql
-- تمكين RLS على جدول
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
-- إنشاء سياسة تصفية حسب المستأجر
CREATE POLICY tenant_isolation ON invoices
FOR SELECT USING (tenant_id = current_setting('app.tenant_id'));
-- كل جلسة ترى فقط بياناتها
SET app.tenant_id = 'company-a';
SELECT * FROM invoices; -- صفوف company-a فقط
```
### لماذا متعدد المستأجرين؟
- **مثيل واحد، مستأجرون كثيرون** — لا حاجة لتشغيل 100 قاعدة بيانات منفصلة
- **مستندات JSONB** — تخزين مخطط مرن، سهل إضافة حقول لكل مستأجر
- **RLS يضمن العزل** — قاعدة البيانات تفرض حدود المستأجر، وليس فقط التطبيق
## الكلمات المفتاحية المدعومة
| الفئة | الكلمات المفتاحية |
|----------|----------|
| DQL | SELECT, FROM, WHERE, ORDER BY, GROUP BY, HAVING, LIMIT, OFFSET, DISTINCT |
| DML | INSERT, UPDATE, DELETE, SET, VALUES |
| DDL | CREATE TYPE, DROP TYPE, CREATE INDEX, DROP INDEX, ALTER TYPE |
| Join | INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN, CROSS JOIN, ON |
| Set | UNION, UNION ALL, INTERSECT, EXCEPT |
| CTEs | WITH, RECURSIVE, AS |
| Case | CASE, WHEN, THEN, ELSE, END |
| Transaction | BEGIN, COMMIT, ROLLBACK, SAVEPOINT |
| Graph | MATCH, RETURN, WHERE, shortestPath, type |
| FTS | MATCH, AGAINST, relevance, IN BOOLEAN MODE, WITH FUZZINESS |
| Vector | cosine_distance, euclidean_distance, inner_product, l1_distance, l2_distance, <-> |
| JSON | ->, ->> |
| FTS | @@ (تطابق BM25) |
| Recovery | RECOVER TO TIMESTAMP |
| Functions | count, sum, avg, min, max, stddev, variance, abs, sqrt, lower, upper, len, trim, substr, now, last_insert_id, current_setting |
| Session | SET, current_setting, current_user, current_role |
| Window | OVER, PARTITION BY, ROWS, RANGE, UNBOUNDED PRECEDING, CURRENT ROW, FOLLOWING |
| Window Functions | ROW_NUMBER, RANK, DENSE_RANK, LEAD, LAG, FIRST_VALUE, LAST_VALUE, NTILE |
+246
View File
@@ -22,38 +22,284 @@
### لينكس ### لينكس
```bash ```bash
# المثبت الرسمي
curl https://nim-lang.org/choosenim/init.sh -sSf | sh curl https://nim-lang.org/choosenim/init.sh -sSf | sh
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install nim
# Fedora
sudo dnf install nim
# Arch Linux
sudo pacman -S nim
``` ```
### macOS ### macOS
```bash ```bash
# Homebrew
brew install nim brew install nim
# MacPorts
sudo port install nim
``` ```
### ويندوز ### ويندوز
```powershell ```powershell
# باستخدام choosenim
curl.exe -A "MSYS2_$(uname -m)" -L https://nim-lang.org/choosenim/init.ps1 | powershell -
# باستخدام winget
winget install nim winget install nim
# باستخدام scoop
scoop install nim
``` ```
### التحقق من التثبيت
```bash
nim --version
# المتوقع: Nim Compiler Version 2.2.0 أو أحدث
```
## تثبيت OpenSSL
### لينكس
```bash
# Ubuntu/Debian
sudo apt-get install libssl-dev
# Fedora
sudo dnf install openssl-devel
# Arch Linux
sudo pacman -S openssl
```
### macOS
OpenSSL مضمن مع النظام. إذا لزم الأمر:
```bash
brew install openssl
```
### ويندوز
OpenSSL مضمن مع توزيع Nim ويندوز. للبناء اليدوي، قم بالتنزيل من [slproweb.com](https://slproweb.com/products/Win32OpenSSL.html).
## بناء BaraDB ## بناء BaraDB
### استنساخ المستودع
```bash ```bash
git clone https://github.com/katehonz/barabaDB.git git clone https://github.com/katehonz/barabaDB.git
cd barabaDB cd barabaDB
```
### تثبيت التبعيات
```bash
nimble install -d -y nimble install -d -y
```
### خيارات البناء
#### بناء التصحيح
```bash
nim c -d:ssl -o:build/baradadb src/baradadb.nim
```
#### بناء الإصدار (موصى به)
```bash
nim c -d:ssl -d:release --opt:speed -o:build/baradadb src/baradadb.nim nim c -d:ssl -d:release --opt:speed -o:build/baradadb src/baradadb.nim
``` ```
#### استخدام مهام Nimble
```bash
# بناء التصحيح
nimble build_debug
# بناء الإصدار
nimble build_release
```
#### تقليل حجم الملف الثنائي
```bash
nim c -d:ssl -d:release --opt:size -o:build/baradadb src/baradadb.nim
strip build/baradadb
```
### التحقق من البناء
```bash
./build/baradadb --version
# المتوقع: BaraDB v1.1.0 — Multimodal Database Engine
```
## تشغيل الاختبارات
### جميع الاختبارات
```bash
nim c -d:ssl -r tests/test_all.nim
```
### مجموعات اختبارات محددة
```bash
# اختبارات التخزين
nim c -d:ssl -r tests/test_storage.nim
# اختبارات محرك الاستعلام
nim c -d:ssl -r tests/test_query.nim
# اختبارات البروتوكول
nim c -d:ssl -r tests/test_protocol.nim
```
### المعايير
```bash
nim c -d:ssl -d:release -r benchmarks/bench_all.nim
```
## خيارات التثبيت
### التثبيت على مستوى النظام
```bash
# بناء إصدار RELEASE
nimble build_release
# التثبيت في /usr/local/bin
sudo cp build/baradadb /usr/local/bin/
sudo chmod +x /usr/local/bin/baradadb
# إنشاء دليل البيانات
sudo mkdir -p /var/lib/baradb
sudo chmod 755 /var/lib/baradb
```
### الملف الثنائي المبنى مسبقًا
قم بتنزيل أحدث إصدار لمنصتك:
```bash
# لينكس x86_64
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-linux-amd64
chmod +x baradadb-linux-amd64
mv baradadb-linux-amd64 /usr/local/bin/baradadb
# لينكس ARM64
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-linux-arm64
chmod +x baradadb-linux-arm64
mv baradadb-linux-arm64 /usr/local/bin/baradadb
# macOS
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-darwin-amd64
chmod +x baradadb-darwin-amd64
mv baradadb-darwin-amd64 /usr/local/bin/baradadb
```
### Docker
```bash
# سحب الصورة الرسمية
docker pull barabadb/barabadb:latest
# التشغيل
docker run -d \
-p 9472:9472 \
-p 9470:9470 \
-p 9471:9471 \
-v baradb_data:/data \
barabadb/barabadb
```
### Docker Compose
```bash
docker-compose up -d
```
### الاستخدام المدمج (مشاريع Nim)
أضف إلى ملف `.nimble` الخاص بك:
```nim
requires "barabadb >= 1.1.0"
```
استخدم في الكود:
```nim
import barabadb/storage/lsm
var db = newLSMTree("./data")
db.put("key", cast[seq[byte]]("value"))
let (found, val) = db.get("key")
db.close()
```
## التشغيل الأول ## التشغيل الأول
```bash ```bash
# بدء الخادم
./build/baradadb ./build/baradadb
# المخرجات المتوقعة:
# BaraDB v1.1.0 — Multimodal Database Engine
# BaraDB TCP listening on 127.0.0.1:9472
# الاختبار عبر HTTP API
curl http://localhost:9470/health curl http://localhost:9470/health
# الصدفة التفاعلية
./build/baradadb --shell ./build/baradadb --shell
``` ```
## حل مشكلات التثبيت
### "cannot open file: hunos"
```bash
nimble install -d -y
```
### "BaraDB requires SSL support"
قم دائمًا بالبناء باستخدام `-d:ssl`:
```bash
nim c -d:ssl -o:build/baradadb src/baradadb.nim
```
### البناء البطيء
استخدم البناء المتوازي:
```bash
nim c -d:ssl -d:release --parallelBuild:4 -o:build/baradadb src/baradadb.nim
```
### حجم الملف الثنائي الكبير
استخدم تحسين الحجم:
```bash
nim c -d:ssl -d:release --opt:size --passL:-s -o:build/baradadb src/baradadb.nim
```
## الخطوات التالية ## الخطوات التالية
- [دليل البداية السريعة](quickstart.md) - [دليل البداية السريعة](quickstart.md)
+107
View File
@@ -0,0 +1,107 @@
# API за Бинарен Протокол
Ниско-нивов wire протокол за високопроизводителни клиентски връзки.
## Формат на Съобщенията
Всички съобщения използват big-endian byte order:
```
┌─────────────┬─────────────┬─────────────┬─────────────────────┐
│ Kind │ Length │ RequestId │ Payload │
│ (4 bytes) │ (4 bytes) │ (4 bytes) │ │
│ uint32 BE │ uint32 BE │ uint32 BE │ (Length bytes) │
└─────────────┴─────────────┴─────────────┴─────────────────────┘
```
## Типове Съобщения
### Query (0x01)
```nim
let msg = makeQueryMessage(requestId, "SELECT * FROM users")
```
### QueryParams (0x02)
```nim
let msg = makeQueryParamsMessage(requestId, "SELECT * FROM users WHERE name = ?", params)
```
### Auth (0x07)
```nim
let msg = makeAuthMessage(requestId, token)
```
### Ping (0x09)
```nim
let msg = makePingMessage(requestId)
```
### Close (0x0A)
```nim
let msg = makeCloseMessage(requestId)
```
## Отговорни Съобщения
### Ready (0x05)
```nim
let msg = makeReadyMessage(requestId)
```
### Error (0x06)
```nim
let msg = makeErrorMessage(requestId, code, message)
```
### Data (0x81)
```nim
# Съдържа резултатите от заявката с колони и редове
```
### Complete (0x82)
```nim
# Потвърждава завършване на заявката
```
### Auth_OK (0x83)
```nim
# Потвърждава успешна автентикация
```
### Pong (0x84)
```nim
# Keepalive отговор
```
## Кодове за Грешки
| Код | Име | Описание |
|------|-----|----------|
| 0x00 | OK | Успех |
| 0x01 | ERROR | Обща грешка |
| 0x02 | AUTH_REQUIRED | Изисква се автентикация |
| 0x03 | INVALID_QUERY | Синтактична грешка в заявката |
| 0x04 | NOT_FOUND | Ресурсът не е намерен |
## Сериализация
```nim
import barabadb/protocol/wire
# Сериализиране на стойност
let bytes = serializeValue(Value(kind: vkString, strVal: "test"))
# Десериализиране на стойност
let value = deserializeValue(bytes)
```
+111
View File
@@ -0,0 +1,111 @@
# HTTP/REST API
JSON-базиран REST API за уеб приложения.
## Базов URL
```
http://localhost:9470
```
## Endpoints
### GET /health
Health проверка:
```bash
curl http://localhost:9470/health
```
### GET /ready
Readiness проверка:
```bash
curl http://localhost:9470/ready
```
### POST /query
Изпълнение на BaraQL заявка:
```bash
curl -X POST http://localhost:9470/api/query \
-H "Content-Type: application/json" \
-d '{"query": "SELECT * FROM users WHERE age > 18"}'
```
Отговор:
```json
{
"columns": ["name", "age"],
"rows": [["Alice", 30], ["Bob", 25]],
"row_count": 2,
"duration_ms": 12
}
```
### POST /batch
Групови заявки:
```bash
curl -X POST http://localhost:9470/api/batch \
-H "Content-Type: application/json" \
-d '{"queries": ["INSERT users { name := \"Alice\" }", "INSERT users { name := \"Bob\" }"]}'
```
### GET /schema
Преглед на схемата:
```bash
curl http://localhost:9470/api/schema
```
### GET /metrics
Prometheus метрики:
```bash
curl http://localhost:9470/metrics
```
### POST /explain
Обяснение на план за изпълнение:
```bash
curl -X POST http://localhost:9470/api/explain \
-H "Content-Type: application/json" \
-d '{"query": "SELECT * FROM users WHERE age > 18"}'
```
### POST /backup
Създаване на backup:
```bash
curl -X POST http://localhost:9470/api/backup \
-H "Content-Type: application/json" \
-d '{"destination": "/backup/snapshot.db"}'
```
## Грешки
```json
{
"error": {
"code": "INVALID_QUERY",
"message": "Грешка в синтаксиса"
}
}
```
## Автентикация
```bash
curl -H "Authorization: Bearer <token>" \
http://localhost:9470/api/users
```
+127
View File
@@ -0,0 +1,127 @@
# WebSocket API
Full-duplex стрийминг за данни в реално време и push известия.
## Свързване
```
ws://localhost:9471
```
## Клиентски Пример
```javascript
const ws = new WebSocket('ws://localhost:9471');
ws.onopen = () => {
console.log('Свързан');
ws.send(JSON.stringify({
type: 'query',
query: 'SELECT * FROM users'
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Получено:', data);
};
```
## Формат на Съобщенията
```json
{
"type": "query",
"id": "1",
"query": "SELECT * FROM users"
}
```
## Типове Съобщения
### Заявка (query)
```json
{
"type": "query",
"id": "1",
"query": "SELECT * FROM users"
}
```
### Резултат (result)
```json
{
"type": "result",
"id": "1",
"columns": ["id", "name"],
"rows": [["1", "Alice"], ["2", "Bob"]]
}
```
### Грешка (error)
```json
{
"type": "error",
"id": "1",
"code": "INVALID_QUERY",
"message": "Синтактична грешка"
}
```
### Абониране (subscribe)
Абониране за промени в таблица:
```json
{
"type": "subscribe",
"id": "sub1",
"table": "users"
}
```
### Известие (notification)
Push известие от сървъра:
```json
{
"type": "notification",
"table": "users",
"operation": "insert",
"data": {"id": 3, "name": "Charlie"}
}
```
### Ping/Pong (keepalive)
```json
{"type": "ping", "id": "ping1"}
```
Отговор:
```json
{"type": "pong", "id": "ping1"}
```
## JavaScript Клиент
```javascript
class BaraDBClient {
constructor(url) {
this.ws = new WebSocket(url);
this.pending = new Map();
}
query(sql) {
return new Promise((resolve, reject) => {
const id = crypto.randomUUID();
this.pending.set(id, { resolve, reject });
this.ws.send(JSON.stringify({ type: 'query', id, query: sql }));
});
}
}
```
+68 -93
View File
@@ -2,150 +2,125 @@
## Преглед ## Преглед
BaraDB е **мултимодална база данни** написана на Nim, която комбинира документно (KV), графично, векторно, колонно и пълнотекстово търсене в един двигател с обединен език за заявки наречен **BaraQL**. BaraDB е **мултимодален database engine**, написан на Nim, който комбинира документно (KV), графово, векторно, колонково и пълнотекстово съхранение в един engine с унифициран език за заявки наречен **BaraQL**.
## Слоеста Архитектура ## Слоеве на Архитектурата
``` ```
┌─────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────┐
│ 1. СЛОЙ ЗА КЛИЕНТИ │ 1. КЛИЕНТСКИ СЛОЙ │
Binary Protocol │ HTTP/REST │ WebSocket │ Embedded Бинарен Протокол │ HTTP/REST │ WebSocket │ Embedded │
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────┤
│ 2. ЗАЯВКИ СЛОЙ (BaraQL) │ │ 2. QUERY СЛОЙ (BaraQL)
│ Lexer → Parser → AST → IR → Optimizer → Codegen │ │ Lexer → Parser → AST → IR → Optimizer → Codegen │
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────┤
│ 3. ИЗПЪЛНИТЕЛЕН ДВИГАТЕЛ │ 3. ИЗПЪЛНИТЕЛЕН ENGINE
Document │ Graph │ Vector │ Columnar │ FTS Документен │ Графов │ Векторен │ Колонков │ FTS │
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────┤
│ 4. СЪХРАНЕНИЕ │ │ 4. СЪХРАНЕНИЕ │
│ LSM-Tree │ B-Tree │ WAL │ Bloom │ Compaction │ Cache │ │ LSM-Tree │ B-Tree │ WAL │ Bloom │ Compaction │ Cache │
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────┤
│ 5. РАЗПРЕДЕЛЕНО │ 5. РАЗПРЕДЕЛЕНИ
│ Raft Consensus │ Sharding │ Replication │ Gossip │ │ Raft Консенсус │ Шардиране │ Репликация │ Gossip │
└─────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────┘
``` ```
## Слой 1: Клиентски Слой ## Слой 1: Клиентски Слой
Множество протоколи за комуникация: Множество комуникационни протоколи:
- **Binary Protocol** (`protocol/wire.nim`): Ефективен big-endian бинарен протокол с 16 типа съобщения - **Бинарен Протокол** (`protocol/wire.nim`): Ефективен big-endian бинарен протокол с 16 типа съобщения
- **HTTP/REST** (`core/httpserver.nim`): JSON REST API с мулти-трединг - **HTTP/REST** (`core/httpserver.nim`): JSON-базиран REST API с multi-threading
- **WebSocket** (`core/websocket.nim`): Пълен дуплекс стрийминг - **WebSocket** (`core/websocket.nim`): Full-duplex стрийминг
- **Embedded** (`storage/lsm.nim`): Директен in-process достъп - **Embedded** (`storage/lsm.nim`): Директен in-process достъп
### Управление на Връзките ### Управление на Връзки
- **Connection Pool** (`protocol/pool.nim`): Мин/макс лимити на връзки - **Connection Pool** (`protocol/pool.nim`): Min/max лимити на връзки с idle timeout
- **Rate Limiting** (`protocol/ratelimit.nim`): Token-bucket лимитиране - **Rate Limiting** (`protocol/ratelimit.nim`): Token-bucket глобални и per-client лимити
- **Authentication** (`protocol/auth.nim`): JWT с HMAC-SHA256 - **Автентикация** (`protocol/auth.nim`): JWT с HMAC-SHA256 и достъп на база роли
- **TLS/SSL** (`protocol/ssl.nim`): TLS 1.3 с авто-генерирани сертификати - **TLS/SSL** (`protocol/ssl.nim`): TLS 1.3 с автоматично генерирани сертификати
## Слой 2: Заявки (BaraQL) ## Слой 2: Query Слой (BaraQL)
Pipeline-а на BaraQL: BaraQL конвейрът:
1. **Lexer** (`query/lexer.nim`): Токенизира входа в 80+ типа токени 1. **Lexer** (`query/lexer.nim`): Токенизира входа в 80+ типа токени
2. **Parser** (`query/parser.nim`): Рекурсивен descent парсър произвеждащ AST 2. **Parser** (`query/parser.nim`): Recursive descent parser генериращ AST
3. **AST** (`query/ast.nim`): 300+ реда покриващи 25+ вида възли 3. **AST** (`query/ast.nim`): 300+ реда покриващи 25+ вида възли
4. **IR** (`query/ir.nim`): Междинно представяне за планове за изпълнение 4. **IR** (`query/ir.nim`): Intermediate representation за планове за изпълнение
5. **Optimizer** (`query/adaptive.nim`): Адаптивен крос-модален оптимизатор 5. **Optimizer** (`query/adaptive.nim`): Adaptive cross-modal оптимизация на заявки
6. **Codegen** (`query/codegen.nim`): Транслира IR към операции върху съхранение 6. **Codegen** (`query/codegen.nim`): Превежда IR към storage операции
7. **Executor** (`query/executor.nim`): Изпълнява планове с паралелизация 7. **Executor** (`query/executor.nim`): Изпълнява планове с паралелизация
### Крос-Модално Планиране ## Слой 3: Изпълнителен Engine
Оптимизаторът определя реда на изпълнение между двигателите: ### Документен/KV Engine
- **LSM-Tree** (`storage/lsm.nim`): Write-оптимизирано съхранение с MemTable, WAL, SSTables
- **B-Tree Индекс** (`storage/btree.nim`): Подреден индекс за range сканиране с COW
``` ### Vector Engine (`vector/`)
1. Оценка на селективност за всеки предикат - **HNSW Индекс** (`vector/engine.nim`): Hierarchical Navigable Small World граф
2. Най-селективният предикат се изпълнява първи - **IVF-PQ Индекс** (`vector/engine.nim`): Inverted File Index с Product Quantization
3. Bloom филтри за KV търсения - **SIMD Операции** (`vector/simd.nim`): AVX2-оптимизирани изчисления на разстояние
4. Паралелизация на независими клонове - **Квантуване** (`vector/quant.nim`): Скаларно, продуктово и бинарно квантуване
```
## Слой 3: Изпълнителен Двигател ### Graph Engine (`graph/`)
- **Adjacency List** (`graph/engine.nim`): Насочен граф с тегла на ребрата
### Document/KV Двигател
- **LSM-Tree** (`storage/lsm.nim`): Оптимизиран за запис с MemTable, WAL, SSTables
- **B-Tree Index** (`storage/btree.nim`): Подреден индекс за диапазони с COW
### Vector Engine
- **HNSW** (`vector/engine.nim`): Иерархичен навигируем малък свят
- **IVF-PQ** (`vector/engine.nim`): Инвертиран файл с продуктово квантуване
- **SIMD** (`vector/simd.nim`): AVX2-оптимизирани изчисления на разстояния
- **Quantization** (`vector/quant.nim`): Скаларно, продуктово и бинарно квантуване
### Graph Engine
- **Списък със съседи** (`graph/engine.nim`): Насочен граф с тегла
- **Алгоритми** (`graph/engine.nim`): BFS, DFS, Dijkstra, PageRank - **Алгоритми** (`graph/engine.nim`): BFS, DFS, Dijkstra, PageRank
- **Community Detection** (`graph/community.nim`): Louvain алгоритъм - **Community Detection** (`graph/community.nim`): Louvain алгоритъм
- **Pattern Matching** (`graph/community.nim`): Subgraph isomorphism - **Pattern Matching** (`graph/community.nim`): Subgraph изоморфизъм
- **Cypher Parser** (`graph/cypher.nim`): Cypher-подобни заявки - **Cypher Parser** (`graph/cypher.nim`): Cypher-подобни графови заявки
### FTS ### Full-Text Search (`fts/`)
- **Инвертиран индекс** (`fts/engine.nim`): Термин-документ индекс - **Inverted Index** (`fts/engine.nim`): Термин-документен индекс
- **Ранжиране** (`fts/engine.nim`): BM25 и TF-IDF - **Ранжиране** (`fts/engine.nim`): BM25 и TF-IDF оценяване
- **Fuzzy Search** (`fts/engine.nim`): Levenshtein разстояние - **Fuzzy Търсене** (`fts/engine.nim`): Съвпадение с Levenshtein разстояние
- **Многоезичен** (`fts/multilang.nim`): Токенизация за EN, BG, DE, FR, RU - **Многоезичност** (`fts/multilang.nim`): Токенизатори за EN, BG, DE, FR, RU
### Columnar Engine ### Columnar Engine (`core/columnar.nim`)
- **Колонно съхранение** (`core/columnar.nim`): Аналитични заявки - Колонково съхранение за аналитични заявки
- **Компресия**: RLE и dictionary encoding - RLE и dictionary encoding
- **SIMD агрегати**: Ускорени агрегатни функции - SIMD-ускорени агрегати
## Слой 4: Съхранение ## Слой 4: Съхранение
- **LSM-Tree** (`storage/lsm.nim`): MemTable, WAL, SSTable, Bloom Filter, Compaction - **LSM-Tree** (`storage/lsm.nim`): MemTable, WAL, SSTable, Bloom Filter, Compaction
- **Page Cache** (`storage/compaction.nim`): LRU кеш - **Page Cache** (`storage/compaction.nim`): LRU кеш с проследяване на hit rate
- **Memory-mapped I/O** (`storage/mmap.nim`): mmap-базиран достъп - **Memory-mapped I/O** (`storage/mmap.nim`): mmap-базиран достъп до файлове
- **Recovery** (`storage/recovery.nim`): WAL replay и възстановяване - **Recovery** (`storage/recovery.nim`): WAL replay и crash recovery
### Път на Запис ## Слой 5: Разпределение
``` - **Raft Консенсус** (`core/raft.nim`): Leader election, log репликация
Client → Protocol → Auth → Parser → AST → IR → Codegen - **Шардиране** (`core/sharding.nim`): Hash, range и consistent hashing
→ StorageOp → MVCC Txn → WAL Write → MemTable → Commit - **Репликация** (`core/replication.nim`): Sync, async, semi-sync режими
``` - **Gossip Протокол** (`core/gossip.nim`): SWIM-подобно управление на членство
- **Разпределени Транзакции** (`core/disttxn.nim`): Two-phase commit
### Път на Четене ## Ключови Дизайнерски Решения
```
Client → Protocol → Auth → Parser → AST → IR → Codegen
→ StorageOp → MVCC Snapshot → MemTable → SSTable → Result
```
## Слой 5: Разпределено
- **Raft Consensus** (`core/raft.nim`): Лидерско избиране, репликация на логове
- **Sharding** (`core/sharding.nim`): Hash, range и консистентно хеширане
- **Replication** (`core/replication.nim`): Sync, async, semi-sync режими
- **Gossip Protocol** (`core/gossip.nim`): SWIM-подобно управление на членство
- **Distributed Transactions** (`core/disttxn.nim`): Two-phase commit
## Ключови Дизайн Решения
1. **Чист Nim**: Без Cython, Python или Rust зависимости 1. **Чист Nim**: Без Cython, Python или Rust зависимости
2. **Обединено Съхранение**: Един двигател за KV, граф, вектор, FTS и колонно 2. **Унифицирано Съхранение**: Един engine обработва KV, graph, vector, FTS и columnar
3. **Вграден Режим**: Работи като библиотека или сървър 3. **Embedded Режим**: Може да работи като библиотека или сървър
4. **Бинарен Протокол**: Ефективен wire протокол 4. **Бинарен Протокол**: Персонализиран ефективен wire протокол
5. **MVCC**: Multi-version concurrency control 5. **MVCC**: Multi-version concurrency control
6. **Schema-First**: Строго типизирана система с наследяване 6. **Schema-First**: Силно типизирана система от схеми с наследяване
7. **Крос-Модал**: Един език за заявки през всички модели данни 7. **Cross-Modal**: Един език за заявки за всички модели на данни
8. **Формално Верифициран**: Разпределените алгоритми са специфицирани в TLA+ и проверени с TLC 8. **Формално Верифициран**: Основните разпределени алгоритми са специфицирани в TLA+ и проверени с TLC
## Статистика на Модулите ## Статистика на Модулите
| Категория | Модули | Редове Код | Предназначение | | Категория | Модули | Редове Код | Предназначение |
|-----------|--------|------------|----------------| |-----------|--------|------------|----------------|
| Core | 16 | ~4,200 | Сървър, протоколи, транзакции, разпределено | | Core | 16 | ~4,200 | Сървър, протоколи, транзакции, разпределени |
| Storage | 7 | ~3,100 | LSM, B-Tree, WAL, bloom, compaction, mmap | | Storage | 7 | ~3,100 | LSM, B-Tree, WAL, bloom, compaction, mmap |
| Query | 7 | ~2,800 | Lexer, parser, AST, IR, оптимизатор, codegen, executor | | Query | 7 | ~2,800 | Lexer, parser, AST, IR, optimizer, codegen, executor |
| Vector | 3 | ~1,200 | HNSW, IVF-PQ, квантуване, SIMD | | Vector | 3 | ~1,200 | HNSW, IVF-PQ, квантуване, SIMD |
| Graph | 3 | ~1,000 | Списък със съседи, алгоритми, community detection | | Graph | 3 | ~1,000 | Adjacency list, алгоритми, community detection |
| FTS | 2 | ~900 | Инвертиран индекс, BM25, fuzzy, многоезичен | | FTS | 2 | ~900 | Inverted index, BM25, fuzzy, многоезичност |
| Protocol | 7 | ~2,400 | Wire, HTTP, WebSocket, pool, auth, rate limit, SSL | | Protocol | 7 | ~2,400 | Wire, HTTP, WebSocket, pool, auth, rate limit, SSL |
| Schema | 1 | ~600 | Типове, връзки, наследяване, миграции | | Schema | 1 | ~600 | Типове, връзки, наследяване, миграции |
| Client | 2 | ~800 | Nim binary client, file helpers | | Client | 2 | ~800 | Nim бинарен клиент, файлови помощници |
| CLI | 1 | ~400 | Интерактивна BaraQL конзола | | CLI | 1 | ~400 | Интерактивна BaraQL обвивка |
| **Общо** | **49** | **~14,100** | | | **Общо** | **49** | **~14,100** | |
+198
View File
@@ -0,0 +1,198 @@
# Backup и Възстановяване
## Online Snapshots
BaraDB поддържа online snapshots без спиране на сървъра. Snapshot-ът заснема консистентен изглед към момент във времето чрез MVCC.
### Създаване на Snapshot
```nim
import barabadb/core/backup
var bm = newBackupManager()
bm.createSnapshot("/backup/baradb_2025-01-15")
```
### Чрез CLI
```bash
./build/baradadb --snapshot --output=/backup/snapshot.db
```
### Чрез HTTP API
```bash
curl -X POST http://localhost:9470/api/backup \
-H "Content-Type: application/json" \
-d '{"destination": "/backup/snapshot.db"}'
```
### Автоматизирани Backups
Използвайте cron за планирани backups:
```bash
# Ежедневен snapshot в 2 сутринта
0 2 * * * /usr/local/bin/baradadb --snapshot --output=/backup/baradb_$(date +\%Y\%m\%d).db
# Запазване на последните 7 дни
find /backup -name "baradb_*.db" -mtime +7 -delete
```
## Point-in-Time Recovery (PITR)
BaraDB използва Write-Ahead Log (WAL) за възстановяване до момент във времето.
### WAL Архивиране
Включете непрекъснато WAL архивиране:
```bash
BARADB_WAL_ARCHIVE_DIR=/backup/wal \
BARADB_WAL_ARCHIVE_INTERVAL_MS=60000 \
./build/baradadb
```
### Възстановяване от Checkpoint + WAL
```bash
# Възстановяване от snapshot
./build/baradadb --recover \
--checkpoint=/backup/snapshot.db \
--wal-dir=/backup/wal
# Възстановяване до конкретен LSN
./build/baradadb --recover \
--checkpoint=/backup/snapshot.db \
--wal-dir=/backup/wal \
--target-lsn=15420
# Възстановяване до конкретно време
./build/baradadb --recover \
--checkpoint=/backup/snapshot.db \
--wal-dir=/backup/wal \
--target-time="2025-01-15T10:30:00Z"
```
### Възстановяване чрез SQL
Можете също да възстановявате директно чрез BaraQL:
```sql
RECOVER TO TIMESTAMP '2026-05-07T12:00:00';
```
### Инкрементални Backups
Инкременталните backups копират само променени SSTables:
```bash
./build/baradadb --backup-incremental \
--last-backup=/backup/previous \
--output=/backup/incremental_$(date +%Y%m%d)
```
## Репликация като Backup
За непрекъсната защита използвайте streaming репликация:
### Primary
```bash
BARADB_REPLICATION_ENABLED=true \
BARADB_REPLICATION_MODE=async \
./build/baradadb
```
### Replica
```bash
BARADB_REPLICATION_ENABLED=true \
BARADB_REPLICATION_PRIMARY=primary:9472 \
./build/baradadb
```
## Disaster Recovery
### Процедури за Възстановяване
#### Сценарий 1: Повреда на Единичен Файл
```bash
# Идентифициране на повреден SSTable от логовете
# Възстановяване на конкретен SSTable от backup
cp /backup/sstables/000012.sst ./data/sstables/
# Възстановяване на индекса
./build/baradadb --rebuild-index
```
#### Сценарий 2: Пълна Загуба на Данни
```bash
# 1. Възстановяване на последния snapshot
cp /backup/snapshot.db ./data/
# 2. Преиграване на WAL
./build/baradadb --recover --wal-dir=/backup/wal
# 3. Проверка
curl http://localhost:9470/health
```
#### Сценарий 3: Отказ на Възел в Клъстер
```bash
# За Raft клъстери, просто стартирайте нов възел
BARADB_RAFT_NODE_ID=newnode \
BARADB_RAFT_PEERS=node1:9001,node2:9001 \
./build/baradadb
# Новият възел ще навакса чрез Raft log репликация
```
## Верификация на Backup
Винаги проверявайте backups:
```bash
# Възстановяване във временна директория
./build/baradadb --recover \
--checkpoint=/backup/snapshot.db \
--data-dir=/tmp/verify_data
# Проверка на консистентност
curl http://localhost:9470/api/admin/check
```
## Изисквания за Съхранение
| Тип Backup | Размер | Честота | Задържане |
|------------|--------|---------|-----------|
| Пълен snapshot | ~1× размер на данните | Ежедневно | 7 дни |
| Инкрементален | ~0.1× размер на данните | На всеки час | 24 часа |
| WAL архив | ~0.05× размер на данните / ден | Непрекъснато | 30 дни |
## Най-добри Практики
1. **Тествайте възстановяването редовно** — Backup, който не може да бъде възстановен, е безполезен
2. **Съхранявайте backups извън локацията** — Използвайте S3, GCS или Azure Blob
3. **Криптирайте backups** — Използвайте `gpg` или криптиране на ниво ОС
4. **Мониторирайте backup задачите** — Алармирайте при неуспешни backups
5. **Документирайте RTO/RPO** — Знайте целите си за време и точка на възстановяване
### Качване на Backup в Облак
```bash
# Качване в S3
aws s3 cp /backup/snapshot.db s3://my-bucket/baradb/
# Качване в GCS
gsutil cp /backup/snapshot.db gs://my-bucket/baradb/
# Качване в Azure
az storage blob upload \
--container-name backups \
--file /backup/snapshot.db \
--name baradb/snapshot.db
```
+558 -31
View File
@@ -2,39 +2,160 @@
BaraQL е SQL-съвместим език за заявки с разширения за графи, вектори и документи. BaraQL е SQL-съвместим език за заявки с разширения за графи, вектори и документи.
## Типове Данни
| Тип | Описание | Пример |
|------|----------|--------|
| `null` | Null стойност | `null` |
| `bool` | Булев | `true`, `false` |
| `int8` | 8-битов signed integer | `127` |
| `int16` | 16-битов signed integer | `32767` |
| `int32` | 32-битов signed integer | `2147483647` |
| `int64` | 64-битов signed integer | `9223372036854775807` |
| `float32` | 32-битов float | `3.14` |
| `float64` | 64-битов float | `3.14159265359` |
| `str` | UTF-8 низ | `'hello'` |
| `bytes` | Сурови байтове | `0xDEADBEEF` |
| `array<T>` | Хомогенен масив | `[1, 2, 3]` |
| `vector` | Float32 вектор | `[0.1, 0.2, 0.3]` |
| `vector(n)` | Float32 вектор с фиксирана размерност (SQL) | `VECTOR(768)` |
| `object` | Ключ-стойност обект | `{"a": 1}` |
| `datetime` | ISO 8601 времеви печат | `'2025-01-15T10:30:00Z'` |
| `uuid` | UUID v4 | `'550e8400-e29b-41d4-a716-446655440000'` |
| `json` | JSON документ | `{"key": "value"}` |
| `jsonb` | Бинарен JSON (валидиран) | `{"key": "value"}` |
## Основни Заявки ## Основни Заявки
### SELECT ### SELECT
```sql ```sql
SELECT name, age FROM users WHERE age > 18 ORDER BY name LIMIT 10; -- Всички колони
SELECT * FROM users;
-- Конкретни колони
SELECT name, age FROM users;
-- Псевдоними
SELECT name AS full_name, age AS years FROM users;
-- DISTINCT
SELECT DISTINCT department FROM employees;
-- LIMIT и OFFSET
SELECT * FROM users LIMIT 10 OFFSET 20;
```
### WHERE
```sql
-- Оператори за сравнение
SELECT * FROM users WHERE age > 18;
SELECT * FROM users WHERE age >= 18 AND age <= 65;
SELECT * FROM users WHERE name = 'Alice';
SELECT * FROM users WHERE name != 'Bob';
-- Диапазон
SELECT * FROM users WHERE age BETWEEN 18 AND 65;
-- Принадлежност към множество
SELECT * FROM users WHERE department IN ('Engineering', 'Sales');
-- Търсене по шаблон
SELECT * FROM users WHERE name LIKE 'A%';
SELECT * FROM users WHERE name ILIKE 'alice'; -- Case-insensitive
-- NULL проверки
SELECT * FROM users WHERE email IS NOT NULL;
-- Логически оператори
SELECT * FROM users WHERE age > 18 AND (department = 'Engineering' OR department = 'Sales');
```
### ORDER BY
```sql
-- Възходящ (по подразбиране)
SELECT * FROM users ORDER BY age;
-- Низходящ
SELECT * FROM users ORDER BY age DESC;
-- Множество колони
SELECT * FROM users ORDER BY department ASC, age DESC;
``` ```
### INSERT ### INSERT
```sql ```sql
-- Един ред
INSERT users { name := 'Alice', age := 30 }; INSERT users { name := 'Alice', age := 30 };
-- С явен тип
INSERT User { name := 'Alice', age := 30 };
-- Множество редове
INSERT users {
{ name := 'Alice', age := 30 },
{ name := 'Bob', age := 25 }
};
``` ```
### UPDATE ### UPDATE
```sql ```sql
-- Обнови всички редове
UPDATE users SET status = 'active';
-- Условно обновяване
UPDATE users SET age = 31 WHERE name = 'Alice'; UPDATE users SET age = 31 WHERE name = 'Alice';
-- Обновяване на няколко колони
UPDATE users SET age = 32, status = 'premium' WHERE name = 'Alice';
``` ```
### DELETE ### DELETE
```sql ```sql
DELETE FROM users WHERE name = 'Bob'; -- Изтрий всички редове
DELETE FROM users;
-- Условно изтриване
DELETE FROM users WHERE age < 18;
``` ```
## Агрегати и Групиране ## Агрегати и Групиране
### Агрегатни Функции
| Функция | Описание |
|----------|-----------|
| `count(*)` | Брой на всички редове |
| `count(column)` | Брой на не-NULL стойности |
| `sum(column)` | Сума на стойностите |
| `avg(column)` | Средно аритметично |
| `min(column)` | Минимална стойност |
| `max(column)` | Максимална стойност |
| `stddev(column)` | Стандартно отклонение |
| `variance(column)` | Дисперсия |
### GROUP BY
```sql ```sql
SELECT department, count(*), avg(salary) SELECT department, count(*) as emp_count, avg(salary) as avg_salary
FROM employees
GROUP BY department;
-- С HAVING
SELECT department, count(*) as emp_count
FROM employees FROM employees
GROUP BY department GROUP BY department
HAVING count(*) > 5; HAVING count(*) > 5;
-- Множествено групиране
SELECT department, role, count(*), avg(salary)
FROM employees
GROUP BY department, role;
``` ```
## JOINs ## JOINs
@@ -49,15 +170,85 @@ INNER JOIN orders o ON u.id = o.user_id;
SELECT u.name, o.total SELECT u.name, o.total
FROM users u FROM users u
LEFT JOIN orders o ON u.id = o.user_id; LEFT JOIN orders o ON u.id = o.user_id;
-- RIGHT JOIN
SELECT u.name, o.total
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
-- FULL JOIN
SELECT u.name, o.total
FROM users u
FULL JOIN orders o ON u.id = o.user_id;
-- CROSS JOIN
SELECT u.name, p.name
FROM users u
CROSS JOIN products p;
-- Множество JOINs
SELECT u.name, o.id, p.name
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN products p ON o.product_id = p.id;
-- Self JOIN
SELECT e.name, m.name as manager
FROM employees e
JOIN employees m ON e.manager_id = m.id;
``` ```
## CTEs (Common Table Expressions) ## CTEs (Common Table Expressions)
```sql ```sql
-- Единичен CTE
WITH active_users AS ( WITH active_users AS (
SELECT * FROM users WHERE active = true SELECT * FROM users WHERE active = true
) )
SELECT * FROM active_users; SELECT * FROM active_users;
-- Множество CTEs
WITH
recent AS (
SELECT * FROM orders WHERE date > '2025-01-01'
),
totals AS (
SELECT user_id, sum(amount) as total FROM recent GROUP BY user_id
)
SELECT u.name, t.total
FROM users u
JOIN totals t ON u.id = t.user_id;
-- Рекурсивен CTE
WITH RECURSIVE subordinates AS (
SELECT id, name, manager_id FROM employees WHERE name = 'CEO'
UNION ALL
SELECT e.id, e.name, e.manager_id
FROM employees e
JOIN subordinates s ON e.manager_id = s.id
)
SELECT * FROM subordinates;
```
## Подзаявки
```sql
-- Подзаявка в SELECT
SELECT name, (SELECT count(*) FROM orders WHERE user_id = u.id) as order_count
FROM users u;
-- Подзаявка в FROM
SELECT * FROM (SELECT id, name FROM users WHERE active = true) AS active;
-- Подзаявка в WHERE (IN)
SELECT name FROM users WHERE id IN (SELECT user_id FROM orders);
-- Подзаявка в WHERE (EXISTS)
SELECT name FROM users WHERE EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id);
-- Корелирана подзаявка
SELECT name FROM users u
WHERE age > (SELECT avg(age) FROM users WHERE department = u.department);
``` ```
## CASE Изрази ## CASE Изрази
@@ -65,54 +256,114 @@ SELECT * FROM active_users;
```sql ```sql
SELECT name, SELECT name,
CASE CASE
WHEN age < 18 THEN 'minor' WHEN age < 13 THEN 'child'
WHEN age < 20 THEN 'teenager'
WHEN age < 65 THEN 'adult' WHEN age < 65 THEN 'adult'
ELSE 'senior' ELSE 'senior'
END AS category END AS category
FROM users; FROM users;
-- Прост CASE
SELECT name,
CASE department
WHEN 'Engineering' THEN 'Tech'
WHEN 'Sales' THEN 'Revenue'
ELSE 'Other'
END AS division
FROM employees;
``` ```
## Схема ## Set Операции
```sql
-- UNION (различни)
SELECT name FROM customers
UNION
SELECT name FROM suppliers;
-- UNION ALL (с дубликати)
SELECT name FROM customers
UNION ALL
SELECT name FROM suppliers;
-- INTERSECT
SELECT name FROM customers
INTERSECT
SELECT name FROM suppliers;
-- EXCEPT
SELECT name FROM customers
EXCEPT
SELECT name FROM suppliers;
```
## Дефиниране на Схема
### CREATE TYPE
```sql ```sql
CREATE TYPE Person { CREATE TYPE Person {
name: str, name: str,
age: int32 age: int32
}; };
```
## Векторно Търсене -- Със задължителни полета
CREATE TYPE User {
```sql email: str REQUIRED,
INSERT articles { name: str,
title := 'Nim Programming', age: int32,
embedding := [0.1, 0.2, 0.3, ...] created_at: datetime DEFAULT now()
}; };
SELECT title FROM articles -- С връзки
ORDER BY cosine_distance(embedding, [0.1, 0.2, 0.3, ...]) CREATE TYPE Movie {
LIMIT 5; title: str,
year: int32,
director: Person
};
-- С изчислими свойства
CREATE TYPE Employee {
name: str,
base_salary: float64,
bonus: float64,
total_compensation: float64 COMPUTED (base_salary + bonus)
};
``` ```
## Графични Шаблони ### Наследяване
```sql ```sql
MATCH (p:Person)-[:KNOWS]->(friend:Person) CREATE TYPE Animal {
WHERE p.name = 'Alice' name: str
RETURN friend.name; };
CREATE TYPE Dog EXTENDING Animal {
breed: str
};
CREATE TYPE Cat EXTENDING Animal {
indoor: bool
};
``` ```
## Пълнотекстово Търсене ### Индекси
```sql ```sql
-- Създаване на FTS индекс CREATE INDEX idx_users_name ON users(name);
CREATE INDEX idx_fts ON articles(body) USING FTS; CREATE UNIQUE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_age ON users(age) USING btree;
-- Търсене с BM25 ранжиране CREATE INDEX idx_vectors ON items(embedding) USING hnsw;
SELECT * FROM articles WHERE body @@ 'database programming';
``` ```
## JSON Оператори ### DROP
```sql
DROP TYPE User;
DROP INDEX idx_users_name;
```
### JSON Оператори за Път
```sql ```sql
-- Извличане на JSON поле като JSON -- Извличане на JSON поле като JSON
@@ -122,16 +373,292 @@ SELECT data->'name' FROM users;
SELECT data->>'name' FROM users; SELECT data->>'name' FROM users;
``` ```
## Set Операции ### Пълнотекстово Търсене (SQL)
```sql ```sql
SELECT name FROM customers -- Създаване на FTS индекс с BM25
UNION ALL CREATE INDEX idx_fts ON articles(body) USING FTS;
SELECT name FROM suppliers;
-- Търсене с BM25 ранжиране
SELECT * FROM articles WHERE body @@ 'machine learning';
``` ```
## Възстановяване до Момент във Времето ### Възстановяване до Момент във Времето
```sql ```sql
RECOVER TO TIMESTAMP '2026-05-07T12:00:00'; RECOVER TO TIMESTAMP '2026-05-07T12:00:00';
``` ```
## Векторно Търсене (SQL)
### Създаване на Векторни Колони
```sql
CREATE TABLE items (
id INT PRIMARY KEY,
embedding VECTOR(768)
);
```
### Вмъкване на Вектори
```sql
INSERT INTO items (id, embedding) VALUES (1, '[0.1, 0.2, 0.3, 0.4]');
```
### Функции за Разстояние
```sql
-- Косинусово разстояние (0 = идентични, 2 = противоположни)
SELECT id, cosine_distance(embedding, '[0.1, 0.2, 0.3, 0.4]') AS dist
FROM items;
-- Евклидово / L2 разстояние
SELECT id, euclidean_distance(embedding, '[0.1, 0.2, 0.3, 0.4]') AS dist
FROM items;
-- L2 разстояние с <-> оператор
SELECT id, embedding <-> '[0.1, 0.2, 0.3, 0.4]' AS dist
FROM items;
-- Скаларно произведение (отрицателно dot product)
SELECT id, inner_product(embedding, '[0.1, 0.2, 0.3, 0.4]') AS dist
FROM items;
-- Манхатън / L1 разстояние
SELECT id, l1_distance(embedding, '[0.1, 0.2, 0.3, 0.4]') AS dist
FROM items;
```
### Търсене на Най-близки Съседи
```sql
-- Топ-10 най-близки съседи по косинусово разстояние
SELECT id FROM items
ORDER BY cosine_distance(embedding, '[0.1, 0.2, 0.3, 0.4]') ASC
LIMIT 10;
-- Топ-5 най-близки съседи по евклидово разстояние
SELECT id FROM items
ORDER BY embedding <-> '[0.1, 0.2, 0.3, 0.4]'
LIMIT 5;
-- С филтър по метаданни
SELECT id FROM items
WHERE category = 'tech'
ORDER BY cosine_distance(embedding, '[0.1, 0.2, 0.3, 0.4]')
LIMIT 5;
```
### Векторни Индекси
```sql
-- Създаване на HNSW индекс за приблизително търсене на най-близки съседи
CREATE INDEX idx_items_vec ON items(embedding) USING hnsw;
-- Поддържани индекс методи: hnsw, ivfpq
```
## Графични Шаблони
```sql
-- Намиране на приятели на Alice
MATCH (p:Person)-[:KNOWS]->(friend:Person)
WHERE p.name = 'Alice'
RETURN friend.name;
-- Намиране на най-кратък път
MATCH path = shortestPath((a:Person)-[:KNOWS*1..5]->(b:Person))
WHERE a.name = 'Alice' AND b.name = 'Bob'
RETURN path;
-- Намиране на всички връзки
MATCH (p:Person)-[r]->(other)
WHERE p.name = 'Alice'
RETURN type(r), other.name;
-- Множество преходи
MATCH (a:Person)-[:KNOWS]->(b:Person)-[:KNOWS]->(c:Person)
WHERE a.name = 'Alice'
RETURN c.name;
-- С агрегати
MATCH (p:Person)-[:KNOWS]->(friend)
RETURN p.name, count(friend) as friend_count
ORDER BY friend_count DESC;
```
## Пълнотекстово Търсене
```sql
-- Основно търсене
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('database programming');
-- С релевантност
SELECT title, relevance()
FROM articles
WHERE MATCH(title, body) AGAINST('Nim language')
ORDER BY relevance() DESC;
-- Булев режим
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('+Nim -Python' IN BOOLEAN MODE);
-- Fuzzy търсене
SELECT * FROM articles
WHERE MATCH(title) AGAINST('programing' WITH FUZZINESS 2);
```
## Транзакции
```sql
BEGIN;
INSERT users { name := 'Alice', age := 30 };
INSERT orders { user_id := last_insert_id(), total := 100 };
COMMIT;
-- С savepoint
BEGIN;
INSERT users { name := 'Bob', age := 25 };
SAVEPOINT sp1;
INSERT orders { user_id := last_insert_id(), total := 200 };
-- Грешка, връщане до savepoint
ROLLBACK TO sp1;
COMMIT;
```
## Потребителски Функции (UDF)
```sql
-- Регистриране на UDF
CREATE FUNCTION greet(name str) -> str {
RETURN 'Hello, ' || name || '!';
};
-- Използване
SELECT greet(name) FROM users;
-- Вградени функции
SELECT abs(-5), sqrt(16), lower('HELLO'), len('test');
```
## Подсказки за Заявки (Query Hints)
```sql
-- Форсиране на индекс
SELECT /*+ USE_INDEX(idx_users_age) */ * FROM users WHERE age > 18;
-- Форсиране на приблизително векторно търсене
SELECT /*+ APPROXIMATE */ * FROM vectors
ORDER BY cosine_distance(embedding, [...])
LIMIT 10;
-- Паралелно изпълнение
SELECT /*+ PARALLEL(4) */ * FROM large_table;
```
## Window Функции
```sql
-- Функции за ранжиране
SELECT
name,
department,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS r,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dr
FROM employees;
-- Стойностни функции
SELECT
name,
salary,
LAG(salary, 1, 0) OVER (ORDER BY salary) AS prev_salary,
LEAD(salary, 1, 0) OVER (ORDER BY salary) AS next_salary,
FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS cheapest,
LAST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS most_expensive
FROM employees;
-- Функции за разпределение
SELECT name, NTILE(4) OVER (ORDER BY salary) AS quartile FROM employees;
```
### Рамкови Спецификации
```sql
-- ROWS рамка
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
)
-- RANGE рамка
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
```
## Multi-Tenant ERP
BaraDB поддържа множество компании (тенанти) в една инстанция чрез **Row-Level Security (RLS)** и **сесийни променливи**.
### Сесийни Променливи
```sql
SET app.tenant_id = 'company-123';
SELECT current_setting('app.tenant_id') AS tenant;
```
### Текущ Потребител / Роля
```sql
SELECT current_user AS me, current_role AS my_role;
```
### RLS Изолация на Тенанти
```sql
-- Включване на RLS за таблица
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
-- Създаване на политика за филтриране по тенант
CREATE POLICY tenant_isolation ON invoices
FOR SELECT USING (tenant_id = current_setting('app.tenant_id'));
-- Всяка сесия вижда само своите данни
SET app.tenant_id = 'company-a';
SELECT * FROM invoices; -- само редове на company-a
```
### Защо Multi-Tenant?
- **Една инстанция, много тенанти** — няма нужда от 100 отделни бази данни
- **JSONB документи** — гъвкаво съхранение без схема, лесно добавяне на полета за всеки тенант
- **RLS гарантира изолация** — базата данни налага границите между тенанти, не само приложението
## Поддържани Ключови Думи
| Категория | Ключови думи |
|-----------|-------------|
| DQL | SELECT, FROM, WHERE, ORDER BY, GROUP BY, HAVING, LIMIT, OFFSET, DISTINCT |
| DML | INSERT, UPDATE, DELETE, SET, VALUES |
| DDL | CREATE TYPE, DROP TYPE, CREATE INDEX, DROP INDEX, ALTER TYPE |
| Join | INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN, CROSS JOIN, ON |
| Set | UNION, UNION ALL, INTERSECT, EXCEPT |
| CTEs | WITH, RECURSIVE, AS |
| Case | CASE, WHEN, THEN, ELSE, END |
| Транзакции | BEGIN, COMMIT, ROLLBACK, SAVEPOINT |
| Графи | MATCH, RETURN, WHERE, shortestPath, type |
| FTS | MATCH, AGAINST, relevance, IN BOOLEAN MODE, WITH FUZZINESS |
| Вектори | cosine_distance, euclidean_distance, inner_product, l1_distance, l2_distance, <-> |
| JSON | ->, ->> |
| FTS | @@ (BM25 съвпадение) |
| Recovery | RECOVER TO TIMESTAMP |
| Функции | count, sum, avg, min, max, stddev, variance, abs, sqrt, lower, upper, len, trim, substr, now, last_insert_id, current_setting |
| Сесийни | SET, current_setting, current_user, current_role |
| Window | OVER, PARTITION BY, ROWS, RANGE, UNBOUNDED PRECEDING, CURRENT ROW, FOLLOWING |
| Window Функции | ROW_NUMBER, RANK, DENSE_RANK, LEAD, LAG, FIRST_VALUE, LAST_VALUE, NTILE |
+223
View File
@@ -0,0 +1,223 @@
# Списък с Промени (Changelog)
Всички забележителни промени в BaraDB са документирани в този файл.
## [Unreleased] — SQL:2023 Стабилизация
### Поправки
- **GROUPING SETS изпълнение** — `lowerSelect` вече създава `irpkGroupBy` когато `selGroupingSetsKind != gskNone`, дори ако `selGroupBy` е празен. Преди това заявки като `GROUP BY GROUPING SETS ((dept), ())` напълно заобикаляха grouping executor-a.
- **FTS CREATE INDEX docId несъответствие** — `CREATE INDEX ... USING FTS` вече изчислява `docId` като хеш на `tableName.$key`, консистентно с DML операциите (`INSERT`/`UPDATE`/`DELETE`). Преди това създаването на индекс използваше последователни ID-та (0, 1, 2...), което причиняваше `@@` заявките никога да не намират индексирани документи.
- **Тестова изолация (всички сюити)** — Всички извиквания на `newLSMTree("")` са заменени с уникални временни директории за всеки сюит. Елиминира проблеми с натрупване на WAL и нестабилни тестове от споделено състояние между тестове.
- **Window frame parser** — `parseFrameBoundary` вече не консумира `tkRow` след `tkCurrent` неправилно (използваше `tkRows`). Също така е поправен конфликт на ключовата дума `tkRow` с парсването на `ENABLE ROW LEVEL SECURITY`.
- **ORDER BY + SELECT проекция** — `lowerSelect` вече поставя `irpkSort` преди `irpkProject`, което позволява `ORDER BY` по колони, които не присъстват в `SELECT` списъка.
- **UNPIVOT изпълнение** — Проверено и поправено липсващо тестово покритие за UNPIVOT трансформация.
### Добавки
- **JSON оператори** — `@>` (съдържа), `<@` (съдържа се в), `?` (има ключ), `?|` (има някой от), `?&` (има всички) вече се поддържат в lexer, parser и executor.
- **Window frame изпълнение** — `ROWS BETWEEN X PRECEDING AND Y FOLLOWING` / `CURRENT ROW` граници на рамката вече се спазват от `FIRST_VALUE` и `LAST_VALUE`.
- **Сесийни променливи** — `SET var_name = value` и `current_setting('var_name')` за ключ/стойност съхранение на ниво връзка.
- **Текущ потребител/роля** — `current_user` и `current_role` SQL ключови думи връщат потребителя и ролята на автентикираната сесия.
- **Auth-executor мост** — Сървърът и HTTP сървърът вече попълват `ExecutionContext.currentUser` и `ExecutionContext.currentRole` след JWT/SCRAM автентикация.
- **Multi-tenant RLS** — Row-Level Security политиките вече могат да реферират `current_user`, `current_role` и `current_setting('app.tenant_id')` за изолация на данни по тенант.
## [1.1.0] — 2026-05-13
### Добавки
- **Client SDKs v1.1.0** — Пълнофункционални клиенти за всички езици:
- JavaScript: TypeScript дефиниции, package.json, примери, unit и integration тестове
- Python: Преструктуриран като пакет (`baradb/` с `__init__.py` и `core.py`), pyproject.toml, примери, тестове (query builder, wire protocol, integration)
- Nim: Примери, integration тестове, README
- Rust: Примери, integration тестове, подобрен Cargo.toml
- **SCRAM-SHA-256 Автентикация** — RFC 7677 съвместима автентикация с PBKDF2 + HMAC + SHA-256 + nonce/salt генериране
- **HTTP SCRAM Endpoints** — `/auth/scram/start` + `/auth/scram/finish` в HTTP сървъра
- **Docker Compose Тестова Конфигурация** — `docker-compose.test.yml` за тестови среди
- **CI/CD Clients Pipeline** — `.github/workflows/clients-ci.yml` за автоматизирано тестване на клиенти
### Поправки
- **Query Executor** — Унарен минус (`irNeg`) вече работи коректно в SELECT и WHERE клаузи
- **Distributed Transactions** — Rollback след commit опит вече не нарушава атомарността
- **Sharding** — Протокол за миграция на данни с TCP + `scanAll` на LSM
- **Raft** — Поправено изчисление на мнозинство за четен брой нодове
- **MVCC** — Прекъснатите транзакции вече не стават видими
- **LSM-Tree** — Поправена загуба на данни при презаписване на immutable memtable; поправено сортиране на SSTable търсене
- **Auth** — JWT подписът е променен на HMAC-SHA256 (вече не е тривиално forgeable); валидация на токен изтичане (`exp`/`nbf`/`iat`); сравнението на подписи вече е constant-time
- **Recovery** — `summary()` вече не мутира базата данни
- **Wire Protocol** — 64MB лимит + bounds проверки + max дълбочина за предотвратяване на OOM/DoS
- **SQL Injection** — `exprToSql` вече escape-ва единични кавички
- **ReDoS** — `irLike`/`irILike` вече escape-ват regex метасимволи
- **Graph** — `addEdge` вече проверява съществуването на възел
- **Vector** — Валидация на несъответствие на размерности + HNSW заключване
- **FTS** — UTF-8 токенизацията вече използва runes вместо байтове
- **Build** — `nim.cfg` добавя `-d:ssl`, така че `nimble build` работи без флагове; `--threads:on` добавен към всички CI команди
### Промени
- **Версията е вдигната до 1.1.0** във всички компоненти (сървър, Docker изображения, клиенти, CLI)
- **README** — Версионният badge е обновен; всички feature таблици вече реферират v1.1.0
- **TLA+ Формална Верификация** — Добавени `crossmodal.tla`, `backup.tla`, `recovery.tla`; symmetry reduction във всички 9 спецификации
- **Чист build** — 0 компилаторни предупреждения на Nim 2.2.10
## [0.1.0] — 2025-01-15
### Добавки
- **Ядро за Съхранение**
- LSM-Tree с MemTable, WAL, SSTables и size-tiered compaction
- B-Tree подреден индекс с range сканиране и MVCC copy-on-write
- Bloom филтри за ефективно пропускане на SSTable
- Memory-mapped I/O за SSTable четене
- LRU page cache с проследяване на hit rate
- **Query Engine (BaraQL)**
- SQL-съвместим lexer с 80+ типа токени
- Recursive descent parser генериращ AST с 25+ вида възли
- Intermediate representation (IR) за планове за изпълнение
- Code generator превеждащ IR към storage операции
- Adaptive query optimizer с cross-modal планиране
- Query executor с паралелизация
- **BaraQL Езикови Възможности**
- SELECT, INSERT, UPDATE, DELETE
- WHERE, ORDER BY, LIMIT, OFFSET
- GROUP BY, HAVING, агрегатни функции (count, sum, avg, min, max)
- INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN, CROSS JOIN
- CTEs (Common Table Expressions) с WITH
- Подзаявки (EXISTS, IN, корелирани)
- CASE изрази
- UNION, INTERSECT, EXCEPT
- Дефиниране на схема: CREATE TYPE, DROP TYPE
- **Vector Engine**
- HNSW индекс за приблизително търсене на най-близки съседи
- IVF-PQ индекс за мащабно векторно търсене
- SIMD-оптимизирани функции за разстояние (cosine, L2, dot product, Manhattan)
- Квантуване: scalar 8-bit/4-bit, product quantization, binary
- Филтриране по метаданни при векторно търсене
- **Graph Engine**
- Adjacency list съхранение за насочени графи с тегла
- BFS и DFS обхождане
- Dijkstra най-кратък път
- PageRank важност на възли
- Louvain community detection
- Subgraph pattern matching
- Cypher-подобен graph query parser
- **Full-Text Search**
- Inverted index с term-document mapping
- BM25 алгоритъм за ранжиране
- TF-IDF оценяване
- Fuzzy търсене с Levenshtein разстояние
- Wildcard/regex търсене
- Многоезични токенизатори (английски, български, немски, френски, руски)
- **Columnar Storage**
- Колонково съхранение за аналитични заявки
- RLE (Run-Length Encoding) компресия
- Dictionary encoding за колони с ниска кардиналност
- SIMD-ускорени агрегати
- **Транзакции**
- MVCC (Multi-Version Concurrency Control) със snapshot изолация
- Deadlock детекция чрез wait-for граф
- Write-ahead log за устойчивост
- Savepoints и частичен rollback
- **Протоколен Слой**
- Бинарен wire протокол с 16 типа съобщения
- HTTP/REST JSON API
- WebSocket стрийминг
- Connection pooling
- JWT-базирана автентикация
- Token-bucket rate limiting
- TLS/SSL с автоматично генерирани сертификати
- **Система за Схеми**
- Силна типова система с 17 нативни типа
- Наследяване на типове с multi-base поддръжка
- Property links между типове
- Schema diffing и миграции
- Изчислими свойства
- **Разпределени Системи**
- Raft консенсус (leader election, log replication)
- Hash, range и consistent-hash шардиране
- Sync/async/semi-sync репликация
- Gossip протокол за управление на членство
- Two-phase commit за разпределени транзакции
- **Cross-Modal Заявки**
- Унифициран език за заявки през всички storage двигатели
- Cross-engine predicate pushdown
- Оптимизирани планове за изпълнение за multi-modal заявки
- **Backup & Recovery**
- Online snapshots без прекъсване
- Point-in-time recovery чрез WAL replay
- Инкрементални backups
- **Client SDKs**
- JavaScript/TypeScript клиент с бинарен протокол
- Python клиент със sync и async API
- Nim embedded режим и клиентска библиотека
- Rust клиент (async)
- **Операции**
- Интерактивен CLI shell (BaraQL REPL)
- Структурирано логване (JSON и текстови формати)
- Prometheus-съвместим metrics endpoint
- Health и readiness проби
- CPU/memory profiling endpoints
- **Docker Поддръжка**
- Multi-stage Dockerfile (Alpine Linux)
- Docker Compose конфигурация
- Health checks
### Производителност
- LSM-Tree: 580K записа/s, 720K четения/s
- B-Tree: 1.2M вмъквания/s, 1.5M търсения/s
- Vector SIMD: 850K косинусови разстояния/s (dim=768)
- FTS: 320K документи/s индексиране, 28K заявки/s BM25
- Graph: 2.5M възела/s вмъкване, 12K BFS обхождания/s
- Бинарен протокол: 380K заявки/s (100 конкурентни връзки)
### Тестове
- 262 теста в 56 тестови сюита
- 100% успеваемост
## [Unreleased]
### Добавки
- **Vector SQL Integration** — Пълна поддръжка на векторно търсене на SQL ниво:
- `VECTOR(n)` тип колона в `CREATE TABLE` с валидация на размерност
- `CREATE INDEX ... USING hnsw` / `USING ivfpq` за приблизителни nearest neighbor индекси
- SQL функции за разстояние: `cosine_distance()`, `euclidean_distance()`, `inner_product()`, `l1_distance()`, `l2_distance()`
- `<->` nearest-neighbor оператор (евклидово разстояние)
- `ORDER BY` поддръжка за изрази с векторно разстояние, включително колони извън `SELECT`
- Автоматична поддръжка на HNSW индекс при `INSERT` и `UPDATE`
- **Advanced SQL Engine** — Window функции, MERGE/UPSERT, LATERAL JOIN, PIVOT/UNPIVOT, SQL/PGQ Property Graph, Разширени агрегати (ARRAY_AGG, STRING_AGG, FILTER, GROUPING SETS/ROLLUP/CUBE)
- **JavaScript Client — TCP Request Queue** — Вътрешна `_requestQueue` + `_requestLock` за безопасни конкурентни заявки. Множество паралелни извиквания на `query()` / `execute()` / `ping()` вече не размесват бинарни frame-ове по връзката.
### Поправки
- **Query Executor — Ескейпване на Стойности** — `execInsert` вече правилно ескейпва запетаи и знаци за равенство в стойностите на колоните, поправяйки корупция на съхранението за векторни литерали като `[1.0, 2.0, 3.0]`
- **Query Planner — ORDER BY Проекция** — `irpkSort` вече се поставя преди `irpkProject` в IR плана, позволявайки на `ORDER BY` да реферира колони, които не са селектирани
- **Wire Protocol — Big-Endian Float Сериализация** — `FLOAT32`/`FLOAT64` и float стойностите във вектори вече се сериализират в big-endian byte order, съвпадайки с `readFloatBE()` / `readDoubleBE()` на клиента и осигурявайки междуплатформена числова точност.
- **Gossip Protocol — Async UDP Socket** — Заменен синхронният `newSocket` + блокиращ `recvFrom` с `newAsyncSocket` + `await recvFrom`, предотвратявайки замръзване на async event loop-а до пристигане на UDP пакет.
### Планирани
- Query plan caching
- Materialized views
- Геопространствен индекс
- Time-series оптимизации
- CDC (Change Data Capture) стрийминг
- Федеративни заявки между BaraDB инстанции
+285
View File
@@ -0,0 +1,285 @@
# Client SDKs
BaraDB предоставя официални клиентски библиотеки за JavaScript/TypeScript, Python, Nim и Rust.
## JavaScript / TypeScript
### Инсталация
```bash
npm install baradb
# или
yarn add baradb
```
### Основна Употреба
```typescript
import { Client } from 'baradb';
const client = new Client('localhost', 9472);
await client.connect();
// Проста заявка
const result = await client.query('SELECT name, age FROM users WHERE age > 18');
console.log(result.rows);
// Параметризирана заявка
const result2 = await client.query(
'SELECT * FROM users WHERE name = ?',
['Alice']
);
// Batch вмъкване
await client.batch([
"INSERT users { name := 'Alice', age := 30 }",
"INSERT users { name := 'Bob', age := 25 }",
]);
// Транзакции
await client.begin();
await client.query("INSERT orders { total := 100 }");
await client.query("UPDATE users SET balance = balance - 100 WHERE name = 'Alice'");
await client.commit();
await client.close();
```
### Конкурентни Заявки
JavaScript клиентът автоматично сериализира конкурентни заявки през една TCP връзка чрез вътрешна опашка. Можете безопасно да изпращате множество паралелни операции — техните бинарни frame-ове няма да се размесят:
```typescript
const [users, orders, stats] = await Promise.all([
client.query('SELECT * FROM users'),
client.query('SELECT * FROM orders'),
client.query('SELECT count(*) FROM visits')
]);
```
### WebSocket Стрийминг
```typescript
import { WebSocketClient } from 'baradb/ws';
const ws = new WebSocketClient('ws://localhost:9471');
ws.onMessage = (data) => console.log(data);
await ws.connect();
await ws.send('SUBSCRIBE updates');
```
## Python
### Инсталация
```bash
pip install baradb
```
### Основна Употреба
```python
from baradb import Client
client = Client("localhost", 9472)
client.connect()
# Проста заявка
result = client.query("SELECT name, age FROM users WHERE age > 18")
for row in result:
print(row["name"], row["age"])
# Параметризирана заявка
result = client.query(
"SELECT * FROM users WHERE name = ?",
["Alice"]
)
# Batch операции
client.batch([
"INSERT users { name := 'Alice', age := 30 }",
"INSERT users { name := 'Bob', age := 25 }",
])
# Context manager (автоматично затваряне)
with Client("localhost", 9472) as c:
result = c.query("SELECT count(*) FROM users")
print(result[0]["count"])
```
### Async Клиент
```python
import asyncio
from baradb import AsyncClient
async def main():
client = AsyncClient("localhost", 9472)
await client.connect()
result = await client.query("SELECT * FROM users")
print(result.rows)
await client.close()
asyncio.run(main())
```
## Nim (Вграден Режим)
### Добавяне на Зависимост
```nim
# Във вашия .nimble файл
requires "barabadb >= 1.1.0"
```
### Вградена Употреба
```nim
import barabadb/storage/lsm
import barabadb/storage/btree
import barabadb/vector/engine
import barabadb/graph/engine
# Key-Value store
var db = newLSMTree("./data")
db.put("user:1", cast[seq[byte]]("Alice"))
let (found, value) = db.get("user:1")
db.close()
# B-Tree индекс
var btree = newBTreeIndex[string, int]()
btree.insert("Alice", 30)
let ages = btree.get("Alice")
# Векторно търсене
var idx = newHNSWIndex(dimensions = 128)
idx.insert(1, @[0.1'f32, 0.2, 0.3], {"category": "A"}.toTable)
let results = idx.search(@[0.1'f32, 0.2, 0.3], k = 10)
# Графи
var g = newGraph()
let alice = g.addNode("Person", {"name": "Alice"}.toTable)
let bob = g.addNode("Person", {"name": "Bob"}.toTable)
discard g.addEdge(alice, bob, "knows")
let path = g.shortestPath(alice, bob)
```
### Клиентска Библиотека
```nim
import barabadb/client/client
var c = newBaraClient("localhost", 9472)
c.connect()
let result = c.query("SELECT name FROM users")
for row in result.rows:
echo row["name"]
c.close()
```
## Rust
### Добавяне на Зависимост
```toml
[dependencies]
baradb = "0.1"
tokio = { version = "1", features = ["full"] }
```
### Основна Употреба
```rust
use baradb::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Client::connect("localhost:9472").await?;
let result = client
.query("SELECT name, age FROM users WHERE age > 18")
.await?;
for row in result.rows {
println!("{} is {} years old", row["name"], row["age"]);
}
client.close().await?;
Ok(())
}
```
## HTTP/REST (Езиково Независим)
Всички езици могат да използват HTTP/REST API директно:
```bash
# Заявка
curl -X POST http://localhost:9470/api/query \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query": "SELECT * FROM users WHERE age > 18"}'
# Вмъкване
curl -X POST http://localhost:9470/api/query \
-H "Content-Type: application/json" \
-d '{"query": "INSERT users { name := \"Alice\", age := 30 }"}'
# Схема
curl http://localhost:9470/api/schema
# Health
curl http://localhost:9470/health
# Метрики
curl http://localhost:9470/metrics
```
## Connection Pooling
Всички официални клиенти поддържат connection pooling:
### JavaScript
```typescript
import { Pool } from 'baradb';
const pool = new Pool({
host: 'localhost',
port: 9472,
min: 5,
max: 50,
idleTimeout: 30000,
});
const client = await pool.acquire();
try {
const result = await client.query('SELECT 1');
} finally {
pool.release(client);
}
```
### Python
```python
from baradb import Pool
pool = Pool("localhost", 9472, min_size=5, max_size=50)
with pool.connection() as conn:
result = conn.query("SELECT 1")
```
## Съответствие на Типове Данни
| BaraDB Тип | JavaScript | Python | Nim | Rust |
|------------|------------|--------|-----|------|
| `null` | `null` | `None` | `nil` | `Option::None` |
| `bool` | `boolean` | `bool` | `bool` | `bool` |
| `int8/16/32/64` | `number` | `int` | `int` | `i8/i16/i32/i64` |
| `float32/64` | `number` | `float` | `float32/float64` | `f32/f64` |
| `str` | `string` | `str` | `string` | `String` |
| `bytes` | `Uint8Array` | `bytes` | `seq[byte]` | `Vec<u8>` |
| `array` | `Array` | `list` | `seq` | `Vec` |
| `object` | `Object` | `dict` | `Table` | `HashMap` |
| `vector` | `Float32Array` | `list[float]` | `seq[float32]` | `Vec<f32>` |
+58
View File
@@ -0,0 +1,58 @@
# Колонково Съхранение (Columnar)
Колонково-ориентирано съхранение за аналитични заявки и агрегации.
## Употреба
```nim
import barabadb/core/columnar
var batch = newColumnBatch()
var ageCol = batch.addInt64Col("age")
var nameCol = batch.addStringCol("name")
ageCol.appendInt64(25)
nameCol.appendString("Alice")
```
## Агрегации
```nim
echo ageCol.sumInt64()
echo ageCol.avgInt64()
echo ageCol.minInt64()
echo ageCol.maxInt64()
echo ageCol.count()
```
## Кодиране
### RLE (Run-Length Encoding)
```nim
let rle = rleEncode(@[1'i64, 1, 1, 2, 2, 3])
```
### Dictionary Encoding
```nim
let dict = dictEncode(@["apple", "banana", "apple"])
```
## Типове Колони
| Тип | Описание |
|------|----------|
| `int32` | 32-битов integer |
| `int64` | 64-битов integer |
| `float32` | 32-битов float |
| `float64` | 64-битов float |
| `string` | Низ с променлива дължина |
| `bool` | Булев |
## Случаи на Употреба
- OLAP натоварвания
- Мащабни агрегации
- Data warehousing
- Анализ на времеви редове
+218
View File
@@ -0,0 +1,218 @@
# Конфигурационна Референция
BaraDB може да се конфигурира чрез **променливи на средата**, **конфигурационен файл** или **командно-редови флагове**.
## Ред на Приоритет
1. Командно-редови флагове (най-висок приоритет)
2. Променливи на средата
3. Конфигурационен файл (`baradb.conf` или `baradb.json`)
4. Вградени стойности по подразбиране (най-нисък приоритет)
## Променливи на Средата
### Мрежа
| Променлива | По подр. | Описание |
|------------|----------|----------|
| `BARADB_ADDRESS` | `127.0.0.1` | Адрес за свързване |
| `BARADB_PORT` | `9472` | TCP бинарен протокол порт |
| `BARADB_HTTP_PORT` | `9470` | HTTP/REST API порт |
| `BARADB_WS_PORT` | `9471` | WebSocket порт |
### Съхранение
| Променлива | По подр. | Описание |
|------------|----------|----------|
| `BARADB_DATA_DIR` | `./data` | Път до директория за данни |
| `BARADB_MEMTABLE_SIZE_MB` | `64` | Размер на MemTable в MB |
| `BARADB_CACHE_SIZE_MB` | `256` | Размер на page cache в MB |
| `BARADB_WAL_SYNC_INTERVAL_MS` | `0` | Интервал за WAL fsync (0 = всеки запис) |
| `BARADB_COMPACTION_INTERVAL_MS` | `60000` | Интервал за фонов compaction |
| `BARADB_BLOOM_BITS_PER_KEY` | `10` | Bloom филтър битове за ключ |
### TLS/SSL
| Променлива | По подр. | Описание |
|------------|----------|----------|
| `BARADB_TLS_ENABLED` | `false` | Включване на TLS |
| `BARADB_CERT_FILE` | — | Път до TLS сертификат |
| `BARADB_KEY_FILE` | — | Път до TLS частен ключ |
### Сигурност
| Променлива | По подр. | Описание |
|------------|----------|----------|
| `BARADB_AUTH_ENABLED` | `false` | Включване на автентикация |
| `BARADB_JWT_SECRET` | — | JWT подписващ secret |
| `BARADB_RATE_LIMIT_GLOBAL` | `10000` | Глобални заявки в секунда |
| `BARADB_RATE_LIMIT_PER_CLIENT` | `1000` | Заявки в секунда за клиент |
### Логване
| Променлива | По подр. | Описание |
|------------|----------|----------|
| `BARADB_LOG_LEVEL` | `info` | Ниво на логване: debug, info, warn, error |
| `BARADB_LOG_FILE` | — | Път до лог файл (stdout ако е празен) |
| `BARADB_LOG_FORMAT` | `json` | Формат на лога: json, text |
### Vector Engine
| Променлива | По подр. | Описание |
|------------|----------|----------|
| `BARADB_VECTOR_M` | `16` | HNSW `M` параметър |
| `BARADB_VECTOR_EF_CONSTRUCTION` | `200` | HNSW `efConstruction` |
| `BARADB_VECTOR_EF_SEARCH` | `64` | HNSW `efSearch` |
### Graph Engine
| Променлива | По подр. | Описание |
|------------|----------|----------|
| `BARADB_GRAPH_PAGE_RANK_ITERATIONS` | `20` | Брой итерации на PageRank |
| `BARADB_GRAPH_PAGE_RANK_DAMPING` | `0.85` | PageRank damping фактор |
| `BARADB_GRAPH_LOUVAIN_RESOLUTION` | `1.0` | Louvain резолюционен параметър |
### Разпределени
| Променлива | По подр. | Описание |
|------------|----------|----------|
| `BARADB_RAFT_NODE_ID` | — | Уникално ID на възел в клъстер |
| `BARADB_RAFT_PEERS` | — | Списък с адреси на peer-ове, разделени със запетая |
| `BARADB_RAFT_PORT` | `9001` | Raft вътрешен комуникационен порт |
| `BARADB_SHARD_COUNT` | `1` | Брой шардове |
| `BARADB_REPLICATION_FACTOR` | `1` | Фактор на репликация |
| `BARADB_SEED_NODES` | — | Gossip seed възли (host:port, разделени със запетая) |
## Конфигурационен Файл
### baradb.conf (INI-подобен)
```ini
[server]
address = "0.0.0.0"
port = 9472
http_port = 9470
ws_port = 9471
[storage]
data_dir = "/var/lib/baradb"
memtable_size_mb = 256
cache_size_mb = 512
wal_sync_interval_ms = 10
compaction_interval_ms = 30000
[tls]
enabled = true
cert_file = "/etc/baradb/server.crt"
key_file = "/etc/baradb/server.key"
[auth]
enabled = true
jwt_secret = "change-me-in-production"
rate_limit_global = 10000
rate_limit_per_client = 1000
[logging]
level = "info"
format = "json"
file = "/var/log/baradb/baradb.log"
[vector]
m = 16
ef_construction = 200
ef_search = 64
[cluster]
raft_node_id = "node1"
raft_peers = "node2:9001,node3:9001"
```
### baradb.json
```json
{
"server": {
"address": "0.0.0.0",
"port": 9472,
"http_port": 9470,
"ws_port": 9471
},
"storage": {
"data_dir": "/var/lib/baradb",
"memtable_size_mb": 256,
"cache_size_mb": 512
},
"tls": {
"enabled": true,
"cert_file": "/etc/baradb/server.crt",
"key_file": "/etc/baradb/server.key"
}
}
```
## Командно-редови Флагове
```bash
./build/baradadb --help
```
```
BaraDB v1.1.0 — Multimodal Database Engine
Употреба:
baradadb [опции]
Опции:
-c, --config <файл> Път до конфигурационен файл
-p, --port <порт> TCP бинарен порт (по подр.: 9472)
--http-port <порт> HTTP порт (по подр.: 9470)
--ws-port <порт> WebSocket порт (по подр.: 9471)
-d, --data-dir <дир> Директория за данни (по подр.: ./data)
--tls-cert <файл> TLS сертификатен файл
--tls-key <файл> TLS файл с частен ключ
--log-level <ниво> Ниво на логване: debug, info, warn, error
--log-file <файл> Път до лог файл
--shell Стартиране на интерактивна обвивка
--version Показване на версия
--recover Изпълнение на WAL възстановяване
--checkpoint <файл> Checkpoint за възстановяване
-h, --help Показване на тази помощ
```
## Примерни Конфигурации
### Разработка
```bash
./build/baradadb \
--log-level debug \
--data-dir ./dev_data
```
### Продукционен Единичен Възел
```bash
BARADB_TLS_ENABLED=true \
BARADB_CERT_FILE=/etc/baradb/server.crt \
BARADB_KEY_FILE=/etc/baradb/server.key \
BARADB_AUTH_ENABLED=true \
BARADB_JWT_SECRET="$(openssl rand -hex 32)" \
BARADB_LOG_LEVEL=warn \
BARADB_LOG_FILE=/var/log/baradb/baradb.log \
BARADB_MEMTABLE_SIZE_MB=256 \
BARADB_CACHE_SIZE_MB=1024 \
./build/baradadb
```
### Продукционен Клъстер (3 възела)
```bash
# Възел 1
BARADB_ADDRESS=0.0.0.0 \
BARADB_PORT=9472 \
BARADB_RAFT_NODE_ID=node1 \
BARADB_RAFT_PEERS=node2:9001,node3:9001 \
BARADB_SHARD_COUNT=4 \
BARADB_REPLICATION_FACTOR=2 \
./build/baradadb
```
+101
View File
@@ -0,0 +1,101 @@
# Cross-Modal Заявки
Уникалната способност на BaraDB да изпълнява заявки, обхващащи множество storage двигатели в една унифицирана BaraQL заявка.
## Преглед
Традиционните бази данни изискват отделни заявки и join-ове на ниво приложение при работа с различни модели на данни. Cross-modal query planner-ът на BaraDB оптимизира изпълнението през:
- **Документи/KV** (LSM-Tree) — структурирани записи
- **Графи** (Adjacency List) — връзки
- **Вектори** (HNSW/IVF-PQ) — търсене на прилика
- **Пълен текст** (Inverted Index) — текстово търсене
- **Колонково** — аналитични агрегати
## Примери за Заявки
### Векторно + Пълнотекстово (Семантично + Ключово Търсене)
```sql
SELECT title, score
FROM articles
WHERE MATCH(body) AGAINST('machine learning')
ORDER BY cosine_distance(embedding, [0.1, 0.2, 0.3, ...])
LIMIT 10;
```
### Графово + Векторно (Социални Препоръки)
```sql
MATCH (u:User)-[:KNOWS]->(friend:User)
WHERE u.name = 'Alice'
ORDER BY cosine_distance(friend.taste_vector, u.taste_vector)
RETURN friend.name, friend.age;
```
### Документно + Графово (Обогатяване на Същности)
```sql
SELECT o.id, o.total, c.name,
(SELECT count(*) FROM orders WHERE customer_id = c.id) as order_count
FROM orders o
MATCH (c:Customer)-[:PLACED]->(o)
WHERE o.date > '2025-01-01';
```
## Cross-Modal Engine API
```nim
import barabadb/core/crossmodal
var engine = newCrossModalEngine("/tmp/baradb")
# Документни операции
engine.put("key1", cast[seq[byte]]("value1"))
let (found, val) = engine.get("key1")
# Векторни операции
engine.insertVector(1, @[1.0'f32, 0.0'f32, ...], {"cat": "A"}.toTable)
let results = engine.searchVector(@[1.0'f32, 0.1'f32, ...], 2)
# Графови операции
let n1 = engine.addNode("Person")
let n2 = engine.addNode("Person")
discard engine.addEdge(n1, n2, "knows")
let traversal = engine.traverseGraph(n1, "bfs")
# FTS операции
engine.indexText(1, "Nim programming language")
let ftsResults = engine.searchText("programming")
# Хибридно търсене
var query = newCrossModalQuery(qmHybrid)
query.vector = @[1.0'f32, 0.0'f32]
query.searchQuery = "fast"
query.vecWeight = 1.0
query.ftsWeight = 1.0
let hybridResult = engine.hybridSearch(query)
```
## 2PC Транзакции
Cross-modal engine-ът поддържа two-phase commit за атомарни операции през множество storage системи:
```nim
var txn = newTPCTransaction(1)
txn.addParticipant("storage")
txn.addParticipant("vector")
txn.addParticipant("graph")
txn.prepare() # Всички участници потвърждават, че могат да комитнат
txn.commit() # Атомарен commit през всички участници
```
## Формална Верификация
Cross-modal консистентността е формално специфицирана в TLA+:
- **Спецификация:** `formal-verification/crossmodal.tla`
- **Проверени свойства:**
- `MetadataVectorConsistency` — insertVector обновява метаданни за филтрирано търсене
- `CrossModalAtomicity` — всички участници комитват или всички абортират
+250
View File
@@ -0,0 +1,250 @@
# Ръководство за Внедряване (Deployment)
## Docker
За пълно ръководство за Docker deployment вижте [Docker Guide](docker.md).
### Бърз старт
```bash
docker build -t baradb:latest .
docker compose up -d
```
### Docker Compose файлове
| Файл | Назначение |
|------|-----------|
| `docker-compose.yml` | Development |
| `docker-compose.prod.yml` | Production |
| `docker-compose.override.yml` | Dev override (автоматично) |
| `docker-compose.test.yml` | Тестова среда |
### Production
```bash
docker compose -f docker-compose.prod.yml up -d
```
### Docker Swarm
```bash
docker stack deploy -c docker-compose.prod.yml baradb
```
## systemd Услуга
Създайте `/etc/systemd/system/baradb.service`:
```ini
[Unit]
Description=BaraDB Multimodal Database
After=network.target
[Service]
Type=simple
User=baradb
Group=baradb
WorkingDirectory=/var/lib/baradb
ExecStart=/usr/local/bin/baradadb
Restart=always
RestartSec=5
Environment=BARADB_PORT=9472
Environment=BARADB_HTTP_PORT=9470
Environment=BARADB_DATA_DIR=/var/lib/baradb/data
Environment=BARADB_LOG_LEVEL=info
# Подсилване на сигурността
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/baradb/data
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
[Install]
WantedBy=multi-user.target
```
Активиране и стартиране:
```bash
sudo useradd -r -s /bin/false baradb
sudo mkdir -p /var/lib/baradb/data
sudo chown -R baradb:baradb /var/lib/baradb
sudo cp build/baradadb /usr/local/bin/
sudo systemctl daemon-reload
sudo systemctl enable --now baradb
```
## Kubernetes
### StatefulSet
```yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: baradb
spec:
serviceName: baradb
replicas: 3
selector:
matchLabels:
app: baradb
template:
metadata:
labels:
app: baradb
spec:
containers:
- name: baradb
image: baradb:latest
ports:
- containerPort: 9472
name: binary
- containerPort: 9470
name: http
- containerPort: 9471
name: websocket
env:
- name: BARADB_DATA_DIR
value: /data
- name: BARADB_RAFT_NODE_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
---
apiVersion: v1
kind: Service
metadata:
name: baradb
spec:
selector:
app: baradb
ports:
- port: 9472
name: binary
- port: 9470
name: http
- port: 9471
name: websocket
clusterIP: None
```
## Reverse Proxy (nginx)
```nginx
upstream baradb_http {
server 127.0.0.1:9470;
}
upstream baradb_ws {
server 127.0.0.1:9471;
}
server {
listen 80;
server_name db.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name db.example.com;
ssl_certificate /etc/letsencrypt/live/db.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/db.example.com/privkey.pem;
location /api/ {
proxy_pass http://baradb_http/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /ws/ {
proxy_pass http://baradb_ws/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
## Висока Достъпност (High Availability)
### 3-Възел Raft Клъстер
```bash
# Възел 1
BARADB_RAFT_NODE_ID=node1 \
BARADB_RAFT_PEERS=node2:9001,node3:9001 \
./build/baradadb
# Възел 2
BARADB_RAFT_NODE_ID=node2 \
BARADB_RAFT_PEERS=node1:9001,node3:9001 \
./build/baradadb
# Възел 3
BARADB_RAFT_NODE_ID=node3 \
BARADB_RAFT_PEERS=node1:9001,node2:9001 \
./build/baradadb
```
## Облачно Внедряване
### AWS EC2
Препоръчителна инстанция: `m6i.2xlarge` (8 vCPU, 32 GB RAM)
```bash
# User data скрипт
#!/bin/bash
apt-get update
apt-get install -y nim
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-linux-amd64
chmod +x baradadb-linux-amd64
mv baradadb-linux-amd64 /usr/local/bin/baradadb
mkdir -p /data/baradb
cat > /etc/systemd/system/baradb.service << 'EOF'
[Unit]
Description=BaraDB
After=network.target
[Service]
ExecStart=/usr/local/bin/baradadb
Environment=BARADB_DATA_DIR=/data/baradb
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now baradb
```
### GCP Cloud Run (само HTTP)
```bash
gcloud run deploy baradb \
--image gcr.io/PROJECT/baradb \
--port 9470 \
--memory 4Gi \
--cpu 2 \
--max-instances 10
```
+57 -4
View File
@@ -1,9 +1,11 @@
# Разпределена Система # Разпределена Система
Поддръжка за разпределено внедряване с Raft консенсус, шардиране и репликация. BaraDB поддържа разпределено внедряване с Raft консенсус, шардиране, репликация и gossip протокол.
## Raft Консенсус ## Raft Консенсус
Leader election и log репликация:
```nim ```nim
import barabadb/core/raft import barabadb/core/raft
@@ -13,19 +15,35 @@ cluster.addNode("node2")
cluster.addNode("node3") cluster.addNode("node3")
let n1 = cluster.nodes["n1"] let n1 = cluster.nodes["n1"]
n1.becomeCandidate()
n1.becomeLeader() n1.becomeLeader()
let entry = n1.appendLog("SET key1 value1")
``` ```
## Шардиране ## Шардиране
Разпределение на данни между възли:
```nim ```nim
import barabadb/core/sharding import barabadb/core/sharding
var router = newShardRouter(ShardConfig(numShards: 4, replicas: 2)) var router = newShardRouter(ShardConfig(
numShards: 4,
replicas: 2,
strategy: ssHash
))
router.rebalance(@["node1", "node2", "node3"]) router.rebalance(@["node1", "node2", "node3"])
let shard = router.getShard("user_123") let shard = router.getShard("user_123")
``` ```
### Стратегии за Шардиране
| Стратегия | Описание |
|-----------|----------|
| `ssHash` | Хеш-базирано шардиране |
| `ssRange` | Range-базирано шардиране |
| `ssConsistent` | Consistent hashing |
## Репликация ## Репликация
```nim ```nim
@@ -34,11 +52,46 @@ import barabadb/core/replication
var rm = newReplicationManager(rmSync) var rm = newReplicationManager(rmSync)
rm.addReplica(newReplica("r1", "10.0.0.1", 9472)) rm.addReplica(newReplica("r1", "10.0.0.1", 9472))
rm.connectReplica("r1") rm.connectReplica("r1")
let lsn = rm.writeLsn(@[1'u8, 2, 3])
rm.ackLsn("r1", lsn)
```
### Режими на Репликация
| Режим | Описание |
|--------|----------|
| `rmSync` | Синхронна репликация |
| `rmAsync` | Асинхронна репликация |
| `rmSemiSync` | Полу-синхронна репликация |
## Gossip Протокол
Управление на членство и детекция на откази:
```nim
import barabadb/core/gossip
var g = newGossipProtocol("node1", "localhost", 9472, gossipPort = 9572)
g.join(newGossipNode("node2", "10.0.0.2", 9472))
```
## Разпределени Транзакции
Two-phase commit между възли:
```nim
import barabadb/core/disttxn
var tm = newDistTxnManager()
let txn = tm.beginTransaction("node1")
txn.addParticipant("node2", "10.0.0.2", 9472)
txn.prepare()
txn.commit()
``` ```
## Формална Верификация ## Формална Верификация
Разпределените алгоритми са формално специфицирани в TLA+ и проверени с TLC: Основните разпределени алгоритми са формално специфицирани в TLA+ и проверени с TLC:
- **Raft Консенсус** — `formal-verification/raft.tla` - **Raft Консенсус** — `formal-verification/raft.tla`
- Проверено: ElectionSafety, StateMachineSafety - Проверено: ElectionSafety, StateMachineSafety
@@ -47,7 +100,7 @@ rm.connectReplica("r1")
- **Репликация** — `formal-verification/replication.tla` - **Репликация** — `formal-verification/replication.tla`
- Проверено: MonotonicLsn, AcksRemovePending - Проверено: MonotonicLsn, AcksRemovePending
Пускане на TLC: Пускане на TLC локално:
```bash ```bash
cd formal-verification cd formal-verification
+183
View File
@@ -0,0 +1,183 @@
# Docker Deployment Ръководство
Това ръководство описва как да използвате BaraDB с Docker и Docker Compose.
## Бърз старт
```bash
# Клониране на репото
git clone https://github.com/katehonz/barabaDB.git
cd barabaDB
# Build на образа
docker build -t baradb:latest .
# Стартиране с Docker Compose
docker compose up -d
# Проверка на статуса
docker compose ps
docker compose logs -f
```
## Файлове
| Файл | Описание |
|------|----------|
| `Dockerfile` | Мулти-stage production build |
| `docker-compose.yml` | Development конфигурация |
| `docker-compose.prod.yml` | Production конфигурация |
| `docker-compose.override.yml` | Development override (автоматично се зарежда) |
| `docker-compose.test.yml` | Тестова конфигурация |
| `docker-entrypoint.sh` | Entrypoint скрипт за инициализация |
| `.dockerignore` | Файлове, които да не се копират в образа |
## Създаване на образ
```bash
# Стандартен build
docker build -t baradb:latest .
# С конкретна версия
docker build -t baradb:1.1.0 .
```
## Стартиране
### Development (docker compose)
```bash
# Стартиране на заден план
docker compose up -d
# Спиране
docker compose down
# Спиране и изтриване на volumes (ВНИМАНИЕ — изтрива данните!)
docker compose down -v
# Преглед на логове
docker compose logs -f
```
### Production (docker compose)
```bash
# Стартиране с production конфигурация
docker compose -f docker-compose.prod.yml up -d
# Проверка на healthcheck
docker compose -f docker-compose.prod.yml ps
```
### Ръчно (docker run)
```bash
docker run -d \
--name baradb \
-p 9472:9472 \
-p 9470:9470 \
-p 9471:9471 \
-v baradb_data:/data \
-e BARADB_LOG_LEVEL=info \
baradb:latest
```
## Портове
| Порт | Описание |
|------|----------|
| `9472` | Binary wire протокол |
| `9470` | HTTP/REST API |
| `9471` | WebSocket |
## Променливи на Средата
| Променлива | Стойност по подразбиране | Описание |
|------------|--------------------------|----------|
| `BARADB_ADDRESS` | `0.0.0.0` | Адрес за слушане |
| `BARADB_PORT` | `9472` | Binary протокол порт |
| `BARADB_HTTP_PORT` | `9470` | HTTP порт |
| `BARADB_WS_PORT` | `9471` | WebSocket порт |
| `BARADB_DATA_DIR` | `/data` | Директория за данни |
| `BARADB_LOG_LEVEL` | `info` | Ниво на логове |
## Volumes
| Път в контейнера | Описание |
|------------------|----------|
| `/data` | Основна директория за базата данни |
| `/data/server/wal` | Write-ahead log |
| `/data/server/sstables` | SSTable файлове |
## Production Checklist
- [ ] Създайте TLS сертификати в `./certs/`
- [ ] Задайте силен `BARADB_JWT_SECRET`
- [ ] Настройте firewall правила
- [ ] Конфигурирайте регулярни backups
- [ ] Проверете resource limits
- [ ] Настройте мониторинг (healthcheck, logs)
## TLS в Docker
1. Създайте сертификати:
```bash
mkdir -p certs
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout certs/server.key -out certs/server.crt
```
2. Активирайте в `docker-compose.prod.yml`:
```yaml
environment:
- BARADB_TLS_ENABLED=true
- BARADB_CERT_FILE=/certs/server.crt
- BARADB_KEY_FILE=/certs/server.key
volumes:
- ./certs:/certs:ro
```
## Backup в Docker
```bash
# Ръчен backup
docker exec baradb baradadb --snapshot --output=/backup/snapshot.db
# Списък на backups
ls /backup/
# Възстановяване
docker exec baradb baradadb --recover --checkpoint=/backup/snapshot.db
```
## Troubleshooting
### Контейнерът не стартира
```bash
# Проверка на логове
docker compose logs -f baradb
# Проверка на статус
docker compose ps
```
### Няма връзка с базата
```bash
# Проверка дали портовете са експозвани
docker port baradb
# Проверка отвътре
docker exec baradb wget -qO- http://localhost:9470/health
```
### Permission denied на /data
Entrypoint скриптът автоматично създава директориите и задава правилните permissions. Ако имате проблем:
```bash
docker exec baradb ls -la /data
docker exec baradb chown -R baradb:baradb /data
```
+66 -14
View File
@@ -1,6 +1,6 @@
# Пълнотекстово Търсене # Full-Text Search Engine
Инвертиран индекс с BM25 и TF-IDF ранжиране. Inverted индекс с BM25 и TF-IDF ранжиране за текстово търсене.
## Употреба ## Употреба
@@ -8,28 +8,80 @@
import barabadb/fts/engine import barabadb/fts/engine
var idx = newInvertedIndex() var idx = newInvertedIndex()
idx.addDocument(1, "Nim е бърз език за програмиране") idx.addDocument(1, "Nim is a fast programming language")
idx.addDocument(2, "Python е популярен за data science") idx.addDocument(2, "Python is popular for data science")
let results = idx.search("език програмиране") # BM25 търсене
let tfidf = idx.searchTfidf("език") let results = idx.search("programming language")
let fuzzy = idx.fuzzySearch("програмиране", maxDistance = 2)
# TF-IDF търсене
let tfidf = idx.searchTfidf("programming language")
# Fuzzy търсене (толеранс на печатни грешки)
let fuzzy = idx.fuzzySearch("programing", maxDistance = 2)
# Wildcard търсене
let wild = idx.regexSearch("prog*")
``` ```
## Методи за Ранжиране ## Методи за Ранжиране
### BM25 ### BM25
Най-добрият алгоритъм за съвпадение Best matching алгоритъм за ранжиране:
```nim
let bm25 = idx.searchBM25("query terms")
```
### TF-IDF ### TF-IDF
Term Frequency-Inverse Document Frequency Term Frequency-Inverse Document Frequency:
## Търсене ```nim
let tfidf = idx.searchTfidf("query terms")
```
| Тип | Описание | ## Функции за Търсене
|-----|----------|
| Fuzzy | Толерантност към правописни грешки | | Функция | Описание |
| Wildcard | Префикс, суфикс, и инфикс заместващи символи | |---------|----------|
| Fuzzy търсене | Levenshtein distance толеранс |
| Wildcard | Префиксни, суфиксни и инфиксни wildcards |
| Regex | Регулярни изрази | | Regex | Регулярни изрази |
| Фразово търсене | Точно съвпадение на фраза |
| Булево | AND, OR, NOT оператори |
## SQL Интерфейс
Пълнотекстовото търсене е достъпно и директно в BaraQL:
```sql
-- Създаване на таблица с текстова колона
CREATE TABLE articles (id INT PRIMARY KEY, title TEXT, body TEXT);
-- Създаване на FTS индекс
CREATE INDEX idx_fts ON articles(body) USING FTS;
-- Търсене с оператора @@ (BM25 ранжиране)
SELECT * FROM articles WHERE body @@ 'machine learning';
-- Търсене с множество термини
SELECT * FROM articles WHERE body @@ 'quick brown fox';
```
## Многоезична Поддръжка
```nim
import barabadb/fts/multilang
# Поддържани езици: EN, BG, DE, FR, RU
var tokenizer = newTokenizer("bg") # Български
let tokens = tokenizer.tokenize("Търсене в пълен текст")
```
Функции за всеки език:
- Токенизация
- Stop думи
- Стеминг
- Детекция на език
+117 -20
View File
@@ -15,6 +15,7 @@
| macOS | x86_64 | ✅ Пълна поддръжка | | macOS | x86_64 | ✅ Пълна поддръжка |
| macOS | ARM64 (Apple Silicon) | ✅ Пълна поддръжка | | macOS | ARM64 (Apple Silicon) | ✅ Пълна поддръжка |
| Windows | x86_64 | ✅ Поддръжка | | Windows | x86_64 | ✅ Поддръжка |
| FreeBSD | x86_64 | 🟡 Тествано от общността |
## Инсталиране на Nim ## Инсталиране на Nim
@@ -48,10 +49,13 @@ sudo port install nim
### Windows ### Windows
```powershell ```powershell
# Winget # С choosenim
curl.exe -A "MSYS2_$(uname -m)" -L https://nim-lang.org/choosenim/init.ps1 | powershell -
# С winget
winget install nim winget install nim
# Scoop # С scoop
scoop install nim scoop install nim
``` ```
@@ -79,10 +83,16 @@ sudo pacman -S openssl
### macOS ### macOS
OpenSSL е включен в системата. Ако е необходимо:
```bash ```bash
brew install openssl brew install openssl
``` ```
### Windows
OpenSSL е включен в Nim Windows дистрибуцията. За ръчни компилации, изтеглете от [slproweb.com](https://slproweb.com/products/Win32OpenSSL.html).
## Компилиране на BaraDB ## Компилиране на BaraDB
### Клониране на Репозиторито ### Клониране на Репозиторито
@@ -103,26 +113,29 @@ nimble install -d -y
#### Debug Компилация #### Debug Компилация
```bash ```bash
nim c -d:ssl -o:build/baradadb src/baradadb.nim nim c -d:ssl --threads:on -o:build/baradadb src/baradadb.nim
``` ```
#### Release Компилация (Препоръчителна) #### Release Компилация (Препоръчителна)
```bash ```bash
nim c -d:ssl -d:release --opt:speed -o:build/baradadb src/baradadb.nim nim c -d:ssl --threads:on -d:release --opt:speed -o:build/baradadb src/baradadb.nim
``` ```
#### Използване на Nimble #### Използване на Nimble Tasks
```bash ```bash
# Debug компилация
nimble build_debug nimble build_debug
# Release компилация
nimble build_release nimble build_release
``` ```
#### Минимален Размер #### Минимален Размер
```bash ```bash
nim c -d:ssl -d:release --opt:size -o:build/baradadb src/baradadb.nim nim c -d:ssl --threads:on -d:release --opt:size -o:build/baradadb src/baradadb.nim
strip build/baradadb strip build/baradadb
``` ```
@@ -130,17 +143,31 @@ strip build/baradadb
```bash ```bash
./build/baradadb --version ./build/baradadb --version
# Очакван резултат: BaraDB v0.1.0 — Multimodal Database Engine # Очакван резултат: BaraDB v1.1.0 — Multimodal Database Engine
``` ```
## Стартиране на Тестове ## Стартиране на Тестове
```bash ### Всички Тестове
# Всички тестове (262 теста, 56 сюита)
nim c -d:ssl -r tests/test_all.nim
# Бенчмаркове ```bash
nim c -d:ssl -d:release -r benchmarks/bench_all.nim nim c --path:src -d:ssl --threads:on -r tests/test_all.nim
```
### Специфични Тестови Сюити
```bash
# Storage тестове
nim c --path:src -d:ssl --threads:on -r tests/test_all.nim
# Stress тестове
nim c --path:src -d:ssl --threads:on -d:release -r tests/stress_test.nim
```
### Бенчмаркове
```bash
nim c --path:src -d:ssl --threads:on -d:release -r benchmarks/bench_all.nim
``` ```
## Опции за Инсталация ## Опции за Инсталация
@@ -148,16 +175,46 @@ nim c -d:ssl -d:release -r benchmarks/bench_all.nim
### Системна Инсталация ### Системна Инсталация
```bash ```bash
# Компилиране на release binary
nimble build_release nimble build_release
# Инсталиране в /usr/local/bin
sudo cp build/baradadb /usr/local/bin/ sudo cp build/baradadb /usr/local/bin/
sudo chmod +x /usr/local/bin/baradadb sudo chmod +x /usr/local/bin/baradadb
# Създаване на директория за данни
sudo mkdir -p /var/lib/baradb sudo mkdir -p /var/lib/baradb
sudo chmod 755 /var/lib/baradb
```
### Предварително Компилиран Binary
Изтеглете най-новата версия за вашата платформа:
```bash
# Linux x86_64
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-linux-amd64
chmod +x baradadb-linux-amd64
mv baradadb-linux-amd64 /usr/local/bin/baradadb
# Linux ARM64
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-linux-arm64
chmod +x baradadb-linux-arm64
mv baradadb-linux-arm64 /usr/local/bin/baradadb
# macOS
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-darwin-amd64
chmod +x baradadb-darwin-amd64
mv baradadb-darwin-amd64 /usr/local/bin/baradadb
``` ```
### Docker ### Docker
```bash ```bash
# Изтегляне на официален образ
docker pull barabadb/barabadb:latest docker pull barabadb/barabadb:latest
# Стартиране
docker run -d \ docker run -d \
-p 9472:9472 \ -p 9472:9472 \
-p 9470:9470 \ -p 9470:9470 \
@@ -172,12 +229,16 @@ docker run -d \
docker-compose up -d docker-compose up -d
``` ```
### Вградено Използване ### Вградено Използване (Nim Проекти)
Добавете към вашия `.nimble` файл:
```nim ```nim
requires "barabadb >= 0.1.0" requires "barabadb >= 1.1.0"
``` ```
Използване в кода:
```nim ```nim
import barabadb/storage/lsm import barabadb/storage/lsm
@@ -193,16 +254,52 @@ db.close()
# Стартиране на сървъра # Стартиране на сървъра
./build/baradadb ./build/baradadb
# Тестване на HTTP API # Очакван изход:
# BaraDB v1.1.0 — Multimodal Database Engine
# BaraDB TCP listening on 127.0.0.1:9472
# Тестване с HTTP API
curl http://localhost:9470/health curl http://localhost:9470/health
# Интерактивна конзола # Интерактивна обвивка
./build/baradadb --shell ./build/baradadb --shell
``` ```
## Отстраняване на Проблеми с Инсталацията
### "cannot open file: hunos"
```bash
nimble install -d -y
```
### "BaraDB requires SSL support"
Винаги компилирайте с `-d:ssl`:
```bash
nim c -d:ssl --threads:on -o:build/baradadb src/baradadb.nim
```
### Бавна компилация
Използвайте паралелна компилация:
```bash
nim c -d:ssl --threads:on -d:release --parallelBuild:4 -o:build/baradadb src/baradadb.nim
```
### Голям размер на binary-то
Използвайте оптимизация на размера:
```bash
nim c -d:ssl --threads:on -d:release --opt:size --passL:-s -o:build/baradadb src/baradadb.nim
```
## Следващи Стъпки ## Следващи Стъпки
- [Бързо Стартиране](bg/quickstart.md) - [Бърз Старт](quickstart.md)
- [Конфигурация](en/configuration.md) - [Конфигурационна Референция](configuration.md)
- [Архитектура](bg/architecture.md) - [Преглед на Архитектурата](architecture.md)
- [BaraQL Заявки](bg/baraql.md) - [BaraQL Език за Заявки](baraql.md)
+48 -9
View File
@@ -1,6 +1,29 @@
# LSM-Tree Съхранение # LSM-Tree Storage Engine
Основният двигател за съхранение използващ Log-Structured Merge-Tree архитектура. Основният storage engine в BaraDB, използващ Log-Structured Merge-Tree архитектура.
## Архитектура
```
┌─────────────────────────────────────────────┐
│ Записи │
│ (добавяне към WAL + MemTable) │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ MemTable │
│ (в-памет сортиран буфер) │
└─────────────────────────────────────────────┘
(при запълване, flush към SSTable)
┌─────────────────────────────────────────────┐
│ SSTable │
│ (сортирана string table на диска) │
└─────────────────────────────────────────────┘
```
## Употреба ## Употреба
@@ -9,17 +32,33 @@ import barabadb/storage/lsm
var db = newLSMTree("./data") var db = newLSMTree("./data")
# Запис
db.put("key1", cast[seq[byte]]("value1")) db.put("key1", cast[seq[byte]]("value1"))
# Четене
let (found, value) = db.get("key1") let (found, value) = db.get("key1")
# Изтриване
db.delete("key1")
db.close() db.close()
``` ```
## Компоненти ## Възможности
- **MemTable**: Сортиран буфер в паметта - **Write-оптимизиран**: Append-only лог структура
- **WAL**: Write-ahead log за трайност - **Устойчивост**: Write-ahead log (WAL) осигурява crash recovery
- **SSTable**: Сортирани таблици на диска - **Bloom Филтър**: Бързи негативни проверки
- **Bloom Filter**: Бързи негативни проверки - **Compaction**: Size-tiered стратегия слива SSTables
- **Compaction**: Сливане на SSTables - **Page Cache**: LRU кеш за често достъпвани страници
- **Page Cache**: LRU кеш
## Конфигурация
```nim
var db = newLSMTree(
path = "./data",
memTableSize = 64 * 1024 * 1024, # 64MB
walEnabled = true,
bloomFpRate = 0.01
)
```
+202
View File
@@ -0,0 +1,202 @@
# Мониторинг и Наблюдаемост
## Health Checks
### HTTP Health Endpoint
```bash
curl http://localhost:9470/health
```
Отговор:
```json
{
"status": "healthy",
"version": "1.1.0",
"uptime_seconds": 86400,
"checks": {
"storage": "ok",
"memory": "ok",
"connections": "ok"
}
}
```
### Readiness Probe
```bash
curl http://localhost:9470/ready
```
Връща `200 OK` когато сървърът е готов да приема трафик, `503` по време на стартиране.
## Метрики
### Prometheus-Съвместими Метрики
```bash
curl http://localhost:9470/metrics
```
Примерен изход:
```
# HELP baradb_queries_total Общ брой изпълнени заявки
# TYPE baradb_queries_total counter
baradb_queries_total 152340
# HELP baradb_queries_duration_seconds Хистограма на времетраене на заявки
# TYPE baradb_queries_duration_seconds histogram
baradb_queries_duration_seconds_bucket{le="0.001"} 45000
baradb_queries_duration_seconds_bucket{le="0.01"} 120000
baradb_queries_duration_seconds_bucket{le="0.1"} 148000
# HELP baradb_storage_lsm_size_bytes Общ размер на LSM-Tree
# TYPE baradb_storage_lsm_size_bytes gauge
baradb_storage_lsm_size_bytes 2147483648
# HELP baradb_cache_hit_rate Page cache hit rate
# TYPE baradb_cache_hit_rate gauge
baradb_cache_hit_rate 0.94
# HELP baradb_active_connections Активни клиентски връзки
# TYPE baradb_active_connections gauge
baradb_active_connections 42
```
### JSON Метрики
```bash
curl http://localhost:9470/metrics?format=json
```
## Логване
### Нива на Логване
| Ниво | Описание |
|------|----------|
| `debug` | Детайлни вътрешни операции |
| `info` | Нормални операции |
| `warn` | Възстановими проблеми |
| `error` | Грешки, изискващи внимание |
### Структурирани JSON Логове
```bash
BARADB_LOG_LEVEL=info \
BARADB_LOG_FORMAT=json \
BARADB_LOG_FILE=/var/log/baradb/baradb.log \
./build/baradadb
```
Примерен лог запис:
```json
{
"timestamp": "2025-01-15T10:30:00.123Z",
"level": "info",
"component": "server",
"message": "Query executed",
"query": "SELECT * FROM users",
"duration_ms": 12,
"client_ip": "10.0.0.15"
}
```
### Текстов Формат
```bash
BARADB_LOG_FORMAT=text ./build/baradadb
```
## Правила за Алармиране
### Prometheus AlertManager
```yaml
groups:
- name: baradb
rules:
- alert: BaraDBHighErrorRate
expr: rate(baradb_errors_total[5m]) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "Висок процент грешки в BaraDB"
- alert: BaraDBLowCacheHitRate
expr: baradb_cache_hit_rate < 0.8
for: 10m
labels:
severity: warning
annotations:
summary: "Cache hit rate под 80%"
- alert: BaraDBHighConnections
expr: baradb_active_connections > 800
for: 5m
labels:
severity: warning
annotations:
summary: "Голям брой връзки към BaraDB"
- alert: BaraDBDown
expr: up{job="baradb"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "BaraDB инстанцията не работи"
```
## Разпределен Мониторинг
### Клъстерни Метрики
За Raft клъстери, мониторирайте:
```bash
curl http://node1:9470/metrics/cluster
```
```json
{
"cluster_id": "baradb-cluster-1",
"nodes": [
{"id": "node1", "role": "leader", "health": "healthy"},
{"id": "node2", "role": "follower", "health": "healthy"},
{"id": "node3", "role": "follower", "health": "healthy"}
],
"raft_log_index": 15420,
"raft_commit_index": 15420,
"shards": 4,
"replication_lag_ms": 5
}
```
## Профилиране на Производителност
### Вграден CPU Profiler
```bash
curl -X POST http://localhost:9470/debug/pprof/cpu?seconds=30 > cpu.prof
```
### Memory Profiler
```bash
curl http://localhost:9470/debug/pprof/heap > heap.prof
```
## Отстраняване на Проблеми с Метрики
| Симптом | Метрика | Действие |
|---------|--------|----------|
| Бавни заявки | `baradb_queries_duration_seconds` | Проверете cache hit rate, добавете индекси |
| Висока памет | `process_resident_memory_bytes` | Намалете memtable/cache размери |
| Растящо съхранение | `baradb_storage_lsm_size_bytes` | Пуснете ръчен compaction |
| Грешки при връзка | `baradb_active_connections` | Увеличете connection pool или добавете възли |
| Репликационно закъснение | `baradb_replication_lag_ms` | Проверете мрежата, увеличете ресурсите |
+125
View File
@@ -0,0 +1,125 @@
# Ръководство за Производителност
## Методология на Бенчмарковете
Всички бенчмаркове са проведени с:
- **Компилатор**: Nim 2.2.0 с `-d:release --opt:speed`
- **CPU**: AMD Ryzen 9 5900X (12 ядра / 24 нишки)
- **Памет**: 64 GB DDR4-3600
- **Диск**: Samsung 980 Pro NVMe SSD
- **ОС**: Ubuntu 24.04 LTS
Пускане на пълния бенчмарк сюит:
```bash
nim c -d:ssl -d:release -r benchmarks/bench_all.nim
```
## Storage Engine Бенчмаркове
### LSM-Tree Key-Value
| Метрика | Стойност |
|---------|----------|
| Пропускателна способност при запис | ~580,000 ops/s |
| Пропускателна способност при четене | ~720,000 ops/s |
| Средна латентност при запис | 1.7 µs |
| Средна латентност при четене | 1.4 µs |
LSM-Tree използва 64MB MemTable, WAL fsync при всеки запис и size-tiered compaction с 6 нива.
### B-Tree Индекс
| Метрика | Стойност |
|---------|----------|
| Пропускателна способност при вмъкване | ~1,200,000 ops/s |
| Пропускателна способност при точково търсене | ~1,500,000 ops/s |
| Range scan (1000 ключа) | ~0.3 ms |
## Vector Engine Бенчмаркове
### HNSW Индекс
| Метрика | Стойност |
|---------|----------|
| Вмъкване (dim=128) | ~45,000 вектора/s |
| Търсене топ-10 (dim=128, n=10K) | ~2 ms |
| Търсене топ-10 (dim=128, n=100K) | ~8 ms |
### SIMD Функции за Разстояние
| Операция | dim=128 | dim=768 | dim=1536 |
|----------|---------|---------|----------|
| Косинусово разстояние | 4.2M/s | 850K/s | 420K/s |
| L2 (Евклидово) | 4.5M/s | 920K/s | 450K/s |
| Скаларно произведение | 4.8M/s | 980K/s | 480K/s |
## Full-Text Search Бенчмаркове
| Метрика | Стойност |
|---------|----------|
| Индексиране | ~320,000 документа/s |
| BM25 търсене | ~28,000 заявки/s |
| Fuzzy търсене (distance=2) | ~850 заявки/s |
## Graph Engine Бенчмаркове
| Операция | Пропускателна способност |
|----------|--------------------------|
| Добавяне на възел | ~2.5M ops/s |
| Добавяне на ребро | ~1.8M ops/s |
| BFS (1K възела, 5K ребра) | ~12K обхождания/s |
| Dijkstra най-кратък път | ~120 µs |
| PageRank (10 итерации) | ~450 графа/s |
## Протоколни Бенчмаркове
| Протокол | Връзки | Заявки/s | Латентност p99 |
|----------|--------|----------|----------------|
| Бинарен (localhost) | 1 | 45,000 | 0.4 ms |
| Бинарен (localhost) | 100 | 380,000 | 1.2 ms |
| HTTP/REST | 1 | 12,000 | 2.1 ms |
| HTTP/REST | 100 | 95,000 | 5.8 ms |
| WebSocket | 1 | 18,000 | 1.8 ms |
## Вертикален Мащабинг
| Ядра | LSM Запис | LSM Четене | Векторно Търсене |
|------|-----------|------------|-------------------|
| 1 | 580K | 720K | 2.0 ms |
| 4 | 1.9M | 2.6M | 1.1 ms |
| 8 | 3.4M | 4.8M | 0.7 ms |
| 16 | 5.8M | 7.2M | 0.5 ms |
## Ръководство за Настройка
### За Write-Heavy Натоварвания
```bash
export BARADB_MEMTABLE_SIZE_MB=256
export BARADB_WAL_SYNC_INTERVAL_MS=10
export BARADB_COMPACTION_INTERVAL_MS=30000
```
### За Read-Heavy Натоварвания
```bash
export BARADB_CACHE_SIZE_MB=1024
export BARADB_BLOOM_BITS_PER_KEY=10
export BARADB_COMPACTION_INTERVAL_MS=120000
```
### За Векторно Търсене
```bash
export BARADB_VECTOR_EF_CONSTRUCTION=200
export BARADB_VECTOR_EF_SEARCH=128
export BARADB_VECTOR_M=32
```
### За Графова Аналитика
```bash
export BARADB_GRAPH_PAGE_RANK_ITERATIONS=20
export BARADB_GRAPH_LOUVAIN_RESOLUTION=1.0
```
+373
View File
@@ -0,0 +1,373 @@
# Протоколна Референция
BaraDB поддържа множество протоколи за клиентска комуникация:
- **Бинарен Wire Протокол** — високопроизводителен, ниска латентност
- **HTTP/REST API** — езиково-независим, лесен за дебъгване
- **WebSocket** — стрийминг и pub/sub
---
## Бинарен Wire Протокол
Бинарният протокол използва big-endian кодиране за всички многобайтови стойности.
### Жизнен Цикъл на Връзката
```
Клиент Сървър
| |
|─── TCP свързване ───────────>|
|<── TLS ръкостискане (опц.) ──|
|─── Auth съобщение ──────────>|
|<── Auth_OK / Грешка ─────────|
|─── Query съобщение ─────────>|
|<── Data / Complete / Error ──|
|─── Close съобщение ─────────>|
|<── TCP затваряне ────────────|
```
### Формат на Съобщенията
Всяко съобщение започва с 12-байтов хедър:
```
┌─────────────┬─────────────┬─────────────┬─────────────────────┐
│ Kind │ Length │ RequestId │ Payload │
│ (4 bytes) │ (4 bytes) │ (4 bytes) │ │
│ uint32 BE │ uint32 BE │ uint32 BE │ (Length bytes) │
└─────────────┴─────────────┴─────────────┴─────────────────────┘
```
### Типове Съобщения
| Тип | ID | Посока | Описание |
|------|----|--------|----------|
| Query | 0x01 | К→С | Изпълни заявка |
| QueryParams | 0x02 | К→С | Параметризирана заявка |
| Auth | 0x07 | К→С | Заявка за автентикация |
| Ping | 0x09 | К→С | Keepalive ping |
| Close | 0x0A | К→С | Затваряне на връзка |
| Data | 0x81 | С→К | Резултат от заявка |
| Complete | 0x82 | С→К | Заявката е завършена |
| Auth_OK | 0x83 | С→К | Успешна автентикация |
| Pong | 0x84 | С→К | Keepalive отговор |
| Error | 0x06 | С→К | Грешка |
### Query Съобщение Payload
```
┌───────────────────┬────────────────────────────┐
│ Query String │ │
│ (променлива) │ │
│ UTF-8 │ │
└───────────────────┴────────────────────────────┘
```
### Data Съобщение Payload
```
┌──────────────┬─────────────────────────────────────────────┐
│ Брой Колони │ Дефиниции на Колони + Данни от Редове │
│ (4 bytes) │ │
│ uint32 BE │ │
└──────────────┴─────────────────────────────────────────────┘
```
### Типове Полета
| Тип | ID | Размер | Описание |
|------|----|--------|----------|
| NULL | 0x00 | 0 | NULL стойност |
| BOOL | 0x01 | 1 | true/false |
| INT8 | 0x02 | 1 | Signed 8-bit integer |
| INT16 | 0x03 | 2 | Signed 16-bit integer |
| INT32 | 0x04 | 4 | Signed 32-bit integer |
| INT64 | 0x05 | 8 | Signed 64-bit integer |
| FLOAT32 | 0x06 | 4 | IEEE 754 единична точност (big-endian) |
| FLOAT64 | 0x07 | 8 | IEEE 754 двойна точност (big-endian) |
| STRING | 0x08 | променлив | UTF-8 низ (4-байтов префикс за дължина) |
| BYTES | 0x09 | променлив | Сурови байтове (4-байтов префикс за дължина) |
| ARRAY | 0x0A | променлив | Масив от стойности |
| OBJECT | 0x0B | променлив | Ключ-стойност обект |
| VECTOR | 0x0C | променлив | Float32 масив (4-байтов префикс, big-endian floats) |
### Error Съобщение Payload
```
┌──────────────┬──────────────┬────────────────────────────┐
│ Код Грешка │ Дълж. Съобщ. │ Съобщение за Грешка │
│ (4 bytes) │ (4 bytes) │ (Дълж. Съобщ. bytes) │
│ uint32 BE │ uint32 BE │ UTF-8 │
└──────────────┴──────────────┴────────────────────────────┘
```
---
## HTTP/REST API
Базов URL: `http://localhost:9470/api/v1`
### Endpoints
#### Health
```http
GET /health
```
Отговор:
```json
{
"status": "healthy",
"version": "1.1.0",
"uptime_seconds": 86400
}
```
#### Ready
```http
GET /ready
```
Връща `200` когато е готов, `503` при стартиране.
#### Query
```http
POST /query
Content-Type: application/json
Authorization: Bearer <token>
{
"query": "SELECT name, age FROM users WHERE age > 18",
"params": [],
"format": "json"
}
```
Отговор:
```json
{
"columns": ["name", "age"],
"rows": [
["Alice", 30],
["Bob", 25]
],
"row_count": 2,
"duration_ms": 12
}
```
#### Batch
```http
POST /batch
Content-Type: application/json
{
"queries": [
"INSERT users { name := 'Alice', age := 30 }",
"INSERT users { name := 'Bob', age := 25 }"
]
}
```
Отговор:
```json
{
"results": [
{"status": "ok", "affected_rows": 1},
{"status": "ok", "affected_rows": 1}
]
}
```
#### Schema
```http
GET /schema
```
#### Metrics
```http
GET /metrics
```
Prometheus-съвместими метрики. Виж [Ръководство за Мониторинг](monitoring.md).
#### Explain
```http
POST /explain
Content-Type: application/json
{
"query": "SELECT * FROM users WHERE age > 18"
}
```
Отговор:
```json
{
"plan": "IndexScan",
"index": "idx_users_age",
"estimated_rows": 42,
"cost": 120
}
```
#### Backup
```http
POST /backup
Content-Type: application/json
{
"destination": "/backup/snapshot.db"
}
```
#### Административни Операции
```http
POST /admin/compact
POST /admin/rebalance
POST /admin/check
```
### HTTP Статус Кодове
| Код | Значение |
|------|----------|
| 200 | Успех |
| 400 | Лоша заявка (синтактична грешка) |
| 401 | Неоторизиран (изисква се auth) |
| 403 | Забранен (недостатъчни права) |
| 404 | Не е намерен (таблица/тип не съществува) |
| 429 | Твърде много заявки (rate limited) |
| 500 | Вътрешна сървърна грешка |
| 503 | Услугата е недостъпна (стартира) |
---
## WebSocket Протокол
URL: `ws://localhost:9471`
### Формат на Frame
WebSocket текстови frame-ове съдържат JSON съобщения:
```json
{
"id": 1,
"type": "query",
"query": "SELECT * FROM users"
}
```
### Типове Съобщения
| Тип | Посока | Описание |
|------|--------|----------|
| `query` | К→С | Изпълни заявка |
| `subscribe` | К→С | Абониране за промени |
| `unsubscribe` | К→С | Отписване |
| `ping` | К→С | Keepalive |
| `result` | С→К | Резултат от заявка |
| `notification` | С→К | Известие за промяна |
| `error` | С→К | Грешка |
| `pong` | С→К | Keepalive отговор |
### Pub/Sub Пример
```javascript
const ws = new WebSocket('ws://localhost:9471');
ws.onopen = () => {
// Абониране за промени в таблица
ws.send(JSON.stringify({
id: 1,
type: 'subscribe',
table: 'users'
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'notification') {
console.log('Промяна:', msg.operation, msg.data);
}
};
```
### Стрийминг Заявки
```javascript
ws.send(JSON.stringify({
id: 2,
type: 'query',
query: 'SELECT * FROM logs ORDER BY timestamp',
streaming: true
}));
// Сървърът изпраща множество result frame-ове
// Последният frame има {"complete": true}
```
---
## Nim API Примери
### Бинарен Протокол
```nim
import barabadb/protocol/wire
let msg = makeQueryMessage(1, "SELECT * FROM users")
let ready = makeReadyMessage(1)
let error = makeErrorMessage(1, 42, "Syntax error")
```
### Connection Pool
```nim
import barabadb/protocol/pool
var pool = newConnectionPool(
minConnections = 5,
maxConnections = 100,
idleTimeout = 30000
)
let conn = pool.acquire()
# Използване на връзка...
pool.release(conn)
```
### Автентикация
```nim
import barabadb/protocol/auth
var am = newAuthManager("secret-key")
let token = am.createToken(JWTClaims(sub: "user1", role: "admin"))
let result = am.validateCredentials(
AuthCredentials(authMethod: amToken, payload: token)
)
```
### Rate Limiting
```nim
import barabadb/protocol/ratelimit
var rl = newRateLimiter(
rlaTokenBucket,
globalRate = 10000,
perClientRate = 1000
)
if rl.allowRequest("client-123"):
echo "Заявката е разрешена"
```
+210
View File
@@ -0,0 +1,210 @@
# Ръководство за Сигурност
## TLS/SSL Криптиране
BaraDB поддържа TLS 1.3 за всички протоколи (бинарен, HTTP, WebSocket). Ако не е предоставен сертификат, сървърът автоматично генерира self-signed сертификат при стартиране за криптиране без конфигурация.
### Използване на Персонализирани Сертификати
```bash
# Предоставяне на съществуващи сертификати
BARADB_TLS_ENABLED=true \
BARADB_CERT_FILE=/etc/baradb/server.crt \
BARADB_KEY_FILE=/etc/baradb/server.key \
./build/baradadb
```
### Генериране на Self-Signed Сертификати
```bash
openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt \
-days 365 -nodes -subj "/CN=localhost"
```
### Let's Encrypt (Продукция)
Използвайте certbot и насочете BaraDB към генерираните файлове:
```bash
sudo certbot certonly --standalone -d db.example.com
BARADB_CERT_FILE=/etc/letsencrypt/live/db.example.com/fullchain.pem \
BARADB_KEY_FILE=/etc/letsencrypt/live/db.example.com/privkey.pem \
./build/baradadb
```
### TLS от Страна на Клиента
```python
from baradb import Client
client = Client("localhost", 9472, tls=True, tls_verify=True)
client.connect()
```
## Автентикация
### JWT-Базирана Автентикация
BaraDB използва JWT (JSON Web Tokens) с HMAC-SHA256 подписване.
#### Включване на Автентикация
```bash
BARADB_AUTH_ENABLED=true \
BARADB_JWT_SECRET="$(openssl rand -hex 32)" \
./build/baradadb
```
#### Създаване на Токени
```nim
import barabadb/protocol/auth
var am = newAuthManager("your-secret-key")
let token = am.createToken(JWTClaims(
sub: "user1",
role: "admin",
exp: getTime() + 24.hours
))
```
#### Контрол на Достъп на База Роли
| Роля | Права |
|------|-------|
| `admin` | Пълен достъп |
| `write` | Четене + запис |
| `read` | Само четене |
| `monitor` | Само метрики и health |
#### Използване на Токени
```bash
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:9470/api/query \
-d '{"query": "SELECT * FROM users"}'
```
```python
from baradb import Client
client = Client("localhost", 9472)
client.connect()
client.authenticate("eyJhbGciOiJIUzI1NiIs...")
```
### Многофакторна Автентикация (MFA)
```nim
import barabadb/protocol/auth
var am = newAuthManager("secret-key")
# TOTP-базирана MFA
let mfaCode = am.generateTOTP("user1")
let valid = am.validateTOTP("user1", mfaCode)
```
## Rate Limiting
Token-bucket rate limiting предотвратява злоупотреби:
```nim
import barabadb/protocol/ratelimit
var rl = newRateLimiter(
rlaTokenBucket,
globalRate = 10000, # 10K заявки/s глобално
perClientRate = 1000, # 1K заявки/s на IP/токен
burstSize = 100 # Разрешаване на 100 заявки burst
)
if not rl.allowRequest("client-ip"):
return error("Лимитът на заявки е надвишен")
```
## Мрежова Сигурност
### Адрес за Свързване
По подразбиране BaraDB се свързва към `127.0.0.1` (само localhost). За продукция:
```bash
# Свързване към всички интерфейси (зад защитна стена или reverse proxy)
BARADB_ADDRESS=0.0.0.0 ./build/baradadb
# Свързване към конкретен вътрешен интерфейс
BARADB_ADDRESS=10.0.0.5 ./build/baradadb
```
### Правила на Защитната Стена
```bash
# Разрешаване само на сървъри на приложения
sudo ufw allow from 10.0.0.0/8 to any port 9472
sudo ufw allow from 10.0.0.0/8 to any port 9470
# Блокиране на външен достъп до портове за управление
sudo ufw deny 9471 # WebSocket (само вътрешна употреба)
```
## Криптиране на Данни в Покой
### Криптиране на Ниво ОС
Използвайте LUKS за пълно дисково криптиране:
```bash
cryptsetup luksFormat /dev/nvme0n1p2
cryptsetup open /dev/nvme0n1p2 baradb-crypt
mkfs.ext4 /dev/mapper/baradb-crypt
mount /dev/mapper/baradb-crypt /var/lib/baradb
```
### Криптиране на Ниво Приложение
BaraDB поддържа прозрачно криптиране на SSTable файлове:
```bash
BARADB_STORAGE_ENCRYPTION_KEY="$(openssl rand -hex 32)" \
./build/baradadb
```
## Одитно Логване
Всички заявки и административни действия се логват:
```json
{
"timestamp": "2025-01-15T10:30:00Z",
"level": "info",
"event": "query_executed",
"client_ip": "10.0.0.15",
"user": "app_user",
"query": "SELECT * FROM users WHERE id = ?",
"duration_ms": 12,
"rows_returned": 1
}
```
Включване на одитно логване:
```bash
BARADB_LOG_LEVEL=info \
BARADB_LOG_FORMAT=json \
BARADB_LOG_FILE=/var/log/baradb/audit.log \
./build/baradadb
```
## Чеклист за Сигурност
- [ ] Сменете JWT secret по подразбиране
- [ ] Включете TLS с валидни сертификати
- [ ] Свържете се към конкретни интерфейси
- [ ] Включете автентикация в продукция
- [ ] Конфигурирайте rate limiting
- [ ] Включете одитно логване
- [ ] Криптирайте данните в покой (LUKS или на ниво приложение)
- [ ] Стартирайте BaraDB като non-root потребител
- [ ] Поддържайте рестриктивни правила на защитната стена
- [ ] Ротирайте JWT secret-и редовно
+78
View File
@@ -0,0 +1,78 @@
# Storage Engines
BaraDB предоставя множество storage двигатели, оптимизирани за различни модели на достъп.
## LSM-Tree (Key-Value)
Основният storage engine с write-оптимизирана append-only лог структура.
### Употреба
```nim
import barabadb/storage/lsm
var db = newLSMTree("./data")
db.put("key1", cast[seq[byte]]("value1"))
let (found, value) = db.get("key1")
db.close()
```
### Компоненти
- **MemTable**: В-памет сортиран буфер
- **WAL**: Write-ahead log за устойчивост
- **SSTable**: Сортирани string таблици на диска
- **Bloom Filter**: Вероятностна проверка за принадлежност
- **Compaction**: Size-tiered стратегия с управление на нива
- **Page Cache**: LRU кеш с проследяване на hit rate
## B-Tree Индекс
Подреден индекс за range сканиране и точково търсене.
### Употреба
```nim
import barabadb/storage/btree
var btree = newBTreeIndex[string, string]()
btree.insert("key1", "value1")
let values = btree.get("key1")
let range = btree.scan("key_a", "key_z")
```
## Write-Ahead Log (WAL)
Осигурява устойчивост на операциите за запис.
```nim
import barabadb/storage/wal
var wal = newWAL("./wal")
wal.append("txn1", "SET key1 value1")
wal.flush()
```
## Bloom Filter
Вероятностна структура от данни за бързи негативни проверки.
```nim
import barabadb/storage/bloom
var filter = newBloomFilter(10000, 0.01)
filter.add("key1")
if filter.mightContain("key1"):
echo "евентуално съществува"
```
## Memory-mapped I/O
Ефективен достъп до файлове чрез mmap.
```nim
import barabadb/storage/mmap
var mapped = mmapFile("./data/file.dat")
let data = mapped.read(0, 100)
```
+45 -11
View File
@@ -1,6 +1,6 @@
# Транзакции & MVCC # Транзакции и MVCC
Multi-Version Concurrency Control със snapshot изолация. MVCC (Multi-Version Concurrency Control) със snapshot изолация и deadlock детекция.
## Употреба ## Употреба
@@ -10,21 +10,55 @@ import barabadb/core/mvcc
var tm = newTxnManager() var tm = newTxnManager()
let txn = tm.beginTxn() let txn = tm.beginTxn()
# Операции за запис
discard tm.write(txn, "key1", cast[seq[byte]]("value1")) discard tm.write(txn, "key1", cast[seq[byte]]("value1"))
discard tm.write(txn, "key2", cast[seq[byte]]("value2")) discard tm.write(txn, "key2", cast[seq[byte]]("value2"))
# Savepoint
tm.savepoint(txn) tm.savepoint(txn)
discard tm.rollbackToSavepoint(txn) discard tm.write(txn, "key3", cast[seq[byte]]("value3"))
discard tm.rollbackToSavepoint(txn) # отмяна на key3
# Commit
discard tm.commit(txn) discard tm.commit(txn)
``` ```
## Изолация ## Изолация на Транзакции
BaraDB използва **snapshot isolation**: BaraDB използва **snapshot изолация**:
- Читателите не блокират писатели - Четящите не блокират пишещите
- Писателите не блокират читатели - Пишещите не блокират четящите
- Всяка транзакция вижда консистентен моментна снимка - Всяка транзакция вижда консистентен snapshot
## Deadlock Детекция
```nim
import barabadb/core/deadlock
var detector = newDeadlockDetector()
if detector.detectCycle(txn1, txn2):
echo "Открит deadlock!"
```
## Write-Ahead Log
```nim
import barabadb/storage/wal
var wal = newWAL("./wal")
wal.append(txnId, "SET key value")
wal.flush()
```
## Savepoints
Вложени savepoints на транзакции:
```nim
tm.savepoint(txn, "sp1")
# ... операции ...
tm.rollbackToSavepoint(txn, "sp1")
```
## Формална Верификация ## Формална Верификация
@@ -32,11 +66,11 @@ MVCC / Snapshot Isolation протоколът е формално специф
- **Спецификация:** `formal-verification/mvcc.tla` - **Спецификация:** `formal-verification/mvcc.tla`
- **Проверени свойства:** - **Проверени свойства:**
- `NoDirtyReads` — транзакциите никога не четат неcommit-нати данни - `NoDirtyReads` — транзакциите никога не четат некомитнати данни
- `ReadOwnWrites` — транзакциите винаги виждат собствените си записи - `ReadOwnWrites` — транзакциите винаги виждат собствените си записи
- `WriteWriteConflict` — first-committer-wins - `WriteWriteConflict` — first-committer-wins (няма две комитнати транзакции да пишат един и същ ключ)
Пускане на TLC: Пускане на TLC локално:
```bash ```bash
cd formal-verification cd formal-verification
+164
View File
@@ -0,0 +1,164 @@
# Ръководство за Отстраняване на Проблеми
## Проблеми с Инсталацията
### Nim не е намерен
```
nim: command not found
```
**Решение:**
```bash
# Linux/macOS
curl https://nim-lang.org/choosenim/init.sh -sSf | sh
# Добавяне към PATH
echo 'export PATH=$HOME/.nimble/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
```
### SSL Грешка при Компилация
```
Error: BaraDB requires SSL support. Compile with -d:ssl
```
**Решение:** Винаги компилирайте с `-d:ssl`:
```bash
nim c -d:ssl -d:release -o:build/baradadb src/baradadb.nim
```
### Липсващи Зависимости
```
Error: cannot open file: hunos
```
**Решение:**
```bash
nimble install -d -y
```
## Проблеми по Време на Изпълнение
### Портът е Зает
```
Error: unhandled exception: Address already in use [OSError]
```
**Решение 1:** Сменете порта:
```bash
BARADB_PORT=5433 ./build/baradadb
```
**Решение 2:** Убийте съществуващия процес:
```bash
lsof -ti:9472 | xargs kill -9
```
### Permission Denied на Директория с Данни
```
Error: Permission denied: ./data
```
**Решение:**
```bash
mkdir -p ./data
chmod 755 ./data
# или използвайте друга директория
BARADB_DATA_DIR=/tmp/baradb ./build/baradadb
```
## Storage Проблеми
### Бавни Заявки
1. Проверете cache hit rate:
```bash
curl http://localhost:9470/metrics | grep cache_hit_rate
```
2. Пуснете ръчен compaction:
```bash
curl -X POST http://localhost:9470/admin/compact
```
3. Проверете броя на SSTables:
```bash
curl http://localhost:9470/metrics | grep sstables
```
### Растящо Дисково Пространство
```bash
# Проверете размера на директорията с данни
du -sh ./data
# Проверете WAL размера
du -sh ./data/server/wal
# Пуснете ръчен compaction за освобождаване на място
curl -X POST http://localhost:9470/admin/compact
```
## Проблеми с Автентикация
### Грешка при Верификация на JWT
```json
{"error": {"code": "AUTH_REQUIRED", "message": "Authentication required"}}
```
**Решение:** Уверете се, че изпращате правилния токен:
```bash
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:9470/api/query \
-d '{"query": "SELECT 1"}'
```
## Разпределени Проблеми
### Възел не се Присъединява към Клъстер
1. Проверете мрежовата свързаност между възлите
2. Проверете gossip порта (raft порт + 100)
3. Проверете логовете за грешки при gossip
### Репликационно Закъснение
```bash
# Проверете replication lag
curl http://localhost:9470/metrics/cluster | jq .replication_lag_ms
```
## Често Задавани Въпроси
### Как да нулирам напълно базата данни?
```bash
# Спрете сървъра
# Изтрийте директорията с данни
rm -rf ./data
# Стартирайте отново — нова празна база ще бъде създадена
./build/baradadb
```
### Как да мигрирам от друга база данни?
BaraDB поддържа импорт чрез JSON и CSV:
```bash
curl -X POST http://localhost:9470/api/import \
-H "Content-Type: application/json" \
-d '{"table": "users", "format": "json", "data": [...]}'
```
+55
View File
@@ -0,0 +1,55 @@
# Потребителски Функции (UDF)
Разширете BaraQL с персонализирани функции.
## Употреба
```nim
import barabadb/query/udf
var reg = newUDFRegistry()
# Регистриране на стандартна библиотека
reg.registerStdlib() # abs, sqrt, pow, lower, upper, len, trim, substr, toString, toInt
# Персонализирана функция
reg.register("greet", @[UDFParam(name: "name", typeName: "str")],
"str", proc(args: seq[Value]): Value =
return Value(kind: vkString, strVal: "Hello, " & args[0].strVal & "!"))
```
## Функции от Стандартната Библиотека
| Функция | Описание | Пример |
|----------|----------|--------|
| `abs(n)` | Абсолютна стойност | `abs(-5)` → 5 |
| `sqrt(n)` | Квадратен корен | `sqrt(16)` → 4 |
| `pow(n, e)` | Степенуване | `pow(2, 3)` → 8 |
| `lower(s)` | Малки букви | `lower('ABC')` → 'abc' |
| `upper(s)` | Главни букви | `upper('abc')` → 'ABC' |
| `len(s)` | Дължина | `len('hello')` → 5 |
| `trim(s)` | Премахване на интервали | `trim(' hello ')` → 'hello' |
| `substr(s, start, len)` | Подниз | `substr('hello', 0, 3)` → 'hel' |
| `toString(n)` | Конвертиране в низ | `toString(123)` → '123' |
| `toInt(s)` | Конвертиране в integer | `toInt('123')` → 123 |
## Регистриране на Функции
```nim
reg.register(
name: "my_function",
params: @[
UDFParam(name: "arg1", typeName: "str"),
UDFParam(name: "arg2", typeName: "int32")
],
returnType: "str",
body: proc(args: seq[Value]): Value =
result = Value(kind: vkString, strVal: "")
)
```
## Използване на UDF в Заявки
```sql
SELECT greet(name) FROM users;
```
+130 -14
View File
@@ -1,8 +1,89 @@
# Vector Търсене # Vector Search Engine
HNSW и IVF-PQ индекси за търсене на прилика. Нативни HNSW и IVF-PQ индекси за търсене на прилика с пълна SQL интеграция.
## Употреба ## SQL Употреба
### Създаване на Векторни Колони
```sql
CREATE TABLE items (
id INT PRIMARY KEY,
embedding VECTOR(768)
);
```
Типът `VECTOR(n)` съхранява float32 масиви с фиксирана размерност `n`.
### Вмъкване на Вектори
```sql
INSERT INTO items (id, embedding) VALUES (1, '[0.1, 0.2, 0.3, ...]');
```
### Функции за Векторно Разстояние
```sql
-- Косинусово разстояние (0 = идентични, 1 = ортогонални)
SELECT id, cosine_distance(embedding, '[0.1, 0.2, 0.3]') AS dist
FROM items;
-- Евклидово / L2 разстояние
SELECT id, euclidean_distance(embedding, '[0.1, 0.2, 0.3]') AS dist
FROM items;
-- L2 разстояние с <-> оператор
SELECT id, embedding <-> '[0.1, 0.2, 0.3]' AS dist
FROM items;
-- Скаларно произведение (отрицателно dot product за минимизация)
SELECT id, inner_product(embedding, '[0.1, 0.2, 0.3]') AS dist
FROM items;
-- Манхатън / L1 разстояние
SELECT id, l1_distance(embedding, '[0.1, 0.2, 0.3]') AS dist
FROM items;
```
### Търсене на Най-близки Съседи
```sql
-- Топ-10 най-близки съседи по косинусово разстояние
SELECT id FROM items
ORDER BY cosine_distance(embedding, '[0.1, 0.2, 0.3]') ASC
LIMIT 10;
-- Топ-5 най-близки съседи по евклидово разстояние
SELECT id FROM items
ORDER BY embedding <-> '[0.1, 0.2, 0.3]'
LIMIT 5;
```
### Векторни Индекси
```sql
-- Създаване на HNSW индекс за приблизително търсене на най-близки съседи
CREATE INDEX idx_items_vec ON items(embedding) USING hnsw;
-- Индексът се поддържа автоматично при INSERT и UPDATE
```
Поддържани индекс методи:
- `USING hnsw` — Hierarchical Navigable Small World (по подразбиране: косинусова метрика)
- `USING ivfpq` — Inverted File с Product Quantization
### Валидация на Размерност
BaraDB валидира размерностите на векторите при вмъкване:
```sql
-- Това ще даде грешка: очаквани 768 размерности, но подадени 3
INSERT INTO items (id, embedding) VALUES (2, '[1.0, 2.0, 3.0]');
```
## Нативно Nim API
За вградена или високопроизводителна употреба използвайте нативното Nim API директно:
```nim ```nim
import barabadb/vector/engine import barabadb/vector/engine
@@ -10,32 +91,67 @@ import barabadb/vector/engine
var idx = newHNSWIndex(dimensions = 128) var idx = newHNSWIndex(dimensions = 128)
idx.insert(1, @[1.0'f32, 0.0'f32, ...], {"category": "A"}.toTable) idx.insert(1, @[1.0'f32, 0.0'f32, ...], {"category": "A"}.toTable)
# Търсене
let results = idx.search(queryVector, k = 10) let results = idx.search(queryVector, k = 10)
# С филтриране по метаданни
let filtered = idx.searchWithFilter(queryVector, k = 10,
filter = proc(meta: Table[string, string]): bool =
return meta.getOrDefault("category") == "A")
``` ```
## Индекс Типове ## Типове Индекси
### HNSW ### HNSW
Иерархичен навигируем малък свят: Иерархичен навигируем малък свят за приблизително търсене на най-близки съседи.
```nim ```nim
var hnsw = newHNSWIndex(dimensions = 128, m = 16) var hnsw = newHNSWIndex(
dimensions = 128,
m = 16, # връзки на слой
efConstruction = 200, # ширина на търсене при изграждане
efSearch = 100 # ширина на търсене при заявка
)
``` ```
### IVF-PQ ### IVF-PQ
Инвертиран файл с продуктово квантуване: Inverted File Index с продуктово квантуване за компресия.
```nim ```nim
var ivfpq = newIVFPQIndex(dimensions = 128, numCentroids = 256) var ivfpq = newIVFPQIndex(
dimensions = 128,
numCentroids = 256,
subQuantizers = 8
)
``` ```
## Метрики за Разстояние ## Метрики за Разстояние
| Метрика | Описание | | Метрика | SQL Функция | Описание |
|---------|----------| |---------|-------------|----------|
| `cosine` | Косинусова прилика | | `cosine` | `cosine_distance(a, b)` | Косинусова dissimilarity (1 - similarity) |
| `euclidean` | L2 разстояние | | `euclidean` | `euclidean_distance(a, b)` / `<->` | L2 разстояние |
| `dotproduct` | Скаларно произведение | | `dotproduct` | `inner_product(a, b)` | Отрицателно скаларно произведение |
| `manhattan` | L1 разстояние | | `manhattan` | `l1_distance(a, b)` | L1 разстояние |
## Квантуване
```nim
import barabadb/vector/quant
# Скаларно квантуване
let scalar = scalarQuantize(data, bits = 8)
# Продуктово квантуване
let pq = productQuantize(data, subVectors = 8, bits = 8)
```
## SIMD Ускорение
```nim
import barabadb/vector/simd
let dist = simdCosineDistance(vec1, vec2)
```
+1 -1
View File
@@ -156,7 +156,7 @@ raft_peers = "node2:9001,node3:9001"
``` ```
``` ```
BaraDB v0.1.0 — Multimodal Database Engine BaraDB v1.1.0 — Multimodal Database Engine
Usage: Usage:
baradadb [options] baradadb [options]
+2 -2
View File
@@ -144,7 +144,7 @@ strip build/baradadb
```bash ```bash
./build/baradadb --version ./build/baradadb --version
# Expected: BaraDB v0.1.0 — Multimodal Database Engine # Expected: BaraDB v1.1.0 — Multimodal Database Engine
``` ```
## Running Tests ## Running Tests
@@ -259,7 +259,7 @@ db.close()
./build/baradadb ./build/baradadb
# Expected output: # Expected output:
# BaraDB v0.1.0 — Multimodal Database Engine # BaraDB v1.1.0 — Multimodal Database Engine
# BaraDB TCP listening on 127.0.0.1:9472 # BaraDB TCP listening on 127.0.0.1:9472
# Test with HTTP API # Test with HTTP API
+105
View File
@@ -490,3 +490,108 @@ LIMIT 10;
-- اجرای موازی -- اجرای موازی
SELECT /*+ PARALLEL(4) */ * FROM large_table; SELECT /*+ PARALLEL(4) */ * FROM large_table;
``` ```
## توابع پنجره‌ای
```sql
-- توابع رتبه‌بندی
SELECT
name,
department,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS r,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dr
FROM employees;
-- توابع مقدار
SELECT
name,
salary,
LAG(salary, 1, 0) OVER (ORDER BY salary) AS prev_salary,
LEAD(salary, 1, 0) OVER (ORDER BY salary) AS next_salary,
FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS cheapest,
LAST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS most_expensive
FROM employees;
-- توابع توزیع
SELECT name, NTILE(4) OVER (ORDER BY salary) AS quartile FROM employees;
```
### مشخصات فریم
```sql
-- فریم ROWS
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
)
-- فریم RANGE
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
```
## ERP چند مستأجری
BaraDB از اجرای چندین شرکت (tenant) در یک نمونه پایگاه داده پشتیبانی می‌کند، با استفاده از **امنیت سطح سطر (RLS)** همراه با **متغیرهای جلسه**.
### متغیرهای جلسه
```sql
SET app.tenant_id = 'company-123';
SELECT current_setting('app.tenant_id') AS tenant;
```
### کاربر / نقش فعلی
```sql
SELECT current_user AS me, current_role AS my_role;
```
### جداسازی مستأجر با RLS
```sql
-- فعال کردن RLS روی جدول
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
-- ایجاد سیاست فیلترینگ بر اساس مستأجر
CREATE POLICY tenant_isolation ON invoices
FOR SELECT USING (tenant_id = current_setting('app.tenant_id'));
-- هر جلسه فقط داده‌های خود را می‌بیند
SET app.tenant_id = 'company-a';
SELECT * FROM invoices; -- فقط ردیف‌های company-a
```
### چرا چند مستأجری؟
- **یک نمونه، مستأجران زیاد** — نیازی به اجرای ۱۰۰ پایگاه داده جداگانه نیست
- **اسناد JSONB** — ذخیره‌سازی با طرح انعطاف‌پذیر، افزودن آسان فیلدها برای هر مستأجر
- **RLS تضمین می‌کند** — پایگاه داده مرزهای مستأجر را اعمال می‌کند، نه فقط برنامه
## کلمات کلیدی پشتیبانی‌شده
| دسته | کلمات کلیدی |
|----------|----------|
| DQL | SELECT, FROM, WHERE, ORDER BY, GROUP BY, HAVING, LIMIT, OFFSET, DISTINCT |
| DML | INSERT, UPDATE, DELETE, SET, VALUES |
| DDL | CREATE TYPE, DROP TYPE, CREATE INDEX, DROP INDEX, ALTER TYPE |
| Join | INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN, CROSS JOIN, ON |
| Set | UNION, UNION ALL, INTERSECT, EXCEPT |
| CTEs | WITH, RECURSIVE, AS |
| Case | CASE, WHEN, THEN, ELSE, END |
| Transaction | BEGIN, COMMIT, ROLLBACK, SAVEPOINT |
| Graph | MATCH, RETURN, WHERE, shortestPath, type |
| FTS | MATCH, AGAINST, relevance, IN BOOLEAN MODE, WITH FUZZINESS |
| Vector | cosine_distance, euclidean_distance, inner_product, l1_distance, l2_distance, <-> |
| JSON | ->, ->> |
| FTS | @@ (BM25 match) |
| Recovery | RECOVER TO TIMESTAMP |
| Functions | count, sum, avg, min, max, stddev, variance, abs, sqrt, lower, upper, len, trim, substr, now, last_insert_id, current_setting |
| Session | SET, current_setting, current_user, current_role |
| Window | OVER, PARTITION BY, ROWS, RANGE, UNBOUNDED PRECEDING, CURRENT ROW, FOLLOWING |
| Window Functions | ROW_NUMBER, RANK, DENSE_RANK, LEAD, LAG, FIRST_VALUE, LAST_VALUE, NTILE |
+2 -2
View File
@@ -144,7 +144,7 @@ strip build/baradadb
```bash ```bash
./build/baradadb --version ./build/baradadb --version
# انتظار: BaraDB v0.1.0 — Multimodal Database Engine # انتظار: BaraDB v1.1.0 — Multimodal Database Engine
``` ```
## اجرای تست‌ها ## اجرای تست‌ها
@@ -259,7 +259,7 @@ db.close()
./build/baradadb ./build/baradadb
# خروجی مورد انتظار: # خروجی مورد انتظار:
# BaraDB v0.1.0 — Multimodal Database Engine # BaraDB v1.1.0 — Multimodal Database Engine
# BaraDB TCP listening on 127.0.0.1:9472 # BaraDB TCP listening on 127.0.0.1:9472
# تست با HTTP API # تست با HTTP API
+105
View File
@@ -490,3 +490,108 @@ LIMIT 10;
-- Параллельное выполнение -- Параллельное выполнение
SELECT /*+ PARALLEL(4) */ * FROM large_table; SELECT /*+ PARALLEL(4) */ * FROM large_table;
``` ```
## Оконные функции
```sql
-- Функции ранжирования
SELECT
name,
department,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS r,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dr
FROM employees;
-- Функции значения
SELECT
name,
salary,
LAG(salary, 1, 0) OVER (ORDER BY salary) AS prev_salary,
LEAD(salary, 1, 0) OVER (ORDER BY salary) AS next_salary,
FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS cheapest,
LAST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS most_expensive
FROM employees;
-- Функции распределения
SELECT name, NTILE(4) OVER (ORDER BY salary) AS quartile FROM employees;
```
### Спецификации фрейма
```sql
-- ROWS фрейм
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
)
-- RANGE фрейм
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
```
## Мультитенантный ERP
BaraDB поддерживает работу нескольких компаний (арендаторов) в одной базе данных, используя **безопасность на уровне строк (RLS)** в сочетании с **переменными сессии**.
### Переменные сессии
```sql
SET app.tenant_id = 'company-123';
SELECT current_setting('app.tenant_id') AS tenant;
```
### Текущий пользователь / роль
```sql
SELECT current_user AS me, current_role AS my_role;
```
### Изоляция арендаторов через RLS
```sql
-- Включить RLS на таблице
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
-- Создать политику фильтрации по арендатору
CREATE POLICY tenant_isolation ON invoices
FOR SELECT USING (tenant_id = current_setting('app.tenant_id'));
-- Каждая сессия видит только свои данные
SET app.tenant_id = 'company-a';
SELECT * FROM invoices; -- только строки company-a
```
### Зачем мультитенантность?
- **Один экземпляр, много арендаторов** — не нужно запускать 100 отдельных баз данных
- **JSONB документы** — гибкая схема, легко добавлять поля для каждого арендатора
- **RLS гарантирует изоляцию** — база данных обеспечивает границы арендаторов, а не только приложение
## Поддерживаемые ключевые слова
| Категория | Ключевые слова |
|----------|----------|
| DQL | SELECT, FROM, WHERE, ORDER BY, GROUP BY, HAVING, LIMIT, OFFSET, DISTINCT |
| DML | INSERT, UPDATE, DELETE, SET, VALUES |
| DDL | CREATE TYPE, DROP TYPE, CREATE INDEX, DROP INDEX, ALTER TYPE |
| Join | INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN, CROSS JOIN, ON |
| Set | UNION, UNION ALL, INTERSECT, EXCEPT |
| CTEs | WITH, RECURSIVE, AS |
| Case | CASE, WHEN, THEN, ELSE, END |
| Transaction | BEGIN, COMMIT, ROLLBACK, SAVEPOINT |
| Graph | MATCH, RETURN, WHERE, shortestPath, type |
| FTS | MATCH, AGAINST, relevance, IN BOOLEAN MODE, WITH FUZZINESS |
| Vector | cosine_distance, euclidean_distance, inner_product, l1_distance, l2_distance, <-> |
| JSON | ->, ->> |
| FTS | @@ (BM25 match) |
| Recovery | RECOVER TO TIMESTAMP |
| Functions | count, sum, avg, min, max, stddev, variance, abs, sqrt, lower, upper, len, trim, substr, now, last_insert_id, current_setting |
| Session | SET, current_setting, current_user, current_role |
| Window | OVER, PARTITION BY, ROWS, RANGE, UNBOUNDED PRECEDING, CURRENT ROW, FOLLOWING |
| Window Functions | ROW_NUMBER, RANK, DENSE_RANK, LEAD, LAG, FIRST_VALUE, LAST_VALUE, NTILE |
+1 -1
View File
@@ -156,7 +156,7 @@ raft_peers = "node2:9001,node3:9001"
``` ```
``` ```
BaraDB v0.1.0 — Multimodal Database Engine BaraDB v1.1.0 — Multimodal Database Engine
Usage: Usage:
baradadb [options] baradadb [options]
+2 -2
View File
@@ -144,7 +144,7 @@ strip build/baradadb
```bash ```bash
./build/baradadb --version ./build/baradadb --version
# Ожидается: BaraDB v0.1.0 — Multimodal Database Engine # Ожидается: BaraDB v1.1.0 — Multimodal Database Engine
``` ```
## Запуск тестов ## Запуск тестов
@@ -259,7 +259,7 @@ db.close()
./build/baradadb ./build/baradadb
# Ожидаемый вывод: # Ожидаемый вывод:
# BaraDB v0.1.0 — Multimodal Database Engine # BaraDB v1.1.0 — Multimodal Database Engine
# BaraDB TCP listening on 127.0.0.1:9472 # BaraDB TCP listening on 127.0.0.1:9472
# Проверка через HTTP API # Проверка через HTTP API
+163 -4
View File
@@ -98,13 +98,172 @@ RETURN friend.name;
```sql ```sql
BEGIN; BEGIN;
INSERT users { name := 'Alice', age := 30 }; INSERT users { name := 'Alice', age := 30 };
INSERT orders { user_id := last_insert_id(), total := 100 };
COMMIT;
-- Savepoint ile
BEGIN;
INSERT users { name := 'Bob', age := 25 };
SAVEPOINT sp1;
INSERT orders { user_id := last_insert_id(), total := 200 };
-- Hata, savepoint'e geri al
ROLLBACK TO sp1;
COMMIT; COMMIT;
``` ```
## Grafik Kalıpları ## Tam Metin Arama
```sql ```sql
MATCH (p:Person)-[:KNOWS]->(friend:Person) -- Temel arama
WHERE p.name = 'Alice' SELECT * FROM articles
RETURN friend.name; WHERE MATCH(title, body) AGAINST('database programming');
-- İlgi puanı ile
SELECT title, relevance()
FROM articles
WHERE MATCH(title, body) AGAINST('Nim language')
ORDER BY relevance() DESC;
-- Boolean modu
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('+Nim -Python' IN BOOLEAN MODE);
-- Fuzzy arama
SELECT * FROM articles
WHERE MATCH(title) AGAINST('programing' WITH FUZZINESS 2);
``` ```
## Kullanıcı Tanımlı Fonksiyonlar
```sql
-- UDF kaydet
CREATE FUNCTION greet(name str) -> str {
RETURN 'Hello, ' || name || '!';
};
-- Kullan
SELECT greet(name) FROM users;
-- Dahili fonksiyonlar
SELECT abs(-5), sqrt(16), lower('HELLO'), len('test');
```
## Sorgu İpuçları
```sql
-- İndeks kullanımını zorla
SELECT /*+ USE_INDEX(idx_users_age) */ * FROM users WHERE age > 18;
-- Approximate vektör araması zorla
SELECT /*+ APPROXIMATE */ * FROM vectors
ORDER BY cosine_distance(embedding, [...])
LIMIT 10;
-- Paralel çalıştırma
SELECT /*+ PARALLEL(4) */ * FROM large_table;
```
## Pencere Fonksiyonları
```sql
-- Sıralama fonksiyonları
SELECT
name,
department,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS r,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dr
FROM employees;
-- Değer fonksiyonları
SELECT
name,
salary,
LAG(salary, 1, 0) OVER (ORDER BY salary) AS prev_salary,
LEAD(salary, 1, 0) OVER (ORDER BY salary) AS next_salary,
FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS cheapest,
LAST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS most_expensive
FROM employees;
-- Dağılım fonksiyonları
SELECT name, NTILE(4) OVER (ORDER BY salary) AS quartile FROM employees;
```
### Çerçeve Spesifikasyonları
```sql
-- ROWS çerçevesi
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
)
-- RANGE çerçevesi
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
```
## Çok Kiracılı ERP
BaraDB, **Satır Düzeyinde Güvenlik (RLS)** ve **oturum değişkenlerini** birleştirerek tek bir veritabanı örneğinde birden fazla şirketi (kiracı) çalıştırmayı destekler.
### Oturum Değişkenleri
```sql
SET app.tenant_id = 'company-123';
SELECT current_setting('app.tenant_id') AS tenant;
```
### Mevcut Kullanıcı / Rol
```sql
SELECT current_user AS me, current_role AS my_role;
```
### RLS Kiracı İzolasyonu
```sql
-- Tabloda RLS etkinleştir
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
-- Kiracıya göre filtreleme ilkesi oluştur
CREATE POLICY tenant_isolation ON invoices
FOR SELECT USING (tenant_id = current_setting('app.tenant_id'));
-- Her oturum yalnızca kendi verilerini görür
SET app.tenant_id = 'company-a';
SELECT * FROM invoices; -- yalnızca company-a satırları
```
### Neden Çok Kiracılı?
- **Bir örnek, çok kiracı** — 100 ayrı veritabanı çalıştırmaya gerek yok
- **JSONB belgeleri** — Esnek şema depolama, her kiracı için kolayca alan ekleme
- **RLS izolasyonu garanti eder** — Veritabanı kiracı sınırlarını uygular, yalnızca uygulama değil
## Desteklenen Anahtar Kelimeler
| Kategori | Anahtar Kelimeler |
|----------|----------|
| DQL | SELECT, FROM, WHERE, ORDER BY, GROUP BY, HAVING, LIMIT, OFFSET, DISTINCT |
| DML | INSERT, UPDATE, DELETE, SET, VALUES |
| DDL | CREATE TYPE, DROP TYPE, CREATE INDEX, DROP INDEX, ALTER TYPE |
| Join | INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN, CROSS JOIN, ON |
| Set | UNION, UNION ALL, INTERSECT, EXCEPT |
| CTEs | WITH, RECURSIVE, AS |
| Case | CASE, WHEN, THEN, ELSE, END |
| Transaction | BEGIN, COMMIT, ROLLBACK, SAVEPOINT |
| Graph | MATCH, RETURN, WHERE, shortestPath, type |
| FTS | MATCH, AGAINST, relevance, IN BOOLEAN MODE, WITH FUZZINESS |
| Vector | cosine_distance, euclidean_distance, inner_product, l1_distance, l2_distance, <-> |
| JSON | ->, ->> |
| FTS | @@ (BM25 eşleşme) |
| Recovery | RECOVER TO TIMESTAMP |
| Functions | count, sum, avg, min, max, stddev, variance, abs, sqrt, lower, upper, len, trim, substr, now, last_insert_id, current_setting |
| Session | SET, current_setting, current_user, current_role |
| Window | OVER, PARTITION BY, ROWS, RANGE, UNBOUNDED PRECEDING, CURRENT ROW, FOLLOWING |
| Window Functions | ROW_NUMBER, RANK, DENSE_RANK, LEAD, LAG, FIRST_VALUE, LAST_VALUE, NTILE |
+246
View File
@@ -22,38 +22,284 @@
### Linux ### Linux
```bash ```bash
# Resmi kurulum scripti
curl https://nim-lang.org/choosenim/init.sh -sSf | sh curl https://nim-lang.org/choosenim/init.sh -sSf | sh
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install nim
# Fedora
sudo dnf install nim
# Arch Linux
sudo pacman -S nim
``` ```
### macOS ### macOS
```bash ```bash
# Homebrew
brew install nim brew install nim
# MacPorts
sudo port install nim
``` ```
### Windows ### Windows
```powershell ```powershell
# choosenim ile
curl.exe -A "MSYS2_$(uname -m)" -L https://nim-lang.org/choosenim/init.ps1 | powershell -
# winget ile
winget install nim winget install nim
# scoop ile
scoop install nim
``` ```
### Kurulumu Doğrulama
```bash
nim --version
# Beklenen: Nim Compiler Version 2.2.0 veya daha yeni
```
## OpenSSL Kurulumu
### Linux
```bash
# Ubuntu/Debian
sudo apt-get install libssl-dev
# Fedora
sudo dnf install openssl-devel
# Arch Linux
sudo pacman -S openssl
```
### macOS
OpenSSL sistemle birlikte gelir. Gerekirse:
```bash
brew install openssl
```
### Windows
OpenSSL, Nim Windows dağıtımıyla birlikte gelir. Manuel derlemeler için [slproweb.com](https://slproweb.com/products/Win32OpenSSL.html) adresinden indirin.
## BaraDB Derleme ## BaraDB Derleme
### Depoyu Klonlama
```bash ```bash
git clone https://github.com/katehonz/barabaDB.git git clone https://github.com/katehonz/barabaDB.git
cd barabaDB cd barabaDB
```
### Bağımlılıkları Kurma
```bash
nimble install -d -y nimble install -d -y
```
### Derleme Seçenekleri
#### Debug Derleme
```bash
nim c -d:ssl -o:build/baradadb src/baradadb.nim
```
#### Release Derleme (Önerilen)
```bash
nim c -d:ssl -d:release --opt:speed -o:build/baradadb src/baradadb.nim nim c -d:ssl -d:release --opt:speed -o:build/baradadb src/baradadb.nim
``` ```
#### Nimble Tasks Kullanma
```bash
# Debug derleme
nimble build_debug
# Release derleme
nimble build_release
```
#### Binary Boyutunu Küçültme
```bash
nim c -d:ssl -d:release --opt:size -o:build/baradadb src/baradadb.nim
strip build/baradadb
```
### Derlemeyi Doğrulama
```bash
./build/baradadb --version
# Beklenen: BaraDB v1.1.0 — Multimodal Database Engine
```
## Testleri Çalıştırma
### Tüm Testler
```bash
nim c -d:ssl -r tests/test_all.nim
```
### Belirli Test Süitleri
```bash
# Depolama testleri
nim c -d:ssl -r tests/test_storage.nim
# Sorgu motoru testleri
nim c -d:ssl -r tests/test_query.nim
# Protokol testleri
nim c -d:ssl -r tests/test_protocol.nim
```
### Benchmarklar
```bash
nim c -d:ssl -d:release -r benchmarks/bench_all.nim
```
## Kurulum Seçenekleri
### Sistem Geneli Kurulum
```bash
# Release binary derle
nimble build_release
# /usr/local/bin'e kur
sudo cp build/baradadb /usr/local/bin/
sudo chmod +x /usr/local/bin/baradadb
# Veri dizini oluştur
sudo mkdir -p /var/lib/baradb
sudo chmod 755 /var/lib/baradb
```
### Ön Derlenmiş Binary
En son sürümü platformunuz için indirin:
```bash
# Linux x86_64
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-linux-amd64
chmod +x baradadb-linux-amd64
mv baradadb-linux-amd64 /usr/local/bin/baradadb
# Linux ARM64
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-linux-arm64
chmod +x baradadb-linux-arm64
mv baradadb-linux-arm64 /usr/local/bin/baradadb
# macOS
wget https://github.com/katehonz/barabaDB/releases/latest/download/baradadb-darwin-amd64
chmod +x baradadb-darwin-amd64
mv baradadb-darwin-amd64 /usr/local/bin/baradadb
```
### Docker
```bash
# Resmi image'i çek
docker pull barabadb/barabadb:latest
# Çalıştır
docker run -d \
-p 9472:9472 \
-p 9470:9470 \
-p 9471:9471 \
-v baradb_data:/data \
barabadb/barabadb
```
### Docker Compose
```bash
docker-compose up -d
```
### Gömülü Kullanım (Nim Projeleri)
`.nimble` dosyanıza ekleyin:
```nim
requires "barabadb >= 1.1.0"
```
Kodunuzda kullanın:
```nim
import barabadb/storage/lsm
var db = newLSMTree("./data")
db.put("key", cast[seq[byte]]("value"))
let (found, val) = db.get("key")
db.close()
```
## İlk Çalıştırma ## İlk Çalıştırma
```bash ```bash
# Sunucuyu başlat
./build/baradadb ./build/baradadb
# Beklenen çıktı:
# BaraDB v1.1.0 — Multimodal Database Engine
# BaraDB TCP listening on 127.0.0.1:9472
# HTTP API ile test et
curl http://localhost:9470/health curl http://localhost:9470/health
# İnteraktif shell
./build/baradadb --shell ./build/baradadb --shell
``` ```
## Kurulum Sorunlarını Giderme
### "cannot open file: hunos"
```bash
nimble install -d -y
```
### "BaraDB requires SSL support"
Her zaman `-d:ssl` ile derleyin:
```bash
nim c -d:ssl -o:build/baradadb src/baradadb.nim
```
### Yavaş derleme
Paralel derleme kullanın:
```bash
nim c -d:ssl -d:release --parallelBuild:4 -o:build/baradadb src/baradadb.nim
```
### Büyük binary boyutu
Boyut optimizasyonu kullanın:
```bash
nim c -d:ssl -d:release --opt:size --passL:-s -o:build/baradadb src/baradadb.nim
```
## Sonraki Adımlar ## Sonraki Adımlar
- [Hızlı Başlangıç](quickstart.md) - [Hızlı Başlangıç](quickstart.md)
+105
View File
@@ -490,3 +490,108 @@ LIMIT 10;
-- 并行执行 -- 并行执行
SELECT /*+ PARALLEL(4) */ * FROM large_table; SELECT /*+ PARALLEL(4) */ * FROM large_table;
``` ```
## 窗口函数
```sql
-- 排名函数
SELECT
name,
department,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS r,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dr
FROM employees;
-- 值函数
SELECT
name,
salary,
LAG(salary, 1, 0) OVER (ORDER BY salary) AS prev_salary,
LEAD(salary, 1, 0) OVER (ORDER BY salary) AS next_salary,
FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS cheapest,
LAST_VALUE(name) OVER (PARTITION BY department ORDER BY salary) AS most_expensive
FROM employees;
-- 分布函数
SELECT name, NTILE(4) OVER (ORDER BY salary) AS quartile FROM employees;
```
### 帧规格
```sql
-- ROWS 帧
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
)
-- RANGE 帧
SUM(salary) OVER (
PARTITION BY department
ORDER BY hire_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
```
## 多租户 ERP
BaraDB 支持在单个数据库实例中运行多个公司(租户),使用**行级安全性(RLS)**结合**会话变量**。
### 会话变量
```sql
SET app.tenant_id = 'company-123';
SELECT current_setting('app.tenant_id') AS tenant;
```
### 当前用户 / 角色
```sql
SELECT current_user AS me, current_role AS my_role;
```
### RLS 租户隔离
```sql
-- 在表上启用 RLS
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
-- 创建按租户过滤的策略
CREATE POLICY tenant_isolation ON invoices
FOR SELECT USING (tenant_id = current_setting('app.tenant_id'));
-- 每个会话只能看到自己的数据
SET app.tenant_id = 'company-a';
SELECT * FROM invoices; -- 仅限 company-a 的行
```
### 为什么选择多租户?
- **一个实例,多个租户** — 无需运行 100 个独立的数据库
- **JSONB 文档** — 模式灵活的存储,易于为每个租户添加字段
- **RLS 保证隔离** — 数据库强制执行租户边界,而不仅仅是应用程序
## 支持的关键字
| 类别 | 关键字 |
|----------|----------|
| DQL | SELECT, FROM, WHERE, ORDER BY, GROUP BY, HAVING, LIMIT, OFFSET, DISTINCT |
| DML | INSERT, UPDATE, DELETE, SET, VALUES |
| DDL | CREATE TYPE, DROP TYPE, CREATE INDEX, DROP INDEX, ALTER TYPE |
| Join | INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN, CROSS JOIN, ON |
| Set | UNION, UNION ALL, INTERSECT, EXCEPT |
| CTEs | WITH, RECURSIVE, AS |
| Case | CASE, WHEN, THEN, ELSE, END |
| Transaction | BEGIN, COMMIT, ROLLBACK, SAVEPOINT |
| Graph | MATCH, RETURN, WHERE, shortestPath, type |
| FTS | MATCH, AGAINST, relevance, IN BOOLEAN MODE, WITH FUZZINESS |
| Vector | cosine_distance, euclidean_distance, inner_product, l1_distance, l2_distance, <-> |
| JSON | ->, ->> |
| FTS | @@ (BM25 match) |
| Recovery | RECOVER TO TIMESTAMP |
| Functions | count, sum, avg, min, max, stddev, variance, abs, sqrt, lower, upper, len, trim, substr, now, last_insert_id, current_setting |
| Session | SET, current_setting, current_user, current_role |
| Window | OVER, PARTITION BY, ROWS, RANGE, UNBOUNDED PRECEDING, CURRENT ROW, FOLLOWING |
| Window Functions | ROW_NUMBER, RANK, DENSE_RANK, LEAD, LAG, FIRST_VALUE, LAST_VALUE, NTILE |
+1 -1
View File
@@ -156,7 +156,7 @@ raft_peers = "node2:9001,node3:9001"
``` ```
``` ```
BaraDB v0.1.0 — Multimodal Database Engine BaraDB v1.1.0 — Multimodal Database Engine
Usage: Usage:
baradadb [options] baradadb [options]
+2 -2
View File
@@ -144,7 +144,7 @@ strip build/baradadb
```bash ```bash
./build/baradadb --version ./build/baradadb --version
# 预期输出: BaraDB v0.1.0 — Multimodal Database Engine # 预期输出: BaraDB v1.1.0 — Multimodal Database Engine
``` ```
## 运行测试 ## 运行测试
@@ -259,7 +259,7 @@ db.close()
./build/baradadb ./build/baradadb
# 预期输出: # 预期输出:
# BaraDB v0.1.0 — Multimodal Database Engine # BaraDB v1.1.0 — Multimodal Database Engine
# BaraDB TCP listening on 127.0.0.1:9472 # BaraDB TCP listening on 127.0.0.1:9472
# 使用 HTTP API 测试 # 使用 HTTP API 测试