@rip-lang/db 0.10.0 → 1.0.1

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/PROTOCOL.md DELETED
@@ -1,258 +0,0 @@
1
- # DuckDB UI Binary Protocol Specification
2
-
3
- This document describes the binary protocol used by DuckDB's built-in UI to communicate
4
- with the database server. rip-db implements this protocol, allowing the official DuckDB UI
5
- to connect transparently.
6
-
7
- ## Architecture
8
-
9
- ```
10
- ┌─────────────┐ HTTP POST ┌─────────────┐ SQL ┌─────────────┐
11
- │ DuckDB UI │ ──────────────────▶│ rip-db │ ──────────────▶│ DuckDB │
12
- │ (Browser) │◀────────────────── │ Server │◀────────────── │ Database │
13
- └─────────────┘ Binary Response └─────────────┘ Results └─────────────┘
14
- ```
15
-
16
- ## Implemented Endpoints
17
-
18
- | Endpoint | Method | Body | Response | Status |
19
- |-------------------|--------|----------------|-------------------|----------|
20
- | `/ddb/run` | POST | SQL (text) | Binary result | ✅ Done |
21
- | `/ddb/interrupt` | POST | Empty | Empty result | ✅ Done |
22
- | `/ddb/tokenize` | POST | SQL (text) | Binary tokens | ✅ Done |
23
- | `/info` | GET | - | Empty + headers | ✅ Done |
24
-
25
- ## Request Headers
26
-
27
- All headers are optional unless noted.
28
-
29
- | Header | Encoding | Purpose |
30
- |-------------------------------------|----------|-----------------------------------|
31
- | `X-DuckDB-UI-Connection-Name` | Plain | Named connection (for persistence) |
32
- | `X-DuckDB-UI-Database-Name` | Base64 | Target database |
33
- | `X-DuckDB-UI-Schema-Name` | Base64 | Target schema |
34
- | `X-DuckDB-UI-Parameter-Count` | Plain | Number of prepared stmt params |
35
- | `X-DuckDB-UI-Parameter-Value-{n}` | Base64 | Param value (0-indexed) |
36
- | `X-DuckDB-UI-Result-Row-Limit` | Plain | Max rows to return |
37
- | `X-DuckDB-UI-Result-Database-Name` | Base64 | Store results in this database |
38
- | `X-DuckDB-UI-Result-Schema-Name` | Base64 | Store results in this schema |
39
- | `X-DuckDB-UI-Result-Table-Name` | Base64 | Store results in this table |
40
- | `X-DuckDB-UI-Result-Table-Row-Limit`| Plain | Max rows to store in table |
41
- | `X-DuckDB-UI-Errors-As-JSON` | Plain | Return errors as JSON |
42
- | `X-DuckDB-UI-Request-Description` | Plain | Human-readable description |
43
-
44
- ## Binary Serialization Format
45
-
46
- ### Primitives
47
-
48
- #### varint (Variable-length Integer)
49
- ```
50
- while (byte & 0x80):
51
- result |= (byte & 0x7F) << shift
52
- shift += 7
53
- ```
54
-
55
- #### uint8
56
- Single byte, unsigned.
57
-
58
- #### uint16 (Field ID)
59
- 2 bytes, little-endian.
60
-
61
- #### string
62
- ```
63
- length: varint
64
- data: UTF-8 bytes (length count)
65
- ```
66
-
67
- #### data (raw bytes)
68
- ```
69
- length: varint
70
- data: raw bytes (length count)
71
- ```
72
-
73
- #### nullable<T>
74
- ```
75
- present: uint8 (0 = null, non-zero = present)
76
- value: T (only if present)
77
- ```
78
-
79
- #### list<T>
80
- ```
81
- count: varint
82
- items: T[] (count items)
83
- ```
84
-
85
- ### Object Structure
86
-
87
- Objects use field IDs to identify properties:
88
- ```
89
- field_id: uint16 (little-endian)
90
- value: <type depends on field>
91
- ...
92
- end: 0xFFFF (end marker)
93
- ```
94
-
95
- ### Response Types
96
-
97
- #### SuccessResult
98
- ```
99
- field_100: boolean (true)
100
- field_101: ColumnNamesAndTypes
101
- field_102: list<DataChunk>
102
- 0xFFFF
103
- ```
104
-
105
- #### ErrorResult
106
- ```
107
- field_100: boolean (false)
108
- field_101: string (error message)
109
- 0xFFFF
110
- ```
111
-
112
- #### EmptyResult
113
- ```
114
- (no fields)
115
- ```
116
-
117
- #### TokenizeResult
118
- ```
119
- field_100: list<varint> (offsets)
120
- field_101: list<varint> (token types)
121
- 0xFFFF
122
- ```
123
-
124
- ### ColumnNamesAndTypes
125
- ```
126
- field_100: list<string> (column names)
127
- field_101: list<Type> (column types)
128
- 0xFFFF
129
- ```
130
-
131
- ### Type
132
- ```
133
- field_100: uint8 (LogicalTypeId)
134
- field_101: nullable<TypeInfo> (extra info for complex types)
135
- 0xFFFF
136
- ```
137
-
138
- ### DataChunk
139
- ```
140
- field_100: varint (row count)
141
- field_101: list<Vector> (vectors - one per column)
142
- 0xFFFF
143
- ```
144
-
145
- ### Vector
146
-
147
- All vectors start with:
148
- ```
149
- field_100: uint8 (allValid flag - 0 means some nulls)
150
- field_101: data (validity bitmap - only if allValid=0)
151
- ```
152
-
153
- Then type-specific data:
154
-
155
- #### Data Vector (numeric/temporal types)
156
- ```
157
- field_102: data (raw bytes - type-specific encoding)
158
- 0xFFFF
159
- ```
160
-
161
- #### String Vector (CHAR, VARCHAR)
162
- ```
163
- field_102: list<string> (string values)
164
- 0xFFFF
165
- ```
166
-
167
- ## LogicalTypeId Constants
168
-
169
- ```javascript
170
- const LogicalTypeId = {
171
- BOOLEAN: 10,
172
- TINYINT: 11,
173
- SMALLINT: 12,
174
- INTEGER: 13,
175
- BIGINT: 14,
176
- DATE: 15,
177
- TIME: 16,
178
- TIMESTAMP_SEC: 17,
179
- TIMESTAMP_MS: 18,
180
- TIMESTAMP: 19,
181
- TIMESTAMP_NS: 20,
182
- DECIMAL: 21,
183
- FLOAT: 22,
184
- DOUBLE: 23,
185
- CHAR: 24,
186
- VARCHAR: 25,
187
- BLOB: 26,
188
- INTERVAL: 27,
189
- UTINYINT: 28,
190
- USMALLINT: 29,
191
- UINTEGER: 30,
192
- UBIGINT: 31,
193
- TIMESTAMP_TZ: 32,
194
- TIME_TZ: 34,
195
- BIT: 36,
196
- BIGNUM: 39,
197
- UHUGEINT: 49,
198
- HUGEINT: 50,
199
- UUID: 54,
200
- STRUCT: 100,
201
- LIST: 101,
202
- MAP: 102,
203
- ENUM: 104,
204
- UNION: 107,
205
- ARRAY: 108,
206
- };
207
- ```
208
-
209
- ## Data Type Byte Sizes
210
-
211
- | Type | Bytes | Format |
212
- |---------------|-------|-------------------------------------|
213
- | BOOLEAN | 1 | 0 or non-zero |
214
- | TINYINT | 1 | int8 |
215
- | UTINYINT | 1 | uint8 |
216
- | SMALLINT | 2 | int16 LE |
217
- | USMALLINT | 2 | uint16 LE |
218
- | INTEGER | 4 | int32 LE |
219
- | UINTEGER | 4 | uint32 LE |
220
- | BIGINT | 8 | int64 LE |
221
- | UBIGINT | 8 | uint64 LE |
222
- | HUGEINT | 16 | int128 LE |
223
- | UHUGEINT | 16 | uint128 LE |
224
- | FLOAT | 4 | IEEE 754 float32 |
225
- | DOUBLE | 8 | IEEE 754 float64 |
226
- | DATE | 4 | int32 (days since 1970-01-01) |
227
- | TIME | 8 | int64 (microseconds since midnight) |
228
- | TIMESTAMP | 8 | int64 (microseconds since epoch) |
229
- | TIMESTAMP_MS | 8 | int64 (milliseconds since epoch) |
230
- | TIMESTAMP_SEC | 8 | int64 (seconds since epoch) |
231
- | TIMESTAMP_NS | 8 | int64 (nanoseconds since epoch) |
232
- | TIMESTAMP_TZ | 8 | same as TIMESTAMP |
233
- | TIME_TZ | 8 | int64 (micros + offset encoded) |
234
- | INTERVAL | 16 | months(4) + days(4) + micros(8) |
235
- | UUID | 16 | 128-bit UUID |
236
- | DECIMAL | varies| depends on width |
237
- | ENUM | varies| depends on enum size |
238
-
239
- ## Validity Bitmap
240
-
241
- When `allValid` is 0, the validity bitmap indicates which values are NULL:
242
- - Bit order: LSB first within each byte
243
- - Bit meaning: 1 = valid, 0 = NULL
244
- - Size: ceil(rowCount / 8) bytes
245
-
246
- ```javascript
247
- // Check if row i is valid
248
- const byteIndex = Math.floor(i / 8);
249
- const bitIndex = i % 8;
250
- const isValid = (validity[byteIndex] >> bitIndex) & 1;
251
- ```
252
-
253
- ## References
254
-
255
- - [DuckDB UI GitHub](https://github.com/duckdb/duckdb-ui)
256
- - [BinaryDeserializer.ts](https://github.com/duckdb/duckdb-ui/blob/main/ts/pkgs/duckdb-ui-client/src/serialization/classes/BinaryDeserializer.ts)
257
- - [DuckDB BinarySerializer](https://github.com/duckdb/duckdb/blob/main/src/include/duckdb/common/serializer/binary_serializer.hpp)
258
- - [Vector::Serialize](https://github.com/duckdb/duckdb/blob/main/src/common/types/vector.cpp)
package/db.html DELETED
@@ -1,122 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>DuckDB Console</title>
6
- <style>
7
- * { box-sizing: border-box; }
8
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 0; padding: 20px; background: #1a1a2e; color: #eee; }
9
- h1 { margin: 0 0 20px; font-size: 24px; color: #fff; }
10
- .container { max-width: 1200px; margin: 0 auto; }
11
- textarea { width: 100%; height: 120px; padding: 12px; font-family: 'Monaco', 'Menlo', monospace; font-size: 14px; background: #16213e; color: #0f0; border: 1px solid #0f4c75; border-radius: 6px; resize: vertical; }
12
- .buttons { margin: 10px 0; }
13
- button { padding: 10px 24px; font-size: 14px; background: #0f4c75; color: #fff; border: none; border-radius: 6px; cursor: pointer; margin-right: 10px; }
14
- button:hover { background: #1b6ca8; }
15
- .info { font-size: 12px; color: #888; margin-bottom: 10px; }
16
- .results { margin-top: 20px; }
17
- table { width: 100%; border-collapse: collapse; background: #16213e; border-radius: 6px; overflow: hidden; }
18
- th { background: #0f4c75; padding: 10px; text-align: left; font-weight: 600; }
19
- td { padding: 8px 10px; border-bottom: 1px solid #1b2838; }
20
- tr:hover td { background: #1b2838; }
21
- .error { color: #ff6b6b; background: #2d1f1f; padding: 12px; border-radius: 6px; }
22
- .meta { color: #888; font-size: 12px; margin-top: 10px; }
23
- .status { padding: 4px 8px; border-radius: 4px; font-size: 12px; }
24
- .status.ok { background: #1d4d1d; color: #4ade80; }
25
- .status.err { background: #4d1d1d; color: #ff6b6b; }
26
- </style>
27
- </head>
28
- <body>
29
- <div class="container">
30
- <h1>🦆 DuckDB Console</h1>
31
- <div class="info">Connected to: <span id="db">loading...</span></div>
32
- <textarea id="sql" placeholder="SELECT * FROM users LIMIT 10;">SELECT * FROM users;</textarea>
33
- <div class="buttons">
34
- <button onclick="run()">▶ Run (Cmd+Enter)</button>
35
- <button onclick="tables()">📋 Tables</button>
36
- <button onclick="status()">ℹ️ Status</button>
37
- </div>
38
- <div id="results" class="results"></div>
39
- </div>
40
- <script>
41
- const sqlEl = document.getElementById('sql');
42
- const resultsEl = document.getElementById('results');
43
-
44
- // Load status on startup
45
- fetch('/status').then(r => r.json()).then(d => {
46
- document.getElementById('db').textContent = d.database;
47
- });
48
-
49
- // Cmd+Enter to run
50
- sqlEl.addEventListener('keydown', e => {
51
- if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
52
- e.preventDefault();
53
- run();
54
- }
55
- });
56
-
57
- function run() {
58
- const sql = sqlEl.value.trim();
59
- if (!sql) return;
60
- fetch('/sql', {
61
- method: 'POST',
62
- headers: { 'Content-Type': 'application/json' },
63
- body: JSON.stringify({ sql })
64
- })
65
- .then(r => r.json())
66
- .then(renderResult)
67
- .catch(e => renderError(e.message));
68
- }
69
-
70
- function tables() {
71
- sqlEl.value = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'main';";
72
- run();
73
- }
74
-
75
- function status() {
76
- fetch('/status')
77
- .then(r => r.json())
78
- .then(data => {
79
- resultsEl.innerHTML = `
80
- <div style="background:#16213e;padding:16px;border-radius:6px;">
81
- <div><strong>Database:</strong> ${data.database}</div>
82
- <div><strong>Tables:</strong> ${data.tables?.join(', ') || 'none'}</div>
83
- <div><strong>Time:</strong> ${data.time}</div>
84
- </div>`;
85
- })
86
- .catch(e => renderError(e.message));
87
- }
88
-
89
- function renderResult(data) {
90
- if (data.error) {
91
- renderError(data.error);
92
- return;
93
- }
94
- if (!data.meta?.length) {
95
- resultsEl.innerHTML = `<div class="meta"><span class="status ok">✓ OK</span> Query executed in ${data.time}s</div>`;
96
- return;
97
- }
98
- let html = '<table><tr>';
99
- data.meta.forEach(col => {
100
- html += `<th>${col.name}<br><span style="font-weight:normal;font-size:11px;color:#888">${col.type}</span></th>`;
101
- });
102
- html += '</tr>';
103
- data.data.forEach(row => {
104
- html += '<tr>';
105
- row.forEach(val => {
106
- html += `<td>${val === null ? '<span style="color:#666">NULL</span>' : val}</td>`;
107
- });
108
- html += '</tr>';
109
- });
110
- html += `</table><div class="meta"><span class="status ok">✓ OK</span> ${data.rows} row${data.rows !== 1 ? 's' : ''} in ${data.time}s</div>`;
111
- resultsEl.innerHTML = html;
112
- }
113
-
114
- function renderError(msg) {
115
- resultsEl.innerHTML = `<div class="error"><span class="status err">✗ Error</span> ${msg}</div>`;
116
- }
117
-
118
- // Run initial query
119
- run();
120
- </script>
121
- </body>
122
- </html>