@rip-lang/db 0.10.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -259
- package/bin/rip-db +5 -10
- package/db.rip +217 -237
- package/lib/duckdb-binary.rip +34 -13
- package/lib/duckdb.mjs +694 -304
- package/package.json +10 -7
- package/PROTOCOL.md +0 -258
- package/db.html +0 -122
- package/lib/darwin-arm64/duckdb.node +0 -0
package/README.md
CHANGED
|
@@ -2,320 +2,159 @@
|
|
|
2
2
|
|
|
3
3
|
# Rip DB - @rip-lang/db
|
|
4
4
|
|
|
5
|
-
> **
|
|
5
|
+
> **A lightweight DuckDB HTTP server with the official DuckDB UI built in**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Rip DB turns any DuckDB database into a full-featured HTTP server — complete
|
|
8
|
+
with the official DuckDB UI for interactive queries, notebooks, and data
|
|
9
|
+
exploration. It connects to DuckDB via pure Bun FFI (no npm packages, no
|
|
10
|
+
native build step) and implements DuckDB's binary serialization protocol
|
|
11
|
+
to power the UI with native-speed data transfer.
|
|
8
12
|
|
|
9
|
-
##
|
|
13
|
+
## Quick Start
|
|
10
14
|
|
|
11
15
|
```bash
|
|
12
|
-
# Install
|
|
13
|
-
|
|
16
|
+
# Install DuckDB and Rip DB
|
|
17
|
+
brew install duckdb # macOS (or see duckdb.org for Linux)
|
|
18
|
+
bun add -g @rip-lang/db # Installs rip-db command
|
|
14
19
|
|
|
15
|
-
#
|
|
16
|
-
rip-db
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
rip-db mydb.duckdb
|
|
20
|
-
|
|
21
|
-
# Specify port
|
|
22
|
-
rip-db mydb.duckdb --port=8080
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Or run directly with Rip:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
rip db.rip :memory: --port=4000
|
|
20
|
+
# Start the server
|
|
21
|
+
rip-db # In-memory database
|
|
22
|
+
rip-db mydata.duckdb # File-based database
|
|
23
|
+
rip-db mydata.duckdb --port 8080
|
|
29
24
|
```
|
|
30
25
|
|
|
31
|
-
|
|
26
|
+
Open **http://localhost:4213** for the official DuckDB UI.
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
## What It Does
|
|
34
29
|
|
|
35
|
-
|
|
30
|
+
Rip DB sits between your clients and DuckDB, providing two interfaces:
|
|
36
31
|
|
|
37
|
-
**Request:**
|
|
38
|
-
```json
|
|
39
|
-
{
|
|
40
|
-
"sql": "SELECT * FROM users WHERE id = ?",
|
|
41
|
-
"params": [1]
|
|
42
|
-
}
|
|
43
32
|
```
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"rows": 1,
|
|
57
|
-
"time": 0.001
|
|
58
|
-
}
|
|
33
|
+
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
34
|
+
│ DuckDB UI │ binary │ rip-db │ FFI │ DuckDB │
|
|
35
|
+
│ (Browser) │◀────────▶│ (Bun) │◀────────▶│ (native) │
|
|
36
|
+
└─────────────┘ └─────────────┘ └─────────────┘
|
|
37
|
+
▲
|
|
38
|
+
│ HTTP/S
|
|
39
|
+
│ (JSON)
|
|
40
|
+
▼
|
|
41
|
+
┌─────────────────┐
|
|
42
|
+
│ HTTP Clients │
|
|
43
|
+
│ (curl, apps) │
|
|
44
|
+
└─────────────────┘
|
|
59
45
|
```
|
|
60
46
|
|
|
61
|
-
|
|
47
|
+
**DuckDB UI** — The official DuckDB notebook interface loads instantly in your
|
|
48
|
+
browser. Rip DB proxies the UI assets from ui.duckdb.org and implements the
|
|
49
|
+
full binary serialization protocol that the UI uses to communicate with DuckDB.
|
|
50
|
+
This includes query execution, SQL tokenization for syntax highlighting, and
|
|
51
|
+
Server-Sent Events for real-time catalog updates.
|
|
62
52
|
|
|
63
|
-
|
|
53
|
+
**JSON API** — Any HTTP client can execute SQL queries and receive JSON
|
|
54
|
+
responses. Use it from curl, your application code, or any language that
|
|
55
|
+
speaks HTTP.
|
|
64
56
|
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
POST / HTTP/1.1
|
|
68
|
-
Content-Type: application/x-www-form-urlencoded
|
|
57
|
+
## Features
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
**
|
|
74
|
-
|
|
75
|
-
|
|
59
|
+
- **Official DuckDB UI** — Interactive notebooks, syntax highlighting, data exploration
|
|
60
|
+
- **Full binary protocol** — Native DuckDB UI serialization implemented in Rip
|
|
61
|
+
- **Pure Bun FFI** — Direct calls to DuckDB's C API using the modern chunk-based interface
|
|
62
|
+
- **Zero npm dependencies for DuckDB** — Uses the system-installed DuckDB library
|
|
63
|
+
- **Parameterized queries** — Prepared statements with type-safe parameter binding
|
|
64
|
+
- **Complete type support** — All DuckDB types handled natively, including UUID, DECIMAL, TIMESTAMP, LIST, STRUCT, MAP
|
|
65
|
+
- **DECIMAL precision preserved** — Exact string representation, never converted to floating point
|
|
66
|
+
- **Timestamps as UTC** — All timestamps returned as JavaScript Date objects (UTC)
|
|
67
|
+
- **Powered by @rip-lang/api** — Fast, lightweight HTTP server framework
|
|
68
|
+
- **Single binary** — One `rip-db` command, one process, one database
|
|
76
69
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
```json
|
|
80
|
-
{ "ok": true }
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### GET /status
|
|
84
|
-
|
|
85
|
-
Database info including table list.
|
|
86
|
-
|
|
87
|
-
```json
|
|
88
|
-
{
|
|
89
|
-
"ok": true,
|
|
90
|
-
"database": "mydb.duckdb",
|
|
91
|
-
"tables": ["users", "orders", "products"],
|
|
92
|
-
"time": "2026-02-02T14:30:00.000Z"
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### GET /tables
|
|
97
|
-
|
|
98
|
-
List all tables in the database.
|
|
99
|
-
|
|
100
|
-
```json
|
|
101
|
-
{
|
|
102
|
-
"ok": true,
|
|
103
|
-
"tables": ["users", "orders", "products"]
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### GET /schema/:table
|
|
108
|
-
|
|
109
|
-
Get schema for a specific table.
|
|
110
|
-
|
|
111
|
-
```json
|
|
112
|
-
{
|
|
113
|
-
"ok": true,
|
|
114
|
-
"table": "users",
|
|
115
|
-
"columns": [
|
|
116
|
-
{ "column_name": "id", "data_type": "INTEGER", "is_nullable": "NO" },
|
|
117
|
-
{ "column_name": "name", "data_type": "VARCHAR", "is_nullable": "YES" },
|
|
118
|
-
{ "column_name": "email", "data_type": "VARCHAR", "is_nullable": "YES" }
|
|
119
|
-
]
|
|
120
|
-
}
|
|
121
|
-
```
|
|
70
|
+
## JSON API
|
|
122
71
|
|
|
123
|
-
|
|
72
|
+
For programmatic access from any HTTP client.
|
|
124
73
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
http://localhost:4000/ui
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## DuckDB UI Compatibility
|
|
132
|
-
|
|
133
|
-
rip-db implements the official DuckDB UI binary protocol, making it compatible with
|
|
134
|
-
DuckDB's built-in UI. This means you can use the beautiful DuckDB UI with rip-db!
|
|
135
|
-
|
|
136
|
-
### Binary Protocol Endpoints
|
|
137
|
-
|
|
138
|
-
| Endpoint | Method | Purpose |
|
|
139
|
-
|-------------------|--------|----------------------------|
|
|
140
|
-
| `/ddb/run` | POST | Execute SQL (binary result)|
|
|
141
|
-
| `/ddb/interrupt` | POST | Cancel running query |
|
|
142
|
-
| `/ddb/tokenize` | POST | Syntax highlighting |
|
|
143
|
-
| `/info` | GET | Version info |
|
|
144
|
-
|
|
145
|
-
### How It Works
|
|
146
|
-
|
|
147
|
-
```
|
|
148
|
-
┌─────────────┐ Binary Protocol ┌─────────────┐
|
|
149
|
-
│ DuckDB UI │ ◀─────────────────────▶│ rip-db │
|
|
150
|
-
│ (Browser) │ │ Server │
|
|
151
|
-
└─────────────┘ └─────────────┘
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
The UI sends SQL to `/ddb/run`, rip-db executes it and returns results in DuckDB's
|
|
155
|
-
binary format. The UI has no idea it's talking to rip-db instead of native DuckDB!
|
|
156
|
-
|
|
157
|
-
For protocol details, see [PROTOCOL.md](./PROTOCOL.md).
|
|
158
|
-
|
|
159
|
-
## Examples
|
|
160
|
-
|
|
161
|
-
### Create a table
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
curl -X POST http://localhost:4000/sql \
|
|
165
|
-
-H "Content-Type: application/json" \
|
|
166
|
-
-d '{"sql": "CREATE TABLE users (id INTEGER PRIMARY KEY, name VARCHAR, email VARCHAR)"}'
|
|
167
|
-
```
|
|
74
|
+
### POST /sql
|
|
168
75
|
|
|
169
|
-
|
|
76
|
+
Execute SQL with optional parameters:
|
|
170
77
|
|
|
171
78
|
```bash
|
|
172
|
-
curl -X POST http://localhost:
|
|
79
|
+
curl -X POST http://localhost:4213/sql \
|
|
173
80
|
-H "Content-Type: application/json" \
|
|
174
|
-
-d '{"sql": "
|
|
81
|
+
-d '{"sql": "SELECT * FROM users WHERE id = $1", "params": [1]}'
|
|
175
82
|
```
|
|
176
83
|
|
|
177
|
-
###
|
|
178
|
-
|
|
179
|
-
```bash
|
|
180
|
-
curl -X POST http://localhost:4000/sql \
|
|
181
|
-
-H "Content-Type: application/json" \
|
|
182
|
-
-d '{"sql": "SELECT * FROM users WHERE name LIKE ?", "params": ["%Ali%"]}'
|
|
183
|
-
```
|
|
84
|
+
### POST /
|
|
184
85
|
|
|
185
|
-
|
|
86
|
+
Execute raw SQL (body is the query):
|
|
186
87
|
|
|
187
88
|
```bash
|
|
188
|
-
curl -X POST http://localhost:
|
|
189
|
-
-H "Content-Type: application/json" \
|
|
190
|
-
-d '{"sql": "SELECT COUNT(*) as total, AVG(age) as avg_age FROM users"}'
|
|
89
|
+
curl -X POST http://localhost:4213/ -d "SELECT 42 as answer"
|
|
191
90
|
```
|
|
192
91
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
All responses use JSONCompact format (compatible with DuckDB HTTP Server and duck-ui):
|
|
196
|
-
|
|
197
|
-
| Field | Type | Description |
|
|
198
|
-
|-------|------|-------------|
|
|
199
|
-
| `meta` | object[] | Column metadata: `[{name, type}, ...]` |
|
|
200
|
-
| `data` | any[][] | Row data as arrays |
|
|
201
|
-
| `rows` | number | Number of rows returned |
|
|
202
|
-
| `time` | number | Execution time in seconds |
|
|
203
|
-
| `error` | string | Error message (on failure) |
|
|
92
|
+
Response format:
|
|
204
93
|
|
|
205
|
-
**Success response:**
|
|
206
94
|
```json
|
|
207
95
|
{
|
|
208
|
-
"meta": [{"name": "
|
|
209
|
-
"data": [[
|
|
210
|
-
"rows":
|
|
96
|
+
"meta": [{"name": "answer", "type": "INTEGER"}],
|
|
97
|
+
"data": [[42]],
|
|
98
|
+
"rows": 1,
|
|
211
99
|
"time": 0.001
|
|
212
100
|
}
|
|
213
101
|
```
|
|
214
102
|
|
|
215
|
-
|
|
216
|
-
```json
|
|
217
|
-
{"error": "Table 'foo' does not exist"}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
This format is compatible with [duck-ui](https://demo.duckui.com) and other DuckDB HTTP clients.
|
|
221
|
-
|
|
222
|
-
## Performance
|
|
103
|
+
### Other Endpoints
|
|
223
104
|
|
|
224
|
-
|
|
105
|
+
| Endpoint | Method | Description |
|
|
106
|
+
|----------|--------|-------------|
|
|
107
|
+
| `/health` | GET | Health check |
|
|
108
|
+
| `/tables` | GET | List all tables |
|
|
109
|
+
| `/schema/:table` | GET | Table schema |
|
|
225
110
|
|
|
226
|
-
|
|
227
|
-
|-----------|---------|------------|
|
|
228
|
-
| Point lookup (WHERE id=?) | 0.09ms | 11,000 qps |
|
|
229
|
-
| Range scan (LIMIT 100) | 0.20ms | 5,000 qps |
|
|
230
|
-
| Aggregation (COUNT/AVG/MAX) | 0.12ms | 8,400 qps |
|
|
231
|
-
| JOIN + GROUP BY | 0.25ms | 4,000 qps |
|
|
232
|
-
| INSERT (single row) | 0.13ms | 7,700 qps |
|
|
111
|
+
## DuckDB UI
|
|
233
112
|
|
|
234
|
-
|
|
113
|
+
The official DuckDB UI is available at the root URL. It provides:
|
|
235
114
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
| Aggregation | **0.12ms** | 2-20ms | 17-170x faster |
|
|
241
|
-
| JOIN + GROUP BY | **0.25ms** | 5-50ms | 20-200x faster |
|
|
242
|
-
| INSERT | **0.13ms** | 0.5-2ms | 4-15x faster |
|
|
115
|
+
- **SQL Notebooks** — Write and execute queries in a notebook interface
|
|
116
|
+
- **Syntax Highlighting** — Real-time SQL tokenization as you type
|
|
117
|
+
- **Data Exploration** — Browse tables, schemas, and query results
|
|
118
|
+
- **Multiple Databases** — Attach and query across databases
|
|
243
119
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
- **Columnar engine** — DuckDB is optimized for analytical queries
|
|
248
|
-
- **Direct FFI** — Zig bindings call DuckDB's C API directly
|
|
120
|
+
The UI communicates with Rip DB using DuckDB's binary serialization protocol,
|
|
121
|
+
which Rip DB implements in full. This means the UI works exactly as it does
|
|
122
|
+
with the official `duckdb -ui` command — same features, same performance.
|
|
249
123
|
|
|
250
|
-
##
|
|
124
|
+
## How It Works
|
|
251
125
|
|
|
252
|
-
|
|
126
|
+
Rip DB is built from three files:
|
|
253
127
|
|
|
254
|
-
|
|
128
|
+
| File | Lines | Role |
|
|
129
|
+
|------|-------|------|
|
|
130
|
+
| `db.rip` | ~390 | HTTP server — routes, middleware, UI proxy |
|
|
131
|
+
| `lib/duckdb.mjs` | ~800 | FFI driver — modern chunk-based DuckDB C API |
|
|
132
|
+
| `lib/duckdb-binary.rip` | ~550 | Binary serializer — DuckDB UI protocol |
|
|
255
133
|
|
|
256
|
-
|
|
134
|
+
The FFI driver uses DuckDB's modern chunk-based API (`duckdb_fetch_chunk`,
|
|
135
|
+
`duckdb_vector_get_data`) to read query results directly from columnar memory.
|
|
136
|
+
No deprecated per-value functions, no intermediate copies. For complex types
|
|
137
|
+
like DECIMAL, ENUM, LIST, and STRUCT, it uses DuckDB's logical type
|
|
138
|
+
introspection to read values with full fidelity.
|
|
257
139
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
├─────────────────────────────────────────────────────────┤
|
|
262
|
-
│ Bun HTTP Server (async I/O) │
|
|
263
|
-
│ ├─ Request 1 ──┐ │
|
|
264
|
-
│ ├─ Request 2 ──┼── thousands of concurrent │
|
|
265
|
-
│ ├─ Request 3 ──┤ connections via event loop │
|
|
266
|
-
│ └─ Request N ──┘ │
|
|
267
|
-
├─────────────────────────────────────────────────────────┤
|
|
268
|
-
│ rip-api (routes, middleware) │
|
|
269
|
-
├─────────────────────────────────────────────────────────┤
|
|
270
|
-
│ DuckDB (multi-threaded query engine) │
|
|
271
|
-
│ └─ Queries parallelized across CPU cores │
|
|
272
|
-
└─────────────────────────────────────────────────────────┘
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
**Layer 1: Bun's Async I/O**
|
|
276
|
-
- Single JavaScript thread with event loop
|
|
277
|
-
- Handles thousands of concurrent HTTP connections
|
|
278
|
-
- Non-blocking I/O — while one request waits on DuckDB, others are processed
|
|
279
|
-
- No thread-per-request overhead
|
|
280
|
-
|
|
281
|
-
**Layer 2: DuckDB's Multi-Threading**
|
|
282
|
-
- Queries are parallelized across all CPU cores internally
|
|
283
|
-
- MVCC for concurrent reads
|
|
284
|
-
- Writes serialized automatically by DuckDB
|
|
285
|
-
|
|
286
|
-
### Why Not Multi-Process?
|
|
287
|
-
|
|
288
|
-
| Approach | Works with DuckDB? | Why |
|
|
289
|
-
|----------|-------------------|-----|
|
|
290
|
-
| Multi-process (rip-server) | ❌ No | DuckDB only allows one process with write access |
|
|
291
|
-
| Multi-threaded | ✅ Yes | DuckDB handles this internally |
|
|
292
|
-
| Async I/O | ✅ Yes | Bun's event loop handles concurrent connections |
|
|
293
|
-
|
|
294
|
-
### The Result
|
|
295
|
-
|
|
296
|
-
Even as a single process, rip-db can handle:
|
|
297
|
-
- **Thousands of concurrent connections** (Bun async I/O)
|
|
298
|
-
- **Parallel query execution** (DuckDB multi-threading)
|
|
299
|
-
- **High throughput** (11,000+ queries/sec on typical hardware)
|
|
300
|
-
|
|
301
|
-
This is the correct architecture for DuckDB — single process, high concurrency.
|
|
140
|
+
The binary serializer implements the same wire protocol that DuckDB's official
|
|
141
|
+
UI extension uses. It handles all DuckDB types including native 16-byte UUID
|
|
142
|
+
serialization, uint64-aligned validity bitmaps, and proper timestamp encoding.
|
|
302
143
|
|
|
303
144
|
## Requirements
|
|
304
145
|
|
|
305
|
-
- Bun 1.0+
|
|
306
|
-
-
|
|
307
|
-
-
|
|
146
|
+
- **Bun** 1.0+
|
|
147
|
+
- **DuckDB** library installed on the system
|
|
148
|
+
- macOS: `brew install duckdb`
|
|
149
|
+
- Linux: Install from [duckdb.org](https://duckdb.org/docs/installation)
|
|
150
|
+
- **rip-lang** 2.8+ (installed automatically as a dependency)
|
|
308
151
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
To rebuild the native DuckDB bindings (requires Zig 0.15+ and DuckDB):
|
|
152
|
+
Set `DUCKDB_LIB_PATH` if DuckDB is not in a standard location:
|
|
312
153
|
|
|
313
154
|
```bash
|
|
314
|
-
|
|
155
|
+
DUCKDB_LIB_PATH=/path/to/libduckdb.dylib rip-db
|
|
315
156
|
```
|
|
316
157
|
|
|
317
|
-
This creates `lib/{platform}-{arch}/duckdb.node` for your platform.
|
|
318
|
-
|
|
319
158
|
## License
|
|
320
159
|
|
|
321
160
|
MIT
|
package/bin/rip-db
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
3
|
+
import { execFileSync } from 'child_process';
|
|
5
4
|
import { dirname, join } from 'path';
|
|
6
5
|
|
|
7
|
-
const
|
|
8
|
-
const __dirname = dirname(__filename);
|
|
9
|
-
|
|
10
|
-
const dbRip = join(__dirname, '..', 'db.rip');
|
|
11
|
-
const args = process.argv.slice(2).join(' ');
|
|
6
|
+
const dbRip = join(dirname(new URL(import.meta.url).pathname), '..', 'db.rip');
|
|
12
7
|
|
|
13
8
|
try {
|
|
14
|
-
|
|
15
|
-
} catch (
|
|
16
|
-
process.exit(
|
|
9
|
+
execFileSync('rip', [dbRip, ...process.argv.slice(2)], { stdio: 'inherit' });
|
|
10
|
+
} catch (e) {
|
|
11
|
+
process.exit(e.status || 1);
|
|
17
12
|
}
|