@visactor/vquery 0.1.49 → 0.1.50
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/data-source-builder/dataSourceBuilder.d.ts +5 -5
- package/dist/data-source-builder/index.d.ts +1 -1
- package/dist/dataset/dataset.d.ts +3 -3
- package/dist/db/indexedDb.d.ts +4 -4
- package/dist/index.cjs +68 -53
- package/dist/index.d.ts +1 -1
- package/dist/index.js +66 -51
- package/dist/types/DataSource.d.ts +8 -4
- package/dist/vquery.d.ts +8 -28
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare class
|
|
1
|
+
import { DatasetSourceType, RawDatasetSource } from '../types';
|
|
2
|
+
export declare class DatasetSourceBuilder {
|
|
3
3
|
private type;
|
|
4
4
|
private value;
|
|
5
|
-
constructor(
|
|
6
|
-
static from(
|
|
5
|
+
constructor(raw: RawDatasetSource);
|
|
6
|
+
static from(raw: RawDatasetSource): DatasetSourceBuilder;
|
|
7
7
|
build(): Promise<{
|
|
8
|
-
type:
|
|
8
|
+
type: DatasetSourceType;
|
|
9
9
|
blob: Blob;
|
|
10
10
|
}>;
|
|
11
11
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { DatasetSourceBuilder } from './dataSourceBuilder';
|
|
@@ -7,7 +7,8 @@ export declare class Dataset {
|
|
|
7
7
|
private _datasetId;
|
|
8
8
|
constructor(duckDB: DuckDB, indexedDB: IndexedDB, datasetId: string);
|
|
9
9
|
init(temporaryColumns?: DatasetColumn[]): Promise<void>;
|
|
10
|
-
|
|
10
|
+
createOrReplaceView(columns?: DatasetColumn[]): Promise<void>;
|
|
11
|
+
query<T extends Record<string, number | string>>(queryDSL: QueryDSL<T>): Promise<{
|
|
11
12
|
performance: {
|
|
12
13
|
startAt: string;
|
|
13
14
|
endAt: string;
|
|
@@ -16,8 +17,7 @@ export declare class Dataset {
|
|
|
16
17
|
dataset: any[];
|
|
17
18
|
table: any;
|
|
18
19
|
}>;
|
|
19
|
-
|
|
20
|
-
query<T extends Record<string, number | string>>(queryDSL: QueryDSL<T>): Promise<{
|
|
20
|
+
queryBySQL(sql: string): Promise<{
|
|
21
21
|
performance: {
|
|
22
22
|
startAt: string;
|
|
23
23
|
endAt: string;
|
package/dist/db/indexedDb.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DatasetSource } from '../types';
|
|
2
2
|
import { DatasetSchema } from '../types/DataSet';
|
|
3
3
|
export declare class IndexedDB {
|
|
4
4
|
private db;
|
|
@@ -7,15 +7,15 @@ export declare class IndexedDB {
|
|
|
7
7
|
constructor(dbName: string);
|
|
8
8
|
open: () => Promise<void>;
|
|
9
9
|
close: () => void;
|
|
10
|
-
writeDataset: (datasetId: string,
|
|
10
|
+
writeDataset: (datasetId: string, datasetSchema: DatasetSchema, datasetSource?: DatasetSource) => Promise<void>;
|
|
11
11
|
readDataset: (datasetId: string) => Promise<{
|
|
12
|
-
|
|
12
|
+
datasetSource?: DatasetSource;
|
|
13
13
|
datasetSchema: DatasetSchema;
|
|
14
14
|
} | null>;
|
|
15
15
|
deleteDataset: (datasetId: string) => Promise<void>;
|
|
16
16
|
listDatasets: () => Promise<{
|
|
17
17
|
datasetId: string;
|
|
18
|
-
dataSource
|
|
18
|
+
dataSource?: DatasetSource;
|
|
19
19
|
datasetSchema: DatasetSchema;
|
|
20
20
|
}[]>;
|
|
21
21
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -27,7 +27,7 @@ var __webpack_require__ = {};
|
|
|
27
27
|
var __webpack_exports__ = {};
|
|
28
28
|
__webpack_require__.r(__webpack_exports__);
|
|
29
29
|
__webpack_require__.d(__webpack_exports__, {
|
|
30
|
-
|
|
30
|
+
DatasetSourceBuilder: ()=>DatasetSourceBuilder,
|
|
31
31
|
isHttpUrl: ()=>isHttpUrl,
|
|
32
32
|
convertDSLToSQL: ()=>convertDSLToSQL,
|
|
33
33
|
isBase64Url: ()=>isBase64Url,
|
|
@@ -186,6 +186,12 @@ class Dataset {
|
|
|
186
186
|
this._datasetId = datasetId;
|
|
187
187
|
}
|
|
188
188
|
async init(temporaryColumns = []) {
|
|
189
|
+
const datasetInfo = await this.indexedDB.readDataset(this._datasetId);
|
|
190
|
+
if (!datasetInfo) throw new Error(`Dataset ${this._datasetId} not found`);
|
|
191
|
+
const columns = temporaryColumns.length > 0 ? temporaryColumns : datasetInfo.datasetSchema.columns;
|
|
192
|
+
if (columns.length > 0) await this.createOrReplaceView(columns);
|
|
193
|
+
}
|
|
194
|
+
async createOrReplaceView(columns = []) {
|
|
189
195
|
const readFunctionMap = {
|
|
190
196
|
csv: 'read_csv_auto',
|
|
191
197
|
json: 'read_json_auto',
|
|
@@ -201,16 +207,20 @@ class Dataset {
|
|
|
201
207
|
};
|
|
202
208
|
const datasetInfo = await this.indexedDB.readDataset(this._datasetId);
|
|
203
209
|
if (!datasetInfo) throw new Error(`Dataset ${this._datasetId} not found`);
|
|
204
|
-
const { dataSource } = datasetInfo;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
const { datasetSource: dataSource } = datasetInfo;
|
|
211
|
+
if (dataSource) {
|
|
212
|
+
const readFunction = readFunctionMap[dataSource.type];
|
|
213
|
+
if (!readFunction) throw new Error(`Unsupported dataSource type: ${dataSource.type}`);
|
|
214
|
+
await this.duckDB.writeFile(this._datasetId, dataSource.blob);
|
|
215
|
+
const columnsStruct = `{${columns.map((c)=>`'${c.name}': '${dataTypeMap[c.type] || 'VARCHAR'}'`).join(', ')}}`;
|
|
216
|
+
const columnNames = columns.map((c)=>`"${c.name}"`).join(', ');
|
|
217
|
+
const createViewSql = `CREATE OR REPLACE VIEW "${this._datasetId}" AS SELECT ${columnNames} FROM ${readFunction}('${this._datasetId}', columns=${columnsStruct})`;
|
|
218
|
+
await this.duckDB.query(createViewSql);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async query(queryDSL) {
|
|
222
|
+
const sql = convertDSLToSQL(queryDSL, this.datasetId);
|
|
223
|
+
return this.queryBySQL(sql);
|
|
214
224
|
}
|
|
215
225
|
async queryBySQL(sql) {
|
|
216
226
|
const start = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
@@ -225,13 +235,6 @@ class Dataset {
|
|
|
225
235
|
}
|
|
226
236
|
};
|
|
227
237
|
}
|
|
228
|
-
convertDSLToSQL(queryDSL) {
|
|
229
|
-
return convertDSLToSQL(queryDSL, this.datasetId);
|
|
230
|
-
}
|
|
231
|
-
async query(queryDSL) {
|
|
232
|
-
const sql = this.convertDSLToSQL(queryDSL);
|
|
233
|
-
return this.queryBySQL(sql);
|
|
234
|
-
}
|
|
235
238
|
async disconnect() {
|
|
236
239
|
await this.duckDB.query(`DROP VIEW IF EXISTS "${this._datasetId}"`);
|
|
237
240
|
}
|
|
@@ -331,7 +334,7 @@ class IndexedDB {
|
|
|
331
334
|
this.db = null;
|
|
332
335
|
}
|
|
333
336
|
};
|
|
334
|
-
writeDataset = (datasetId,
|
|
337
|
+
writeDataset = (datasetId, datasetSchema, datasetSource)=>new Promise((resolve, reject)=>{
|
|
335
338
|
if (!this.db) return reject('DB is not open');
|
|
336
339
|
const transaction = this.db.transaction([
|
|
337
340
|
this.datasetStoreName
|
|
@@ -339,8 +342,8 @@ class IndexedDB {
|
|
|
339
342
|
const store = transaction.objectStore(this.datasetStoreName);
|
|
340
343
|
const request = store.put({
|
|
341
344
|
datasetId,
|
|
342
|
-
|
|
343
|
-
|
|
345
|
+
datasetSchema,
|
|
346
|
+
datasetSource
|
|
344
347
|
});
|
|
345
348
|
request.onsuccess = ()=>{
|
|
346
349
|
resolve();
|
|
@@ -397,18 +400,18 @@ class IndexedDB {
|
|
|
397
400
|
const isUrl = (url)=>isHttpUrl(url) || isBase64Url(url);
|
|
398
401
|
const isHttpUrl = (url)=>url.startsWith('http://') || url.startsWith('https://');
|
|
399
402
|
const isBase64Url = (url)=>url.startsWith('data:');
|
|
400
|
-
class
|
|
403
|
+
class DatasetSourceBuilder {
|
|
401
404
|
type;
|
|
402
405
|
value;
|
|
403
|
-
constructor(
|
|
404
|
-
this.type = type;
|
|
405
|
-
this.value =
|
|
406
|
+
constructor(raw){
|
|
407
|
+
this.type = raw.type;
|
|
408
|
+
this.value = raw.rawDataset;
|
|
406
409
|
}
|
|
407
|
-
static from(
|
|
408
|
-
return new
|
|
410
|
+
static from(raw) {
|
|
411
|
+
return new DatasetSourceBuilder(raw);
|
|
409
412
|
}
|
|
410
413
|
async build() {
|
|
411
|
-
const blob = await
|
|
414
|
+
const blob = await DatasetSourceBuilder.convertToBlob(this.type, this.value);
|
|
412
415
|
return {
|
|
413
416
|
type: this.type,
|
|
414
417
|
blob: blob
|
|
@@ -422,7 +425,7 @@ class DataSourceBuilder {
|
|
|
422
425
|
], {
|
|
423
426
|
type: 'text/csv'
|
|
424
427
|
});
|
|
425
|
-
if ('string' == typeof csvSource && isUrl(csvSource)) return
|
|
428
|
+
if ('string' == typeof csvSource && isUrl(csvSource)) return DatasetSourceBuilder.fetchBlob(csvSource);
|
|
426
429
|
return new Blob([
|
|
427
430
|
JSON.stringify(csvSource)
|
|
428
431
|
], {
|
|
@@ -435,7 +438,7 @@ class DataSourceBuilder {
|
|
|
435
438
|
], {
|
|
436
439
|
type: 'application/json'
|
|
437
440
|
});
|
|
438
|
-
if ('string' == typeof jsonSource && isUrl(jsonSource)) return
|
|
441
|
+
if ('string' == typeof jsonSource && isUrl(jsonSource)) return DatasetSourceBuilder.fetchBlob(jsonSource);
|
|
439
442
|
return new Blob([
|
|
440
443
|
JSON.stringify(jsonSource)
|
|
441
444
|
], {
|
|
@@ -448,7 +451,7 @@ class DataSourceBuilder {
|
|
|
448
451
|
], {
|
|
449
452
|
type: 'application/parquet'
|
|
450
453
|
});
|
|
451
|
-
if ('string' == typeof parquetSource && isUrl(parquetSource)) return
|
|
454
|
+
if ('string' == typeof parquetSource && isUrl(parquetSource)) return DatasetSourceBuilder.fetchBlob(parquetSource);
|
|
452
455
|
return new Blob([
|
|
453
456
|
parquetSource
|
|
454
457
|
], {
|
|
@@ -461,7 +464,7 @@ class DataSourceBuilder {
|
|
|
461
464
|
], {
|
|
462
465
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
463
466
|
});
|
|
464
|
-
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return
|
|
467
|
+
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return DatasetSourceBuilder.fetchBlob(xlsxSource);
|
|
465
468
|
return new Blob([
|
|
466
469
|
xlsxSource
|
|
467
470
|
], {
|
|
@@ -496,60 +499,72 @@ class VQuery {
|
|
|
496
499
|
this.duckDB = new DuckDB();
|
|
497
500
|
this.indexedDB = new IndexedDB(dbName);
|
|
498
501
|
}
|
|
499
|
-
async
|
|
502
|
+
async checkInitialized() {
|
|
500
503
|
if (!this.isInitialized) {
|
|
501
504
|
await this.duckDB.init();
|
|
502
505
|
await this.indexedDB.open();
|
|
503
506
|
this.isInitialized = true;
|
|
504
507
|
}
|
|
505
508
|
}
|
|
506
|
-
async
|
|
507
|
-
await this.
|
|
508
|
-
|
|
509
|
+
async checkDatasetExists(datasetId) {
|
|
510
|
+
if (!await this.hasDataset(datasetId)) throw new Error(`dataset ${datasetId} not exists, please create it first`);
|
|
511
|
+
}
|
|
512
|
+
async createDataset(datasetId, columns = [], rawDatasetSource) {
|
|
513
|
+
await this.checkInitialized();
|
|
514
|
+
const datasetSource = rawDatasetSource ? await DatasetSourceBuilder.from(rawDatasetSource).build() : void 0;
|
|
515
|
+
if (await this.hasDataset(datasetId)) throw new Error(`dataset ${datasetId} already exists`);
|
|
509
516
|
const datasetSchema = {
|
|
510
517
|
datasetId,
|
|
511
518
|
datasetAlias: datasetId,
|
|
512
519
|
columns: columns
|
|
513
520
|
};
|
|
514
|
-
await this.indexedDB.writeDataset(datasetId,
|
|
521
|
+
await this.indexedDB.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
515
522
|
}
|
|
516
|
-
async
|
|
517
|
-
await this.
|
|
518
|
-
|
|
519
|
-
await
|
|
523
|
+
async updateDatasetSource(datasetId, columns = [], rawDatasetSource) {
|
|
524
|
+
await this.checkInitialized();
|
|
525
|
+
await this.checkDatasetExists(datasetId);
|
|
526
|
+
const datasetSource = rawDatasetSource ? await DatasetSourceBuilder.from(rawDatasetSource).build() : void 0;
|
|
527
|
+
const datasetSchema = {
|
|
528
|
+
datasetId,
|
|
529
|
+
datasetAlias: datasetId,
|
|
530
|
+
columns: columns
|
|
531
|
+
};
|
|
532
|
+
await this.indexedDB.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
520
533
|
}
|
|
521
534
|
async dropDataset(datasetId) {
|
|
522
|
-
await this.
|
|
535
|
+
await this.checkInitialized();
|
|
536
|
+
await this.checkDatasetExists(datasetId);
|
|
523
537
|
await this.indexedDB.deleteDataset(datasetId);
|
|
524
538
|
}
|
|
539
|
+
async connectDataset(datasetId, temporaryColumns = []) {
|
|
540
|
+
await this.checkInitialized();
|
|
541
|
+
await this.checkDatasetExists(datasetId);
|
|
542
|
+
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
543
|
+
await dataset.init(temporaryColumns);
|
|
544
|
+
return dataset;
|
|
545
|
+
}
|
|
525
546
|
async hasDataset(datasetId) {
|
|
526
|
-
await this.
|
|
547
|
+
await this.checkInitialized();
|
|
527
548
|
const datasets = await this.indexedDB.listDatasets();
|
|
528
549
|
return datasets.some((item)=>item.datasetId === datasetId);
|
|
529
550
|
}
|
|
530
551
|
async listDatasets() {
|
|
531
|
-
await this.
|
|
552
|
+
await this.checkInitialized();
|
|
532
553
|
return this.indexedDB.listDatasets();
|
|
533
554
|
}
|
|
534
|
-
async connectDataset(datasetId, temporaryColumns = []) {
|
|
535
|
-
await this.ensureInitialized();
|
|
536
|
-
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
537
|
-
await dataset.init(temporaryColumns);
|
|
538
|
-
return dataset;
|
|
539
|
-
}
|
|
540
555
|
async close() {
|
|
541
|
-
await this.
|
|
556
|
+
await this.checkInitialized();
|
|
542
557
|
await this.duckDB.close();
|
|
543
558
|
}
|
|
544
559
|
}
|
|
545
|
-
exports.
|
|
560
|
+
exports.DatasetSourceBuilder = __webpack_exports__.DatasetSourceBuilder;
|
|
546
561
|
exports.VQuery = __webpack_exports__.VQuery;
|
|
547
562
|
exports.convertDSLToSQL = __webpack_exports__.convertDSLToSQL;
|
|
548
563
|
exports.isBase64Url = __webpack_exports__.isBase64Url;
|
|
549
564
|
exports.isHttpUrl = __webpack_exports__.isHttpUrl;
|
|
550
565
|
exports.isUrl = __webpack_exports__.isUrl;
|
|
551
566
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
552
|
-
"
|
|
567
|
+
"DatasetSourceBuilder",
|
|
553
568
|
"VQuery",
|
|
554
569
|
"convertDSLToSQL",
|
|
555
570
|
"isBase64Url",
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -151,6 +151,12 @@ class Dataset {
|
|
|
151
151
|
this._datasetId = datasetId;
|
|
152
152
|
}
|
|
153
153
|
async init(temporaryColumns = []) {
|
|
154
|
+
const datasetInfo = await this.indexedDB.readDataset(this._datasetId);
|
|
155
|
+
if (!datasetInfo) throw new Error(`Dataset ${this._datasetId} not found`);
|
|
156
|
+
const columns = temporaryColumns.length > 0 ? temporaryColumns : datasetInfo.datasetSchema.columns;
|
|
157
|
+
if (columns.length > 0) await this.createOrReplaceView(columns);
|
|
158
|
+
}
|
|
159
|
+
async createOrReplaceView(columns = []) {
|
|
154
160
|
const readFunctionMap = {
|
|
155
161
|
csv: 'read_csv_auto',
|
|
156
162
|
json: 'read_json_auto',
|
|
@@ -166,16 +172,20 @@ class Dataset {
|
|
|
166
172
|
};
|
|
167
173
|
const datasetInfo = await this.indexedDB.readDataset(this._datasetId);
|
|
168
174
|
if (!datasetInfo) throw new Error(`Dataset ${this._datasetId} not found`);
|
|
169
|
-
const { dataSource } = datasetInfo;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
175
|
+
const { datasetSource: dataSource } = datasetInfo;
|
|
176
|
+
if (dataSource) {
|
|
177
|
+
const readFunction = readFunctionMap[dataSource.type];
|
|
178
|
+
if (!readFunction) throw new Error(`Unsupported dataSource type: ${dataSource.type}`);
|
|
179
|
+
await this.duckDB.writeFile(this._datasetId, dataSource.blob);
|
|
180
|
+
const columnsStruct = `{${columns.map((c)=>`'${c.name}': '${dataTypeMap[c.type] || 'VARCHAR'}'`).join(', ')}}`;
|
|
181
|
+
const columnNames = columns.map((c)=>`"${c.name}"`).join(', ');
|
|
182
|
+
const createViewSql = `CREATE OR REPLACE VIEW "${this._datasetId}" AS SELECT ${columnNames} FROM ${readFunction}('${this._datasetId}', columns=${columnsStruct})`;
|
|
183
|
+
await this.duckDB.query(createViewSql);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async query(queryDSL) {
|
|
187
|
+
const sql = convertDSLToSQL(queryDSL, this.datasetId);
|
|
188
|
+
return this.queryBySQL(sql);
|
|
179
189
|
}
|
|
180
190
|
async queryBySQL(sql) {
|
|
181
191
|
const start = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
@@ -190,13 +200,6 @@ class Dataset {
|
|
|
190
200
|
}
|
|
191
201
|
};
|
|
192
202
|
}
|
|
193
|
-
convertDSLToSQL(queryDSL) {
|
|
194
|
-
return convertDSLToSQL(queryDSL, this.datasetId);
|
|
195
|
-
}
|
|
196
|
-
async query(queryDSL) {
|
|
197
|
-
const sql = this.convertDSLToSQL(queryDSL);
|
|
198
|
-
return this.queryBySQL(sql);
|
|
199
|
-
}
|
|
200
203
|
async disconnect() {
|
|
201
204
|
await this.duckDB.query(`DROP VIEW IF EXISTS "${this._datasetId}"`);
|
|
202
205
|
}
|
|
@@ -295,7 +298,7 @@ class IndexedDB {
|
|
|
295
298
|
this.db = null;
|
|
296
299
|
}
|
|
297
300
|
};
|
|
298
|
-
writeDataset = (datasetId,
|
|
301
|
+
writeDataset = (datasetId, datasetSchema, datasetSource)=>new Promise((resolve, reject)=>{
|
|
299
302
|
if (!this.db) return reject('DB is not open');
|
|
300
303
|
const transaction = this.db.transaction([
|
|
301
304
|
this.datasetStoreName
|
|
@@ -303,8 +306,8 @@ class IndexedDB {
|
|
|
303
306
|
const store = transaction.objectStore(this.datasetStoreName);
|
|
304
307
|
const request = store.put({
|
|
305
308
|
datasetId,
|
|
306
|
-
|
|
307
|
-
|
|
309
|
+
datasetSchema,
|
|
310
|
+
datasetSource
|
|
308
311
|
});
|
|
309
312
|
request.onsuccess = ()=>{
|
|
310
313
|
resolve();
|
|
@@ -361,18 +364,18 @@ class IndexedDB {
|
|
|
361
364
|
const isUrl = (url)=>isHttpUrl(url) || isBase64Url(url);
|
|
362
365
|
const isHttpUrl = (url)=>url.startsWith('http://') || url.startsWith('https://');
|
|
363
366
|
const isBase64Url = (url)=>url.startsWith('data:');
|
|
364
|
-
class
|
|
367
|
+
class DatasetSourceBuilder {
|
|
365
368
|
type;
|
|
366
369
|
value;
|
|
367
|
-
constructor(
|
|
368
|
-
this.type = type;
|
|
369
|
-
this.value =
|
|
370
|
+
constructor(raw){
|
|
371
|
+
this.type = raw.type;
|
|
372
|
+
this.value = raw.rawDataset;
|
|
370
373
|
}
|
|
371
|
-
static from(
|
|
372
|
-
return new
|
|
374
|
+
static from(raw) {
|
|
375
|
+
return new DatasetSourceBuilder(raw);
|
|
373
376
|
}
|
|
374
377
|
async build() {
|
|
375
|
-
const blob = await
|
|
378
|
+
const blob = await DatasetSourceBuilder.convertToBlob(this.type, this.value);
|
|
376
379
|
return {
|
|
377
380
|
type: this.type,
|
|
378
381
|
blob: blob
|
|
@@ -386,7 +389,7 @@ class DataSourceBuilder {
|
|
|
386
389
|
], {
|
|
387
390
|
type: 'text/csv'
|
|
388
391
|
});
|
|
389
|
-
if ('string' == typeof csvSource && isUrl(csvSource)) return
|
|
392
|
+
if ('string' == typeof csvSource && isUrl(csvSource)) return DatasetSourceBuilder.fetchBlob(csvSource);
|
|
390
393
|
return new Blob([
|
|
391
394
|
JSON.stringify(csvSource)
|
|
392
395
|
], {
|
|
@@ -399,7 +402,7 @@ class DataSourceBuilder {
|
|
|
399
402
|
], {
|
|
400
403
|
type: 'application/json'
|
|
401
404
|
});
|
|
402
|
-
if ('string' == typeof jsonSource && isUrl(jsonSource)) return
|
|
405
|
+
if ('string' == typeof jsonSource && isUrl(jsonSource)) return DatasetSourceBuilder.fetchBlob(jsonSource);
|
|
403
406
|
return new Blob([
|
|
404
407
|
JSON.stringify(jsonSource)
|
|
405
408
|
], {
|
|
@@ -412,7 +415,7 @@ class DataSourceBuilder {
|
|
|
412
415
|
], {
|
|
413
416
|
type: 'application/parquet'
|
|
414
417
|
});
|
|
415
|
-
if ('string' == typeof parquetSource && isUrl(parquetSource)) return
|
|
418
|
+
if ('string' == typeof parquetSource && isUrl(parquetSource)) return DatasetSourceBuilder.fetchBlob(parquetSource);
|
|
416
419
|
return new Blob([
|
|
417
420
|
parquetSource
|
|
418
421
|
], {
|
|
@@ -425,7 +428,7 @@ class DataSourceBuilder {
|
|
|
425
428
|
], {
|
|
426
429
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
427
430
|
});
|
|
428
|
-
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return
|
|
431
|
+
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return DatasetSourceBuilder.fetchBlob(xlsxSource);
|
|
429
432
|
return new Blob([
|
|
430
433
|
xlsxSource
|
|
431
434
|
], {
|
|
@@ -460,50 +463,62 @@ class VQuery {
|
|
|
460
463
|
this.duckDB = new DuckDB();
|
|
461
464
|
this.indexedDB = new IndexedDB(dbName);
|
|
462
465
|
}
|
|
463
|
-
async
|
|
466
|
+
async checkInitialized() {
|
|
464
467
|
if (!this.isInitialized) {
|
|
465
468
|
await this.duckDB.init();
|
|
466
469
|
await this.indexedDB.open();
|
|
467
470
|
this.isInitialized = true;
|
|
468
471
|
}
|
|
469
472
|
}
|
|
470
|
-
async
|
|
471
|
-
await this.
|
|
472
|
-
|
|
473
|
+
async checkDatasetExists(datasetId) {
|
|
474
|
+
if (!await this.hasDataset(datasetId)) throw new Error(`dataset ${datasetId} not exists, please create it first`);
|
|
475
|
+
}
|
|
476
|
+
async createDataset(datasetId, columns = [], rawDatasetSource) {
|
|
477
|
+
await this.checkInitialized();
|
|
478
|
+
const datasetSource = rawDatasetSource ? await DatasetSourceBuilder.from(rawDatasetSource).build() : void 0;
|
|
479
|
+
if (await this.hasDataset(datasetId)) throw new Error(`dataset ${datasetId} already exists`);
|
|
473
480
|
const datasetSchema = {
|
|
474
481
|
datasetId,
|
|
475
482
|
datasetAlias: datasetId,
|
|
476
483
|
columns: columns
|
|
477
484
|
};
|
|
478
|
-
await this.indexedDB.writeDataset(datasetId,
|
|
485
|
+
await this.indexedDB.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
479
486
|
}
|
|
480
|
-
async
|
|
481
|
-
await this.
|
|
482
|
-
|
|
483
|
-
await
|
|
487
|
+
async updateDatasetSource(datasetId, columns = [], rawDatasetSource) {
|
|
488
|
+
await this.checkInitialized();
|
|
489
|
+
await this.checkDatasetExists(datasetId);
|
|
490
|
+
const datasetSource = rawDatasetSource ? await DatasetSourceBuilder.from(rawDatasetSource).build() : void 0;
|
|
491
|
+
const datasetSchema = {
|
|
492
|
+
datasetId,
|
|
493
|
+
datasetAlias: datasetId,
|
|
494
|
+
columns: columns
|
|
495
|
+
};
|
|
496
|
+
await this.indexedDB.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
484
497
|
}
|
|
485
498
|
async dropDataset(datasetId) {
|
|
486
|
-
await this.
|
|
499
|
+
await this.checkInitialized();
|
|
500
|
+
await this.checkDatasetExists(datasetId);
|
|
487
501
|
await this.indexedDB.deleteDataset(datasetId);
|
|
488
502
|
}
|
|
503
|
+
async connectDataset(datasetId, temporaryColumns = []) {
|
|
504
|
+
await this.checkInitialized();
|
|
505
|
+
await this.checkDatasetExists(datasetId);
|
|
506
|
+
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
507
|
+
await dataset.init(temporaryColumns);
|
|
508
|
+
return dataset;
|
|
509
|
+
}
|
|
489
510
|
async hasDataset(datasetId) {
|
|
490
|
-
await this.
|
|
511
|
+
await this.checkInitialized();
|
|
491
512
|
const datasets = await this.indexedDB.listDatasets();
|
|
492
513
|
return datasets.some((item)=>item.datasetId === datasetId);
|
|
493
514
|
}
|
|
494
515
|
async listDatasets() {
|
|
495
|
-
await this.
|
|
516
|
+
await this.checkInitialized();
|
|
496
517
|
return this.indexedDB.listDatasets();
|
|
497
518
|
}
|
|
498
|
-
async connectDataset(datasetId, temporaryColumns = []) {
|
|
499
|
-
await this.ensureInitialized();
|
|
500
|
-
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
501
|
-
await dataset.init(temporaryColumns);
|
|
502
|
-
return dataset;
|
|
503
|
-
}
|
|
504
519
|
async close() {
|
|
505
|
-
await this.
|
|
520
|
+
await this.checkInitialized();
|
|
506
521
|
await this.duckDB.close();
|
|
507
522
|
}
|
|
508
523
|
}
|
|
509
|
-
export {
|
|
524
|
+
export { DatasetSourceBuilder, VQuery, convertDSLToSQL, isBase64Url, isHttpUrl, isUrl };
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export type TidyDatum = Record<string, number | string | null | boolean | undefined>;
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
4
|
-
export interface
|
|
5
|
-
type:
|
|
2
|
+
export type DatasetSourceType = 'csv' | 'json' | 'xlsx' | 'parquet';
|
|
3
|
+
export type DatasetSourceValue = string | ArrayBuffer | Blob | TidyDatum[];
|
|
4
|
+
export interface DatasetSource {
|
|
5
|
+
type: DatasetSourceType;
|
|
6
6
|
blob: Blob;
|
|
7
7
|
}
|
|
8
|
+
export interface RawDatasetSource {
|
|
9
|
+
type: DatasetSourceType;
|
|
10
|
+
rawDataset: DatasetSourceValue;
|
|
11
|
+
}
|
package/dist/vquery.d.ts
CHANGED
|
@@ -1,41 +1,21 @@
|
|
|
1
1
|
import { Dataset } from './dataset/dataset';
|
|
2
|
-
import {
|
|
2
|
+
import { RawDatasetSource, DatasetColumn } from './types';
|
|
3
3
|
export declare class VQuery {
|
|
4
4
|
private duckDB;
|
|
5
5
|
private indexedDB;
|
|
6
6
|
private isInitialized;
|
|
7
7
|
constructor(dbName?: string);
|
|
8
|
-
private
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
createDataset(datasetId: string, data: string | ArrayBuffer | Blob | TidyDatum[], type: DataSourceType, columns?: DatasetColumn[]): Promise<void>;
|
|
13
|
-
/**
|
|
14
|
-
* 修改数据集,更新信息到indexedDB内
|
|
15
|
-
*/
|
|
16
|
-
updateDataset(datasetId: string, data: string | ArrayBuffer | Blob | TidyDatum[], type: DataSourceType, datasetSchema: DatasetSchema): Promise<void>;
|
|
17
|
-
/**
|
|
18
|
-
* 删除数据集,从indexdb移除数据集
|
|
19
|
-
*/
|
|
8
|
+
private checkInitialized;
|
|
9
|
+
private checkDatasetExists;
|
|
10
|
+
createDataset(datasetId: string, columns?: DatasetColumn[], rawDatasetSource?: RawDatasetSource): Promise<void>;
|
|
11
|
+
updateDatasetSource(datasetId: string, columns?: DatasetColumn[], rawDatasetSource?: RawDatasetSource): Promise<void>;
|
|
20
12
|
dropDataset(datasetId: string): Promise<void>;
|
|
21
|
-
|
|
22
|
-
* 检查数据集是否存在
|
|
23
|
-
*/
|
|
13
|
+
connectDataset(datasetId: string, temporaryColumns?: DatasetColumn[]): Promise<Dataset>;
|
|
24
14
|
hasDataset(datasetId: string): Promise<boolean>;
|
|
25
|
-
/**
|
|
26
|
-
* 获取所有可用数据集
|
|
27
|
-
*/
|
|
28
15
|
listDatasets(): Promise<{
|
|
29
16
|
datasetId: string;
|
|
30
|
-
dataSource
|
|
31
|
-
datasetSchema: DatasetSchema;
|
|
17
|
+
dataSource?: import("./types").DatasetSource;
|
|
18
|
+
datasetSchema: import("./types").DatasetSchema;
|
|
32
19
|
}[]>;
|
|
33
|
-
/**
|
|
34
|
-
* 连接数据集,返回数据集信息,从indexedDB获取表结构,使用DuckDB在内存中创建表
|
|
35
|
-
*/
|
|
36
|
-
connectDataset(datasetId: string, temporaryColumns?: DatasetColumn[]): Promise<Dataset>;
|
|
37
|
-
/**
|
|
38
|
-
* 关闭所有数据集连接,释放DuckDB资源
|
|
39
|
-
*/
|
|
40
20
|
close(): Promise<void>;
|
|
41
21
|
}
|