@sqlrooms/duckdb 0.15.0 → 0.16.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/dist/DuckDbSlice.d.ts +98 -23
- package/dist/DuckDbSlice.d.ts.map +1 -1
- package/dist/DuckDbSlice.js +190 -63
- package/dist/DuckDbSlice.js.map +1 -1
- package/dist/connectors/BaseDuckDbConnector.d.ts +22 -5
- package/dist/connectors/BaseDuckDbConnector.d.ts.map +1 -1
- package/dist/connectors/BaseDuckDbConnector.js +66 -15
- package/dist/connectors/BaseDuckDbConnector.js.map +1 -1
- package/dist/connectors/DuckDbConnector.d.ts +237 -4
- package/dist/connectors/DuckDbConnector.d.ts.map +1 -1
- package/dist/connectors/DuckDbConnector.js.map +1 -1
- package/dist/connectors/WasmDuckDbConnector.d.ts +2 -1
- package/dist/connectors/WasmDuckDbConnector.d.ts.map +1 -1
- package/dist/connectors/WasmDuckDbConnector.js +90 -17
- package/dist/connectors/WasmDuckDbConnector.js.map +1 -1
- package/dist/duckdb-utils.d.ts +67 -0
- package/dist/duckdb-utils.d.ts.map +1 -1
- package/dist/duckdb-utils.js +195 -0
- package/dist/duckdb-utils.js.map +1 -1
- package/dist/exportToCsv.js +1 -1
- package/dist/exportToCsv.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/schemaTree.d.ts +8 -0
- package/dist/schemaTree.d.ts.map +1 -0
- package/dist/schemaTree.js +76 -0
- package/dist/schemaTree.js.map +1 -0
- package/dist/typeCategories.d.ts +16 -0
- package/dist/typeCategories.d.ts.map +1 -0
- package/dist/typeCategories.js +72 -0
- package/dist/typeCategories.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/useSql.d.ts.map +1 -1
- package/dist/useSql.js +11 -7
- package/dist/useSql.js.map +1 -1
- package/package.json +11 -12
package/dist/DuckDbSlice.d.ts
CHANGED
|
@@ -2,10 +2,15 @@ import { ProjectState } from '@sqlrooms/project';
|
|
|
2
2
|
import * as arrow from 'apache-arrow';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { StateCreator } from 'zustand';
|
|
5
|
-
import { DuckDbConnector } from './connectors/DuckDbConnector';
|
|
6
|
-
import {
|
|
5
|
+
import { DuckDbConnector, QueryHandle } from './connectors/DuckDbConnector';
|
|
6
|
+
import { QualifiedTableName } from './duckdb-utils';
|
|
7
|
+
import { DataTable, DbSchemaNode } from './types';
|
|
7
8
|
export declare const DuckDbSliceConfig: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
8
9
|
export type DuckDbSliceConfig = z.infer<typeof DuckDbSliceConfig>;
|
|
10
|
+
export type SchemaAndDatabase = {
|
|
11
|
+
schema?: string;
|
|
12
|
+
database?: string;
|
|
13
|
+
};
|
|
9
14
|
export declare function createDefaultDuckDbConfig(): DuckDbSliceConfig;
|
|
10
15
|
/**
|
|
11
16
|
* State and actions for the DuckDB slice
|
|
@@ -16,11 +21,34 @@ export type DuckDbSliceState = {
|
|
|
16
21
|
* The DuckDB connector instance
|
|
17
22
|
*/
|
|
18
23
|
connector: DuckDbConnector;
|
|
24
|
+
/**
|
|
25
|
+
* @deprecated We shouldn't limit the schema to a single one.
|
|
26
|
+
*/
|
|
19
27
|
schema: string;
|
|
28
|
+
/**
|
|
29
|
+
* Cache of refreshed table schemas
|
|
30
|
+
*/
|
|
20
31
|
tables: DataTable[];
|
|
32
|
+
/**
|
|
33
|
+
* Cache of row counts for tables
|
|
34
|
+
*/
|
|
21
35
|
tableRowCounts: {
|
|
22
36
|
[tableName: string]: number;
|
|
23
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* Cache of schema trees for tables
|
|
40
|
+
*/
|
|
41
|
+
schemaTrees?: DbSchemaNode[];
|
|
42
|
+
/**
|
|
43
|
+
* Cache of currently running query handles
|
|
44
|
+
*/
|
|
45
|
+
queryCache: {
|
|
46
|
+
[key: string]: QueryHandle;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Whether the table schemas are being refreshed
|
|
50
|
+
*/
|
|
51
|
+
isRefreshingTableSchemas: boolean;
|
|
24
52
|
/**
|
|
25
53
|
* Set a new DuckDB connector
|
|
26
54
|
*/
|
|
@@ -39,10 +67,27 @@ export type DuckDbSliceState = {
|
|
|
39
67
|
* @param data - The data to add to the table: an arrow table or an array of records.
|
|
40
68
|
* @returns A promise that resolves to the table that was added.
|
|
41
69
|
*/
|
|
42
|
-
addTable(tableName: string, data: arrow.Table | Record<string, unknown>[]): Promise<DataTable>;
|
|
70
|
+
addTable(tableName: string | QualifiedTableName, data: arrow.Table | Record<string, unknown>[]): Promise<DataTable>;
|
|
71
|
+
/**
|
|
72
|
+
* Load the schemas of the tables in the database.
|
|
73
|
+
*/
|
|
74
|
+
loadTableSchemas(filter?: SchemaAndDatabase & {
|
|
75
|
+
table?: string;
|
|
76
|
+
}): Promise<DataTable[]>;
|
|
77
|
+
/**
|
|
78
|
+
* @deprecated Use findTableByName instead
|
|
79
|
+
*/
|
|
43
80
|
getTable(tableName: string): DataTable | undefined;
|
|
44
|
-
|
|
45
|
-
|
|
81
|
+
/**
|
|
82
|
+
* @internal Avoid using this directly, it's for internal use.
|
|
83
|
+
*/
|
|
84
|
+
setTableRowCount(tableName: string | QualifiedTableName, rowCount: number): void;
|
|
85
|
+
/**
|
|
86
|
+
* Find a table by name in the last refreshed table schemas
|
|
87
|
+
* @param tableName - The name of the table to find or a qualified table name.
|
|
88
|
+
* @returns The table or undefined if not found.
|
|
89
|
+
*/
|
|
90
|
+
findTableByName(tableName: string | QualifiedTableName): DataTable | undefined;
|
|
46
91
|
/**
|
|
47
92
|
* Refresh table schemas from the database.
|
|
48
93
|
* @returns A promise that resolves to the updated tables.
|
|
@@ -53,45 +98,75 @@ export type DuckDbSliceState = {
|
|
|
53
98
|
*/
|
|
54
99
|
getConnector: () => Promise<DuckDbConnector>;
|
|
55
100
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* @param schema - The schema to get the tables from. Defaults to 'main'. Pass '*' to get all tables.
|
|
59
|
-
* @returns The tables in the database.
|
|
101
|
+
* @deprecated Use .loadTableRowCount() instead
|
|
60
102
|
*/
|
|
61
|
-
|
|
103
|
+
getTableRowCount: (table: string, schema?: string) => Promise<number>;
|
|
62
104
|
/**
|
|
63
|
-
*
|
|
105
|
+
* Load the row count of a table
|
|
64
106
|
*/
|
|
65
|
-
|
|
107
|
+
loadTableRowCount: (tableName: string | QualifiedTableName) => Promise<number>;
|
|
66
108
|
/**
|
|
67
|
-
*
|
|
109
|
+
* Execute a query with query handle (not result) caching and deduplication
|
|
110
|
+
* @param query - The SQL query to execute
|
|
111
|
+
* @returns The QueryHandle for the query or null if disabled
|
|
68
112
|
*/
|
|
69
|
-
|
|
113
|
+
executeSql: (query: string) => Promise<QueryHandle | null>;
|
|
70
114
|
/**
|
|
71
|
-
*
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
115
|
+
* @deprecated Use .tables or .loadTableSchemas() instead
|
|
116
|
+
*/
|
|
117
|
+
getTables: (schema?: string) => Promise<string[]>;
|
|
118
|
+
/**
|
|
119
|
+
* @deprecated Use .loadTableSchemas() instead
|
|
120
|
+
*/
|
|
121
|
+
getTableSchema: (tableName: string, schema?: string) => Promise<DataTable | undefined>;
|
|
122
|
+
/**
|
|
123
|
+
* @deprecated Use .tables or .loadTableSchemas() instead
|
|
75
124
|
*/
|
|
76
125
|
getTableSchemas: (schema?: string) => Promise<DataTable[]>;
|
|
77
126
|
/**
|
|
78
127
|
* Check if a table exists
|
|
79
128
|
*/
|
|
80
|
-
checkTableExists: (tableName: string
|
|
129
|
+
checkTableExists: (tableName: string | QualifiedTableName) => Promise<boolean>;
|
|
81
130
|
/**
|
|
82
|
-
*
|
|
131
|
+
* Delete a table with optional schema and database
|
|
132
|
+
* @param tableName - The name of the table to delete
|
|
133
|
+
* @param options - Optional parameters including schema and database
|
|
83
134
|
*/
|
|
84
|
-
dropTable: (tableName: string) => Promise<void>;
|
|
135
|
+
dropTable: (tableName: string | QualifiedTableName) => Promise<void>;
|
|
85
136
|
/**
|
|
86
137
|
* Create a table from a query.
|
|
87
138
|
* @param tableName - The name of the table to create.
|
|
88
139
|
* @param query - The query to create the table from.
|
|
89
140
|
* @returns The table that was created.
|
|
90
141
|
*/
|
|
91
|
-
createTableFromQuery: (tableName: string, query: string) => Promise<{
|
|
92
|
-
tableName: string;
|
|
142
|
+
createTableFromQuery: (tableName: string | QualifiedTableName, query: string) => Promise<{
|
|
143
|
+
tableName: string | QualifiedTableName;
|
|
93
144
|
rowCount: number;
|
|
94
145
|
}>;
|
|
146
|
+
/**
|
|
147
|
+
* Parse a SQL SELECT statement to JSON
|
|
148
|
+
* @param sql - The SQL SELECT statement to parse.
|
|
149
|
+
* @returns A promise that resolves to the parsed JSON.
|
|
150
|
+
*/
|
|
151
|
+
sqlSelectToJson: (sql: string) => Promise<{
|
|
152
|
+
error: true;
|
|
153
|
+
error_type: string;
|
|
154
|
+
error_message: string;
|
|
155
|
+
error_subtype: string;
|
|
156
|
+
position: string;
|
|
157
|
+
} | {
|
|
158
|
+
error: false;
|
|
159
|
+
statements: {
|
|
160
|
+
node: {
|
|
161
|
+
from_table: {
|
|
162
|
+
alias: string;
|
|
163
|
+
show_type: string;
|
|
164
|
+
table_name: string;
|
|
165
|
+
};
|
|
166
|
+
select_list: Record<string, unknown>[];
|
|
167
|
+
};
|
|
168
|
+
}[];
|
|
169
|
+
}>;
|
|
95
170
|
};
|
|
96
171
|
};
|
|
97
172
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DuckDbSlice.d.ts","sourceRoot":"","sources":["../src/DuckDbSlice.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,YAAY,EAAC,MAAM,SAAS,CAAC;AACrC,OAAO,EAAC,eAAe,EAAC,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"DuckDbSlice.d.ts","sourceRoot":"","sources":["../src/DuckDbSlice.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,YAAY,EAAC,MAAM,SAAS,CAAC;AACrC,OAAO,EAAC,eAAe,EAAE,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAE1E,OAAO,EAML,kBAAkB,EAEnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAC,SAAS,EAAe,YAAY,EAAC,MAAM,SAAS,CAAC;AAE7D,eAAO,MAAM,iBAAiB,gDAE5B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAgB,yBAAyB,IAAI,iBAAiB,CAI7D;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,EAAE;QACF;;WAEG;QACH,SAAS,EAAE,eAAe,CAAC;QAC3B;;WAEG;QACH,MAAM,EAAE,MAAM,CAAC;QAEf;;WAEG;QACH,MAAM,EAAE,SAAS,EAAE,CAAC;QACpB;;WAEG;QACH,cAAc,EAAE;YAAC,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAA;SAAC,CAAC;QAC9C;;WAEG;QACH,WAAW,CAAC,EAAE,YAAY,EAAE,CAAC;QAC7B;;WAEG;QACH,UAAU,EAAE;YAAC,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAA;SAAC,CAAC;QACzC;;WAEG;QACH,wBAAwB,EAAE,OAAO,CAAC;QAElC;;WAEG;QACH,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;QAEnD;;WAEG;QACH,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAEhC;;WAEG;QACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAE7B;;;;;WAKG;QACH,QAAQ,CACN,SAAS,EAAE,MAAM,GAAG,kBAAkB,EACtC,IAAI,EAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAC5C,OAAO,CAAC,SAAS,CAAC,CAAC;QAEtB;;WAEG;QACH,gBAAgB,CACd,MAAM,CAAC,EAAE,iBAAiB,GAAG;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAC,GAC5C,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAExB;;WAEG;QACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;QAEnD;;WAEG;QACH,gBAAgB,CACd,SAAS,EAAE,MAAM,GAAG,kBAAkB,EACtC,QAAQ,EAAE,MAAM,GACf,IAAI,CAAC;QAER;;;;WAIG;QACH,eAAe,CACb,SAAS,EAAE,MAAM,GAAG,kBAAkB,GACrC,SAAS,GAAG,SAAS,CAAC;QAEzB;;;WAGG;QACH,mBAAmB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAC5C;;WAEG;QACH,YAAY,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;QAE7C;;WAEG;QACH,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;QAEtE;;WAEG;QACH,iBAAiB,EAAE,CACjB,SAAS,EAAE,MAAM,GAAG,kBAAkB,KACnC,OAAO,CAAC,MAAM,CAAC,CAAC;QAErB;;;;WAIG;QACH,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;QAE3D;;WAEG;QACH,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAElD;;WAEG;QACH,cAAc,EAAE,CACd,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,KACZ,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;QAEpC;;WAEG;QACH,eAAe,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAE3D;;WAEG;QACH,gBAAgB,EAAE,CAChB,SAAS,EAAE,MAAM,GAAG,kBAAkB,KACnC,OAAO,CAAC,OAAO,CAAC,CAAC;QAEtB;;;;WAIG;QACH,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAErE;;;;;WAKG;QACH,oBAAoB,EAAE,CACpB,SAAS,EAAE,MAAM,GAAG,kBAAkB,EACtC,KAAK,EAAE,MAAM,KACV,OAAO,CAAC;YAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAC,CAAC,CAAC;QAEzE;;;;WAIG;QACH,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CACrC;YACE,KAAK,EAAE,IAAI,CAAC;YACZ,UAAU,EAAE,MAAM,CAAC;YACnB,aAAa,EAAE,MAAM,CAAC;YACtB,aAAa,EAAE,MAAM,CAAC;YACtB,QAAQ,EAAE,MAAM,CAAC;SAClB,GACD;YACE,KAAK,EAAE,KAAK,CAAC;YACb,UAAU,EAAE;gBACV,IAAI,EAAE;oBACJ,UAAU,EAAE;wBACV,KAAK,EAAE,MAAM,CAAC;wBACd,SAAS,EAAE,MAAM,CAAC;wBAClB,UAAU,EAAE,MAAM,CAAC;qBACpB,CAAC;oBACF,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;iBACxC,CAAC;aACH,EAAE,CAAC;SACL,CACJ,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAqC,GACtC,EAAE;IACD,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAgUjC;AAED,KAAK,sBAAsB,GAAG,YAAY,CAAC,iBAAiB,CAAC,GAC3D,gBAAgB,CAAC;AAEnB,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,QAAQ,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,CAAC,GAC7C,CAAC,CAMH"}
|
package/dist/DuckDbSlice.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { createBaseSlice, useBaseProjectStore, } from '@sqlrooms/project';
|
|
2
2
|
import * as arrow from 'apache-arrow';
|
|
3
|
-
import { produce } from 'immer';
|
|
4
3
|
import deepEquals from 'fast-deep-equal';
|
|
4
|
+
import { produce } from 'immer';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { WasmDuckDbConnector } from './connectors/WasmDuckDbConnector';
|
|
7
|
-
import { getColValAsNumber } from './duckdb-utils';
|
|
7
|
+
import { escapeId, escapeVal, getColValAsNumber, isQualifiedTableName, makeQualifiedTableName, splitSqlStatements, } from './duckdb-utils';
|
|
8
|
+
import { createDbSchemaTrees as createDbSchemaTrees } from './schemaTree';
|
|
8
9
|
export const DuckDbSliceConfig = z.object({
|
|
9
10
|
// nothing yet
|
|
10
11
|
});
|
|
@@ -21,9 +22,12 @@ export function createDuckDbSlice({ connector = new WasmDuckDbConnector(), }) {
|
|
|
21
22
|
return {
|
|
22
23
|
db: {
|
|
23
24
|
connector, // Will be initialized during init
|
|
24
|
-
schema: 'main',
|
|
25
|
+
schema: 'main', // TODO: remove schema, we should not limit the schema to a single one.
|
|
26
|
+
isRefreshingTableSchemas: false,
|
|
25
27
|
tables: [],
|
|
26
28
|
tableRowCounts: {},
|
|
29
|
+
schemaTree: undefined,
|
|
30
|
+
queryCache: {},
|
|
27
31
|
setConnector: (connector) => {
|
|
28
32
|
set(produce((state) => {
|
|
29
33
|
state.config.dataSources = [];
|
|
@@ -32,9 +36,9 @@ export function createDuckDbSlice({ connector = new WasmDuckDbConnector(), }) {
|
|
|
32
36
|
},
|
|
33
37
|
initialize: async () => {
|
|
34
38
|
await get().db.connector.initialize();
|
|
39
|
+
await get().db.refreshTableSchemas();
|
|
35
40
|
},
|
|
36
41
|
getConnector: async () => {
|
|
37
|
-
await get().db.initialize();
|
|
38
42
|
return get().db.connector;
|
|
39
43
|
},
|
|
40
44
|
destroy: async () => {
|
|
@@ -48,99 +52,222 @@ export function createDuckDbSlice({ connector = new WasmDuckDbConnector(), }) {
|
|
|
48
52
|
}
|
|
49
53
|
},
|
|
50
54
|
async createTableFromQuery(tableName, query) {
|
|
55
|
+
const qualifiedName = isQualifiedTableName(tableName)
|
|
56
|
+
? tableName
|
|
57
|
+
: makeQualifiedTableName({ table: tableName });
|
|
51
58
|
const connector = await get().db.getConnector();
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
const statements = splitSqlStatements(query);
|
|
60
|
+
if (statements.length !== 1) {
|
|
61
|
+
throw new Error('Query must contain exactly one statement');
|
|
62
|
+
}
|
|
63
|
+
const statement = statements[0];
|
|
64
|
+
const parsedQuery = await get().db.sqlSelectToJson(statement);
|
|
65
|
+
if (parsedQuery.error) {
|
|
66
|
+
throw new Error('Query is not a valid SELECT statement');
|
|
67
|
+
}
|
|
68
|
+
const rowCount = getColValAsNumber(await connector.query(`CREATE OR REPLACE TABLE ${qualifiedName} AS (
|
|
69
|
+
${statements[0]}
|
|
70
|
+
)`).result);
|
|
55
71
|
return { tableName, rowCount };
|
|
56
72
|
},
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
for (let i = 0; i < tablesResults.numRows; i++) {
|
|
64
|
-
tableNames.push(tablesResults.getChild('table_name')?.get(i));
|
|
65
|
-
}
|
|
66
|
-
return tableNames;
|
|
73
|
+
/**
|
|
74
|
+
* @deprecated Use .tables or .loadTableSchemas() instead
|
|
75
|
+
*/
|
|
76
|
+
async getTables(schema) {
|
|
77
|
+
const tableSchemas = await get().db.loadTableSchemas({ schema });
|
|
78
|
+
return tableSchemas.map((t) => t.table.table);
|
|
67
79
|
},
|
|
80
|
+
/**
|
|
81
|
+
* @deprecated Use .loadTableSchemas() instead
|
|
82
|
+
*/
|
|
68
83
|
async getTableSchema(tableName, schema = 'main') {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
tableName,
|
|
81
|
-
columns,
|
|
82
|
-
};
|
|
84
|
+
const newLocal = await get().db.loadTableSchemas({
|
|
85
|
+
schema,
|
|
86
|
+
table: tableName,
|
|
87
|
+
});
|
|
88
|
+
return newLocal[0];
|
|
89
|
+
},
|
|
90
|
+
/**
|
|
91
|
+
* @deprecated Use .loadTableRowCount() instead
|
|
92
|
+
*/
|
|
93
|
+
async getTableRowCount(table, schema = 'main') {
|
|
94
|
+
return get().db.loadTableRowCount({ table, schema });
|
|
83
95
|
},
|
|
84
|
-
async
|
|
96
|
+
async loadTableRowCount(tableName) {
|
|
97
|
+
const { schema, database, table } = typeof tableName === 'string'
|
|
98
|
+
? { table: tableName }
|
|
99
|
+
: tableName || {};
|
|
85
100
|
const connector = await get().db.getConnector();
|
|
86
|
-
const result = await connector.query(`SELECT COUNT(*) FROM ${
|
|
101
|
+
const result = await connector.query(`SELECT COUNT(*) FROM ${makeQualifiedTableName({
|
|
102
|
+
schema,
|
|
103
|
+
database,
|
|
104
|
+
table,
|
|
105
|
+
})}`).result;
|
|
87
106
|
return getColValAsNumber(result);
|
|
88
107
|
},
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
/**
|
|
109
|
+
* @deprecated Use .loadTableSchemas() instead
|
|
110
|
+
*/
|
|
111
|
+
async getTableSchemas(schema) {
|
|
112
|
+
return await get().db.loadTableSchemas({ schema });
|
|
113
|
+
},
|
|
114
|
+
async loadTableSchemas(filter) {
|
|
115
|
+
const { schema, database, table } = filter || {};
|
|
116
|
+
const describeResults = await connector.query(`FROM (DESCRIBE)
|
|
117
|
+
SELECT
|
|
118
|
+
(CASE WHEN database = current_database() THEN NULL ELSE database END) AS database,
|
|
119
|
+
(CASE WHEN schema = current_schema() THEN NULL ELSE schema END) AS schema,
|
|
120
|
+
name, column_names, column_types
|
|
121
|
+
${schema || database || table
|
|
122
|
+
? `WHERE ${[
|
|
123
|
+
schema ? `schema = '${escapeId(schema)}'` : '',
|
|
124
|
+
database ? `database = '${escapeId(database)}'` : '',
|
|
125
|
+
table ? `name = '${escapeId(table)}'` : '',
|
|
126
|
+
]
|
|
127
|
+
.filter(Boolean)
|
|
128
|
+
.join(' AND ')}`
|
|
129
|
+
: ''}`).result;
|
|
130
|
+
const newTables = [];
|
|
131
|
+
for (let i = 0; i < describeResults.numRows; i++) {
|
|
132
|
+
const database = describeResults.getChild('database')?.get(i);
|
|
133
|
+
const schema = describeResults.getChild('schema')?.get(i);
|
|
134
|
+
const table = describeResults.getChild('name')?.get(i);
|
|
135
|
+
const columnNames = describeResults
|
|
136
|
+
.getChild('column_names')
|
|
137
|
+
?.get(i);
|
|
138
|
+
const columnTypes = describeResults
|
|
139
|
+
.getChild('column_types')
|
|
140
|
+
?.get(i);
|
|
141
|
+
const columns = [];
|
|
142
|
+
for (let di = 0; di < columnNames.length; di++) {
|
|
143
|
+
columns.push({
|
|
144
|
+
name: columnNames.get(di),
|
|
145
|
+
type: columnTypes.get(di),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
newTables.push({
|
|
149
|
+
table: makeQualifiedTableName({ database, schema, table }),
|
|
150
|
+
database,
|
|
151
|
+
schema,
|
|
152
|
+
tableName: table,
|
|
153
|
+
columns,
|
|
154
|
+
});
|
|
94
155
|
}
|
|
95
|
-
return
|
|
156
|
+
return newTables;
|
|
96
157
|
},
|
|
97
|
-
async checkTableExists(tableName
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
158
|
+
async checkTableExists(tableName) {
|
|
159
|
+
const qualifiedName = isQualifiedTableName(tableName)
|
|
160
|
+
? tableName
|
|
161
|
+
: makeQualifiedTableName({ table: tableName });
|
|
162
|
+
const table = (await get().db.loadTableSchemas(qualifiedName))[0];
|
|
163
|
+
if (!table) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
return true;
|
|
101
167
|
},
|
|
102
168
|
async dropTable(tableName) {
|
|
103
169
|
const connector = await get().db.getConnector();
|
|
104
|
-
|
|
170
|
+
const qualifiedTable = isQualifiedTableName(tableName)
|
|
171
|
+
? tableName
|
|
172
|
+
: makeQualifiedTableName({ table: tableName });
|
|
173
|
+
await connector.query(`DROP TABLE IF EXISTS ${qualifiedTable};`)
|
|
174
|
+
.result;
|
|
175
|
+
await get().db.refreshTableSchemas();
|
|
105
176
|
},
|
|
106
177
|
async addTable(tableName, data) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return table;
|
|
111
|
-
}
|
|
178
|
+
const qualifiedName = isQualifiedTableName(tableName)
|
|
179
|
+
? tableName
|
|
180
|
+
: makeQualifiedTableName({ table: tableName });
|
|
112
181
|
const { db } = get();
|
|
113
182
|
if (data instanceof arrow.Table) {
|
|
114
|
-
|
|
183
|
+
// TODO: make sure the table is replaced
|
|
184
|
+
await db.connector.loadArrow(data, qualifiedName.toString());
|
|
115
185
|
}
|
|
116
186
|
else {
|
|
117
|
-
await db.connector.loadObjects(data,
|
|
187
|
+
await db.connector.loadObjects(data, qualifiedName.toString(), {
|
|
188
|
+
replace: true,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const newTable = (await db.loadTableSchemas(qualifiedName))[0];
|
|
192
|
+
if (!newTable) {
|
|
193
|
+
throw new Error('Failed to add table');
|
|
118
194
|
}
|
|
119
|
-
const newTable = await db.getTableSchema(tableName);
|
|
120
195
|
set((state) => produce(state, (draft) => {
|
|
121
196
|
draft.db.tables.push(newTable);
|
|
122
197
|
}));
|
|
198
|
+
await get().db.refreshTableSchemas();
|
|
123
199
|
return newTable;
|
|
124
200
|
},
|
|
125
|
-
setTableRowCount
|
|
126
|
-
|
|
127
|
-
|
|
201
|
+
async setTableRowCount(tableName, rowCount) {
|
|
202
|
+
const qualifiedName = isQualifiedTableName(tableName)
|
|
203
|
+
? tableName
|
|
204
|
+
: makeQualifiedTableName({ table: tableName });
|
|
205
|
+
set((state) => produce(state, (draft) => {
|
|
206
|
+
draft.db.tableRowCounts[qualifiedName.toString()] = rowCount;
|
|
207
|
+
}));
|
|
208
|
+
},
|
|
128
209
|
getTable(tableName) {
|
|
129
|
-
return get().db.
|
|
210
|
+
return get().db.findTableByName(tableName);
|
|
130
211
|
},
|
|
131
212
|
findTableByName(tableName) {
|
|
132
|
-
|
|
213
|
+
const qualifiedName = (isQualifiedTableName(tableName)
|
|
214
|
+
? tableName
|
|
215
|
+
: makeQualifiedTableName({ table: tableName })).toString();
|
|
216
|
+
return get().db.tables.find((t) => t.table.toString() === qualifiedName);
|
|
133
217
|
},
|
|
134
218
|
async refreshTableSchemas() {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
219
|
+
set((state) => produce(state, (draft) => {
|
|
220
|
+
draft.db.isRefreshingTableSchemas = true;
|
|
221
|
+
}));
|
|
222
|
+
try {
|
|
223
|
+
const newTables = await get().db.loadTableSchemas();
|
|
224
|
+
// Only update if there's an actual change in the schemas
|
|
225
|
+
if (!deepEquals(newTables, get().db.tables)) {
|
|
226
|
+
set((state) => produce(state, (draft) => {
|
|
227
|
+
draft.db.tables = newTables;
|
|
228
|
+
draft.db.schemaTrees = createDbSchemaTrees(newTables);
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
231
|
+
return newTables;
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
get().project.captureException(err);
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
139
238
|
set((state) => produce(state, (draft) => {
|
|
140
|
-
draft.db.
|
|
239
|
+
draft.db.isRefreshingTableSchemas = false;
|
|
141
240
|
}));
|
|
142
241
|
}
|
|
143
|
-
|
|
242
|
+
},
|
|
243
|
+
async sqlSelectToJson(sql) {
|
|
244
|
+
const connector = await get().db.getConnector();
|
|
245
|
+
const parsedQuery = (await connector.query(`SELECT json_serialize_sql(${escapeVal(sql)})`).result)
|
|
246
|
+
.getChildAt(0)
|
|
247
|
+
?.get(0);
|
|
248
|
+
return JSON.parse(parsedQuery);
|
|
249
|
+
},
|
|
250
|
+
async executeSql(query) {
|
|
251
|
+
// Create a unique key for this query
|
|
252
|
+
const queryKey = `${query}`;
|
|
253
|
+
const connector = await get().db.getConnector();
|
|
254
|
+
// Check if we already have a cached query for this key
|
|
255
|
+
const existingQuery = get().db.queryCache[queryKey];
|
|
256
|
+
if (existingQuery) {
|
|
257
|
+
return existingQuery;
|
|
258
|
+
}
|
|
259
|
+
const queryHandle = connector.query(query);
|
|
260
|
+
// Cache the query handle immediately
|
|
261
|
+
set((state) => produce(state, (draft) => {
|
|
262
|
+
draft.db.queryCache[queryKey] = queryHandle;
|
|
263
|
+
}));
|
|
264
|
+
queryHandle.result.finally(() => {
|
|
265
|
+
// remove from cache after completion
|
|
266
|
+
set((state) => produce(state, (draft) => {
|
|
267
|
+
delete draft.db.queryCache[queryKey];
|
|
268
|
+
}));
|
|
269
|
+
});
|
|
270
|
+
return queryHandle;
|
|
144
271
|
},
|
|
145
272
|
},
|
|
146
273
|
};
|
package/dist/DuckDbSlice.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DuckDbSlice.js","sourceRoot":"","sources":["../src/DuckDbSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createBaseSlice,\n ProjectState,\n useBaseProjectStore,\n} from '@sqlrooms/project';\nimport * as arrow from 'apache-arrow';\nimport {produce} from 'immer';\nimport deepEquals from 'fast-deep-equal';\nimport {z} from 'zod';\nimport {StateCreator} from 'zustand';\nimport {DuckDbConnector} from './connectors/DuckDbConnector';\nimport {WasmDuckDbConnector} from './connectors/WasmDuckDbConnector';\nimport {getColValAsNumber} from './duckdb-utils';\nimport {DataTable, TableColumn} from './types';\n\nexport const DuckDbSliceConfig = z.object({\n // nothing yet\n});\nexport type DuckDbSliceConfig = z.infer<typeof DuckDbSliceConfig>;\n\nexport function createDefaultDuckDbConfig(): DuckDbSliceConfig {\n return {\n // nothing yet\n };\n}\n\n/**\n * State and actions for the DuckDB slice\n */\nexport type DuckDbSliceState = {\n db: {\n /**\n * The DuckDB connector instance\n */\n connector: DuckDbConnector;\n schema: string;\n\n tables: DataTable[];\n tableRowCounts: {[tableName: string]: number};\n\n /**\n * Set a new DuckDB connector\n */\n setConnector: (connector: DuckDbConnector) => void;\n\n /**\n * Initialize the connector (creates a WasmDuckDbConnector if none exists)\n */\n initialize: () => Promise<void>;\n\n /**\n * Close and clean up the connector\n */\n destroy: () => Promise<void>;\n\n /**\n * Add a table to the project.\n * @param tableName - The name of the table to add.\n * @param data - The data to add to the table: an arrow table or an array of records.\n * @returns A promise that resolves to the table that was added.\n */\n addTable(\n tableName: string,\n data: arrow.Table | Record<string, unknown>[],\n ): Promise<DataTable>;\n getTable(tableName: string): DataTable | undefined;\n setTableRowCount(tableName: string, rowCount: number): void;\n findTableByName(tableName: string): DataTable | undefined;\n /**\n * Refresh table schemas from the database.\n * @returns A promise that resolves to the updated tables.\n */\n refreshTableSchemas(): Promise<DataTable[]>;\n /**\n * Get the connector. If it's not initialized, it will be initialized.\n */\n getConnector: () => Promise<DuckDbConnector>;\n\n /**\n * Get the tables in the database\n *\n * @param schema - The schema to get the tables from. Defaults to 'main'. Pass '*' to get all tables.\n * @returns The tables in the database.\n */\n getTables: (schema?: string) => Promise<string[]>;\n\n /**\n * Get the row count of a table\n */\n getTableRowCount: (tableName: string, schema?: string) => Promise<number>;\n\n /**\n * Get the schema of a table\n */\n getTableSchema: (tableName: string, schema?: string) => Promise<DataTable>;\n\n /**\n * Get the schemas of all tables in the database.\n *\n * @param schema - The schema to get the tables from. Defaults to 'main'. Pass '*' to get all schemas.\n * @returns The schemas of all tables in the database.\n */\n getTableSchemas: (schema?: string) => Promise<DataTable[]>;\n\n /**\n * Check if a table exists\n */\n checkTableExists: (tableName: string, schema?: string) => Promise<boolean>;\n\n /**\n * Drop a table\n */\n dropTable: (tableName: string) => Promise<void>;\n\n /**\n * Create a table from a query.\n * @param tableName - The name of the table to create.\n * @param query - The query to create the table from.\n * @returns The table that was created.\n */\n createTableFromQuery: (\n tableName: string,\n query: string,\n ) => Promise<{tableName: string; rowCount: number}>;\n };\n};\n\n/**\n * Create a DuckDB slice for managing the connector\n */\nexport function createDuckDbSlice({\n connector = new WasmDuckDbConnector(),\n}: {\n connector?: DuckDbConnector;\n}): StateCreator<DuckDbSliceState> {\n return createBaseSlice<DuckDbSliceConfig, DuckDbSliceState>((set, get) => {\n return {\n db: {\n connector, // Will be initialized during init\n schema: 'main',\n tables: [],\n tableRowCounts: {},\n\n setConnector: (connector: DuckDbConnector) => {\n set(\n produce((state) => {\n state.config.dataSources = [];\n state.db.connector = connector;\n }),\n );\n },\n\n initialize: async () => {\n await get().db.connector.initialize();\n },\n\n getConnector: async () => {\n await get().db.initialize();\n return get().db.connector;\n },\n\n destroy: async () => {\n try {\n if (get().db.connector) {\n await get().db.connector.destroy();\n }\n } catch (err) {\n console.error('Error during DuckDB shutdown:', err);\n }\n },\n\n async createTableFromQuery(tableName: string, query: string) {\n const connector = await get().db.getConnector();\n const rowCount = getColValAsNumber(\n await connector.query(\n `CREATE OR REPLACE TABLE main.${tableName} AS (\n ${query}\n )`,\n ),\n );\n return {tableName, rowCount};\n },\n\n async getTables(schema = 'main'): Promise<string[]> {\n const connector = await get().db.getConnector();\n const tablesResults = await connector.query(\n `SELECT * FROM information_schema.tables \n ${schema === '*' ? '' : `WHERE table_schema = '${schema}'`}\n ORDER BY table_name`,\n );\n const tableNames: string[] = [];\n for (let i = 0; i < tablesResults.numRows; i++) {\n tableNames.push(tablesResults.getChild('table_name')?.get(i));\n }\n return tableNames;\n },\n\n async getTableSchema(\n tableName: string,\n schema = 'main',\n ): Promise<DataTable> {\n const connector = await get().db.getConnector();\n const describeResults = await connector.query(\n `DESCRIBE ${schema}.${tableName}`,\n );\n const columnNames = describeResults.getChild('column_name');\n const columnTypes = describeResults.getChild('column_type');\n const columns: TableColumn[] = [];\n for (let di = 0; di < describeResults.numRows; di++) {\n const columnName = columnNames?.get(di);\n const columnType = columnTypes?.get(di);\n columns.push({name: columnName, type: columnType});\n }\n return {\n tableName,\n columns,\n };\n },\n\n async getTableRowCount(\n tableName: string,\n schema = 'main',\n ): Promise<number> {\n const connector = await get().db.getConnector();\n const result = await connector.query(\n `SELECT COUNT(*) FROM ${schema}.${tableName}`,\n );\n return getColValAsNumber(result);\n },\n\n async getTableSchemas(schema = 'main'): Promise<DataTable[]> {\n const tableNames = await get().db.getTables(schema);\n const tablesInfo: DataTable[] = [];\n for (const tableName of tableNames) {\n tablesInfo.push(await get().db.getTableSchema(tableName, schema));\n }\n return tablesInfo;\n },\n\n async checkTableExists(\n tableName: string,\n schema = 'main',\n ): Promise<boolean> {\n const connector = await get().db.getConnector();\n const res = await connector.query(\n `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '${schema}' AND table_name = '${tableName}'`,\n );\n return getColValAsNumber(res) > 0;\n },\n\n async dropTable(tableName: string): Promise<void> {\n const connector = await get().db.getConnector();\n await connector.query(`DROP TABLE IF EXISTS ${tableName};`);\n },\n\n async addTable(tableName, data) {\n const {tables} = get().db;\n const table = tables.find((t) => t.tableName === tableName);\n if (table) {\n return table;\n }\n\n const {db} = get();\n if (data instanceof arrow.Table) {\n await db.connector.loadArrow(data, tableName);\n } else {\n await db.connector.loadObjects(data, tableName);\n }\n const newTable = await db.getTableSchema(tableName);\n\n set((state) =>\n produce(state, (draft) => {\n draft.db.tables.push(newTable);\n }),\n );\n return newTable;\n },\n\n setTableRowCount: (tableName, rowCount) =>\n set((state) =>\n produce(state, (draft) => {\n draft.db.tableRowCounts[tableName] = rowCount;\n }),\n ),\n\n getTable(tableName) {\n return get().db.tables.find((t) => t.tableName === tableName);\n },\n\n findTableByName(tableName: string) {\n return get().db.tables.find((t) => t.tableName === tableName);\n },\n\n async refreshTableSchemas(): Promise<DataTable[]> {\n const newTables = await get().db.getTableSchemas();\n const currentTables = get().db.tables;\n\n // Only update if there's an actual change in the schemas\n if (!deepEquals(newTables, currentTables)) {\n set((state) =>\n produce(state, (draft) => {\n draft.db.tables = newTables;\n }),\n );\n }\n return newTables;\n },\n },\n };\n });\n}\n\ntype ProjectStateWithDuckDb = ProjectState<DuckDbSliceConfig> &\n DuckDbSliceState;\n\nexport function useStoreWithDuckDb<T>(\n selector: (state: ProjectStateWithDuckDb) => T,\n): T {\n return useBaseProjectStore<\n DuckDbSliceConfig,\n ProjectState<DuckDbSliceConfig>,\n T\n >((state) => selector(state as unknown as ProjectStateWithDuckDb));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DuckDbSlice.js","sourceRoot":"","sources":["../src/DuckDbSlice.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEf,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,UAAU,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAC,OAAO,EAAC,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAC,mBAAmB,EAAC,MAAM,kCAAkC,CAAC;AACrE,OAAO,EACL,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EAEtB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAC,mBAAmB,IAAI,mBAAmB,EAAC,MAAM,cAAc,CAAC;AAGxE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;AACxC,cAAc;CACf,CAAC,CAAC;AAQH,MAAM,UAAU,yBAAyB;IACvC,OAAO;IACL,cAAc;KACf,CAAC;AACJ,CAAC;AAkMD;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,SAAS,GAAG,IAAI,mBAAmB,EAAE,GAGtC;IACC,OAAO,eAAe,CAAsC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACvE,OAAO;YACL,EAAE,EAAE;gBACF,SAAS,EAAE,kCAAkC;gBAC7C,MAAM,EAAE,MAAM,EAAE,uEAAuE;gBACvF,wBAAwB,EAAE,KAAK;gBAC/B,MAAM,EAAE,EAAE;gBACV,cAAc,EAAE,EAAE;gBAClB,UAAU,EAAE,SAAS;gBACrB,UAAU,EAAE,EAAE;gBAEd,YAAY,EAAE,CAAC,SAA0B,EAAE,EAAE;oBAC3C,GAAG,CACD,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;wBAChB,KAAK,CAAC,MAAM,CAAC,WAAW,GAAG,EAAE,CAAC;wBAC9B,KAAK,CAAC,EAAE,CAAC,SAAS,GAAG,SAAS,CAAC;oBACjC,CAAC,CAAC,CACH,CAAC;gBACJ,CAAC;gBAED,UAAU,EAAE,KAAK,IAAI,EAAE;oBACrB,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;oBACtC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC;gBACvC,CAAC;gBAED,YAAY,EAAE,KAAK,IAAI,EAAE;oBACvB,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;gBAC5B,CAAC;gBAED,OAAO,EAAE,KAAK,IAAI,EAAE;oBAClB,IAAI,CAAC;wBACH,IAAI,GAAG,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;4BACvB,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;wBACrC,CAAC;oBACH,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;oBACtD,CAAC;gBACH,CAAC;gBAED,KAAK,CAAC,oBAAoB,CACxB,SAAsC,EACtC,KAAa;oBAEb,MAAM,aAAa,GAAG,oBAAoB,CAAC,SAAS,CAAC;wBACnD,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,sBAAsB,CAAC,EAAC,KAAK,EAAE,SAAS,EAAC,CAAC,CAAC;oBAE/C,MAAM,SAAS,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;oBAEhD,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;oBAC7C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC5B,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;oBAC9D,CAAC;oBACD,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAW,CAAC;oBAC1C,MAAM,WAAW,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;oBAC9D,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;wBACtB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;oBAC3D,CAAC;oBAED,MAAM,QAAQ,GAAG,iBAAiB,CAChC,MAAM,SAAS,CAAC,KAAK,CACnB,2BAA2B,aAAa;gBACtC,UAAU,CAAC,CAAC,CAAC;cACf,CACD,CAAC,MAAM,CACT,CAAC;oBACF,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAC,CAAC;gBAC/B,CAAC;gBAED;;mBAEG;gBACH,KAAK,CAAC,SAAS,CAAC,MAAM;oBACpB,MAAM,YAAY,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAC,MAAM,EAAC,CAAC,CAAC;oBAC/D,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAChD,CAAC;gBAED;;mBAEG;gBACH,KAAK,CAAC,cAAc,CAAC,SAAiB,EAAE,MAAM,GAAG,MAAM;oBACrD,MAAM,QAAQ,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC;wBAC/C,MAAM;wBACN,KAAK,EAAE,SAAS;qBACjB,CAAC,CAAC;oBACH,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACrB,CAAC;gBAED;;mBAEG;gBACH,KAAK,CAAC,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;oBAC3C,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAC,KAAK,EAAE,MAAM,EAAC,CAAC,CAAC;gBACrD,CAAC;gBAED,KAAK,CAAC,iBAAiB,CAAC,SAAsC;oBAC5D,MAAM,EAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAC,GAC7B,OAAO,SAAS,KAAK,QAAQ;wBAC3B,CAAC,CAAC,EAAC,KAAK,EAAE,SAAS,EAAC;wBACpB,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;oBACtB,MAAM,SAAS,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;oBAChD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAClC,wBAAwB,sBAAsB,CAAC;wBAC7C,MAAM;wBACN,QAAQ;wBACR,KAAK;qBACN,CAAC,EAAE,CACL,CAAC,MAAM,CAAC;oBACT,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;gBACnC,CAAC;gBAED;;mBAEG;gBACH,KAAK,CAAC,eAAe,CAAC,MAAM;oBAC1B,OAAO,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAC,MAAM,EAAC,CAAC,CAAC;gBACnD,CAAC;gBAED,KAAK,CAAC,gBAAgB,CACpB,MAA6C;oBAE7C,MAAM,EAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAC,GAAG,MAAM,IAAI,EAAE,CAAC;oBAC/C,MAAM,eAAe,GAAG,MAAM,SAAS,CAAC,KAAK,CAC3C;;;;;cAME,MAAM,IAAI,QAAQ,IAAI,KAAK;wBACzB,CAAC,CAAC,SAAS;4BACP,MAAM,CAAC,CAAC,CAAC,aAAa,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;4BAC9C,QAAQ,CAAC,CAAC,CAAC,eAAe,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;4BACpD,KAAK,CAAC,CAAC,CAAC,WAAW,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;yBAC3C;6BACE,MAAM,CAAC,OAAO,CAAC;6BACf,IAAI,CAAC,OAAO,CAAC,EAAE;wBACpB,CAAC,CAAC,EACN,EAAE,CACH,CAAC,MAAM,CAAC;oBAET,MAAM,SAAS,GAAgB,EAAE,CAAC;oBAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;wBACjD,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;wBAC9D,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;wBAC1D,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;wBACvD,MAAM,WAAW,GAAG,eAAe;6BAChC,QAAQ,CAAC,cAAc,CAAC;4BACzB,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;wBACX,MAAM,WAAW,GAAG,eAAe;6BAChC,QAAQ,CAAC,cAAc,CAAC;4BACzB,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;wBACX,MAAM,OAAO,GAAkB,EAAE,CAAC;wBAClC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;4BAC/C,OAAO,CAAC,IAAI,CAAC;gCACX,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gCACzB,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;6BAC1B,CAAC,CAAC;wBACL,CAAC;wBACD,SAAS,CAAC,IAAI,CAAC;4BACb,KAAK,EAAE,sBAAsB,CAAC,EAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAC,CAAC;4BACxD,QAAQ;4BACR,MAAM;4BACN,SAAS,EAAE,KAAK;4BAChB,OAAO;yBACR,CAAC,CAAC;oBACL,CAAC;oBACD,OAAO,SAAS,CAAC;gBACnB,CAAC;gBAED,KAAK,CAAC,gBAAgB,CAAC,SAAsC;oBAC3D,MAAM,aAAa,GAAG,oBAAoB,CAAC,SAAS,CAAC;wBACnD,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,sBAAsB,CAAC,EAAC,KAAK,EAAE,SAAS,EAAC,CAAC,CAAC;oBAC/C,MAAM,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAClE,IAAI,CAAC,KAAK,EAAE,CAAC;wBACX,OAAO,KAAK,CAAC;oBACf,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,KAAK,CAAC,SAAS,CAAC,SAAS;oBACvB,MAAM,SAAS,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;oBAChD,MAAM,cAAc,GAAG,oBAAoB,CAAC,SAAS,CAAC;wBACpD,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,sBAAsB,CAAC,EAAC,KAAK,EAAE,SAAS,EAAC,CAAC,CAAC;oBAC/C,MAAM,SAAS,CAAC,KAAK,CAAC,wBAAwB,cAAc,GAAG,CAAC;yBAC7D,MAAM,CAAC;oBACV,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC;gBACvC,CAAC;gBAED,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI;oBAC5B,MAAM,aAAa,GAAG,oBAAoB,CAAC,SAAS,CAAC;wBACnD,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,sBAAsB,CAAC,EAAC,KAAK,EAAE,SAAS,EAAC,CAAC,CAAC;oBAE/C,MAAM,EAAC,EAAE,EAAC,GAAG,GAAG,EAAE,CAAC;oBACnB,IAAI,IAAI,YAAY,KAAK,CAAC,KAAK,EAAE,CAAC;wBAChC,wCAAwC;wBACxC,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC;oBAC/D,CAAC;yBAAM,CAAC;wBACN,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,aAAa,CAAC,QAAQ,EAAE,EAAE;4BAC7D,OAAO,EAAE,IAAI;yBACd,CAAC,CAAC;oBACL,CAAC;oBACD,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC/D,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACd,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;oBACzC,CAAC;oBACD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;wBACvB,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACjC,CAAC,CAAC,CACH,CAAC;oBACF,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC;oBACrC,OAAO,QAAQ,CAAC;gBAClB,CAAC;gBAED,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ;oBACxC,MAAM,aAAa,GAAG,oBAAoB,CAAC,SAAS,CAAC;wBACnD,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,sBAAsB,CAAC,EAAC,KAAK,EAAE,SAAS,EAAC,CAAC,CAAC;oBAC/C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;wBACvB,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC;oBAC/D,CAAC,CAAC,CACH,CAAC;gBACJ,CAAC;gBAED,QAAQ,CAAC,SAAS;oBAChB,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;gBAC7C,CAAC;gBAED,eAAe,CAAC,SAAsC;oBACpD,MAAM,aAAa,GAAG,CACpB,oBAAoB,CAAC,SAAS,CAAC;wBAC7B,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,sBAAsB,CAAC,EAAC,KAAK,EAAE,SAAS,EAAC,CAAC,CAC/C,CAAC,QAAQ,EAAE,CAAC;oBACb,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CACzB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,aAAa,CAC5C,CAAC;gBACJ,CAAC;gBAED,KAAK,CAAC,mBAAmB;oBACvB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;wBACvB,KAAK,CAAC,EAAE,CAAC,wBAAwB,GAAG,IAAI,CAAC;oBAC3C,CAAC,CAAC,CACH,CAAC;oBACF,IAAI,CAAC;wBACH,MAAM,SAAS,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC;wBACpD,yDAAyD;wBACzD,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;4BAC5C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;gCACvB,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC;gCAC5B,KAAK,CAAC,EAAE,CAAC,WAAW,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;4BACxD,CAAC,CAAC,CACH,CAAC;wBACJ,CAAC;wBACD,OAAO,SAAS,CAAC;oBACnB,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,GAAG,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;wBACpC,OAAO,EAAE,CAAC;oBACZ,CAAC;4BAAS,CAAC;wBACT,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;4BACvB,KAAK,CAAC,EAAE,CAAC,wBAAwB,GAAG,KAAK,CAAC;wBAC5C,CAAC,CAAC,CACH,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAED,KAAK,CAAC,eAAe,CAAC,GAAW;oBAC/B,MAAM,SAAS,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;oBAChD,MAAM,WAAW,GAAG,CAClB,MAAM,SAAS,CAAC,KAAK,CACnB,6BAA6B,SAAS,CAAC,GAAG,CAAC,GAAG,CAC/C,CAAC,MAAM,CACT;yBACE,UAAU,CAAC,CAAC,CAAC;wBACd,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;oBACX,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;gBACjC,CAAC;gBAED,KAAK,CAAC,UAAU,CAAC,KAAa;oBAC5B,qCAAqC;oBACrC,MAAM,QAAQ,GAAG,GAAG,KAAK,EAAE,CAAC;oBAC5B,MAAM,SAAS,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;oBAEhD,uDAAuD;oBACvD,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;oBACpD,IAAI,aAAa,EAAE,CAAC;wBAClB,OAAO,aAAa,CAAC;oBACvB,CAAC;oBAED,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBAC3C,qCAAqC;oBACrC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;wBACvB,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,WAAW,CAAC;oBAC9C,CAAC,CAAC,CACH,CAAC;oBAEF,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;wBAC9B,qCAAqC;wBACrC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACZ,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;4BACvB,OAAO,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;wBACvC,CAAC,CAAC,CACH,CAAC;oBACJ,CAAC,CAAC,CAAC;oBAEH,OAAO,WAAW,CAAC;gBACrB,CAAC;aACF;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAKD,MAAM,UAAU,kBAAkB,CAChC,QAA8C;IAE9C,OAAO,mBAAmB,CAIxB,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAA0C,CAAC,CAAC,CAAC;AACrE,CAAC","sourcesContent":["import {\n createBaseSlice,\n ProjectState,\n useBaseProjectStore,\n} from '@sqlrooms/project';\nimport * as arrow from 'apache-arrow';\nimport deepEquals from 'fast-deep-equal';\nimport {produce} from 'immer';\nimport {z} from 'zod';\nimport {StateCreator} from 'zustand';\nimport {DuckDbConnector, QueryHandle} from './connectors/DuckDbConnector';\nimport {WasmDuckDbConnector} from './connectors/WasmDuckDbConnector';\nimport {\n escapeId,\n escapeVal,\n getColValAsNumber,\n isQualifiedTableName,\n makeQualifiedTableName,\n QualifiedTableName,\n splitSqlStatements,\n} from './duckdb-utils';\nimport {createDbSchemaTrees as createDbSchemaTrees} from './schemaTree';\nimport {DataTable, TableColumn, DbSchemaNode} from './types';\n\nexport const DuckDbSliceConfig = z.object({\n // nothing yet\n});\nexport type DuckDbSliceConfig = z.infer<typeof DuckDbSliceConfig>;\n\nexport type SchemaAndDatabase = {\n schema?: string;\n database?: string;\n};\n\nexport function createDefaultDuckDbConfig(): DuckDbSliceConfig {\n return {\n // nothing yet\n };\n}\n\n/**\n * State and actions for the DuckDB slice\n */\nexport type DuckDbSliceState = {\n db: {\n /**\n * The DuckDB connector instance\n */\n connector: DuckDbConnector;\n /**\n * @deprecated We shouldn't limit the schema to a single one.\n */\n schema: string;\n\n /**\n * Cache of refreshed table schemas\n */\n tables: DataTable[];\n /**\n * Cache of row counts for tables\n */\n tableRowCounts: {[tableName: string]: number};\n /**\n * Cache of schema trees for tables\n */\n schemaTrees?: DbSchemaNode[];\n /**\n * Cache of currently running query handles\n */\n queryCache: {[key: string]: QueryHandle};\n /**\n * Whether the table schemas are being refreshed\n */\n isRefreshingTableSchemas: boolean;\n\n /**\n * Set a new DuckDB connector\n */\n setConnector: (connector: DuckDbConnector) => void;\n\n /**\n * Initialize the connector (creates a WasmDuckDbConnector if none exists)\n */\n initialize: () => Promise<void>;\n\n /**\n * Close and clean up the connector\n */\n destroy: () => Promise<void>;\n\n /**\n * Add a table to the project.\n * @param tableName - The name of the table to add.\n * @param data - The data to add to the table: an arrow table or an array of records.\n * @returns A promise that resolves to the table that was added.\n */\n addTable(\n tableName: string | QualifiedTableName,\n data: arrow.Table | Record<string, unknown>[],\n ): Promise<DataTable>;\n\n /**\n * Load the schemas of the tables in the database.\n */\n loadTableSchemas(\n filter?: SchemaAndDatabase & {table?: string},\n ): Promise<DataTable[]>;\n\n /**\n * @deprecated Use findTableByName instead\n */\n getTable(tableName: string): DataTable | undefined;\n\n /**\n * @internal Avoid using this directly, it's for internal use.\n */\n setTableRowCount(\n tableName: string | QualifiedTableName,\n rowCount: number,\n ): void;\n\n /**\n * Find a table by name in the last refreshed table schemas\n * @param tableName - The name of the table to find or a qualified table name.\n * @returns The table or undefined if not found.\n */\n findTableByName(\n tableName: string | QualifiedTableName,\n ): DataTable | undefined;\n\n /**\n * Refresh table schemas from the database.\n * @returns A promise that resolves to the updated tables.\n */\n refreshTableSchemas(): Promise<DataTable[]>;\n /**\n * Get the connector. If it's not initialized, it will be initialized.\n */\n getConnector: () => Promise<DuckDbConnector>;\n\n /**\n * @deprecated Use .loadTableRowCount() instead\n */\n getTableRowCount: (table: string, schema?: string) => Promise<number>;\n\n /**\n * Load the row count of a table\n */\n loadTableRowCount: (\n tableName: string | QualifiedTableName,\n ) => Promise<number>;\n\n /**\n * Execute a query with query handle (not result) caching and deduplication\n * @param query - The SQL query to execute\n * @returns The QueryHandle for the query or null if disabled\n */\n executeSql: (query: string) => Promise<QueryHandle | null>;\n\n /**\n * @deprecated Use .tables or .loadTableSchemas() instead\n */\n getTables: (schema?: string) => Promise<string[]>;\n\n /**\n * @deprecated Use .loadTableSchemas() instead\n */\n getTableSchema: (\n tableName: string,\n schema?: string,\n ) => Promise<DataTable | undefined>;\n\n /**\n * @deprecated Use .tables or .loadTableSchemas() instead\n */\n getTableSchemas: (schema?: string) => Promise<DataTable[]>;\n\n /**\n * Check if a table exists\n */\n checkTableExists: (\n tableName: string | QualifiedTableName,\n ) => Promise<boolean>;\n\n /**\n * Delete a table with optional schema and database\n * @param tableName - The name of the table to delete\n * @param options - Optional parameters including schema and database\n */\n dropTable: (tableName: string | QualifiedTableName) => Promise<void>;\n\n /**\n * Create a table from a query.\n * @param tableName - The name of the table to create.\n * @param query - The query to create the table from.\n * @returns The table that was created.\n */\n createTableFromQuery: (\n tableName: string | QualifiedTableName,\n query: string,\n ) => Promise<{tableName: string | QualifiedTableName; rowCount: number}>;\n\n /**\n * Parse a SQL SELECT statement to JSON\n * @param sql - The SQL SELECT statement to parse.\n * @returns A promise that resolves to the parsed JSON.\n */\n sqlSelectToJson: (sql: string) => Promise<\n | {\n error: true;\n error_type: string;\n error_message: string;\n error_subtype: string;\n position: string;\n }\n | {\n error: false;\n statements: {\n node: {\n from_table: {\n alias: string;\n show_type: string;\n table_name: string;\n };\n select_list: Record<string, unknown>[];\n };\n }[];\n }\n >;\n };\n};\n\n/**\n * Create a DuckDB slice for managing the connector\n */\nexport function createDuckDbSlice({\n connector = new WasmDuckDbConnector(),\n}: {\n connector?: DuckDbConnector;\n}): StateCreator<DuckDbSliceState> {\n return createBaseSlice<DuckDbSliceConfig, DuckDbSliceState>((set, get) => {\n return {\n db: {\n connector, // Will be initialized during init\n schema: 'main', // TODO: remove schema, we should not limit the schema to a single one.\n isRefreshingTableSchemas: false,\n tables: [],\n tableRowCounts: {},\n schemaTree: undefined,\n queryCache: {},\n\n setConnector: (connector: DuckDbConnector) => {\n set(\n produce((state) => {\n state.config.dataSources = [];\n state.db.connector = connector;\n }),\n );\n },\n\n initialize: async () => {\n await get().db.connector.initialize();\n await get().db.refreshTableSchemas();\n },\n\n getConnector: async () => {\n return get().db.connector;\n },\n\n destroy: async () => {\n try {\n if (get().db.connector) {\n await get().db.connector.destroy();\n }\n } catch (err) {\n console.error('Error during DuckDB shutdown:', err);\n }\n },\n\n async createTableFromQuery(\n tableName: string | QualifiedTableName,\n query: string,\n ) {\n const qualifiedName = isQualifiedTableName(tableName)\n ? tableName\n : makeQualifiedTableName({table: tableName});\n\n const connector = await get().db.getConnector();\n\n const statements = splitSqlStatements(query);\n if (statements.length !== 1) {\n throw new Error('Query must contain exactly one statement');\n }\n const statement = statements[0] as string;\n const parsedQuery = await get().db.sqlSelectToJson(statement);\n if (parsedQuery.error) {\n throw new Error('Query is not a valid SELECT statement');\n }\n\n const rowCount = getColValAsNumber(\n await connector.query(\n `CREATE OR REPLACE TABLE ${qualifiedName} AS (\n ${statements[0]}\n )`,\n ).result,\n );\n return {tableName, rowCount};\n },\n\n /**\n * @deprecated Use .tables or .loadTableSchemas() instead\n */\n async getTables(schema) {\n const tableSchemas = await get().db.loadTableSchemas({schema});\n return tableSchemas.map((t) => t.table.table);\n },\n\n /**\n * @deprecated Use .loadTableSchemas() instead\n */\n async getTableSchema(tableName: string, schema = 'main') {\n const newLocal = await get().db.loadTableSchemas({\n schema,\n table: tableName,\n });\n return newLocal[0];\n },\n\n /**\n * @deprecated Use .loadTableRowCount() instead\n */\n async getTableRowCount(table, schema = 'main') {\n return get().db.loadTableRowCount({table, schema});\n },\n\n async loadTableRowCount(tableName: string | QualifiedTableName) {\n const {schema, database, table} =\n typeof tableName === 'string'\n ? {table: tableName}\n : tableName || {};\n const connector = await get().db.getConnector();\n const result = await connector.query(\n `SELECT COUNT(*) FROM ${makeQualifiedTableName({\n schema,\n database,\n table,\n })}`,\n ).result;\n return getColValAsNumber(result);\n },\n\n /**\n * @deprecated Use .loadTableSchemas() instead\n */\n async getTableSchemas(schema) {\n return await get().db.loadTableSchemas({schema});\n },\n\n async loadTableSchemas(\n filter?: SchemaAndDatabase & {table?: string},\n ): Promise<DataTable[]> {\n const {schema, database, table} = filter || {};\n const describeResults = await connector.query(\n `FROM (DESCRIBE)\n SELECT \n (CASE WHEN database = current_database() THEN NULL ELSE database END) AS database,\n (CASE WHEN schema = current_schema() THEN NULL ELSE schema END) AS schema,\n name, column_names, column_types\n ${\n schema || database || table\n ? `WHERE ${[\n schema ? `schema = '${escapeId(schema)}'` : '',\n database ? `database = '${escapeId(database)}'` : '',\n table ? `name = '${escapeId(table)}'` : '',\n ]\n .filter(Boolean)\n .join(' AND ')}`\n : ''\n }`,\n ).result;\n\n const newTables: DataTable[] = [];\n for (let i = 0; i < describeResults.numRows; i++) {\n const database = describeResults.getChild('database')?.get(i);\n const schema = describeResults.getChild('schema')?.get(i);\n const table = describeResults.getChild('name')?.get(i);\n const columnNames = describeResults\n .getChild('column_names')\n ?.get(i);\n const columnTypes = describeResults\n .getChild('column_types')\n ?.get(i);\n const columns: TableColumn[] = [];\n for (let di = 0; di < columnNames.length; di++) {\n columns.push({\n name: columnNames.get(di),\n type: columnTypes.get(di),\n });\n }\n newTables.push({\n table: makeQualifiedTableName({database, schema, table}),\n database,\n schema,\n tableName: table,\n columns,\n });\n }\n return newTables;\n },\n\n async checkTableExists(tableName: string | QualifiedTableName) {\n const qualifiedName = isQualifiedTableName(tableName)\n ? tableName\n : makeQualifiedTableName({table: tableName});\n const table = (await get().db.loadTableSchemas(qualifiedName))[0];\n if (!table) {\n return false;\n }\n return true;\n },\n\n async dropTable(tableName): Promise<void> {\n const connector = await get().db.getConnector();\n const qualifiedTable = isQualifiedTableName(tableName)\n ? tableName\n : makeQualifiedTableName({table: tableName});\n await connector.query(`DROP TABLE IF EXISTS ${qualifiedTable};`)\n .result;\n await get().db.refreshTableSchemas();\n },\n\n async addTable(tableName, data) {\n const qualifiedName = isQualifiedTableName(tableName)\n ? tableName\n : makeQualifiedTableName({table: tableName});\n\n const {db} = get();\n if (data instanceof arrow.Table) {\n // TODO: make sure the table is replaced\n await db.connector.loadArrow(data, qualifiedName.toString());\n } else {\n await db.connector.loadObjects(data, qualifiedName.toString(), {\n replace: true,\n });\n }\n const newTable = (await db.loadTableSchemas(qualifiedName))[0];\n if (!newTable) {\n throw new Error('Failed to add table');\n }\n set((state) =>\n produce(state, (draft) => {\n draft.db.tables.push(newTable);\n }),\n );\n await get().db.refreshTableSchemas();\n return newTable;\n },\n\n async setTableRowCount(tableName, rowCount) {\n const qualifiedName = isQualifiedTableName(tableName)\n ? tableName\n : makeQualifiedTableName({table: tableName});\n set((state) =>\n produce(state, (draft) => {\n draft.db.tableRowCounts[qualifiedName.toString()] = rowCount;\n }),\n );\n },\n\n getTable(tableName) {\n return get().db.findTableByName(tableName);\n },\n\n findTableByName(tableName: string | QualifiedTableName) {\n const qualifiedName = (\n isQualifiedTableName(tableName)\n ? tableName\n : makeQualifiedTableName({table: tableName})\n ).toString();\n return get().db.tables.find(\n (t) => t.table.toString() === qualifiedName,\n );\n },\n\n async refreshTableSchemas(): Promise<DataTable[]> {\n set((state) =>\n produce(state, (draft) => {\n draft.db.isRefreshingTableSchemas = true;\n }),\n );\n try {\n const newTables = await get().db.loadTableSchemas();\n // Only update if there's an actual change in the schemas\n if (!deepEquals(newTables, get().db.tables)) {\n set((state) =>\n produce(state, (draft) => {\n draft.db.tables = newTables;\n draft.db.schemaTrees = createDbSchemaTrees(newTables);\n }),\n );\n }\n return newTables;\n } catch (err) {\n get().project.captureException(err);\n return [];\n } finally {\n set((state) =>\n produce(state, (draft) => {\n draft.db.isRefreshingTableSchemas = false;\n }),\n );\n }\n },\n\n async sqlSelectToJson(sql: string) {\n const connector = await get().db.getConnector();\n const parsedQuery = (\n await connector.query(\n `SELECT json_serialize_sql(${escapeVal(sql)})`,\n ).result\n )\n .getChildAt(0)\n ?.get(0);\n return JSON.parse(parsedQuery);\n },\n\n async executeSql(query: string): Promise<QueryHandle | null> {\n // Create a unique key for this query\n const queryKey = `${query}`;\n const connector = await get().db.getConnector();\n\n // Check if we already have a cached query for this key\n const existingQuery = get().db.queryCache[queryKey];\n if (existingQuery) {\n return existingQuery;\n }\n\n const queryHandle = connector.query(query);\n // Cache the query handle immediately\n set((state) =>\n produce(state, (draft) => {\n draft.db.queryCache[queryKey] = queryHandle;\n }),\n );\n\n queryHandle.result.finally(() => {\n // remove from cache after completion\n set((state) =>\n produce(state, (draft) => {\n delete draft.db.queryCache[queryKey];\n }),\n );\n });\n\n return queryHandle;\n },\n },\n };\n });\n}\n\ntype ProjectStateWithDuckDb = ProjectState<DuckDbSliceConfig> &\n DuckDbSliceState;\n\nexport function useStoreWithDuckDb<T>(\n selector: (state: ProjectStateWithDuckDb) => T,\n): T {\n return useBaseProjectStore<\n DuckDbSliceConfig,\n ProjectState<DuckDbSliceConfig>,\n T\n >((state) => selector(state as unknown as ProjectStateWithDuckDb));\n}\n"]}
|