@visactor/vquery 0.1.49 → 0.1.51
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 +5 -5
- package/dist/db/indexedDb.d.ts +4 -4
- package/dist/index.cjs +70 -56
- package/dist/index.d.ts +1 -1
- package/dist/index.js +68 -54
- 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';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DatasetColumn, QueryDSL } from '../types';
|
|
1
|
+
import { DatasetColumn, DatasetSource, QueryDSL } from '../types';
|
|
2
2
|
import { DuckDB } from '../db/duckDb';
|
|
3
3
|
import { IndexedDB } from '../db/indexedDb';
|
|
4
4
|
export declare class Dataset {
|
|
@@ -6,8 +6,9 @@ export declare class Dataset {
|
|
|
6
6
|
private indexedDB;
|
|
7
7
|
private _datasetId;
|
|
8
8
|
constructor(duckDB: DuckDB, indexedDB: IndexedDB, datasetId: string);
|
|
9
|
-
init(temporaryColumns?: DatasetColumn[]): Promise<void>;
|
|
10
|
-
|
|
9
|
+
init(temporaryColumns?: DatasetColumn[], temporaryDatasetSource?: DatasetSource): Promise<void>;
|
|
10
|
+
createOrReplaceView(columns: DatasetColumn[], datasetSource: DatasetSource): 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,
|
|
@@ -185,7 +185,14 @@ class Dataset {
|
|
|
185
185
|
this.indexedDB = indexedDB1;
|
|
186
186
|
this._datasetId = datasetId;
|
|
187
187
|
}
|
|
188
|
-
async init(temporaryColumns
|
|
188
|
+
async init(temporaryColumns, temporaryDatasetSource) {
|
|
189
|
+
const datasetInfo = await this.indexedDB.readDataset(this._datasetId);
|
|
190
|
+
if (!datasetInfo) throw new Error(`Dataset ${this._datasetId} not found`);
|
|
191
|
+
const columns = temporaryColumns ? temporaryColumns : datasetInfo.datasetSchema.columns;
|
|
192
|
+
const datasetSource = temporaryDatasetSource || datasetInfo.datasetSource;
|
|
193
|
+
if (columns.length > 0 && datasetSource) await this.createOrReplaceView(columns, datasetSource);
|
|
194
|
+
}
|
|
195
|
+
async createOrReplaceView(columns, datasetSource) {
|
|
189
196
|
const readFunctionMap = {
|
|
190
197
|
csv: 'read_csv_auto',
|
|
191
198
|
json: 'read_json_auto',
|
|
@@ -199,18 +206,19 @@ class Dataset {
|
|
|
199
206
|
datetime: 'TIMESTAMP',
|
|
200
207
|
timestamp: 'TIMESTAMP'
|
|
201
208
|
};
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
209
|
+
if (datasetSource) {
|
|
210
|
+
const readFunction = readFunctionMap[datasetSource.type];
|
|
211
|
+
if (!readFunction) throw new Error(`Unsupported dataSource type: ${datasetSource.type}`);
|
|
212
|
+
await this.duckDB.writeFile(this._datasetId, datasetSource.blob);
|
|
213
|
+
const columnsStruct = `{${columns.map((c)=>`'${c.name}': '${dataTypeMap[c.type] || 'VARCHAR'}'`).join(', ')}}`;
|
|
214
|
+
const columnNames = columns.map((c)=>`"${c.name}"`).join(', ');
|
|
215
|
+
const createViewSql = `CREATE OR REPLACE VIEW "${this._datasetId}" AS SELECT ${columnNames} FROM ${readFunction}('${this._datasetId}', columns=${columnsStruct})`;
|
|
216
|
+
await this.duckDB.query(createViewSql);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async query(queryDSL) {
|
|
220
|
+
const sql = convertDSLToSQL(queryDSL, this.datasetId);
|
|
221
|
+
return this.queryBySQL(sql);
|
|
214
222
|
}
|
|
215
223
|
async queryBySQL(sql) {
|
|
216
224
|
const start = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
@@ -225,13 +233,6 @@ class Dataset {
|
|
|
225
233
|
}
|
|
226
234
|
};
|
|
227
235
|
}
|
|
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
236
|
async disconnect() {
|
|
236
237
|
await this.duckDB.query(`DROP VIEW IF EXISTS "${this._datasetId}"`);
|
|
237
238
|
}
|
|
@@ -331,7 +332,7 @@ class IndexedDB {
|
|
|
331
332
|
this.db = null;
|
|
332
333
|
}
|
|
333
334
|
};
|
|
334
|
-
writeDataset = (datasetId,
|
|
335
|
+
writeDataset = (datasetId, datasetSchema, datasetSource)=>new Promise((resolve, reject)=>{
|
|
335
336
|
if (!this.db) return reject('DB is not open');
|
|
336
337
|
const transaction = this.db.transaction([
|
|
337
338
|
this.datasetStoreName
|
|
@@ -339,8 +340,8 @@ class IndexedDB {
|
|
|
339
340
|
const store = transaction.objectStore(this.datasetStoreName);
|
|
340
341
|
const request = store.put({
|
|
341
342
|
datasetId,
|
|
342
|
-
|
|
343
|
-
|
|
343
|
+
datasetSchema,
|
|
344
|
+
datasetSource
|
|
344
345
|
});
|
|
345
346
|
request.onsuccess = ()=>{
|
|
346
347
|
resolve();
|
|
@@ -397,18 +398,18 @@ class IndexedDB {
|
|
|
397
398
|
const isUrl = (url)=>isHttpUrl(url) || isBase64Url(url);
|
|
398
399
|
const isHttpUrl = (url)=>url.startsWith('http://') || url.startsWith('https://');
|
|
399
400
|
const isBase64Url = (url)=>url.startsWith('data:');
|
|
400
|
-
class
|
|
401
|
+
class DatasetSourceBuilder {
|
|
401
402
|
type;
|
|
402
403
|
value;
|
|
403
|
-
constructor(
|
|
404
|
-
this.type = type;
|
|
405
|
-
this.value =
|
|
404
|
+
constructor(raw){
|
|
405
|
+
this.type = raw.type;
|
|
406
|
+
this.value = raw.rawDataset;
|
|
406
407
|
}
|
|
407
|
-
static from(
|
|
408
|
-
return new
|
|
408
|
+
static from(raw) {
|
|
409
|
+
return new DatasetSourceBuilder(raw);
|
|
409
410
|
}
|
|
410
411
|
async build() {
|
|
411
|
-
const blob = await
|
|
412
|
+
const blob = await DatasetSourceBuilder.convertToBlob(this.type, this.value);
|
|
412
413
|
return {
|
|
413
414
|
type: this.type,
|
|
414
415
|
blob: blob
|
|
@@ -422,7 +423,7 @@ class DataSourceBuilder {
|
|
|
422
423
|
], {
|
|
423
424
|
type: 'text/csv'
|
|
424
425
|
});
|
|
425
|
-
if ('string' == typeof csvSource && isUrl(csvSource)) return
|
|
426
|
+
if ('string' == typeof csvSource && isUrl(csvSource)) return DatasetSourceBuilder.fetchBlob(csvSource);
|
|
426
427
|
return new Blob([
|
|
427
428
|
JSON.stringify(csvSource)
|
|
428
429
|
], {
|
|
@@ -435,7 +436,7 @@ class DataSourceBuilder {
|
|
|
435
436
|
], {
|
|
436
437
|
type: 'application/json'
|
|
437
438
|
});
|
|
438
|
-
if ('string' == typeof jsonSource && isUrl(jsonSource)) return
|
|
439
|
+
if ('string' == typeof jsonSource && isUrl(jsonSource)) return DatasetSourceBuilder.fetchBlob(jsonSource);
|
|
439
440
|
return new Blob([
|
|
440
441
|
JSON.stringify(jsonSource)
|
|
441
442
|
], {
|
|
@@ -448,7 +449,7 @@ class DataSourceBuilder {
|
|
|
448
449
|
], {
|
|
449
450
|
type: 'application/parquet'
|
|
450
451
|
});
|
|
451
|
-
if ('string' == typeof parquetSource && isUrl(parquetSource)) return
|
|
452
|
+
if ('string' == typeof parquetSource && isUrl(parquetSource)) return DatasetSourceBuilder.fetchBlob(parquetSource);
|
|
452
453
|
return new Blob([
|
|
453
454
|
parquetSource
|
|
454
455
|
], {
|
|
@@ -461,7 +462,7 @@ class DataSourceBuilder {
|
|
|
461
462
|
], {
|
|
462
463
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
463
464
|
});
|
|
464
|
-
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return
|
|
465
|
+
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return DatasetSourceBuilder.fetchBlob(xlsxSource);
|
|
465
466
|
return new Blob([
|
|
466
467
|
xlsxSource
|
|
467
468
|
], {
|
|
@@ -496,60 +497,73 @@ class VQuery {
|
|
|
496
497
|
this.duckDB = new DuckDB();
|
|
497
498
|
this.indexedDB = new IndexedDB(dbName);
|
|
498
499
|
}
|
|
499
|
-
async
|
|
500
|
+
async checkInitialized() {
|
|
500
501
|
if (!this.isInitialized) {
|
|
501
502
|
await this.duckDB.init();
|
|
502
503
|
await this.indexedDB.open();
|
|
503
504
|
this.isInitialized = true;
|
|
504
505
|
}
|
|
505
506
|
}
|
|
506
|
-
async
|
|
507
|
-
await this.
|
|
508
|
-
|
|
507
|
+
async checkDatasetExists(datasetId) {
|
|
508
|
+
if (!await this.hasDataset(datasetId)) throw new Error(`dataset ${datasetId} not exists, please create it first`);
|
|
509
|
+
}
|
|
510
|
+
async createDataset(datasetId, columns = [], rawDatasetSource) {
|
|
511
|
+
await this.checkInitialized();
|
|
512
|
+
const datasetSource = rawDatasetSource ? await DatasetSourceBuilder.from(rawDatasetSource).build() : void 0;
|
|
513
|
+
if (await this.hasDataset(datasetId)) throw new Error(`dataset ${datasetId} already exists`);
|
|
509
514
|
const datasetSchema = {
|
|
510
515
|
datasetId,
|
|
511
516
|
datasetAlias: datasetId,
|
|
512
517
|
columns: columns
|
|
513
518
|
};
|
|
514
|
-
await this.indexedDB.writeDataset(datasetId,
|
|
519
|
+
await this.indexedDB.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
515
520
|
}
|
|
516
|
-
async
|
|
517
|
-
await this.
|
|
518
|
-
|
|
519
|
-
await
|
|
521
|
+
async updateDatasetSource(datasetId, columns = [], rawDatasetSource) {
|
|
522
|
+
await this.checkInitialized();
|
|
523
|
+
await this.checkDatasetExists(datasetId);
|
|
524
|
+
const datasetSource = rawDatasetSource ? await DatasetSourceBuilder.from(rawDatasetSource).build() : void 0;
|
|
525
|
+
const datasetSchema = {
|
|
526
|
+
datasetId,
|
|
527
|
+
datasetAlias: datasetId,
|
|
528
|
+
columns: columns
|
|
529
|
+
};
|
|
530
|
+
await this.indexedDB.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
520
531
|
}
|
|
521
532
|
async dropDataset(datasetId) {
|
|
522
|
-
await this.
|
|
533
|
+
await this.checkInitialized();
|
|
534
|
+
await this.checkDatasetExists(datasetId);
|
|
523
535
|
await this.indexedDB.deleteDataset(datasetId);
|
|
524
536
|
}
|
|
537
|
+
async connectDataset(datasetId, temporaryColumns, temporaryRawDatasetSource) {
|
|
538
|
+
await this.checkInitialized();
|
|
539
|
+
await this.checkDatasetExists(datasetId);
|
|
540
|
+
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
541
|
+
const temporaryDatasetSource = temporaryRawDatasetSource ? await DatasetSourceBuilder.from(temporaryRawDatasetSource).build() : void 0;
|
|
542
|
+
await dataset.init(temporaryColumns, temporaryDatasetSource);
|
|
543
|
+
return dataset;
|
|
544
|
+
}
|
|
525
545
|
async hasDataset(datasetId) {
|
|
526
|
-
await this.
|
|
546
|
+
await this.checkInitialized();
|
|
527
547
|
const datasets = await this.indexedDB.listDatasets();
|
|
528
548
|
return datasets.some((item)=>item.datasetId === datasetId);
|
|
529
549
|
}
|
|
530
550
|
async listDatasets() {
|
|
531
|
-
await this.
|
|
551
|
+
await this.checkInitialized();
|
|
532
552
|
return this.indexedDB.listDatasets();
|
|
533
553
|
}
|
|
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
554
|
async close() {
|
|
541
|
-
await this.
|
|
555
|
+
await this.checkInitialized();
|
|
542
556
|
await this.duckDB.close();
|
|
543
557
|
}
|
|
544
558
|
}
|
|
545
|
-
exports.
|
|
559
|
+
exports.DatasetSourceBuilder = __webpack_exports__.DatasetSourceBuilder;
|
|
546
560
|
exports.VQuery = __webpack_exports__.VQuery;
|
|
547
561
|
exports.convertDSLToSQL = __webpack_exports__.convertDSLToSQL;
|
|
548
562
|
exports.isBase64Url = __webpack_exports__.isBase64Url;
|
|
549
563
|
exports.isHttpUrl = __webpack_exports__.isHttpUrl;
|
|
550
564
|
exports.isUrl = __webpack_exports__.isUrl;
|
|
551
565
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
552
|
-
"
|
|
566
|
+
"DatasetSourceBuilder",
|
|
553
567
|
"VQuery",
|
|
554
568
|
"convertDSLToSQL",
|
|
555
569
|
"isBase64Url",
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -150,7 +150,14 @@ class Dataset {
|
|
|
150
150
|
this.indexedDB = indexedDB1;
|
|
151
151
|
this._datasetId = datasetId;
|
|
152
152
|
}
|
|
153
|
-
async init(temporaryColumns
|
|
153
|
+
async init(temporaryColumns, temporaryDatasetSource) {
|
|
154
|
+
const datasetInfo = await this.indexedDB.readDataset(this._datasetId);
|
|
155
|
+
if (!datasetInfo) throw new Error(`Dataset ${this._datasetId} not found`);
|
|
156
|
+
const columns = temporaryColumns ? temporaryColumns : datasetInfo.datasetSchema.columns;
|
|
157
|
+
const datasetSource = temporaryDatasetSource || datasetInfo.datasetSource;
|
|
158
|
+
if (columns.length > 0 && datasetSource) await this.createOrReplaceView(columns, datasetSource);
|
|
159
|
+
}
|
|
160
|
+
async createOrReplaceView(columns, datasetSource) {
|
|
154
161
|
const readFunctionMap = {
|
|
155
162
|
csv: 'read_csv_auto',
|
|
156
163
|
json: 'read_json_auto',
|
|
@@ -164,18 +171,19 @@ class Dataset {
|
|
|
164
171
|
datetime: 'TIMESTAMP',
|
|
165
172
|
timestamp: 'TIMESTAMP'
|
|
166
173
|
};
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
174
|
+
if (datasetSource) {
|
|
175
|
+
const readFunction = readFunctionMap[datasetSource.type];
|
|
176
|
+
if (!readFunction) throw new Error(`Unsupported dataSource type: ${datasetSource.type}`);
|
|
177
|
+
await this.duckDB.writeFile(this._datasetId, datasetSource.blob);
|
|
178
|
+
const columnsStruct = `{${columns.map((c)=>`'${c.name}': '${dataTypeMap[c.type] || 'VARCHAR'}'`).join(', ')}}`;
|
|
179
|
+
const columnNames = columns.map((c)=>`"${c.name}"`).join(', ');
|
|
180
|
+
const createViewSql = `CREATE OR REPLACE VIEW "${this._datasetId}" AS SELECT ${columnNames} FROM ${readFunction}('${this._datasetId}', columns=${columnsStruct})`;
|
|
181
|
+
await this.duckDB.query(createViewSql);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async query(queryDSL) {
|
|
185
|
+
const sql = convertDSLToSQL(queryDSL, this.datasetId);
|
|
186
|
+
return this.queryBySQL(sql);
|
|
179
187
|
}
|
|
180
188
|
async queryBySQL(sql) {
|
|
181
189
|
const start = performance?.now?.()?.toFixed(3) ?? Date.now().toFixed(3);
|
|
@@ -190,13 +198,6 @@ class Dataset {
|
|
|
190
198
|
}
|
|
191
199
|
};
|
|
192
200
|
}
|
|
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
201
|
async disconnect() {
|
|
201
202
|
await this.duckDB.query(`DROP VIEW IF EXISTS "${this._datasetId}"`);
|
|
202
203
|
}
|
|
@@ -295,7 +296,7 @@ class IndexedDB {
|
|
|
295
296
|
this.db = null;
|
|
296
297
|
}
|
|
297
298
|
};
|
|
298
|
-
writeDataset = (datasetId,
|
|
299
|
+
writeDataset = (datasetId, datasetSchema, datasetSource)=>new Promise((resolve, reject)=>{
|
|
299
300
|
if (!this.db) return reject('DB is not open');
|
|
300
301
|
const transaction = this.db.transaction([
|
|
301
302
|
this.datasetStoreName
|
|
@@ -303,8 +304,8 @@ class IndexedDB {
|
|
|
303
304
|
const store = transaction.objectStore(this.datasetStoreName);
|
|
304
305
|
const request = store.put({
|
|
305
306
|
datasetId,
|
|
306
|
-
|
|
307
|
-
|
|
307
|
+
datasetSchema,
|
|
308
|
+
datasetSource
|
|
308
309
|
});
|
|
309
310
|
request.onsuccess = ()=>{
|
|
310
311
|
resolve();
|
|
@@ -361,18 +362,18 @@ class IndexedDB {
|
|
|
361
362
|
const isUrl = (url)=>isHttpUrl(url) || isBase64Url(url);
|
|
362
363
|
const isHttpUrl = (url)=>url.startsWith('http://') || url.startsWith('https://');
|
|
363
364
|
const isBase64Url = (url)=>url.startsWith('data:');
|
|
364
|
-
class
|
|
365
|
+
class DatasetSourceBuilder {
|
|
365
366
|
type;
|
|
366
367
|
value;
|
|
367
|
-
constructor(
|
|
368
|
-
this.type = type;
|
|
369
|
-
this.value =
|
|
368
|
+
constructor(raw){
|
|
369
|
+
this.type = raw.type;
|
|
370
|
+
this.value = raw.rawDataset;
|
|
370
371
|
}
|
|
371
|
-
static from(
|
|
372
|
-
return new
|
|
372
|
+
static from(raw) {
|
|
373
|
+
return new DatasetSourceBuilder(raw);
|
|
373
374
|
}
|
|
374
375
|
async build() {
|
|
375
|
-
const blob = await
|
|
376
|
+
const blob = await DatasetSourceBuilder.convertToBlob(this.type, this.value);
|
|
376
377
|
return {
|
|
377
378
|
type: this.type,
|
|
378
379
|
blob: blob
|
|
@@ -386,7 +387,7 @@ class DataSourceBuilder {
|
|
|
386
387
|
], {
|
|
387
388
|
type: 'text/csv'
|
|
388
389
|
});
|
|
389
|
-
if ('string' == typeof csvSource && isUrl(csvSource)) return
|
|
390
|
+
if ('string' == typeof csvSource && isUrl(csvSource)) return DatasetSourceBuilder.fetchBlob(csvSource);
|
|
390
391
|
return new Blob([
|
|
391
392
|
JSON.stringify(csvSource)
|
|
392
393
|
], {
|
|
@@ -399,7 +400,7 @@ class DataSourceBuilder {
|
|
|
399
400
|
], {
|
|
400
401
|
type: 'application/json'
|
|
401
402
|
});
|
|
402
|
-
if ('string' == typeof jsonSource && isUrl(jsonSource)) return
|
|
403
|
+
if ('string' == typeof jsonSource && isUrl(jsonSource)) return DatasetSourceBuilder.fetchBlob(jsonSource);
|
|
403
404
|
return new Blob([
|
|
404
405
|
JSON.stringify(jsonSource)
|
|
405
406
|
], {
|
|
@@ -412,7 +413,7 @@ class DataSourceBuilder {
|
|
|
412
413
|
], {
|
|
413
414
|
type: 'application/parquet'
|
|
414
415
|
});
|
|
415
|
-
if ('string' == typeof parquetSource && isUrl(parquetSource)) return
|
|
416
|
+
if ('string' == typeof parquetSource && isUrl(parquetSource)) return DatasetSourceBuilder.fetchBlob(parquetSource);
|
|
416
417
|
return new Blob([
|
|
417
418
|
parquetSource
|
|
418
419
|
], {
|
|
@@ -425,7 +426,7 @@ class DataSourceBuilder {
|
|
|
425
426
|
], {
|
|
426
427
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
427
428
|
});
|
|
428
|
-
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return
|
|
429
|
+
if ('string' == typeof xlsxSource && isUrl(xlsxSource)) return DatasetSourceBuilder.fetchBlob(xlsxSource);
|
|
429
430
|
return new Blob([
|
|
430
431
|
xlsxSource
|
|
431
432
|
], {
|
|
@@ -460,50 +461,63 @@ class VQuery {
|
|
|
460
461
|
this.duckDB = new DuckDB();
|
|
461
462
|
this.indexedDB = new IndexedDB(dbName);
|
|
462
463
|
}
|
|
463
|
-
async
|
|
464
|
+
async checkInitialized() {
|
|
464
465
|
if (!this.isInitialized) {
|
|
465
466
|
await this.duckDB.init();
|
|
466
467
|
await this.indexedDB.open();
|
|
467
468
|
this.isInitialized = true;
|
|
468
469
|
}
|
|
469
470
|
}
|
|
470
|
-
async
|
|
471
|
-
await this.
|
|
472
|
-
|
|
471
|
+
async checkDatasetExists(datasetId) {
|
|
472
|
+
if (!await this.hasDataset(datasetId)) throw new Error(`dataset ${datasetId} not exists, please create it first`);
|
|
473
|
+
}
|
|
474
|
+
async createDataset(datasetId, columns = [], rawDatasetSource) {
|
|
475
|
+
await this.checkInitialized();
|
|
476
|
+
const datasetSource = rawDatasetSource ? await DatasetSourceBuilder.from(rawDatasetSource).build() : void 0;
|
|
477
|
+
if (await this.hasDataset(datasetId)) throw new Error(`dataset ${datasetId} already exists`);
|
|
473
478
|
const datasetSchema = {
|
|
474
479
|
datasetId,
|
|
475
480
|
datasetAlias: datasetId,
|
|
476
481
|
columns: columns
|
|
477
482
|
};
|
|
478
|
-
await this.indexedDB.writeDataset(datasetId,
|
|
483
|
+
await this.indexedDB.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
479
484
|
}
|
|
480
|
-
async
|
|
481
|
-
await this.
|
|
482
|
-
|
|
483
|
-
await
|
|
485
|
+
async updateDatasetSource(datasetId, columns = [], rawDatasetSource) {
|
|
486
|
+
await this.checkInitialized();
|
|
487
|
+
await this.checkDatasetExists(datasetId);
|
|
488
|
+
const datasetSource = rawDatasetSource ? await DatasetSourceBuilder.from(rawDatasetSource).build() : void 0;
|
|
489
|
+
const datasetSchema = {
|
|
490
|
+
datasetId,
|
|
491
|
+
datasetAlias: datasetId,
|
|
492
|
+
columns: columns
|
|
493
|
+
};
|
|
494
|
+
await this.indexedDB.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
484
495
|
}
|
|
485
496
|
async dropDataset(datasetId) {
|
|
486
|
-
await this.
|
|
497
|
+
await this.checkInitialized();
|
|
498
|
+
await this.checkDatasetExists(datasetId);
|
|
487
499
|
await this.indexedDB.deleteDataset(datasetId);
|
|
488
500
|
}
|
|
501
|
+
async connectDataset(datasetId, temporaryColumns, temporaryRawDatasetSource) {
|
|
502
|
+
await this.checkInitialized();
|
|
503
|
+
await this.checkDatasetExists(datasetId);
|
|
504
|
+
const dataset = new Dataset(this.duckDB, this.indexedDB, datasetId);
|
|
505
|
+
const temporaryDatasetSource = temporaryRawDatasetSource ? await DatasetSourceBuilder.from(temporaryRawDatasetSource).build() : void 0;
|
|
506
|
+
await dataset.init(temporaryColumns, temporaryDatasetSource);
|
|
507
|
+
return dataset;
|
|
508
|
+
}
|
|
489
509
|
async hasDataset(datasetId) {
|
|
490
|
-
await this.
|
|
510
|
+
await this.checkInitialized();
|
|
491
511
|
const datasets = await this.indexedDB.listDatasets();
|
|
492
512
|
return datasets.some((item)=>item.datasetId === datasetId);
|
|
493
513
|
}
|
|
494
514
|
async listDatasets() {
|
|
495
|
-
await this.
|
|
515
|
+
await this.checkInitialized();
|
|
496
516
|
return this.indexedDB.listDatasets();
|
|
497
517
|
}
|
|
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
518
|
async close() {
|
|
505
|
-
await this.
|
|
519
|
+
await this.checkInitialized();
|
|
506
520
|
await this.duckDB.close();
|
|
507
521
|
}
|
|
508
522
|
}
|
|
509
|
-
export {
|
|
523
|
+
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[], temporaryRawDatasetSource?: RawDatasetSource): 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
|
}
|