@sqlrooms/duckdb 0.5.1 → 0.7.0
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 +169 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/useSql.d.ts +184 -0
- package/dist/useSql.d.ts.map +1 -0
- package/dist/{useDuckDbQuery.js → useSql.js} +19 -3
- package/dist/useSql.js.map +1 -0
- package/package.json +4 -4
- package/dist/useDuckDbQuery.d.ts +0 -106
- package/dist/useDuckDbQuery.d.ts.map +0 -1
- package/dist/useDuckDbQuery.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
A powerful wrapper around DuckDB-WASM that provides React hooks and utilities for working with DuckDB in browser environments.
|
|
2
|
+
|
|
3
|
+
## Features
|
|
4
|
+
|
|
5
|
+
- 🔄 **React Integration**: Hooks for seamless integration with React applications
|
|
6
|
+
- 📊 **Type-Safe Queries**: Execute SQL queries with TypeScript type safety
|
|
7
|
+
- 🔍 **Data Validation**: Optional runtime validation using Zod schemas
|
|
8
|
+
- 📁 **File Operations**: Import data from various file formats (CSV, JSON, Parquet)
|
|
9
|
+
- 📤 **Data Export**: Export query results to CSV files
|
|
10
|
+
- 🏹 **Arrow Integration**: Work with Apache Arrow tables for efficient data processing
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @sqlrooms/duckdb
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
### Using the SQL Hook
|
|
21
|
+
|
|
22
|
+
````tsx
|
|
23
|
+
import {useSql} from '@sqlrooms/duckdb';
|
|
24
|
+
|
|
25
|
+
function UserList() {
|
|
26
|
+
// Basic usage with TypeScript types
|
|
27
|
+
const {data, isLoading, error} = useSql<{id: number; name: string}>({
|
|
28
|
+
query: 'SELECT id, name FROM users',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (isLoading) return <div>Loading...</div>;
|
|
32
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
33
|
+
if (!data) return null;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<ul>
|
|
37
|
+
{Array.from(data.rows()).map((user) => (
|
|
38
|
+
<li key={user.id}>{user.name}</li>
|
|
39
|
+
))}
|
|
40
|
+
</ul>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For more information and examples on using the `useSql` hook, see the [useSql API documentation](/api/duckdb/functions/useSql).
|
|
46
|
+
|
|
47
|
+
### Using Zod for Runtime Validation
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import {useSql} from '@sqlrooms/duckdb';
|
|
51
|
+
import {z} from 'zod';
|
|
52
|
+
|
|
53
|
+
const userSchema = z.object({
|
|
54
|
+
id: z.number(),
|
|
55
|
+
name: z.string(),
|
|
56
|
+
email: z.string().email(),
|
|
57
|
+
created_at: z.string().transform((str) => new Date(str)),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
function ValidatedUserList() {
|
|
61
|
+
const {data, isLoading, error} = useSql(userSchema, {
|
|
62
|
+
query: 'SELECT id, name, email, created_at FROM users',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (isLoading) return <div>Loading...</div>;
|
|
66
|
+
if (error) {
|
|
67
|
+
if (error instanceof z.ZodError) {
|
|
68
|
+
return <div>Validation Error: {error.errors[0].message}</div>;
|
|
69
|
+
}
|
|
70
|
+
return <div>Error: {error.message}</div>;
|
|
71
|
+
}
|
|
72
|
+
if (!data) return null;
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<ul>
|
|
76
|
+
{data.toArray().map((user) => (
|
|
77
|
+
<li key={user.id}>
|
|
78
|
+
{user.name} ({user.email}) - Joined:{' '}
|
|
79
|
+
{user.created_at.toLocaleDateString()}
|
|
80
|
+
</li>
|
|
81
|
+
))}
|
|
82
|
+
</ul>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Creating Tables from Different Sources
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import {
|
|
91
|
+
createTableFromQuery,
|
|
92
|
+
createTableFromObjects,
|
|
93
|
+
createViewFromFile,
|
|
94
|
+
} from '@sqlrooms/duckdb';
|
|
95
|
+
|
|
96
|
+
// Create a table from a SQL query
|
|
97
|
+
await createTableFromQuery(
|
|
98
|
+
'filtered_users',
|
|
99
|
+
'SELECT * FROM users WHERE active = true',
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Create a table from JavaScript objects
|
|
103
|
+
const users = [
|
|
104
|
+
{id: 1, name: 'Alice', email: 'alice@example.com'},
|
|
105
|
+
{id: 2, name: 'Bob', email: 'bob@example.com'},
|
|
106
|
+
];
|
|
107
|
+
await createTableFromObjects('new_users', users);
|
|
108
|
+
|
|
109
|
+
// Create a view from a file upload
|
|
110
|
+
function FileUploader() {
|
|
111
|
+
const handleFileUpload = async (event) => {
|
|
112
|
+
const file = event.target.files[0];
|
|
113
|
+
if (file) {
|
|
114
|
+
await createViewFromFile(file.name, 'main', 'uploaded_data', file);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<input
|
|
120
|
+
type="file"
|
|
121
|
+
accept=".csv,.json,.parquet"
|
|
122
|
+
onChange={handleFileUpload}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Exporting Data to CSV
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
import {exportToCsv} from '@sqlrooms/duckdb';
|
|
132
|
+
|
|
133
|
+
function ExportButton() {
|
|
134
|
+
const handleExport = async () => {
|
|
135
|
+
await exportToCsv('SELECT * FROM users ORDER BY name', 'users_export.csv');
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
return <button onClick={handleExport}>Export to CSV</button>;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Low-Level DuckDB Access
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
import {getDuckDb} from '@sqlrooms/duckdb';
|
|
146
|
+
|
|
147
|
+
async function executeCustomQuery() {
|
|
148
|
+
const {conn} = await getDuckDb();
|
|
149
|
+
|
|
150
|
+
// Execute a query directly
|
|
151
|
+
const result = await conn.query('SELECT COUNT(*) as count FROM users');
|
|
152
|
+
|
|
153
|
+
// Access the Arrow table directly
|
|
154
|
+
const count = result.getChildAt(0)?.get(0);
|
|
155
|
+
console.log(`Total users: ${count}`);
|
|
156
|
+
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Advanced Features
|
|
162
|
+
|
|
163
|
+
- **Batch Processing**: Handle large datasets with pagination
|
|
164
|
+
- **Arrow Integration**: Work directly with Apache Arrow tables for efficient data processing
|
|
165
|
+
- **Schema Management**: Create, inspect, and manage database schemas
|
|
166
|
+
- **File Management**: Register and manage files in the DuckDB instance
|
|
167
|
+
|
|
168
|
+
For more information, visit the SQLRooms documentation.
|
|
169
|
+
````
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {@include ../README.md}
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
1
5
|
export * from './duckdb';
|
|
2
6
|
export * from './types';
|
|
3
7
|
export * from './useDuckDb';
|
|
4
8
|
export * from './exportToCsv';
|
|
5
9
|
export * from './arrow-utils';
|
|
6
|
-
export * from './
|
|
10
|
+
export * from './useSql';
|
|
7
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {@include ../README.md}
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
1
5
|
export * from './duckdb';
|
|
2
6
|
export * from './types';
|
|
3
7
|
export * from './useDuckDb';
|
|
4
8
|
export * from './exportToCsv';
|
|
5
9
|
export * from './arrow-utils';
|
|
6
|
-
export * from './
|
|
10
|
+
export * from './useSql';
|
|
7
11
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC","sourcesContent":["/**\n * {@include ../README.md}\n * @packageDocumentation\n */\n\nexport * from './duckdb';\nexport * from './types';\nexport * from './useDuckDb';\nexport * from './exportToCsv';\nexport * from './arrow-utils';\nexport * from './useSql';\n"]}
|
package/dist/useSql.d.ts
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import * as arrow from 'apache-arrow';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* A wrapper interface that exposes the underlying Arrow table,
|
|
5
|
+
* a typed row accessor, and the number of rows.
|
|
6
|
+
*/
|
|
7
|
+
export interface UseSqlQueryResult<T> {
|
|
8
|
+
/** The underlying Arrow table */
|
|
9
|
+
arrowTable: arrow.Table;
|
|
10
|
+
/** Returns a typed row at the specified index by converting on demand */
|
|
11
|
+
getRow(index: number): T;
|
|
12
|
+
/** Number of rows in the table */
|
|
13
|
+
length: number;
|
|
14
|
+
/** Returns an iterator that yields each row in the table */
|
|
15
|
+
rows(): IterableIterator<T>;
|
|
16
|
+
/** Returns an array containing all rows in the table */
|
|
17
|
+
toArray(): T[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated Use UseSqlQueryResult instead
|
|
21
|
+
*/
|
|
22
|
+
export type DuckDbQueryResult<T> = UseSqlQueryResult<T>;
|
|
23
|
+
/**
|
|
24
|
+
* A React hook for executing SQL queries with automatic state management.
|
|
25
|
+
* Provides two ways to ensure type safety:
|
|
26
|
+
* 1. Using TypeScript types (compile-time safety only)
|
|
27
|
+
* 2. Using Zod schemas (both compile-time and runtime validation)
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* // Option 1: Using TypeScript types (faster, no runtime validation)
|
|
32
|
+
* interface User {
|
|
33
|
+
* id: number;
|
|
34
|
+
* name: string;
|
|
35
|
+
* email: string;
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* const {data, isLoading, error} = useSql<User>({
|
|
39
|
+
* query: 'SELECT id, name, email FROM users'
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* // Option 2: Using Zod schema (slower but with runtime validation)
|
|
43
|
+
* const userSchema = z.object({
|
|
44
|
+
* id: z.number(),
|
|
45
|
+
* name: z.string(),
|
|
46
|
+
* email: z.string().email(),
|
|
47
|
+
* createdAt: z.string().transform(str => new Date(str)) // Transform string to Date
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* const {data: validatedData, isLoading, error} = useSql(
|
|
51
|
+
* userSchema,
|
|
52
|
+
* {query: 'SELECT id, name, email, created_at as createdAt FROM users'}
|
|
53
|
+
* );
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* ## Error Handling
|
|
57
|
+
* ```typescript
|
|
58
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
59
|
+
* if (error) {
|
|
60
|
+
* // With Zod, you can catch validation errors specifically
|
|
61
|
+
* if (error instanceof z.ZodError) {
|
|
62
|
+
* return <div>Validation Error: {error.errors[0].message}</div>;
|
|
63
|
+
* }
|
|
64
|
+
* return <div>Error: {error.message}</div>;
|
|
65
|
+
* }
|
|
66
|
+
* if (!data) return null;
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* ## Data Access Methods
|
|
70
|
+
*
|
|
71
|
+
* There are several ways to access data with different performance characteristics:
|
|
72
|
+
*
|
|
73
|
+
* ### 1. Typed Row Access (getRow, rows(), toArray())
|
|
74
|
+
* - Provides type safety and validation
|
|
75
|
+
* - Converts data to JavaScript objects
|
|
76
|
+
* - Slower for large datasets due to object creation and validation
|
|
77
|
+
*
|
|
78
|
+
* ```typescript
|
|
79
|
+
* // Iterate through rows using the rows() iterator (recommended)
|
|
80
|
+
* for (const user of data.rows()) {
|
|
81
|
+
* console.log(user.name, user.email);
|
|
82
|
+
* }
|
|
83
|
+
*
|
|
84
|
+
* // Traditional for loop with index access
|
|
85
|
+
* for (let i = 0; i < data.length; i++) {
|
|
86
|
+
* const user = data.getRow(i);
|
|
87
|
+
* console.log(`User ${i}: ${user.name} (${user.email})`);
|
|
88
|
+
* }
|
|
89
|
+
*
|
|
90
|
+
* // Get all rows as an array
|
|
91
|
+
* const allUsers = data.toArray();
|
|
92
|
+
*
|
|
93
|
+
* // With Zod schema, transformed fields are available
|
|
94
|
+
* for (const user of validatedData.rows()) {
|
|
95
|
+
* console.log(`Created: ${user.createdAt.toISOString()}`); // createdAt is a Date object
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* ### 2. Direct Arrow Table Access
|
|
100
|
+
* - Much faster for large datasets
|
|
101
|
+
* - Columnar access is more efficient for analytics
|
|
102
|
+
* - No type safety or validation
|
|
103
|
+
*
|
|
104
|
+
* ```typescript
|
|
105
|
+
* // For performance-critical operations with large datasets:
|
|
106
|
+
* const nameColumn = data.arrowTable.getChild('name');
|
|
107
|
+
* const emailColumn = data.arrowTable.getChild('email');
|
|
108
|
+
*
|
|
109
|
+
* // Fast columnar iteration (no object creation)
|
|
110
|
+
* for (let i = 0; i < data.length; i++) {
|
|
111
|
+
* console.log(nameColumn.get(i), emailColumn.get(i));
|
|
112
|
+
* }
|
|
113
|
+
*
|
|
114
|
+
* // Note: For filtering data, it's most efficient to use SQL in your query
|
|
115
|
+
* const { data } = useSql<User>({
|
|
116
|
+
* query: "SELECT * FROM users WHERE age > 30"
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* ### 3. Using Flechette for Advanced Operations
|
|
121
|
+
*
|
|
122
|
+
* For more advanced Arrow operations, consider using [Flechette](https://idl.uw.edu/flechette/),
|
|
123
|
+
* a faster and lighter alternative to the standard Arrow JS implementation.
|
|
124
|
+
*
|
|
125
|
+
* ```typescript
|
|
126
|
+
* // Example using Flechette with SQL query results
|
|
127
|
+
* import { tableFromIPC } from '@uwdata/flechette';
|
|
128
|
+
*
|
|
129
|
+
* // Convert Arrow table to Flechette table
|
|
130
|
+
* const serializedData = data.arrowTable.serialize();
|
|
131
|
+
* const flechetteTable = tableFromIPC(serializedData);
|
|
132
|
+
*
|
|
133
|
+
* // Extract all columns into a { name: array, ... } object
|
|
134
|
+
* const columns = flechetteTable.toColumns();
|
|
135
|
+
*
|
|
136
|
+
* // Create a new table with a selected subset of columns
|
|
137
|
+
* const subtable = flechetteTable.select(['name', 'email']);
|
|
138
|
+
*
|
|
139
|
+
* // Convert to array of objects with customization options
|
|
140
|
+
* const objects = flechetteTable.toArray({
|
|
141
|
+
* useDate: true, // Convert timestamps to Date objects
|
|
142
|
+
* useMap: true // Create Map objects for key-value pairs
|
|
143
|
+
* });
|
|
144
|
+
*
|
|
145
|
+
* // For large datasets, consider memory management
|
|
146
|
+
* serializedData = null; // Allow garbage collection of the serialized data
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* Flechette provides several advantages:
|
|
150
|
+
* - Better performance (1.3-1.6x faster value iteration, 7-11x faster row object extraction)
|
|
151
|
+
* - Smaller footprint (~43k minified vs 163k for Arrow JS)
|
|
152
|
+
* - Support for additional data types (including decimal-to-number conversion)
|
|
153
|
+
* - More flexible data value conversion options
|
|
154
|
+
*
|
|
155
|
+
* @template Row The TypeScript type for each row in the result
|
|
156
|
+
* @param options Configuration object containing the query and execution control
|
|
157
|
+
* @returns Object containing the query result, loading state, and any error
|
|
158
|
+
*
|
|
159
|
+
* @template Schema The Zod schema type that defines the shape and validation of each row
|
|
160
|
+
* @param schema A Zod schema that defines the expected shape and validation rules for each row
|
|
161
|
+
* @param options Configuration object containing the query and execution control
|
|
162
|
+
* @returns Object containing the validated query result, loading state, and any error
|
|
163
|
+
*/
|
|
164
|
+
export declare function useSql<Row>(options: {
|
|
165
|
+
query: string;
|
|
166
|
+
enabled?: boolean;
|
|
167
|
+
}): {
|
|
168
|
+
data: UseSqlQueryResult<Row> | undefined;
|
|
169
|
+
error: Error | null;
|
|
170
|
+
isLoading: boolean;
|
|
171
|
+
};
|
|
172
|
+
export declare function useSql<Schema extends z.ZodType>(schema: Schema, options: {
|
|
173
|
+
query: string;
|
|
174
|
+
enabled?: boolean;
|
|
175
|
+
}): {
|
|
176
|
+
data: UseSqlQueryResult<z.infer<Schema>> | undefined;
|
|
177
|
+
error: Error | null;
|
|
178
|
+
isLoading: boolean;
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* @deprecated Use useSql instead
|
|
182
|
+
*/
|
|
183
|
+
export declare const useDuckDbQuery: typeof useSql;
|
|
184
|
+
//# sourceMappingURL=useSql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSql.d.ts","sourceRoot":"","sources":["../src/useSql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,iCAAiC;IACjC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC;IACxB,yEAAyE;IACzE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC;IACzB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,IAAI,IAAI,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC5B,wDAAwD;IACxD,OAAO,IAAI,CAAC,EAAE,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC;AA+CxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4IG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAC,GAAG;IACxE,IAAI,EAAE,iBAAiB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACzC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,wBAAgB,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC,OAAO,EAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IACP,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA;IACD,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IACrD,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAuEF;;GAEG;AACH,eAAO,MAAM,cAAc,eAAS,CAAC"}
|
|
@@ -23,12 +23,24 @@ function createTypedRowAccessor({ arrowTable, validate, }) {
|
|
|
23
23
|
}
|
|
24
24
|
return row;
|
|
25
25
|
},
|
|
26
|
+
*rows() {
|
|
27
|
+
for (let i = 0; i < this.length; i++) {
|
|
28
|
+
yield this.getRow(i);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
toArray() {
|
|
32
|
+
const result = [];
|
|
33
|
+
for (let i = 0; i < this.length; i++) {
|
|
34
|
+
result.push(this.getRow(i));
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
},
|
|
26
38
|
};
|
|
27
39
|
}
|
|
28
40
|
/**
|
|
29
|
-
* Implementation of
|
|
41
|
+
* Implementation of useSql that handles both overloads
|
|
30
42
|
*/
|
|
31
|
-
export function
|
|
43
|
+
export function useSql(schemaOrOptions, maybeOptions) {
|
|
32
44
|
// Determine if we're using the schema overload
|
|
33
45
|
const hasSchema = maybeOptions !== undefined;
|
|
34
46
|
const options = hasSchema
|
|
@@ -80,4 +92,8 @@ export function useDuckDbQuery(schemaOrOptions, maybeOptions) {
|
|
|
80
92
|
isLoading,
|
|
81
93
|
};
|
|
82
94
|
}
|
|
83
|
-
|
|
95
|
+
/**
|
|
96
|
+
* @deprecated Use useSql instead
|
|
97
|
+
*/
|
|
98
|
+
export const useDuckDbQuery = useSql;
|
|
99
|
+
//# sourceMappingURL=useSql.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSql.js","sourceRoot":"","sources":["../src/useSql.ts"],"names":[],"mappings":"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","sourcesContent":["import * as arrow from 'apache-arrow';\nimport {useEffect, useState} from 'react';\nimport {getDuckDb} from './useDuckDb';\nimport {z} from 'zod';\n\n/**\n * A wrapper interface that exposes the underlying Arrow table,\n * a typed row accessor, and the number of rows.\n */\nexport interface UseSqlQueryResult<T> {\n /** The underlying Arrow table */\n arrowTable: arrow.Table;\n /** Returns a typed row at the specified index by converting on demand */\n getRow(index: number): T;\n /** Number of rows in the table */\n length: number;\n /** Returns an iterator that yields each row in the table */\n rows(): IterableIterator<T>;\n /** Returns an array containing all rows in the table */\n toArray(): T[];\n}\n\n/**\n * @deprecated Use UseSqlQueryResult instead\n */\nexport type DuckDbQueryResult<T> = UseSqlQueryResult<T>;\n\n/**\n * Creates a row accessor wrapper around an Arrow table that provides typed row access.\n */\nfunction createTypedRowAccessor<T>({\n arrowTable,\n validate,\n}: {\n arrowTable: arrow.Table;\n validate?: (row: unknown) => T;\n}): UseSqlQueryResult<T> {\n return {\n arrowTable,\n get length() {\n return arrowTable.numRows;\n },\n getRow(index: number): T {\n const row: Record<string, unknown> = {};\n arrowTable.schema.fields.forEach((field: arrow.Field) => {\n const column = arrowTable.getChild(field.name);\n if (column) {\n row[field.name] = column.get(index);\n }\n });\n\n // If a validator is provided, use it to validate/parse the row\n if (validate) {\n return validate(row);\n }\n return row as T;\n },\n *rows(): IterableIterator<T> {\n for (let i = 0; i < this.length; i++) {\n yield this.getRow(i);\n }\n },\n toArray(): T[] {\n const result: T[] = [];\n for (let i = 0; i < this.length; i++) {\n result.push(this.getRow(i));\n }\n return result;\n },\n };\n}\n\n/**\n * A React hook for executing SQL queries with automatic state management.\n * Provides two ways to ensure type safety:\n * 1. Using TypeScript types (compile-time safety only)\n * 2. Using Zod schemas (both compile-time and runtime validation)\n *\n * @example\n * ```typescript\n * // Option 1: Using TypeScript types (faster, no runtime validation)\n * interface User {\n * id: number;\n * name: string;\n * email: string;\n * }\n *\n * const {data, isLoading, error} = useSql<User>({\n * query: 'SELECT id, name, email FROM users'\n * });\n *\n * // Option 2: Using Zod schema (slower but with runtime validation)\n * const userSchema = z.object({\n * id: z.number(),\n * name: z.string(),\n * email: z.string().email(),\n * createdAt: z.string().transform(str => new Date(str)) // Transform string to Date\n * });\n *\n * const {data: validatedData, isLoading, error} = useSql(\n * userSchema,\n * {query: 'SELECT id, name, email, created_at as createdAt FROM users'}\n * );\n * ```\n *\n * ## Error Handling\n * ```typescript\n * if (isLoading) return <div>Loading...</div>;\n * if (error) {\n * // With Zod, you can catch validation errors specifically\n * if (error instanceof z.ZodError) {\n * return <div>Validation Error: {error.errors[0].message}</div>;\n * }\n * return <div>Error: {error.message}</div>;\n * }\n * if (!data) return null;\n * ```\n *\n * ## Data Access Methods\n *\n * There are several ways to access data with different performance characteristics:\n *\n * ### 1. Typed Row Access (getRow, rows(), toArray())\n * - Provides type safety and validation\n * - Converts data to JavaScript objects\n * - Slower for large datasets due to object creation and validation\n *\n * ```typescript\n * // Iterate through rows using the rows() iterator (recommended)\n * for (const user of data.rows()) {\n * console.log(user.name, user.email);\n * }\n *\n * // Traditional for loop with index access\n * for (let i = 0; i < data.length; i++) {\n * const user = data.getRow(i);\n * console.log(`User ${i}: ${user.name} (${user.email})`);\n * }\n *\n * // Get all rows as an array\n * const allUsers = data.toArray();\n *\n * // With Zod schema, transformed fields are available\n * for (const user of validatedData.rows()) {\n * console.log(`Created: ${user.createdAt.toISOString()}`); // createdAt is a Date object\n * }\n * ```\n *\n * ### 2. Direct Arrow Table Access\n * - Much faster for large datasets\n * - Columnar access is more efficient for analytics\n * - No type safety or validation\n *\n * ```typescript\n * // For performance-critical operations with large datasets:\n * const nameColumn = data.arrowTable.getChild('name');\n * const emailColumn = data.arrowTable.getChild('email');\n *\n * // Fast columnar iteration (no object creation)\n * for (let i = 0; i < data.length; i++) {\n * console.log(nameColumn.get(i), emailColumn.get(i));\n * }\n *\n * // Note: For filtering data, it's most efficient to use SQL in your query\n * const { data } = useSql<User>({\n * query: \"SELECT * FROM users WHERE age > 30\"\n * });\n * ```\n *\n * ### 3. Using Flechette for Advanced Operations\n *\n * For more advanced Arrow operations, consider using [Flechette](https://idl.uw.edu/flechette/),\n * a faster and lighter alternative to the standard Arrow JS implementation.\n *\n * ```typescript\n * // Example using Flechette with SQL query results\n * import { tableFromIPC } from '@uwdata/flechette';\n *\n * // Convert Arrow table to Flechette table\n * const serializedData = data.arrowTable.serialize();\n * const flechetteTable = tableFromIPC(serializedData);\n *\n * // Extract all columns into a { name: array, ... } object\n * const columns = flechetteTable.toColumns();\n *\n * // Create a new table with a selected subset of columns\n * const subtable = flechetteTable.select(['name', 'email']);\n *\n * // Convert to array of objects with customization options\n * const objects = flechetteTable.toArray({\n * useDate: true, // Convert timestamps to Date objects\n * useMap: true // Create Map objects for key-value pairs\n * });\n *\n * // For large datasets, consider memory management\n * serializedData = null; // Allow garbage collection of the serialized data\n * ```\n *\n * Flechette provides several advantages:\n * - Better performance (1.3-1.6x faster value iteration, 7-11x faster row object extraction)\n * - Smaller footprint (~43k minified vs 163k for Arrow JS)\n * - Support for additional data types (including decimal-to-number conversion)\n * - More flexible data value conversion options\n *\n * @template Row The TypeScript type for each row in the result\n * @param options Configuration object containing the query and execution control\n * @returns Object containing the query result, loading state, and any error\n *\n * @template Schema The Zod schema type that defines the shape and validation of each row\n * @param schema A Zod schema that defines the expected shape and validation rules for each row\n * @param options Configuration object containing the query and execution control\n * @returns Object containing the validated query result, loading state, and any error\n */\nexport function useSql<Row>(options: {query: string; enabled?: boolean}): {\n data: UseSqlQueryResult<Row> | undefined;\n error: Error | null;\n isLoading: boolean;\n};\n\nexport function useSql<Schema extends z.ZodType>(\n schema: Schema,\n options: {\n query: string;\n enabled?: boolean;\n },\n): {\n data: UseSqlQueryResult<z.infer<Schema>> | undefined;\n error: Error | null;\n isLoading: boolean;\n};\n\n/**\n * Implementation of useSql that handles both overloads\n */\nexport function useSql<Row, Schema extends z.ZodType = z.ZodType>(\n schemaOrOptions: Schema | {query: string; enabled?: boolean},\n maybeOptions?: {query: string; enabled?: boolean},\n) {\n // Determine if we're using the schema overload\n const hasSchema = maybeOptions !== undefined;\n const options = hasSchema\n ? maybeOptions\n : (schemaOrOptions as {query: string; enabled?: boolean});\n const schema = hasSchema ? (schemaOrOptions as Schema) : undefined;\n\n const [data, setData] = useState<UseSqlQueryResult<Row> | undefined>(\n undefined,\n );\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n useEffect(() => {\n let isMounted = true;\n\n const fetchData = async () => {\n if (!options.enabled && options.enabled !== undefined) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const duckDb = await getDuckDb();\n const result = await duckDb.conn.query(options.query);\n\n // Create a row accessor that optionally validates with the schema\n const rowAccessor = createTypedRowAccessor<Row>({\n arrowTable: result,\n validate: schema ? (row: unknown) => schema.parse(row) : undefined,\n });\n\n if (isMounted) {\n setData(rowAccessor);\n }\n } catch (err) {\n if (isMounted) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n } finally {\n if (isMounted) {\n setIsLoading(false);\n }\n }\n };\n\n fetchData();\n\n return () => {\n isMounted = false;\n };\n }, [options.query, options.enabled]);\n\n return {\n data,\n error,\n isLoading,\n };\n}\n\n/**\n * @deprecated Use useSql instead\n */\nexport const useDuckDbQuery = useSql;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sqlrooms/duckdb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@duckdb/duckdb-wasm": "
|
|
22
|
+
"@duckdb/duckdb-wasm": "1.29.0",
|
|
23
23
|
"apache-arrow": "^18.1.0",
|
|
24
24
|
"zod": "^3.24.1"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@sqlrooms/jest-config": "0.
|
|
27
|
+
"@sqlrooms/jest-config": "0.7.0",
|
|
28
28
|
"@types/jest": "^29.5.12",
|
|
29
29
|
"jest": "^29.7.0",
|
|
30
30
|
"ts-jest": "^29.1.2"
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"test": "jest",
|
|
39
39
|
"test:watch": "jest --watch"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "8be65f051c588d3a963f721322429657913b6c63"
|
|
42
42
|
}
|
package/dist/useDuckDbQuery.d.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import * as arrow from 'apache-arrow';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
/**
|
|
4
|
-
* A wrapper interface that exposes the underlying Arrow table,
|
|
5
|
-
* a typed row accessor, and the number of rows.
|
|
6
|
-
*/
|
|
7
|
-
export interface DuckDbQueryResult<T> {
|
|
8
|
-
/** The underlying Arrow table */
|
|
9
|
-
arrowTable: arrow.Table;
|
|
10
|
-
/** Returns a typed row at the specified index by converting on demand */
|
|
11
|
-
getRow(index: number): T;
|
|
12
|
-
/** Number of rows in the table */
|
|
13
|
-
length: number;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* A React hook for executing DuckDB queries with automatic state management.
|
|
17
|
-
* This version provides type safety through TypeScript types but no runtime validation.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* interface User {
|
|
22
|
-
* id: number;
|
|
23
|
-
* name: string;
|
|
24
|
-
* email: string;
|
|
25
|
-
* }
|
|
26
|
-
*
|
|
27
|
-
* const {data, isLoading, error} = useDuckDbQuery<User>({
|
|
28
|
-
* query: 'SELECT id, name, email FROM users'
|
|
29
|
-
* });
|
|
30
|
-
*
|
|
31
|
-
* if (isLoading) return <div>Loading...</div>;
|
|
32
|
-
* if (error) return <div>Error: {error.message}</div>;
|
|
33
|
-
* if (!data) return null;
|
|
34
|
-
*
|
|
35
|
-
* // Access typed rows
|
|
36
|
-
* const firstUser = data.getRow(0); // Type: User
|
|
37
|
-
* console.log(firstUser.name);
|
|
38
|
-
* ```
|
|
39
|
-
*
|
|
40
|
-
* @template Row The TypeScript type for each row in the result
|
|
41
|
-
* @param options Configuration object containing the query and execution control
|
|
42
|
-
* @returns Object containing the query result, loading state, and any error
|
|
43
|
-
*/
|
|
44
|
-
export declare function useDuckDbQuery<Row>(options: {
|
|
45
|
-
query: string;
|
|
46
|
-
enabled?: boolean;
|
|
47
|
-
}): {
|
|
48
|
-
data: DuckDbQueryResult<Row> | undefined;
|
|
49
|
-
error: Error | null;
|
|
50
|
-
isLoading: boolean;
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* A React hook for executing DuckDB queries with automatic state management and runtime validation.
|
|
54
|
-
* This version uses Zod schemas to provide both compile-time and runtime type safety.
|
|
55
|
-
*
|
|
56
|
-
* Key features:
|
|
57
|
-
* - Runtime validation of each row as it's accessed
|
|
58
|
-
* - Automatic TypeScript type inference from the Zod schema
|
|
59
|
-
* - Validation errors if the data doesn't match the expected shape
|
|
60
|
-
* - Ability to transform data during validation
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
* ```typescript
|
|
64
|
-
* // Define a schema for your data
|
|
65
|
-
* const userSchema = z.object({
|
|
66
|
-
* id: z.number(),
|
|
67
|
-
* name: z.string(),
|
|
68
|
-
* email: z.string().email(),
|
|
69
|
-
* createdAt: z.string().transform(str => new Date(str)) // Transform string to Date
|
|
70
|
-
* });
|
|
71
|
-
*
|
|
72
|
-
* // The type is automatically inferred from the schema
|
|
73
|
-
* const {data, isLoading, error} = useDuckDbQuery(
|
|
74
|
-
* userSchema,
|
|
75
|
-
* {query: 'SELECT id, name, email, created_at FROM users'}
|
|
76
|
-
* );
|
|
77
|
-
*
|
|
78
|
-
* if (isLoading) return <div>Loading...</div>;
|
|
79
|
-
* if (error) {
|
|
80
|
-
* // Error will be a ZodError if validation fails
|
|
81
|
-
* if (error instanceof z.ZodError) {
|
|
82
|
-
* return <div>Validation Error: {error.errors[0].message}</div>;
|
|
83
|
-
* }
|
|
84
|
-
* return <div>Error: {error.message}</div>;
|
|
85
|
-
* }
|
|
86
|
-
* if (!data) return null;
|
|
87
|
-
*
|
|
88
|
-
* // Rows are validated and transformed according to the schema
|
|
89
|
-
* const user = data.getRow(0);
|
|
90
|
-
* console.log(user.createdAt.toISOString()); // createdAt is now a Date object
|
|
91
|
-
* ```
|
|
92
|
-
*
|
|
93
|
-
* @template Schema The Zod schema type that defines the shape and validation of each row
|
|
94
|
-
* @param schema A Zod schema that defines the expected shape and validation rules for each row
|
|
95
|
-
* @param options Configuration object containing the query and execution control
|
|
96
|
-
* @returns Object containing the validated query result, loading state, and any error
|
|
97
|
-
*/
|
|
98
|
-
export declare function useDuckDbQuery<Schema extends z.ZodType>(schema: Schema, options: {
|
|
99
|
-
query: string;
|
|
100
|
-
enabled?: boolean;
|
|
101
|
-
}): {
|
|
102
|
-
data: DuckDbQueryResult<z.infer<Schema>> | undefined;
|
|
103
|
-
error: Error | null;
|
|
104
|
-
isLoading: boolean;
|
|
105
|
-
};
|
|
106
|
-
//# sourceMappingURL=useDuckDbQuery.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useDuckDbQuery.d.ts","sourceRoot":"","sources":["../src/useDuckDbQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,iCAAiC;IACjC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC;IACxB,yEAAyE;IACzE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC;IACzB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;CAChB;AAmCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG;IACF,IAAI,EAAE,iBAAiB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACzC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,cAAc,CAAC,MAAM,SAAS,CAAC,CAAC,OAAO,EACrD,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IACP,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA;IACD,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IACrD,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useDuckDbQuery.js","sourceRoot":"","sources":["../src/useDuckDbQuery.ts"],"names":[],"mappings":"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","sourcesContent":["import * as arrow from 'apache-arrow';\nimport {useEffect, useState} from 'react';\nimport {getDuckDb} from './useDuckDb';\nimport {z} from 'zod';\n\n/**\n * A wrapper interface that exposes the underlying Arrow table,\n * a typed row accessor, and the number of rows.\n */\nexport interface DuckDbQueryResult<T> {\n /** The underlying Arrow table */\n arrowTable: arrow.Table;\n /** Returns a typed row at the specified index by converting on demand */\n getRow(index: number): T;\n /** Number of rows in the table */\n length: number;\n}\n\n/**\n * Creates a row accessor wrapper around an Arrow table that provides typed row access.\n */\nfunction createTypedRowAccessor<T>({\n arrowTable,\n validate,\n}: {\n arrowTable: arrow.Table;\n validate?: (row: unknown) => T;\n}): DuckDbQueryResult<T> {\n return {\n arrowTable,\n get length() {\n return arrowTable.numRows;\n },\n getRow(index: number): T {\n const row: Record<string, unknown> = {};\n arrowTable.schema.fields.forEach((field: arrow.Field) => {\n const column = arrowTable.getChild(field.name);\n if (column) {\n row[field.name] = column.get(index);\n }\n });\n\n // If a validator is provided, use it to validate/parse the row\n if (validate) {\n return validate(row);\n }\n return row as T;\n },\n };\n}\n\n/**\n * A React hook for executing DuckDB queries with automatic state management.\n * This version provides type safety through TypeScript types but no runtime validation.\n *\n * @example\n * ```typescript\n * interface User {\n * id: number;\n * name: string;\n * email: string;\n * }\n *\n * const {data, isLoading, error} = useDuckDbQuery<User>({\n * query: 'SELECT id, name, email FROM users'\n * });\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!data) return null;\n *\n * // Access typed rows\n * const firstUser = data.getRow(0); // Type: User\n * console.log(firstUser.name);\n * ```\n *\n * @template Row The TypeScript type for each row in the result\n * @param options Configuration object containing the query and execution control\n * @returns Object containing the query result, loading state, and any error\n */\nexport function useDuckDbQuery<Row>(options: {\n query: string;\n enabled?: boolean;\n}): {\n data: DuckDbQueryResult<Row> | undefined;\n error: Error | null;\n isLoading: boolean;\n};\n\n/**\n * A React hook for executing DuckDB queries with automatic state management and runtime validation.\n * This version uses Zod schemas to provide both compile-time and runtime type safety.\n *\n * Key features:\n * - Runtime validation of each row as it's accessed\n * - Automatic TypeScript type inference from the Zod schema\n * - Validation errors if the data doesn't match the expected shape\n * - Ability to transform data during validation\n *\n * @example\n * ```typescript\n * // Define a schema for your data\n * const userSchema = z.object({\n * id: z.number(),\n * name: z.string(),\n * email: z.string().email(),\n * createdAt: z.string().transform(str => new Date(str)) // Transform string to Date\n * });\n *\n * // The type is automatically inferred from the schema\n * const {data, isLoading, error} = useDuckDbQuery(\n * userSchema,\n * {query: 'SELECT id, name, email, created_at FROM users'}\n * );\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) {\n * // Error will be a ZodError if validation fails\n * if (error instanceof z.ZodError) {\n * return <div>Validation Error: {error.errors[0].message}</div>;\n * }\n * return <div>Error: {error.message}</div>;\n * }\n * if (!data) return null;\n *\n * // Rows are validated and transformed according to the schema\n * const user = data.getRow(0);\n * console.log(user.createdAt.toISOString()); // createdAt is now a Date object\n * ```\n *\n * @template Schema The Zod schema type that defines the shape and validation of each row\n * @param schema A Zod schema that defines the expected shape and validation rules for each row\n * @param options Configuration object containing the query and execution control\n * @returns Object containing the validated query result, loading state, and any error\n */\nexport function useDuckDbQuery<Schema extends z.ZodType>(\n schema: Schema,\n options: {\n query: string;\n enabled?: boolean;\n },\n): {\n data: DuckDbQueryResult<z.infer<Schema>> | undefined;\n error: Error | null;\n isLoading: boolean;\n};\n\n/**\n * Implementation of useDuckDbQuery that handles both overloads\n */\nexport function useDuckDbQuery<Row, Schema extends z.ZodType = z.ZodType>(\n schemaOrOptions: Schema | {query: string; enabled?: boolean},\n maybeOptions?: {query: string; enabled?: boolean},\n) {\n // Determine if we're using the schema overload\n const hasSchema = maybeOptions !== undefined;\n const options = hasSchema\n ? maybeOptions\n : (schemaOrOptions as {query: string; enabled?: boolean});\n const schema = hasSchema ? (schemaOrOptions as Schema) : undefined;\n\n const [data, setData] = useState<DuckDbQueryResult<Row> | undefined>(\n undefined,\n );\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n useEffect(() => {\n let isMounted = true;\n\n const fetchData = async () => {\n if (!options.enabled && options.enabled !== undefined) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const duckDb = await getDuckDb();\n const result = await duckDb.conn.query(options.query);\n\n // Create a row accessor that optionally validates with the schema\n const rowAccessor = createTypedRowAccessor<Row>({\n arrowTable: result,\n validate: schema ? (row: unknown) => schema.parse(row) : undefined,\n });\n\n if (isMounted) {\n setData(rowAccessor);\n }\n } catch (err) {\n if (isMounted) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n } finally {\n if (isMounted) {\n setIsLoading(false);\n }\n }\n };\n\n fetchData();\n\n return () => {\n isMounted = false;\n };\n }, [options.query, options.enabled]);\n\n return {\n data,\n error,\n isLoading,\n };\n}\n"]}
|