@qualithm/arrow-flight-sql-js 0.4.0 → 0.4.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/README.md +17 -271
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -17,18 +17,6 @@ servers. It handles the complete protocol stack:
|
|
|
17
17
|
- **Arrow IPC Streaming** – Native Arrow record batch handling
|
|
18
18
|
- **Authentication** – Bearer tokens, basic auth, and custom handlers
|
|
19
19
|
|
|
20
|
-
## Design Goals
|
|
21
|
-
|
|
22
|
-
Arrow Flight SQL JS is modeled on the canonical implementations:
|
|
23
|
-
|
|
24
|
-
| Reference | What We Adopt |
|
|
25
|
-
| ------------------------- | ---------------------------------------------------- |
|
|
26
|
-
| **Java** (reference impl) | Comprehensive API surface, error handling patterns |
|
|
27
|
-
| **C++** | Streaming-first patterns, performance considerations |
|
|
28
|
-
| **Go** | Connection pooling, context/cancellation model |
|
|
29
|
-
|
|
30
|
-
We aim for **API parity** with the official clients where JavaScript idioms allow.
|
|
31
|
-
|
|
32
20
|
## Installation
|
|
33
21
|
|
|
34
22
|
```bash
|
|
@@ -185,86 +173,6 @@ for await (const batch of result.stream()) {
|
|
|
185
173
|
| Export to file | Stream and write chunks |
|
|
186
174
|
| Memory-constrained environment | Always `stream()`, never `collect()` unbounded results |
|
|
187
175
|
|
|
188
|
-
## Real-Time Subscriptions
|
|
189
|
-
|
|
190
|
-
Subscribe to live data updates using the `DoExchange` bidirectional streaming protocol:
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
import { FlightSqlClient, SubscriptionMode } from "@qualithm/arrow-flight-sql-js"
|
|
194
|
-
|
|
195
|
-
const client = new FlightSqlClient({
|
|
196
|
-
host: "localhost",
|
|
197
|
-
port: 31337,
|
|
198
|
-
tls: true,
|
|
199
|
-
auth: { type: "bearer", token: "your-bearer-token" }
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
await client.connect()
|
|
203
|
-
|
|
204
|
-
// Subscribe to real-time updates
|
|
205
|
-
const subscription = client.subscribe("SELECT * FROM events WHERE status = 'pending'", {
|
|
206
|
-
mode: SubscriptionMode.ChangesOnly, // Full | ChangesOnly | Tail
|
|
207
|
-
heartbeatMs: 30_000 // Server heartbeat interval
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
// Consume batches as they arrive
|
|
211
|
-
for await (const batch of subscription) {
|
|
212
|
-
console.log(`Received ${batch.numRows} rows`)
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Or with cancellation
|
|
216
|
-
const controller = new AbortController()
|
|
217
|
-
const cancelableSubscription = client.subscribe(query, {
|
|
218
|
-
signal: controller.signal,
|
|
219
|
-
autoReconnect: true,
|
|
220
|
-
maxReconnectAttempts: 10
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
// Later: cancel the subscription
|
|
224
|
-
controller.abort()
|
|
225
|
-
|
|
226
|
-
// Or manually unsubscribe
|
|
227
|
-
await cancelableSubscription.unsubscribe()
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
### Subscription Options
|
|
231
|
-
|
|
232
|
-
| Option | Default | Description |
|
|
233
|
-
| ---------------------- | ------------- | -------------------------------------------------- |
|
|
234
|
-
| `mode` | `ChangesOnly` | Subscription mode (Full, ChangesOnly, Tail) |
|
|
235
|
-
| `heartbeatMs` | `30000` | Server heartbeat interval in milliseconds |
|
|
236
|
-
| `signal` | - | AbortSignal for cancellation |
|
|
237
|
-
| `autoReconnect` | `true` | Auto-reconnect on connection loss |
|
|
238
|
-
| `maxReconnectAttempts` | `10` | Maximum reconnection attempts |
|
|
239
|
-
| `reconnectDelayMs` | `1000` | Initial reconnect delay |
|
|
240
|
-
| `maxReconnectDelayMs` | `30000` | Maximum reconnect delay (with exponential backoff) |
|
|
241
|
-
|
|
242
|
-
### Low-Level DoExchange
|
|
243
|
-
|
|
244
|
-
For custom bidirectional protocols:
|
|
245
|
-
|
|
246
|
-
```typescript
|
|
247
|
-
const exchange = client.doExchange({
|
|
248
|
-
type: DescriptorType.CMD,
|
|
249
|
-
cmd: new TextEncoder().encode("CUSTOM_COMMAND")
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
// Send data to server
|
|
253
|
-
await exchange.send({
|
|
254
|
-
dataHeader: new Uint8Array(),
|
|
255
|
-
dataBody: new Uint8Array(),
|
|
256
|
-
appMetadata: new TextEncoder().encode(JSON.stringify({ action: "subscribe" }))
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
// Receive data from server
|
|
260
|
-
for await (const data of exchange) {
|
|
261
|
-
console.log("Received:", data)
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Half-close (signal end of client stream)
|
|
265
|
-
await exchange.end()
|
|
266
|
-
```
|
|
267
|
-
|
|
268
176
|
## Observability & Metrics
|
|
269
177
|
|
|
270
178
|
Integrate with your observability stack using the metrics handler interface:
|
|
@@ -490,90 +398,30 @@ try {
|
|
|
490
398
|
}
|
|
491
399
|
```
|
|
492
400
|
|
|
493
|
-
##
|
|
494
|
-
|
|
495
|
-
### FlightSqlClient
|
|
496
|
-
|
|
497
|
-
The main client for interacting with Flight SQL servers.
|
|
498
|
-
|
|
499
|
-
#### Constructor Options
|
|
401
|
+
## Real-Time Subscriptions
|
|
500
402
|
|
|
501
|
-
|
|
502
|
-
| ------------------ | ------------------------ | ------- | ------------------------------- |
|
|
503
|
-
| `host` | `string` | — | Server hostname |
|
|
504
|
-
| `port` | `number` | — | Server port |
|
|
505
|
-
| `tls` | `boolean` | `true` | Enable TLS |
|
|
506
|
-
| `auth` | `AuthConfig` | — | Authentication configuration |
|
|
507
|
-
| `credentials` | `ChannelCredentials` | — | Custom gRPC channel credentials |
|
|
508
|
-
| `metadata` | `Record<string, string>` | — | Custom metadata headers |
|
|
509
|
-
| `connectTimeoutMs` | `number` | `30000` | Connection timeout in ms |
|
|
510
|
-
| `requestTimeoutMs` | `number` | `60000` | Request timeout in ms |
|
|
403
|
+
> **Note:** Requires server support. Not all Flight SQL servers implement `DoExchange`.
|
|
511
404
|
|
|
512
|
-
|
|
405
|
+
Subscribe to live data updates:
|
|
513
406
|
|
|
514
407
|
```typescript
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
#### Methods
|
|
522
|
-
|
|
523
|
-
##### Query Execution
|
|
524
|
-
|
|
525
|
-
- `query(query: string, options?): Promise<QueryResult>` – Execute SQL, returns result with
|
|
526
|
-
`stream()` and `collect()` methods
|
|
527
|
-
- `execute(query: string, options?): Promise<FlightInfo>` – _(deprecated)_ Execute SQL, return
|
|
528
|
-
flight info
|
|
529
|
-
- `executeUpdate(query: string): Promise<bigint>` – Execute DML, return affected rows
|
|
530
|
-
- `prepare(query: string): Promise<PreparedStatement>` – Create prepared statement
|
|
531
|
-
|
|
532
|
-
##### Catalog Introspection
|
|
533
|
-
|
|
534
|
-
- `getCatalogs(): Promise<string[]>` – List available catalogs
|
|
535
|
-
- `getSchemas(catalog?, schemaPattern?): Promise<Schema[]>` – List schemas
|
|
536
|
-
- `getTables(options?): Promise<Table[]>` – List tables with filters
|
|
537
|
-
- `getTableTypes(): Promise<string[]>` – List table type names
|
|
538
|
-
- `getPrimaryKeys(table, catalog?, schema?): Promise<PrimaryKey[]>` – Get primary keys
|
|
539
|
-
- `getExportedKeys(table, catalog?, schema?): Promise<ForeignKey[]>` – Get exported foreign keys
|
|
540
|
-
- `getImportedKeys(table, catalog?, schema?): Promise<ForeignKey[]>` – Get imported foreign keys
|
|
541
|
-
|
|
542
|
-
##### Low-Level Flight Operations
|
|
543
|
-
|
|
544
|
-
- `getFlightInfo(descriptor): Promise<FlightInfo>` – Get flight metadata
|
|
545
|
-
- `doGet(ticket): AsyncIterable<RecordBatch>` – Fetch data by ticket
|
|
546
|
-
- `doPut(descriptor, stream): Promise<void>` – Upload Arrow data
|
|
547
|
-
- `doAction(type, body?): AsyncIterable<Result>` – Execute custom action
|
|
548
|
-
|
|
549
|
-
##### Connection Management
|
|
550
|
-
|
|
551
|
-
- `connect(): Promise<void>` – Establish connection and authenticate
|
|
552
|
-
- `close(): void` – Close connection and release resources
|
|
553
|
-
- `isConnected(): boolean` – Check connection status
|
|
408
|
+
const subscription = client.subscribe("SELECT * FROM events", {
|
|
409
|
+
mode: SubscriptionMode.ChangesOnly,
|
|
410
|
+
heartbeatMs: 30_000
|
|
411
|
+
})
|
|
554
412
|
|
|
555
|
-
|
|
413
|
+
for await (const batch of subscription) {
|
|
414
|
+
console.log(`Received ${batch.numRows} rows`)
|
|
415
|
+
}
|
|
556
416
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
│ Query Builder │ Prepared Statements │ Catalog API │
|
|
562
|
-
├─────────────────────────────────────────────────────────┤
|
|
563
|
-
│ Flight SQL Protocol │
|
|
564
|
-
│ (GetFlightInfo, DoGet, DoPut, DoAction) │
|
|
565
|
-
├─────────────────────────────────────────────────────────┤
|
|
566
|
-
│ Protocol Buffers Layer │
|
|
567
|
-
│ (FlightDescriptor, FlightInfo, etc.) │
|
|
568
|
-
├─────────────────────────────────────────────────────────┤
|
|
569
|
-
│ gRPC Transport │
|
|
570
|
-
│ (HTTP/2 + TLS + Auth Headers) │
|
|
571
|
-
├─────────────────────────────────────────────────────────┤
|
|
572
|
-
│ Connection Pool │
|
|
573
|
-
│ (Health checks, reconnection, backoff) │
|
|
574
|
-
└─────────────────────────────────────────────────────────┘
|
|
417
|
+
// Cancel with AbortController
|
|
418
|
+
controller.abort()
|
|
419
|
+
// Or manually
|
|
420
|
+
await subscription.unsubscribe()
|
|
575
421
|
```
|
|
576
422
|
|
|
423
|
+
See the [API documentation](https://qualithm.github.io/arrow-flight-sql-js/) for full options.
|
|
424
|
+
|
|
577
425
|
## Compatibility
|
|
578
426
|
|
|
579
427
|
### Runtime Support
|
|
@@ -620,93 +468,6 @@ const result = await client.query("SELECT * FROM my_table")
|
|
|
620
468
|
- Bidirectional streaming (`DoExchange`, `Handshake`) is not supported
|
|
621
469
|
- Use bearer token auth via `setAuthToken()` instead of `Handshake`
|
|
622
470
|
|
|
623
|
-
**Envoy gRPC-Web Proxy Example:**
|
|
624
|
-
|
|
625
|
-
```yaml
|
|
626
|
-
# envoy.yaml
|
|
627
|
-
static_resources:
|
|
628
|
-
listeners:
|
|
629
|
-
- address:
|
|
630
|
-
socket_address:
|
|
631
|
-
address: 0.0.0.0
|
|
632
|
-
port_value: 8080
|
|
633
|
-
filter_chains:
|
|
634
|
-
- filters:
|
|
635
|
-
- name: envoy.filters.network.http_connection_manager
|
|
636
|
-
typed_config:
|
|
637
|
-
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
|
|
638
|
-
codec_type: AUTO
|
|
639
|
-
stat_prefix: ingress_http
|
|
640
|
-
route_config:
|
|
641
|
-
name: local_route
|
|
642
|
-
virtual_hosts:
|
|
643
|
-
- name: backend
|
|
644
|
-
domains: ["*"]
|
|
645
|
-
routes:
|
|
646
|
-
- match: { prefix: "/" }
|
|
647
|
-
route:
|
|
648
|
-
cluster: flight_sql_backend
|
|
649
|
-
cors:
|
|
650
|
-
allow_origin_string_match:
|
|
651
|
-
- prefix: "*"
|
|
652
|
-
allow_methods: "GET, PUT, DELETE, POST, OPTIONS"
|
|
653
|
-
allow_headers: "content-type,x-grpc-web,x-user-agent"
|
|
654
|
-
expose_headers: "grpc-status,grpc-message"
|
|
655
|
-
http_filters:
|
|
656
|
-
- name: envoy.filters.http.grpc_web
|
|
657
|
-
- name: envoy.filters.http.cors
|
|
658
|
-
- name: envoy.filters.http.router
|
|
659
|
-
clusters:
|
|
660
|
-
- name: flight_sql_backend
|
|
661
|
-
connect_timeout: 0.25s
|
|
662
|
-
type: LOGICAL_DNS
|
|
663
|
-
http2_protocol_options: {}
|
|
664
|
-
lb_policy: ROUND_ROBIN
|
|
665
|
-
load_assignment:
|
|
666
|
-
cluster_name: flight_sql_backend
|
|
667
|
-
endpoints:
|
|
668
|
-
- lb_endpoints:
|
|
669
|
-
- endpoint:
|
|
670
|
-
address:
|
|
671
|
-
socket_address:
|
|
672
|
-
address: your-flight-sql-server
|
|
673
|
-
port_value: 50051
|
|
674
|
-
```
|
|
675
|
-
|
|
676
|
-
### Flight SQL Servers
|
|
677
|
-
|
|
678
|
-
Tested against:
|
|
679
|
-
|
|
680
|
-
- Apache Arrow Flight SQL reference server
|
|
681
|
-
- DuckDB Flight SQL extension
|
|
682
|
-
- DataFusion Ballista
|
|
683
|
-
- Custom lakehouse implementations
|
|
684
|
-
|
|
685
|
-
### Server Compatibility Matrix
|
|
686
|
-
|
|
687
|
-
| Server | Version | Query | Prepared Stmt | Catalog | Subscriptions |
|
|
688
|
-
| ---------------------- | ------- | ----- | ------------- | ------- | ------------- |
|
|
689
|
-
| Arrow Flight SQL (ref) | 13.0+ | ✅ | ✅ | ✅ | ❌ |
|
|
690
|
-
| DuckDB Flight SQL | 0.9+ | ✅ | ✅ | ✅ | ❌ |
|
|
691
|
-
| DataFusion Ballista | 0.12+ | ✅ | ✅ | ✅ | ❌ |
|
|
692
|
-
| Qualithm Lakehouse | 1.0+ | ✅ | ✅ | ✅ | ✅ |
|
|
693
|
-
|
|
694
|
-
**Feature Support Notes:**
|
|
695
|
-
|
|
696
|
-
- **Query**: Basic SQL query execution via `query()` and `execute()`
|
|
697
|
-
- **Prepared Stmt**: Prepared statements with parameter binding
|
|
698
|
-
- **Catalog**: `getCatalogs()`, `getSchemas()`, `getTables()`, `getSqlInfo()`, etc.
|
|
699
|
-
- **Subscriptions**: Real-time streaming via `DoExchange` (server-specific feature)
|
|
700
|
-
|
|
701
|
-
**Arrow Protocol Versions:**
|
|
702
|
-
|
|
703
|
-
| Arrow Version | Flight SQL Version | Status |
|
|
704
|
-
| ------------- | ------------------ | ----------------------- |
|
|
705
|
-
| 18.0+ | 13.0+ | ✅ Fully supported |
|
|
706
|
-
| 15.0-17.x | 13.0 | ✅ Supported |
|
|
707
|
-
| 12.0-14.x | 12.0 | ⚠️ May work, not tested |
|
|
708
|
-
| <12.0 | <12.0 | ❌ Not supported |
|
|
709
|
-
|
|
710
471
|
## Development
|
|
711
472
|
|
|
712
473
|
```bash
|
|
@@ -730,23 +491,8 @@ bun run format:fix
|
|
|
730
491
|
bun run docs
|
|
731
492
|
```
|
|
732
493
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
This client implements the
|
|
736
|
-
[Arrow Flight SQL specification](https://arrow.apache.org/docs/format/FlightSql.html):
|
|
737
|
-
|
|
738
|
-
- **Flight SQL 13.0** – Current target version
|
|
739
|
-
- Full protobuf message support
|
|
740
|
-
- All standard actions (CreatePreparedStatement, ClosePreparedStatement, etc.)
|
|
741
|
-
- Catalog introspection commands
|
|
742
|
-
- Transaction support (where server supports it)
|
|
494
|
+
Implements [Arrow Flight SQL 13.0](https://arrow.apache.org/docs/format/FlightSql.html).
|
|
743
495
|
|
|
744
496
|
## License
|
|
745
497
|
|
|
746
498
|
MIT
|
|
747
|
-
|
|
748
|
-
## Related Projects
|
|
749
|
-
|
|
750
|
-
- [Apache Arrow](https://arrow.apache.org/) – The Arrow columnar format
|
|
751
|
-
- [Arrow Flight](https://arrow.apache.org/docs/format/Flight.html) – High-performance data transport
|
|
752
|
-
- [Arrow Flight SQL](https://arrow.apache.org/docs/format/FlightSql.html) – SQL over Flight
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qualithm/arrow-flight-sql-js",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Arrow Flight SQL client for JavaScript and TypeScript runtimes.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -91,6 +91,9 @@
|
|
|
91
91
|
"@grpc/proto-loader": "0.8.0",
|
|
92
92
|
"apache-arrow": "21.1.0"
|
|
93
93
|
},
|
|
94
|
+
"overrides": {
|
|
95
|
+
"markdown-it": "14.1.1"
|
|
96
|
+
},
|
|
94
97
|
"devDependencies": {
|
|
95
98
|
"@eslint/js": "9.39.2",
|
|
96
99
|
"@playwright/test": "1.58.2",
|
|
@@ -102,7 +105,7 @@
|
|
|
102
105
|
"jiti": "2.6.1",
|
|
103
106
|
"playwright": "1.58.2",
|
|
104
107
|
"prettier": "3.8.1",
|
|
105
|
-
"typedoc": "0.28.
|
|
108
|
+
"typedoc": "0.28.17",
|
|
106
109
|
"typedoc-plugin-markdown": "4.10.0",
|
|
107
110
|
"typescript": "5.9.3",
|
|
108
111
|
"typescript-eslint": "8.55.0"
|