@visactor/vquery 0.1.45 → 0.1.47
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/dataSourceBuilder/dataSourceBuilder.d.ts +16 -0
- package/dist/dataSourceBuilder/index.d.ts +1 -0
- package/dist/dataset/dataset.d.ts +21 -0
- package/dist/dataset/index.d.ts +1 -0
- package/dist/db/duckDb.d.ts +2 -7
- package/dist/db/indexedDb.d.ts +14 -4
- package/dist/index.cjs +241 -77
- package/dist/index.d.ts +2 -0
- package/dist/index.js +229 -77
- package/dist/types/DataSet.d.ts +11 -0
- package/dist/types/DataSource.d.ts +7 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/url.d.ts +3 -0
- package/dist/vquery.d.ts +24 -29
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DataSourceType, DataSourceValue } from '../types';
|
|
2
|
+
export declare class DataSourceBuilder {
|
|
3
|
+
private type;
|
|
4
|
+
private value;
|
|
5
|
+
constructor(type: DataSourceType, value: DataSourceValue);
|
|
6
|
+
static from(type: DataSourceType, value: DataSourceValue): DataSourceBuilder;
|
|
7
|
+
build(): Promise<{
|
|
8
|
+
type: DataSourceType;
|
|
9
|
+
blob: Blob;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* 将不同类型的数据转换为Blob
|
|
13
|
+
*/
|
|
14
|
+
private static convertToBlob;
|
|
15
|
+
private static fetchBlob;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DataSourceBuilder } from './dataSourceBuilder';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DatasetColumn } from '../types';
|
|
2
|
+
import { DuckDB } from '../db/duckDb';
|
|
3
|
+
import { IndexedDB } from '../db/indexedDb';
|
|
4
|
+
export declare class Dataset {
|
|
5
|
+
private duckDB;
|
|
6
|
+
private indexedDB;
|
|
7
|
+
private _datasetId;
|
|
8
|
+
constructor(duckDB: DuckDB, indexedDB: IndexedDB, datasetId: string);
|
|
9
|
+
init(temporaryStructs?: DatasetColumn[]): Promise<void>;
|
|
10
|
+
queryBySQL(sql: string): Promise<{
|
|
11
|
+
performance: {
|
|
12
|
+
startAt: string;
|
|
13
|
+
endAt: string;
|
|
14
|
+
duration: number;
|
|
15
|
+
};
|
|
16
|
+
dataset: any[];
|
|
17
|
+
table: any;
|
|
18
|
+
}>;
|
|
19
|
+
disconnect(): Promise<void>;
|
|
20
|
+
get datasetId(): string;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Dataset } from './dataset';
|
package/dist/db/duckDb.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { QueryResult } from '../types';
|
|
1
|
+
import { QueryResult } from '../types/DataSet';
|
|
2
2
|
export declare class DuckDB {
|
|
3
3
|
private db;
|
|
4
4
|
private connection;
|
|
@@ -16,7 +16,7 @@ export declare class DuckDB {
|
|
|
16
16
|
* @param fileName 文件名
|
|
17
17
|
* @param source 文件内容
|
|
18
18
|
*/
|
|
19
|
-
writeFile: <T extends
|
|
19
|
+
writeFile: <T extends Blob>(fileName: string, source: T) => Promise<void>;
|
|
20
20
|
/**
|
|
21
21
|
* @description 执行 SQL 查询
|
|
22
22
|
* @param sql SQL 语句
|
|
@@ -26,11 +26,6 @@ export declare class DuckDB {
|
|
|
26
26
|
dataset: any[];
|
|
27
27
|
table: any;
|
|
28
28
|
}>;
|
|
29
|
-
/**
|
|
30
|
-
* 确保一个文件存在,如果不存在,则根据同名文件创建临时表
|
|
31
|
-
* @param fileName 文件名
|
|
32
|
-
*/
|
|
33
|
-
private ensureSchema;
|
|
34
29
|
/**
|
|
35
30
|
* @description 获取文件的 Schema
|
|
36
31
|
* @param fileName 文件名
|
package/dist/db/indexedDb.d.ts
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
|
+
import { DataSource } from '../types';
|
|
2
|
+
import { DatasetSchema } from '../types/DataSet';
|
|
1
3
|
export declare class IndexedDB {
|
|
2
4
|
private db;
|
|
3
5
|
private dbName;
|
|
4
|
-
private
|
|
6
|
+
private datasetStoreName;
|
|
5
7
|
constructor(dbName: string);
|
|
6
8
|
open: () => Promise<void>;
|
|
7
9
|
close: () => void;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
writeDataset: (datasetId: string, dataSource: DataSource, datasetSchema: DatasetSchema) => Promise<void>;
|
|
11
|
+
readDataset: (datasetId: string) => Promise<{
|
|
12
|
+
dataSource: DataSource;
|
|
13
|
+
datasetSchema: DatasetSchema;
|
|
14
|
+
} | null>;
|
|
15
|
+
deleteDataset: (datasetId: string) => Promise<void>;
|
|
16
|
+
listDatasets: () => Promise<{
|
|
17
|
+
datasetId: string;
|
|
18
|
+
dataSource: DataSource;
|
|
19
|
+
datasetSchema: DatasetSchema;
|
|
20
|
+
}[]>;
|
|
11
21
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -27,8 +27,68 @@ var __webpack_require__ = {};
|
|
|
27
27
|
var __webpack_exports__ = {};
|
|
28
28
|
__webpack_require__.r(__webpack_exports__);
|
|
29
29
|
__webpack_require__.d(__webpack_exports__, {
|
|
30
|
+
DataSourceBuilder: ()=>DataSourceBuilder,
|
|
31
|
+
isHttpUrl: ()=>isHttpUrl,
|
|
32
|
+
isBase64Url: ()=>isBase64Url,
|
|
33
|
+
isUrl: ()=>isUrl,
|
|
30
34
|
VQuery: ()=>VQuery
|
|
31
35
|
});
|
|
36
|
+
class Dataset {
|
|
37
|
+
duckDB;
|
|
38
|
+
indexedDB;
|
|
39
|
+
_datasetId;
|
|
40
|
+
constructor(duckDB, indexedDB1, datasetId){
|
|
41
|
+
this.duckDB = duckDB;
|
|
42
|
+
this.indexedDB = indexedDB1;
|
|
43
|
+
this._datasetId = datasetId;
|
|
44
|
+
}
|
|
45
|
+
async init(temporaryStructs) {
|
|
46
|
+
const readFunctionMap = {
|
|
47
|
+
csv: 'read_csv_auto',
|
|
48
|
+
json: 'read_json_auto',
|
|
49
|
+
xlsx: 'read_excel',
|
|
50
|
+
parquet: 'read_parquet'
|
|
51
|
+
};
|
|
52
|
+
const dataTypeMap = {
|
|
53
|
+
number: 'DOUBLE',
|
|
54
|
+
string: 'VARCHAR',
|
|
55
|
+
date: 'DATE',
|
|
56
|
+
datetime: 'TIMESTAMP',
|
|
57
|
+
timestamp: 'TIMESTAMP'
|
|
58
|
+
};
|
|
59
|
+
const datasetInfo = await this.indexedDB.readDataset(this._datasetId);
|
|
60
|
+
if (!datasetInfo) throw new Error(`Dataset ${this._datasetId} not found`);
|
|
61
|
+
const { dataSource } = datasetInfo;
|
|
62
|
+
const datasetSchema = datasetInfo.datasetSchema;
|
|
63
|
+
const columns = temporaryStructs || datasetSchema.columns;
|
|
64
|
+
const readFunction = readFunctionMap[dataSource.type];
|
|
65
|
+
if (!readFunction) throw new Error(`Unsupported dataSource type: ${dataSource.type}`);
|
|
66
|
+
await this.duckDB.writeFile(this._datasetId, dataSource.blob);
|
|
67
|
+
const columnsStruct = `{${columns.map((c)=>`'${c.name}': '${dataTypeMap[c.type] || 'VARCHAR'}'`).join(', ')}}`;
|
|
68
|
+
const columnNames = columns.map((c)=>`"${c.name}"`).join(', ');
|
|
69
|
+
const createViewSql = `CREATE OR REPLACE VIEW "${this._datasetId}" AS SELECT ${columnNames} FROM ${readFunction}('${this._datasetId}', columns=${columnsStruct})`;
|
|
70
|
+
await this.duckDB.query(createViewSql);
|
|
71
|
+
}
|
|
72
|
+
async queryBySQL(sql) {
|
|
73
|
+
const start = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
74
|
+
const result = await this.duckDB.query(sql);
|
|
75
|
+
const end = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
76
|
+
return {
|
|
77
|
+
...result,
|
|
78
|
+
performance: {
|
|
79
|
+
startAt: start,
|
|
80
|
+
endAt: end,
|
|
81
|
+
duration: Number(end) - Number(start)
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async disconnect() {
|
|
86
|
+
await this.duckDB.query(`DROP VIEW IF EXISTS "${this._datasetId}"`);
|
|
87
|
+
}
|
|
88
|
+
get datasetId() {
|
|
89
|
+
return this._datasetId;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
32
92
|
const duckdb_wasm_namespaceObject = require("@duckdb/duckdb-wasm");
|
|
33
93
|
class DuckDB {
|
|
34
94
|
db = null;
|
|
@@ -71,16 +131,10 @@ class DuckDB {
|
|
|
71
131
|
writeFile = async (fileName, source)=>{
|
|
72
132
|
if (!this.db) throw new Error('db is null');
|
|
73
133
|
let uint8Array;
|
|
74
|
-
if (
|
|
75
|
-
const response = await fetch(source);
|
|
76
|
-
const buffer = await response.arrayBuffer();
|
|
77
|
-
uint8Array = new Uint8Array(buffer);
|
|
78
|
-
} else if (source instanceof Blob) {
|
|
134
|
+
if (source instanceof Blob) {
|
|
79
135
|
const buffer = await source.arrayBuffer();
|
|
80
136
|
uint8Array = new Uint8Array(buffer);
|
|
81
|
-
} else
|
|
82
|
-
else if (source instanceof Uint8Array) uint8Array = source;
|
|
83
|
-
else throw new Error('Unsupported source type');
|
|
137
|
+
} else throw new Error('Unsupported source type');
|
|
84
138
|
await this.db.registerFileBuffer(fileName, uint8Array);
|
|
85
139
|
};
|
|
86
140
|
query = async (sql)=>{
|
|
@@ -92,13 +146,8 @@ class DuckDB {
|
|
|
92
146
|
table
|
|
93
147
|
};
|
|
94
148
|
};
|
|
95
|
-
ensureSchema = async (fileName)=>{
|
|
96
|
-
if (!this.connection) throw new Error('connection is null');
|
|
97
|
-
await this.connection.query(`CREATE TEMP TABLE IF NOT EXISTS "${fileName}" AS SELECT * FROM read_csv_auto('${fileName}')`);
|
|
98
|
-
};
|
|
99
149
|
getSchema = async (fileName)=>{
|
|
100
150
|
if (!this.connection) throw new Error('connection is null');
|
|
101
|
-
await this.ensureSchema(fileName);
|
|
102
151
|
const result = await this.connection.query(`PRAGMA table_info('${fileName}')`);
|
|
103
152
|
return result.toArray().map((row)=>row.toJSON());
|
|
104
153
|
};
|
|
@@ -106,16 +155,16 @@ class DuckDB {
|
|
|
106
155
|
class IndexedDB {
|
|
107
156
|
db = null;
|
|
108
157
|
dbName;
|
|
109
|
-
|
|
158
|
+
datasetStoreName = 'vqueryDatasets';
|
|
110
159
|
constructor(dbName){
|
|
111
160
|
this.dbName = dbName;
|
|
112
161
|
}
|
|
113
162
|
open = ()=>new Promise((resolve, reject)=>{
|
|
114
|
-
const request = indexedDB.open(this.dbName,
|
|
163
|
+
const request = indexedDB.open(this.dbName, 2);
|
|
115
164
|
request.onupgradeneeded = (event)=>{
|
|
116
165
|
const db = event.target.result;
|
|
117
|
-
if (!db.objectStoreNames.contains(this.
|
|
118
|
-
keyPath: '
|
|
166
|
+
if (!db.objectStoreNames.contains(this.datasetStoreName)) db.createObjectStore(this.datasetStoreName, {
|
|
167
|
+
keyPath: 'datasetId'
|
|
119
168
|
});
|
|
120
169
|
};
|
|
121
170
|
request.onsuccess = (event)=>{
|
|
@@ -132,15 +181,16 @@ class IndexedDB {
|
|
|
132
181
|
this.db = null;
|
|
133
182
|
}
|
|
134
183
|
};
|
|
135
|
-
|
|
184
|
+
writeDataset = (datasetId, dataSource, datasetSchema)=>new Promise((resolve, reject)=>{
|
|
136
185
|
if (!this.db) return reject('DB is not open');
|
|
137
186
|
const transaction = this.db.transaction([
|
|
138
|
-
this.
|
|
187
|
+
this.datasetStoreName
|
|
139
188
|
], 'readwrite');
|
|
140
|
-
const store = transaction.objectStore(this.
|
|
189
|
+
const store = transaction.objectStore(this.datasetStoreName);
|
|
141
190
|
const request = store.put({
|
|
142
|
-
|
|
143
|
-
|
|
191
|
+
datasetId,
|
|
192
|
+
dataSource,
|
|
193
|
+
datasetSchema
|
|
144
194
|
});
|
|
145
195
|
request.onsuccess = ()=>{
|
|
146
196
|
resolve();
|
|
@@ -149,92 +199,206 @@ class IndexedDB {
|
|
|
149
199
|
reject(event.target.error);
|
|
150
200
|
};
|
|
151
201
|
});
|
|
152
|
-
|
|
202
|
+
readDataset = (datasetId)=>new Promise((resolve, reject)=>{
|
|
153
203
|
if (!this.db) return reject('DB is not open');
|
|
154
204
|
const transaction = this.db.transaction([
|
|
155
|
-
this.
|
|
205
|
+
this.datasetStoreName
|
|
156
206
|
], 'readonly');
|
|
157
|
-
const store = transaction.objectStore(this.
|
|
158
|
-
const request = store.get(
|
|
207
|
+
const store = transaction.objectStore(this.datasetStoreName);
|
|
208
|
+
const request = store.get(datasetId);
|
|
159
209
|
request.onsuccess = (event)=>{
|
|
160
210
|
const result = event.target.result;
|
|
161
|
-
|
|
211
|
+
resolve(result || null);
|
|
162
212
|
};
|
|
163
213
|
request.onerror = (event)=>{
|
|
164
214
|
reject(event.target.error);
|
|
165
215
|
};
|
|
166
216
|
});
|
|
167
|
-
|
|
217
|
+
deleteDataset = (datasetId)=>new Promise((resolve, reject)=>{
|
|
168
218
|
if (!this.db) return reject('DB is not open');
|
|
169
219
|
const transaction = this.db.transaction([
|
|
170
|
-
this.
|
|
220
|
+
this.datasetStoreName
|
|
221
|
+
], 'readwrite');
|
|
222
|
+
const store = transaction.objectStore(this.datasetStoreName);
|
|
223
|
+
const request = store.delete(datasetId);
|
|
224
|
+
request.onsuccess = ()=>{
|
|
225
|
+
resolve();
|
|
226
|
+
};
|
|
227
|
+
request.onerror = (event)=>{
|
|
228
|
+
reject(event.target.error);
|
|
229
|
+
};
|
|
230
|
+
});
|
|
231
|
+
listDatasets = ()=>new Promise((resolve, reject)=>{
|
|
232
|
+
if (!this.db) return reject('DB is not open');
|
|
233
|
+
const transaction = this.db.transaction([
|
|
234
|
+
this.datasetStoreName
|
|
171
235
|
], 'readonly');
|
|
172
|
-
const store = transaction.objectStore(this.
|
|
173
|
-
const request = store.
|
|
236
|
+
const store = transaction.objectStore(this.datasetStoreName);
|
|
237
|
+
const request = store.getAll();
|
|
174
238
|
request.onsuccess = (event)=>{
|
|
175
|
-
const
|
|
176
|
-
resolve(
|
|
239
|
+
const result = event.target.result;
|
|
240
|
+
resolve(result);
|
|
177
241
|
};
|
|
178
242
|
request.onerror = (event)=>{
|
|
179
243
|
reject(event.target.error);
|
|
180
244
|
};
|
|
181
245
|
});
|
|
182
246
|
}
|
|
247
|
+
const isUrl = (url)=>isHttpUrl(url) || isBase64Url(url);
|
|
248
|
+
const isHttpUrl = (url)=>url.startsWith('http://') || url.startsWith('https://');
|
|
249
|
+
const isBase64Url = (url)=>url.startsWith('data:');
|
|
250
|
+
class DataSourceBuilder {
|
|
251
|
+
type;
|
|
252
|
+
value;
|
|
253
|
+
constructor(type, value){
|
|
254
|
+
this.type = type;
|
|
255
|
+
this.value = value;
|
|
256
|
+
}
|
|
257
|
+
static from(type, value) {
|
|
258
|
+
return new DataSourceBuilder(type, value);
|
|
259
|
+
}
|
|
260
|
+
async build() {
|
|
261
|
+
const blob = await DataSourceBuilder.convertToBlob(this.type, this.value);
|
|
262
|
+
return {
|
|
263
|
+
type: this.type,
|
|
264
|
+
blob: blob
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
static async convertToBlob(type, value) {
|
|
268
|
+
if (value instanceof Blob) return value;
|
|
269
|
+
const convertCsvToBlob = (csvSource)=>{
|
|
270
|
+
if (csvSource instanceof ArrayBuffer) return new Blob([
|
|
271
|
+
csvSource
|
|
272
|
+
], {
|
|
273
|
+
type: 'text/csv'
|
|
274
|
+
});
|
|
275
|
+
if ('string' == typeof csvSource && isUrl(csvSource)) return DataSourceBuilder.fetchBlob(csvSource);
|
|
276
|
+
return new Blob([
|
|
277
|
+
JSON.stringify(csvSource)
|
|
278
|
+
], {
|
|
279
|
+
type: 'text/csv'
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
const convertJsonToBlob = (jsonSource)=>{
|
|
283
|
+
if (jsonSource instanceof ArrayBuffer) return new Blob([
|
|
284
|
+
jsonSource
|
|
285
|
+
], {
|
|
286
|
+
type: 'application/json'
|
|
287
|
+
});
|
|
288
|
+
if ('string' == typeof jsonSource && isUrl(jsonSource)) return DataSourceBuilder.fetchBlob(jsonSource);
|
|
289
|
+
return new Blob([
|
|
290
|
+
JSON.stringify(jsonSource)
|
|
291
|
+
], {
|
|
292
|
+
type: 'application/json'
|
|
293
|
+
});
|
|
294
|
+
};
|
|
295
|
+
const convertParquetToBlob = (parquetSource)=>{
|
|
296
|
+
if (parquetSource instanceof ArrayBuffer) return new Blob([
|
|
297
|
+
parquetSource
|
|
298
|
+
], {
|
|
299
|
+
type: 'application/parquet'
|
|
300
|
+
});
|
|
301
|
+
if ('string' == typeof parquetSource && isUrl(parquetSource)) return DataSourceBuilder.fetchBlob(parquetSource);
|
|
302
|
+
return new Blob([
|
|
303
|
+
parquetSource
|
|
304
|
+
], {
|
|
305
|
+
type: 'application/parquet'
|
|
306
|
+
});
|
|
307
|
+
};
|
|
308
|
+
const convertXlsxToBlob = (xlsxSource)=>{
|
|
309
|
+
if (xlsxSource instanceof ArrayBuffer) return new Blob([
|
|
310
|
+
xlsxSource
|
|
311
|
+
], {
|
|
312
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
313
|
+
});
|
|
314
|
+
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return DataSourceBuilder.fetchBlob(xlsxSource);
|
|
315
|
+
return new Blob([
|
|
316
|
+
xlsxSource
|
|
317
|
+
], {
|
|
318
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
319
|
+
});
|
|
320
|
+
};
|
|
321
|
+
switch(type){
|
|
322
|
+
case 'csv':
|
|
323
|
+
return convertCsvToBlob(value);
|
|
324
|
+
case 'json':
|
|
325
|
+
return convertJsonToBlob(value);
|
|
326
|
+
case 'xlsx':
|
|
327
|
+
return convertXlsxToBlob(value);
|
|
328
|
+
case 'parquet':
|
|
329
|
+
return convertParquetToBlob(value);
|
|
330
|
+
default:
|
|
331
|
+
return new Blob([
|
|
332
|
+
value
|
|
333
|
+
]);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
static async fetchBlob(url) {
|
|
337
|
+
const response = await fetch(url);
|
|
338
|
+
return await response.blob();
|
|
339
|
+
}
|
|
340
|
+
}
|
|
183
341
|
class VQuery {
|
|
184
342
|
duckDB;
|
|
185
343
|
indexedDB;
|
|
344
|
+
isInitialized = false;
|
|
186
345
|
constructor(dbName = 'vquery'){
|
|
187
346
|
this.duckDB = new DuckDB();
|
|
188
347
|
this.indexedDB = new IndexedDB(dbName);
|
|
189
348
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
349
|
+
async ensureInitialized() {
|
|
350
|
+
if (!this.isInitialized) {
|
|
351
|
+
await this.duckDB.init();
|
|
352
|
+
await this.indexedDB.open();
|
|
353
|
+
this.isInitialized = true;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async createDataset(datasetId, data, type, datasetSchema) {
|
|
357
|
+
await this.ensureInitialized();
|
|
358
|
+
const dataSource = await DataSourceBuilder.from(type, data).build();
|
|
359
|
+
await this.indexedDB.writeDataset(datasetId, dataSource, datasetSchema);
|
|
360
|
+
}
|
|
361
|
+
async updateDataset(datasetId, data, type, datasetSchema) {
|
|
362
|
+
await this.ensureInitialized();
|
|
363
|
+
const dataSource = await DataSourceBuilder.from(type, data).build();
|
|
364
|
+
await this.indexedDB.writeDataset(datasetId, dataSource, datasetSchema);
|
|
365
|
+
}
|
|
366
|
+
async deleteDataset(datasetId) {
|
|
367
|
+
await this.ensureInitialized();
|
|
368
|
+
await this.indexedDB.deleteDataset(datasetId);
|
|
369
|
+
}
|
|
370
|
+
async listDatasets() {
|
|
371
|
+
await this.ensureInitialized();
|
|
372
|
+
return this.indexedDB.listDatasets();
|
|
373
|
+
}
|
|
374
|
+
async connectDataset(datasetId) {
|
|
375
|
+
await this.ensureInitialized();
|
|
376
|
+
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
377
|
+
await dataset.init();
|
|
378
|
+
return dataset;
|
|
379
|
+
}
|
|
380
|
+
async connectTemporaryDataset(datasetId, temporaryDatasetSchema) {
|
|
381
|
+
await this.ensureInitialized();
|
|
382
|
+
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
383
|
+
await dataset.init(temporaryDatasetSchema);
|
|
384
|
+
return dataset;
|
|
385
|
+
}
|
|
386
|
+
async close() {
|
|
387
|
+
await this.ensureInitialized();
|
|
195
388
|
await this.duckDB.close();
|
|
196
|
-
|
|
197
|
-
};
|
|
198
|
-
writeFile = async (fileName, source)=>{
|
|
199
|
-
let blob;
|
|
200
|
-
if ('string' == typeof source) {
|
|
201
|
-
const response = await fetch(source);
|
|
202
|
-
blob = await response.blob();
|
|
203
|
-
} else if (source instanceof ArrayBuffer) blob = new Blob([
|
|
204
|
-
source
|
|
205
|
-
]);
|
|
206
|
-
else if (source instanceof Uint8Array) blob = new Blob([
|
|
207
|
-
source.slice()
|
|
208
|
-
]);
|
|
209
|
-
else if (source instanceof Blob) blob = source;
|
|
210
|
-
else throw new Error('Unsupported source type');
|
|
211
|
-
await this.indexedDB.writeFile(fileName, blob);
|
|
212
|
-
await this.duckDB.writeFile(fileName, blob);
|
|
213
|
-
};
|
|
214
|
-
readFile = async (fileName)=>{
|
|
215
|
-
const blob = await this.indexedDB.readFile(fileName);
|
|
216
|
-
if (blob) await this.duckDB.writeFile(fileName, blob);
|
|
217
|
-
else throw new Error(`File ${fileName} not found in IndexedDB`);
|
|
218
|
-
};
|
|
219
|
-
listFiles = ()=>this.indexedDB.listFiles();
|
|
220
|
-
query = async (sql)=>{
|
|
221
|
-
const start = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
222
|
-
const result = await this.duckDB.query(sql);
|
|
223
|
-
const end = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
224
|
-
return {
|
|
225
|
-
...result,
|
|
226
|
-
performance: {
|
|
227
|
-
startAt: start,
|
|
228
|
-
endAt: end,
|
|
229
|
-
duration: Number(end) - Number(start)
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
};
|
|
233
|
-
getSchema = async (fileName)=>this.duckDB.getSchema(fileName);
|
|
389
|
+
}
|
|
234
390
|
}
|
|
391
|
+
exports.DataSourceBuilder = __webpack_exports__.DataSourceBuilder;
|
|
235
392
|
exports.VQuery = __webpack_exports__.VQuery;
|
|
393
|
+
exports.isBase64Url = __webpack_exports__.isBase64Url;
|
|
394
|
+
exports.isHttpUrl = __webpack_exports__.isHttpUrl;
|
|
395
|
+
exports.isUrl = __webpack_exports__.isUrl;
|
|
236
396
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
237
|
-
"
|
|
397
|
+
"DataSourceBuilder",
|
|
398
|
+
"VQuery",
|
|
399
|
+
"isBase64Url",
|
|
400
|
+
"isHttpUrl",
|
|
401
|
+
"isUrl"
|
|
238
402
|
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
239
403
|
Object.defineProperty(exports, '__esModule', {
|
|
240
404
|
value: true
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,60 @@
|
|
|
1
1
|
import { AsyncDuckDB, ConsoleLogger, selectBundle } from "@duckdb/duckdb-wasm";
|
|
2
|
+
class Dataset {
|
|
3
|
+
duckDB;
|
|
4
|
+
indexedDB;
|
|
5
|
+
_datasetId;
|
|
6
|
+
constructor(duckDB, indexedDB1, datasetId){
|
|
7
|
+
this.duckDB = duckDB;
|
|
8
|
+
this.indexedDB = indexedDB1;
|
|
9
|
+
this._datasetId = datasetId;
|
|
10
|
+
}
|
|
11
|
+
async init(temporaryStructs) {
|
|
12
|
+
const readFunctionMap = {
|
|
13
|
+
csv: 'read_csv_auto',
|
|
14
|
+
json: 'read_json_auto',
|
|
15
|
+
xlsx: 'read_excel',
|
|
16
|
+
parquet: 'read_parquet'
|
|
17
|
+
};
|
|
18
|
+
const dataTypeMap = {
|
|
19
|
+
number: 'DOUBLE',
|
|
20
|
+
string: 'VARCHAR',
|
|
21
|
+
date: 'DATE',
|
|
22
|
+
datetime: 'TIMESTAMP',
|
|
23
|
+
timestamp: 'TIMESTAMP'
|
|
24
|
+
};
|
|
25
|
+
const datasetInfo = await this.indexedDB.readDataset(this._datasetId);
|
|
26
|
+
if (!datasetInfo) throw new Error(`Dataset ${this._datasetId} not found`);
|
|
27
|
+
const { dataSource } = datasetInfo;
|
|
28
|
+
const datasetSchema = datasetInfo.datasetSchema;
|
|
29
|
+
const columns = temporaryStructs || datasetSchema.columns;
|
|
30
|
+
const readFunction = readFunctionMap[dataSource.type];
|
|
31
|
+
if (!readFunction) throw new Error(`Unsupported dataSource type: ${dataSource.type}`);
|
|
32
|
+
await this.duckDB.writeFile(this._datasetId, dataSource.blob);
|
|
33
|
+
const columnsStruct = `{${columns.map((c)=>`'${c.name}': '${dataTypeMap[c.type] || 'VARCHAR'}'`).join(', ')}}`;
|
|
34
|
+
const columnNames = columns.map((c)=>`"${c.name}"`).join(', ');
|
|
35
|
+
const createViewSql = `CREATE OR REPLACE VIEW "${this._datasetId}" AS SELECT ${columnNames} FROM ${readFunction}('${this._datasetId}', columns=${columnsStruct})`;
|
|
36
|
+
await this.duckDB.query(createViewSql);
|
|
37
|
+
}
|
|
38
|
+
async queryBySQL(sql) {
|
|
39
|
+
const start = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
40
|
+
const result = await this.duckDB.query(sql);
|
|
41
|
+
const end = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
42
|
+
return {
|
|
43
|
+
...result,
|
|
44
|
+
performance: {
|
|
45
|
+
startAt: start,
|
|
46
|
+
endAt: end,
|
|
47
|
+
duration: Number(end) - Number(start)
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async disconnect() {
|
|
52
|
+
await this.duckDB.query(`DROP VIEW IF EXISTS "${this._datasetId}"`);
|
|
53
|
+
}
|
|
54
|
+
get datasetId() {
|
|
55
|
+
return this._datasetId;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
2
58
|
class DuckDB {
|
|
3
59
|
db = null;
|
|
4
60
|
connection = null;
|
|
@@ -40,16 +96,10 @@ class DuckDB {
|
|
|
40
96
|
writeFile = async (fileName, source)=>{
|
|
41
97
|
if (!this.db) throw new Error('db is null');
|
|
42
98
|
let uint8Array;
|
|
43
|
-
if (
|
|
44
|
-
const response = await fetch(source);
|
|
45
|
-
const buffer = await response.arrayBuffer();
|
|
46
|
-
uint8Array = new Uint8Array(buffer);
|
|
47
|
-
} else if (source instanceof Blob) {
|
|
99
|
+
if (source instanceof Blob) {
|
|
48
100
|
const buffer = await source.arrayBuffer();
|
|
49
101
|
uint8Array = new Uint8Array(buffer);
|
|
50
|
-
} else
|
|
51
|
-
else if (source instanceof Uint8Array) uint8Array = source;
|
|
52
|
-
else throw new Error('Unsupported source type');
|
|
102
|
+
} else throw new Error('Unsupported source type');
|
|
53
103
|
await this.db.registerFileBuffer(fileName, uint8Array);
|
|
54
104
|
};
|
|
55
105
|
query = async (sql)=>{
|
|
@@ -61,13 +111,8 @@ class DuckDB {
|
|
|
61
111
|
table
|
|
62
112
|
};
|
|
63
113
|
};
|
|
64
|
-
ensureSchema = async (fileName)=>{
|
|
65
|
-
if (!this.connection) throw new Error('connection is null');
|
|
66
|
-
await this.connection.query(`CREATE TEMP TABLE IF NOT EXISTS "${fileName}" AS SELECT * FROM read_csv_auto('${fileName}')`);
|
|
67
|
-
};
|
|
68
114
|
getSchema = async (fileName)=>{
|
|
69
115
|
if (!this.connection) throw new Error('connection is null');
|
|
70
|
-
await this.ensureSchema(fileName);
|
|
71
116
|
const result = await this.connection.query(`PRAGMA table_info('${fileName}')`);
|
|
72
117
|
return result.toArray().map((row)=>row.toJSON());
|
|
73
118
|
};
|
|
@@ -75,16 +120,16 @@ class DuckDB {
|
|
|
75
120
|
class IndexedDB {
|
|
76
121
|
db = null;
|
|
77
122
|
dbName;
|
|
78
|
-
|
|
123
|
+
datasetStoreName = 'vqueryDatasets';
|
|
79
124
|
constructor(dbName){
|
|
80
125
|
this.dbName = dbName;
|
|
81
126
|
}
|
|
82
127
|
open = ()=>new Promise((resolve, reject)=>{
|
|
83
|
-
const request = indexedDB.open(this.dbName,
|
|
128
|
+
const request = indexedDB.open(this.dbName, 2);
|
|
84
129
|
request.onupgradeneeded = (event)=>{
|
|
85
130
|
const db = event.target.result;
|
|
86
|
-
if (!db.objectStoreNames.contains(this.
|
|
87
|
-
keyPath: '
|
|
131
|
+
if (!db.objectStoreNames.contains(this.datasetStoreName)) db.createObjectStore(this.datasetStoreName, {
|
|
132
|
+
keyPath: 'datasetId'
|
|
88
133
|
});
|
|
89
134
|
};
|
|
90
135
|
request.onsuccess = (event)=>{
|
|
@@ -101,15 +146,16 @@ class IndexedDB {
|
|
|
101
146
|
this.db = null;
|
|
102
147
|
}
|
|
103
148
|
};
|
|
104
|
-
|
|
149
|
+
writeDataset = (datasetId, dataSource, datasetSchema)=>new Promise((resolve, reject)=>{
|
|
105
150
|
if (!this.db) return reject('DB is not open');
|
|
106
151
|
const transaction = this.db.transaction([
|
|
107
|
-
this.
|
|
152
|
+
this.datasetStoreName
|
|
108
153
|
], 'readwrite');
|
|
109
|
-
const store = transaction.objectStore(this.
|
|
154
|
+
const store = transaction.objectStore(this.datasetStoreName);
|
|
110
155
|
const request = store.put({
|
|
111
|
-
|
|
112
|
-
|
|
156
|
+
datasetId,
|
|
157
|
+
dataSource,
|
|
158
|
+
datasetSchema
|
|
113
159
|
});
|
|
114
160
|
request.onsuccess = ()=>{
|
|
115
161
|
resolve();
|
|
@@ -118,87 +164,193 @@ class IndexedDB {
|
|
|
118
164
|
reject(event.target.error);
|
|
119
165
|
};
|
|
120
166
|
});
|
|
121
|
-
|
|
167
|
+
readDataset = (datasetId)=>new Promise((resolve, reject)=>{
|
|
122
168
|
if (!this.db) return reject('DB is not open');
|
|
123
169
|
const transaction = this.db.transaction([
|
|
124
|
-
this.
|
|
170
|
+
this.datasetStoreName
|
|
125
171
|
], 'readonly');
|
|
126
|
-
const store = transaction.objectStore(this.
|
|
127
|
-
const request = store.get(
|
|
172
|
+
const store = transaction.objectStore(this.datasetStoreName);
|
|
173
|
+
const request = store.get(datasetId);
|
|
128
174
|
request.onsuccess = (event)=>{
|
|
129
175
|
const result = event.target.result;
|
|
130
|
-
|
|
176
|
+
resolve(result || null);
|
|
131
177
|
};
|
|
132
178
|
request.onerror = (event)=>{
|
|
133
179
|
reject(event.target.error);
|
|
134
180
|
};
|
|
135
181
|
});
|
|
136
|
-
|
|
182
|
+
deleteDataset = (datasetId)=>new Promise((resolve, reject)=>{
|
|
137
183
|
if (!this.db) return reject('DB is not open');
|
|
138
184
|
const transaction = this.db.transaction([
|
|
139
|
-
this.
|
|
185
|
+
this.datasetStoreName
|
|
186
|
+
], 'readwrite');
|
|
187
|
+
const store = transaction.objectStore(this.datasetStoreName);
|
|
188
|
+
const request = store.delete(datasetId);
|
|
189
|
+
request.onsuccess = ()=>{
|
|
190
|
+
resolve();
|
|
191
|
+
};
|
|
192
|
+
request.onerror = (event)=>{
|
|
193
|
+
reject(event.target.error);
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
listDatasets = ()=>new Promise((resolve, reject)=>{
|
|
197
|
+
if (!this.db) return reject('DB is not open');
|
|
198
|
+
const transaction = this.db.transaction([
|
|
199
|
+
this.datasetStoreName
|
|
140
200
|
], 'readonly');
|
|
141
|
-
const store = transaction.objectStore(this.
|
|
142
|
-
const request = store.
|
|
201
|
+
const store = transaction.objectStore(this.datasetStoreName);
|
|
202
|
+
const request = store.getAll();
|
|
143
203
|
request.onsuccess = (event)=>{
|
|
144
|
-
const
|
|
145
|
-
resolve(
|
|
204
|
+
const result = event.target.result;
|
|
205
|
+
resolve(result);
|
|
146
206
|
};
|
|
147
207
|
request.onerror = (event)=>{
|
|
148
208
|
reject(event.target.error);
|
|
149
209
|
};
|
|
150
210
|
});
|
|
151
211
|
}
|
|
212
|
+
const isUrl = (url)=>isHttpUrl(url) || isBase64Url(url);
|
|
213
|
+
const isHttpUrl = (url)=>url.startsWith('http://') || url.startsWith('https://');
|
|
214
|
+
const isBase64Url = (url)=>url.startsWith('data:');
|
|
215
|
+
class DataSourceBuilder {
|
|
216
|
+
type;
|
|
217
|
+
value;
|
|
218
|
+
constructor(type, value){
|
|
219
|
+
this.type = type;
|
|
220
|
+
this.value = value;
|
|
221
|
+
}
|
|
222
|
+
static from(type, value) {
|
|
223
|
+
return new DataSourceBuilder(type, value);
|
|
224
|
+
}
|
|
225
|
+
async build() {
|
|
226
|
+
const blob = await DataSourceBuilder.convertToBlob(this.type, this.value);
|
|
227
|
+
return {
|
|
228
|
+
type: this.type,
|
|
229
|
+
blob: blob
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
static async convertToBlob(type, value) {
|
|
233
|
+
if (value instanceof Blob) return value;
|
|
234
|
+
const convertCsvToBlob = (csvSource)=>{
|
|
235
|
+
if (csvSource instanceof ArrayBuffer) return new Blob([
|
|
236
|
+
csvSource
|
|
237
|
+
], {
|
|
238
|
+
type: 'text/csv'
|
|
239
|
+
});
|
|
240
|
+
if ('string' == typeof csvSource && isUrl(csvSource)) return DataSourceBuilder.fetchBlob(csvSource);
|
|
241
|
+
return new Blob([
|
|
242
|
+
JSON.stringify(csvSource)
|
|
243
|
+
], {
|
|
244
|
+
type: 'text/csv'
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
const convertJsonToBlob = (jsonSource)=>{
|
|
248
|
+
if (jsonSource instanceof ArrayBuffer) return new Blob([
|
|
249
|
+
jsonSource
|
|
250
|
+
], {
|
|
251
|
+
type: 'application/json'
|
|
252
|
+
});
|
|
253
|
+
if ('string' == typeof jsonSource && isUrl(jsonSource)) return DataSourceBuilder.fetchBlob(jsonSource);
|
|
254
|
+
return new Blob([
|
|
255
|
+
JSON.stringify(jsonSource)
|
|
256
|
+
], {
|
|
257
|
+
type: 'application/json'
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
const convertParquetToBlob = (parquetSource)=>{
|
|
261
|
+
if (parquetSource instanceof ArrayBuffer) return new Blob([
|
|
262
|
+
parquetSource
|
|
263
|
+
], {
|
|
264
|
+
type: 'application/parquet'
|
|
265
|
+
});
|
|
266
|
+
if ('string' == typeof parquetSource && isUrl(parquetSource)) return DataSourceBuilder.fetchBlob(parquetSource);
|
|
267
|
+
return new Blob([
|
|
268
|
+
parquetSource
|
|
269
|
+
], {
|
|
270
|
+
type: 'application/parquet'
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
const convertXlsxToBlob = (xlsxSource)=>{
|
|
274
|
+
if (xlsxSource instanceof ArrayBuffer) return new Blob([
|
|
275
|
+
xlsxSource
|
|
276
|
+
], {
|
|
277
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
278
|
+
});
|
|
279
|
+
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return DataSourceBuilder.fetchBlob(xlsxSource);
|
|
280
|
+
return new Blob([
|
|
281
|
+
xlsxSource
|
|
282
|
+
], {
|
|
283
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
switch(type){
|
|
287
|
+
case 'csv':
|
|
288
|
+
return convertCsvToBlob(value);
|
|
289
|
+
case 'json':
|
|
290
|
+
return convertJsonToBlob(value);
|
|
291
|
+
case 'xlsx':
|
|
292
|
+
return convertXlsxToBlob(value);
|
|
293
|
+
case 'parquet':
|
|
294
|
+
return convertParquetToBlob(value);
|
|
295
|
+
default:
|
|
296
|
+
return new Blob([
|
|
297
|
+
value
|
|
298
|
+
]);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
static async fetchBlob(url) {
|
|
302
|
+
const response = await fetch(url);
|
|
303
|
+
return await response.blob();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
152
306
|
class VQuery {
|
|
153
307
|
duckDB;
|
|
154
308
|
indexedDB;
|
|
309
|
+
isInitialized = false;
|
|
155
310
|
constructor(dbName = 'vquery'){
|
|
156
311
|
this.duckDB = new DuckDB();
|
|
157
312
|
this.indexedDB = new IndexedDB(dbName);
|
|
158
313
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
314
|
+
async ensureInitialized() {
|
|
315
|
+
if (!this.isInitialized) {
|
|
316
|
+
await this.duckDB.init();
|
|
317
|
+
await this.indexedDB.open();
|
|
318
|
+
this.isInitialized = true;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async createDataset(datasetId, data, type, datasetSchema) {
|
|
322
|
+
await this.ensureInitialized();
|
|
323
|
+
const dataSource = await DataSourceBuilder.from(type, data).build();
|
|
324
|
+
await this.indexedDB.writeDataset(datasetId, dataSource, datasetSchema);
|
|
325
|
+
}
|
|
326
|
+
async updateDataset(datasetId, data, type, datasetSchema) {
|
|
327
|
+
await this.ensureInitialized();
|
|
328
|
+
const dataSource = await DataSourceBuilder.from(type, data).build();
|
|
329
|
+
await this.indexedDB.writeDataset(datasetId, dataSource, datasetSchema);
|
|
330
|
+
}
|
|
331
|
+
async deleteDataset(datasetId) {
|
|
332
|
+
await this.ensureInitialized();
|
|
333
|
+
await this.indexedDB.deleteDataset(datasetId);
|
|
334
|
+
}
|
|
335
|
+
async listDatasets() {
|
|
336
|
+
await this.ensureInitialized();
|
|
337
|
+
return this.indexedDB.listDatasets();
|
|
338
|
+
}
|
|
339
|
+
async connectDataset(datasetId) {
|
|
340
|
+
await this.ensureInitialized();
|
|
341
|
+
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
342
|
+
await dataset.init();
|
|
343
|
+
return dataset;
|
|
344
|
+
}
|
|
345
|
+
async connectTemporaryDataset(datasetId, temporaryDatasetSchema) {
|
|
346
|
+
await this.ensureInitialized();
|
|
347
|
+
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
348
|
+
await dataset.init(temporaryDatasetSchema);
|
|
349
|
+
return dataset;
|
|
350
|
+
}
|
|
351
|
+
async close() {
|
|
352
|
+
await this.ensureInitialized();
|
|
164
353
|
await this.duckDB.close();
|
|
165
|
-
|
|
166
|
-
};
|
|
167
|
-
writeFile = async (fileName, source)=>{
|
|
168
|
-
let blob;
|
|
169
|
-
if ('string' == typeof source) {
|
|
170
|
-
const response = await fetch(source);
|
|
171
|
-
blob = await response.blob();
|
|
172
|
-
} else if (source instanceof ArrayBuffer) blob = new Blob([
|
|
173
|
-
source
|
|
174
|
-
]);
|
|
175
|
-
else if (source instanceof Uint8Array) blob = new Blob([
|
|
176
|
-
source.slice()
|
|
177
|
-
]);
|
|
178
|
-
else if (source instanceof Blob) blob = source;
|
|
179
|
-
else throw new Error('Unsupported source type');
|
|
180
|
-
await this.indexedDB.writeFile(fileName, blob);
|
|
181
|
-
await this.duckDB.writeFile(fileName, blob);
|
|
182
|
-
};
|
|
183
|
-
readFile = async (fileName)=>{
|
|
184
|
-
const blob = await this.indexedDB.readFile(fileName);
|
|
185
|
-
if (blob) await this.duckDB.writeFile(fileName, blob);
|
|
186
|
-
else throw new Error(`File ${fileName} not found in IndexedDB`);
|
|
187
|
-
};
|
|
188
|
-
listFiles = ()=>this.indexedDB.listFiles();
|
|
189
|
-
query = async (sql)=>{
|
|
190
|
-
const start = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
191
|
-
const result = await this.duckDB.query(sql);
|
|
192
|
-
const end = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
193
|
-
return {
|
|
194
|
-
...result,
|
|
195
|
-
performance: {
|
|
196
|
-
startAt: start,
|
|
197
|
-
endAt: end,
|
|
198
|
-
duration: Number(end) - Number(start)
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
};
|
|
202
|
-
getSchema = async (fileName)=>this.duckDB.getSchema(fileName);
|
|
354
|
+
}
|
|
203
355
|
}
|
|
204
|
-
export { VQuery };
|
|
356
|
+
export { DataSourceBuilder, VQuery, isBase64Url, isHttpUrl, isUrl };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type { QueryResult } from './QueryResult';
|
|
2
|
+
export type DataType = 'number' | 'string' | 'date' | 'datetime' | 'timestamp';
|
|
3
|
+
export interface DatasetColumn {
|
|
4
|
+
type: DataType;
|
|
5
|
+
name: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DatasetSchema {
|
|
8
|
+
datasetId: string;
|
|
9
|
+
datasetAlias: string;
|
|
10
|
+
columns: DatasetColumn[];
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type TidyDatum = Record<string, number | string | null | boolean | undefined>;
|
|
2
|
+
export type DataSourceType = 'csv' | 'json' | 'xlsx' | 'parquet';
|
|
3
|
+
export type DataSourceValue = string | ArrayBuffer | Blob | TidyDatum[];
|
|
4
|
+
export interface DataSource {
|
|
5
|
+
type: DataSourceType;
|
|
6
|
+
blob: Blob;
|
|
7
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { isUrl, isHttpUrl, isBase64Url } from './url';
|
package/dist/vquery.d.ts
CHANGED
|
@@ -1,48 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Dataset } from './dataset/dataset';
|
|
2
|
+
import { DatasetSchema, TidyDatum, DataSourceType, DatasetColumn } from './types';
|
|
2
3
|
export declare class VQuery {
|
|
3
4
|
private duckDB;
|
|
4
5
|
private indexedDB;
|
|
6
|
+
private isInitialized;
|
|
5
7
|
constructor(dbName?: string);
|
|
8
|
+
private ensureInitialized;
|
|
6
9
|
/**
|
|
7
|
-
*
|
|
10
|
+
* 创建数据集,根据表结构和数据,存储信息到indexedDB
|
|
8
11
|
*/
|
|
9
|
-
|
|
12
|
+
createDataset(datasetId: string, data: string | ArrayBuffer | Blob | TidyDatum[], type: DataSourceType, datasetSchema: DatasetSchema): Promise<void>;
|
|
10
13
|
/**
|
|
11
|
-
*
|
|
14
|
+
* 修改数据集,更新信息到indexedDB内
|
|
12
15
|
*/
|
|
13
|
-
|
|
16
|
+
updateDataset(datasetId: string, data: string | ArrayBuffer | Blob | TidyDatum[], type: DataSourceType, datasetSchema: DatasetSchema): Promise<void>;
|
|
14
17
|
/**
|
|
15
|
-
*
|
|
16
|
-
* @param fileName 文件名
|
|
17
|
-
* @param source 文件内容
|
|
18
|
+
* 删除数据集,从indexdb移除数据集
|
|
18
19
|
*/
|
|
19
|
-
|
|
20
|
+
deleteDataset(datasetId: string): Promise<void>;
|
|
20
21
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @param fileName 文件名
|
|
22
|
+
* 获取所有可用数据集
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
listDatasets(): Promise<{
|
|
25
|
+
datasetId: string;
|
|
26
|
+
dataSource: import("./types").DataSource;
|
|
27
|
+
datasetSchema: DatasetSchema;
|
|
28
|
+
}[]>;
|
|
25
29
|
/**
|
|
26
|
-
*
|
|
30
|
+
* 连接数据集,返回数据集信息,从indexedDB获取表结构,使用DuckDB在内存中创建表
|
|
27
31
|
*/
|
|
28
|
-
|
|
32
|
+
connectDataset(datasetId: string): Promise<Dataset>;
|
|
29
33
|
/**
|
|
30
|
-
*
|
|
31
|
-
* @param
|
|
34
|
+
* 连接临时数据集,返回数据集信息,从indexedDB获取表结构,使用DuckDB在内存中创建表
|
|
35
|
+
* @param datasetId
|
|
36
|
+
* @returns
|
|
32
37
|
*/
|
|
33
|
-
|
|
34
|
-
performance: {
|
|
35
|
-
startAt: string;
|
|
36
|
-
endAt: string;
|
|
37
|
-
duration: number;
|
|
38
|
-
};
|
|
39
|
-
dataset: any[];
|
|
40
|
-
table: any;
|
|
41
|
-
}>;
|
|
38
|
+
connectTemporaryDataset(datasetId: string, temporaryDatasetSchema?: DatasetColumn[]): Promise<Dataset>;
|
|
42
39
|
/**
|
|
43
|
-
*
|
|
44
|
-
* @param fileName 文件名
|
|
45
|
-
* @returns 文件的 Schema
|
|
40
|
+
* 关闭所有数据集连接,释放DuckDB资源
|
|
46
41
|
*/
|
|
47
|
-
|
|
42
|
+
close(): Promise<void>;
|
|
48
43
|
}
|