@visactor/vquery 0.4.11 → 0.4.13
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/browser/esm/adapters/storage-adapter/idb-helpers.d.ts +4 -0
- package/dist/browser/esm/browser.js +60 -92
- package/dist/browser/esm/dataset/constants.d.ts +7 -0
- package/dist/browser/esm/dataset/dataset.d.ts +0 -18
- package/dist/browser/esm/sql-builder/utils/escape.d.ts +1 -0
- package/dist/browser/esm/sql-builder/utils/guards.d.ts +2 -0
- package/dist/browser/esm/sql-builder/utils/index.d.ts +3 -0
- package/dist/browser/esm/sql-builder/utils/operator.d.ts +5 -0
- package/dist/node/cjs/adapters/storage-adapter/idb-helpers.d.ts +4 -0
- package/dist/node/cjs/dataset/constants.d.ts +7 -0
- package/dist/node/cjs/dataset/dataset.d.ts +0 -18
- package/dist/node/cjs/node.cjs +14 -23
- package/dist/node/cjs/sql-builder/utils/escape.d.ts +1 -0
- package/dist/node/cjs/sql-builder/utils/guards.d.ts +2 -0
- package/dist/node/cjs/sql-builder/utils/index.d.ts +3 -0
- package/dist/node/cjs/sql-builder/utils/operator.d.ts +5 -0
- package/dist/node/esm/adapters/storage-adapter/idb-helpers.d.ts +4 -0
- package/dist/node/esm/dataset/constants.d.ts +7 -0
- package/dist/node/esm/dataset/dataset.d.ts +0 -18
- package/dist/node/esm/node.js +21 -30
- package/dist/node/esm/sql-builder/utils/escape.d.ts +1 -0
- package/dist/node/esm/sql-builder/utils/guards.d.ts +2 -0
- package/dist/node/esm/sql-builder/utils/index.d.ts +3 -0
- package/dist/node/esm/sql-builder/utils/operator.d.ts +5 -0
- package/package.json +14 -13
- package/dist/browser/esm/sql-builder/utils.d.ts +0 -8
- package/dist/node/cjs/sql-builder/utils.d.ts +0 -8
- package/dist/node/esm/sql-builder/utils.d.ts +0 -8
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const idbPut: <T>(db: IDBDatabase, storeName: string, value: T) => Promise<any>;
|
|
2
|
+
export declare const idbGet: <T>(db: IDBDatabase, storeName: string, key: any) => Promise<T | undefined>;
|
|
3
|
+
export declare const idbDelete: (db: IDBDatabase, storeName: string, key: any) => Promise<any>;
|
|
4
|
+
export declare const idbGetAll: <T>(db: IDBDatabase, storeName: string) => Promise<T[]>;
|
|
@@ -29,7 +29,15 @@ class PostgresDialect {
|
|
|
29
29
|
return new NullIntrospector();
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
const
|
|
32
|
+
const OPERATOR_MAP = {
|
|
33
|
+
gt: '>',
|
|
34
|
+
gte: '>=',
|
|
35
|
+
lt: '<',
|
|
36
|
+
lte: '<=',
|
|
37
|
+
eq: '=',
|
|
38
|
+
neq: '!='
|
|
39
|
+
};
|
|
40
|
+
const toSqlOperator = (op)=>OPERATOR_MAP[op] ?? op;
|
|
33
41
|
const escapeValue = (value)=>{
|
|
34
42
|
if (null === value) return 'null';
|
|
35
43
|
if ('string' == typeof value) return `'${value.replace(/'/g, "''")}'`;
|
|
@@ -37,6 +45,7 @@ const escapeValue = (value)=>{
|
|
|
37
45
|
if ('boolean' == typeof value) return value ? 'TRUE' : 'FALSE';
|
|
38
46
|
return `'${String(value).replace(/'/g, "''")}'`;
|
|
39
47
|
};
|
|
48
|
+
const isSelectItem = (item)=>'object' == typeof item && 'field' in item;
|
|
40
49
|
const inlineParameters = (sql, params)=>{
|
|
41
50
|
if (0 === params.length) return sql;
|
|
42
51
|
if (sql.includes('?')) {
|
|
@@ -51,15 +60,6 @@ const inlineParameters = (sql, params)=>{
|
|
|
51
60
|
});
|
|
52
61
|
return sql;
|
|
53
62
|
};
|
|
54
|
-
const operatorMap = {
|
|
55
|
-
gt: '>',
|
|
56
|
-
gte: '>=',
|
|
57
|
-
lt: '<',
|
|
58
|
-
lte: '<=',
|
|
59
|
-
eq: '=',
|
|
60
|
-
neq: '!='
|
|
61
|
-
};
|
|
62
|
-
const toSqlOperator = (op)=>operatorMap[op] ?? op;
|
|
63
63
|
const applyWhere = (qb, where)=>{
|
|
64
64
|
if (!where) return qb;
|
|
65
65
|
const toRaw = (w)=>{
|
|
@@ -114,15 +114,6 @@ const applyGroupBy = (qb, fields)=>{
|
|
|
114
114
|
}
|
|
115
115
|
return qb;
|
|
116
116
|
};
|
|
117
|
-
const having_operatorMap = {
|
|
118
|
-
gt: '>',
|
|
119
|
-
gte: '>=',
|
|
120
|
-
lt: '<',
|
|
121
|
-
lte: '<=',
|
|
122
|
-
eq: '=',
|
|
123
|
-
neq: '!='
|
|
124
|
-
};
|
|
125
|
-
const having_toSqlOperator = (op)=>having_operatorMap[op] ?? op;
|
|
126
117
|
const applyHaving = (qb, having)=>{
|
|
127
118
|
if (!having) return qb;
|
|
128
119
|
const toRaw = (h)=>{
|
|
@@ -134,7 +125,7 @@ const applyHaving = (qb, having)=>{
|
|
|
134
125
|
const leaf = h;
|
|
135
126
|
const field = leaf.field;
|
|
136
127
|
const value = leaf.value;
|
|
137
|
-
const op =
|
|
128
|
+
const op = toSqlOperator(leaf.op);
|
|
138
129
|
if ([
|
|
139
130
|
'sum',
|
|
140
131
|
'avg',
|
|
@@ -265,6 +256,13 @@ const DATA_TYPE_MAP = {
|
|
|
265
256
|
datetime: 'TIMESTAMP',
|
|
266
257
|
timestamp: 'TIMESTAMP'
|
|
267
258
|
};
|
|
259
|
+
const buildColumnsStruct = (columns)=>{
|
|
260
|
+
const columnDefs = columns.map((c)=>{
|
|
261
|
+
const duckDBType = DATA_TYPE_MAP[c.type] || 'VARCHAR';
|
|
262
|
+
return `'${c.name}': '${duckDBType}'`;
|
|
263
|
+
});
|
|
264
|
+
return `{${columnDefs.join(', ')}}`;
|
|
265
|
+
};
|
|
268
266
|
class Dataset {
|
|
269
267
|
queryAdapter;
|
|
270
268
|
storageAdapter;
|
|
@@ -286,7 +284,7 @@ class Dataset {
|
|
|
286
284
|
const readFunction = READ_FUNCTION_MAP[datasetSource.type];
|
|
287
285
|
if (!readFunction) throw new Error(`Unsupported dataSource type: ${datasetSource.type}`);
|
|
288
286
|
await this.queryAdapter.writeFile(this._datasetId, datasetSource.blob);
|
|
289
|
-
const columnsStruct =
|
|
287
|
+
const columnsStruct = buildColumnsStruct(columns);
|
|
290
288
|
const columnNames = columns.map((c)=>`"${c.name}"`).join(', ');
|
|
291
289
|
let readSql = `${readFunction}('${this._datasetId}')`;
|
|
292
290
|
if ('csv' === datasetSource.type || 'json' === datasetSource.type) readSql = `${readFunction}('${this._datasetId}', columns=${columnsStruct})`;
|
|
@@ -316,13 +314,6 @@ class Dataset {
|
|
|
316
314
|
get datasetId() {
|
|
317
315
|
return this._datasetId;
|
|
318
316
|
}
|
|
319
|
-
buildColumnsStruct(columns) {
|
|
320
|
-
const columnDefs = columns.map((c)=>{
|
|
321
|
-
const duckDBType = DATA_TYPE_MAP[c.type] || 'VARCHAR';
|
|
322
|
-
return `'${c.name}': '${duckDBType}'`;
|
|
323
|
-
});
|
|
324
|
-
return `{${columnDefs.join(', ')}}`;
|
|
325
|
-
}
|
|
326
317
|
}
|
|
327
318
|
const isUrl = (url)=>isHttpUrl(url) || isBase64Url(url);
|
|
328
319
|
const isHttpUrl = (url)=>url.startsWith('http://') || url.startsWith('https://');
|
|
@@ -369,6 +360,23 @@ class DatasetSourceBuilder {
|
|
|
369
360
|
});
|
|
370
361
|
}
|
|
371
362
|
}
|
|
363
|
+
const wrapIDBRequest = (db, storeName, mode, operation)=>new Promise((resolve, reject)=>{
|
|
364
|
+
const transaction = db.transaction([
|
|
365
|
+
storeName
|
|
366
|
+
], mode);
|
|
367
|
+
const store = transaction.objectStore(storeName);
|
|
368
|
+
const request = operation(store);
|
|
369
|
+
request.onsuccess = ()=>{
|
|
370
|
+
resolve(request.result);
|
|
371
|
+
};
|
|
372
|
+
request.onerror = ()=>{
|
|
373
|
+
reject(request.error);
|
|
374
|
+
};
|
|
375
|
+
});
|
|
376
|
+
const idbPut = (db, storeName, value)=>wrapIDBRequest(db, storeName, 'readwrite', (store)=>store.put(value));
|
|
377
|
+
const idbGet = (db, storeName, key)=>wrapIDBRequest(db, storeName, 'readonly', (store)=>store.get(key));
|
|
378
|
+
const idbDelete = (db, storeName, key)=>wrapIDBRequest(db, storeName, 'readwrite', (store)=>store.delete(key));
|
|
379
|
+
const idbGetAll = (db, storeName)=>wrapIDBRequest(db, storeName, 'readonly', (store)=>store.getAll());
|
|
372
380
|
class IndexedDBAdapter {
|
|
373
381
|
db = null;
|
|
374
382
|
dbName;
|
|
@@ -398,68 +406,28 @@ class IndexedDBAdapter {
|
|
|
398
406
|
this.db = null;
|
|
399
407
|
}
|
|
400
408
|
};
|
|
401
|
-
writeDataset = (datasetId, datasetSchema, datasetSource)=>
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
], 'readonly');
|
|
424
|
-
const store = transaction.objectStore(this.datasetStoreName);
|
|
425
|
-
const request = store.get(datasetId);
|
|
426
|
-
request.onsuccess = (event)=>{
|
|
427
|
-
const result = event.target.result;
|
|
428
|
-
resolve(result || null);
|
|
429
|
-
};
|
|
430
|
-
request.onerror = (event)=>{
|
|
431
|
-
reject(event.target.error);
|
|
432
|
-
};
|
|
433
|
-
});
|
|
434
|
-
deleteDataset = (datasetId)=>new Promise((resolve, reject)=>{
|
|
435
|
-
if (!this.db) return reject('DB is not open');
|
|
436
|
-
const transaction = this.db.transaction([
|
|
437
|
-
this.datasetStoreName
|
|
438
|
-
], 'readwrite');
|
|
439
|
-
const store = transaction.objectStore(this.datasetStoreName);
|
|
440
|
-
const request = store.delete(datasetId);
|
|
441
|
-
request.onsuccess = ()=>{
|
|
442
|
-
resolve();
|
|
443
|
-
};
|
|
444
|
-
request.onerror = (event)=>{
|
|
445
|
-
reject(event.target.error);
|
|
446
|
-
};
|
|
447
|
-
});
|
|
448
|
-
listDatasets = ()=>new Promise((resolve, reject)=>{
|
|
449
|
-
if (!this.db) return reject('DB is not open');
|
|
450
|
-
const transaction = this.db.transaction([
|
|
451
|
-
this.datasetStoreName
|
|
452
|
-
], 'readonly');
|
|
453
|
-
const store = transaction.objectStore(this.datasetStoreName);
|
|
454
|
-
const request = store.getAll();
|
|
455
|
-
request.onsuccess = (event)=>{
|
|
456
|
-
const result = event.target.result;
|
|
457
|
-
resolve(result);
|
|
458
|
-
};
|
|
459
|
-
request.onerror = (event)=>{
|
|
460
|
-
reject(event.target.error);
|
|
461
|
-
};
|
|
462
|
-
});
|
|
409
|
+
writeDataset = (datasetId, datasetSchema, datasetSource)=>{
|
|
410
|
+
if (!this.db) return Promise.reject('DB is not open');
|
|
411
|
+
const record = {
|
|
412
|
+
datasetId,
|
|
413
|
+
datasetSchema,
|
|
414
|
+
datasetSource
|
|
415
|
+
};
|
|
416
|
+
return idbPut(this.db, this.datasetStoreName, record).then(()=>void 0);
|
|
417
|
+
};
|
|
418
|
+
readDataset = async (datasetId)=>{
|
|
419
|
+
if (!this.db) return Promise.reject('DB is not open');
|
|
420
|
+
const result = await idbGet(this.db, this.datasetStoreName, datasetId);
|
|
421
|
+
return result ?? null;
|
|
422
|
+
};
|
|
423
|
+
deleteDataset = (datasetId)=>{
|
|
424
|
+
if (!this.db) return Promise.reject('DB is not open');
|
|
425
|
+
return idbDelete(this.db, this.datasetStoreName, datasetId).then(()=>void 0);
|
|
426
|
+
};
|
|
427
|
+
listDatasets = async ()=>{
|
|
428
|
+
if (!this.db) return Promise.reject('DB is not open');
|
|
429
|
+
return idbGetAll(this.db, this.datasetStoreName);
|
|
430
|
+
};
|
|
463
431
|
}
|
|
464
432
|
class DuckDBWebQueryAdapter {
|
|
465
433
|
db = null;
|
|
@@ -548,7 +516,7 @@ class VQuery {
|
|
|
548
516
|
const datasetSchema = {
|
|
549
517
|
datasetId,
|
|
550
518
|
datasetAlias: datasetId,
|
|
551
|
-
columns
|
|
519
|
+
columns
|
|
552
520
|
};
|
|
553
521
|
await this.storageAdapter.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
554
522
|
}
|
|
@@ -559,7 +527,7 @@ class VQuery {
|
|
|
559
527
|
const datasetSchema = {
|
|
560
528
|
datasetId,
|
|
561
529
|
datasetAlias: datasetId,
|
|
562
|
-
columns
|
|
530
|
+
columns
|
|
563
531
|
};
|
|
564
532
|
await this.storageAdapter.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
565
533
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DatasetSourceType, DataType } from '../types';
|
|
2
|
+
export declare const READ_FUNCTION_MAP: Record<DatasetSourceType, string>;
|
|
3
|
+
export declare const DATA_TYPE_MAP: Record<DataType, string>;
|
|
4
|
+
export declare const buildColumnsStruct: (columns: {
|
|
5
|
+
name: string;
|
|
6
|
+
type: DataType;
|
|
7
|
+
}[]) => string;
|
|
@@ -5,19 +5,8 @@ export declare class Dataset {
|
|
|
5
5
|
private storageAdapter;
|
|
6
6
|
private _datasetId;
|
|
7
7
|
constructor(queryAdapter: QueryAdapter, storageAdapter: StorageAdapter, datasetId: string);
|
|
8
|
-
/**
|
|
9
|
-
* Initialize the dataset by loading it into the query engine
|
|
10
|
-
* @param temporaryColumns Optional temporary columns to override storage schema
|
|
11
|
-
* @param temporaryDatasetSource Optional temporary data source to override storage source
|
|
12
|
-
*/
|
|
13
8
|
init(temporaryColumns?: DatasetColumn[], temporaryDatasetSource?: DatasetSource): Promise<void>;
|
|
14
|
-
/**
|
|
15
|
-
* Register file and create a view in DuckDB
|
|
16
|
-
*/
|
|
17
9
|
createOrReplaceView(columns: DatasetColumn[], datasetSource: DatasetSource): Promise<void>;
|
|
18
|
-
/**
|
|
19
|
-
* Execute query using VQuery DSL
|
|
20
|
-
*/
|
|
21
10
|
query<T extends Record<string, number | string>>(queryDSL: QueryDSL<T> | VQueryDSL<T>): Promise<{
|
|
22
11
|
performance: {
|
|
23
12
|
startAt: string;
|
|
@@ -27,9 +16,6 @@ export declare class Dataset {
|
|
|
27
16
|
dataset: any[];
|
|
28
17
|
table: any;
|
|
29
18
|
}>;
|
|
30
|
-
/**
|
|
31
|
-
* Execute raw SQL query
|
|
32
|
-
*/
|
|
33
19
|
queryBySQL(sql: string): Promise<{
|
|
34
20
|
performance: {
|
|
35
21
|
startAt: string;
|
|
@@ -39,10 +25,6 @@ export declare class Dataset {
|
|
|
39
25
|
dataset: any[];
|
|
40
26
|
table: any;
|
|
41
27
|
}>;
|
|
42
|
-
/**
|
|
43
|
-
* Clean up resources
|
|
44
|
-
*/
|
|
45
28
|
disconnect(): Promise<void>;
|
|
46
29
|
get datasetId(): string;
|
|
47
|
-
private buildColumnsStruct;
|
|
48
30
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const escapeValue: (value: unknown) => string;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const idbPut: <T>(db: IDBDatabase, storeName: string, value: T) => Promise<any>;
|
|
2
|
+
export declare const idbGet: <T>(db: IDBDatabase, storeName: string, key: any) => Promise<T | undefined>;
|
|
3
|
+
export declare const idbDelete: (db: IDBDatabase, storeName: string, key: any) => Promise<any>;
|
|
4
|
+
export declare const idbGetAll: <T>(db: IDBDatabase, storeName: string) => Promise<T[]>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DatasetSourceType, DataType } from '../types';
|
|
2
|
+
export declare const READ_FUNCTION_MAP: Record<DatasetSourceType, string>;
|
|
3
|
+
export declare const DATA_TYPE_MAP: Record<DataType, string>;
|
|
4
|
+
export declare const buildColumnsStruct: (columns: {
|
|
5
|
+
name: string;
|
|
6
|
+
type: DataType;
|
|
7
|
+
}[]) => string;
|
|
@@ -5,19 +5,8 @@ export declare class Dataset {
|
|
|
5
5
|
private storageAdapter;
|
|
6
6
|
private _datasetId;
|
|
7
7
|
constructor(queryAdapter: QueryAdapter, storageAdapter: StorageAdapter, datasetId: string);
|
|
8
|
-
/**
|
|
9
|
-
* Initialize the dataset by loading it into the query engine
|
|
10
|
-
* @param temporaryColumns Optional temporary columns to override storage schema
|
|
11
|
-
* @param temporaryDatasetSource Optional temporary data source to override storage source
|
|
12
|
-
*/
|
|
13
8
|
init(temporaryColumns?: DatasetColumn[], temporaryDatasetSource?: DatasetSource): Promise<void>;
|
|
14
|
-
/**
|
|
15
|
-
* Register file and create a view in DuckDB
|
|
16
|
-
*/
|
|
17
9
|
createOrReplaceView(columns: DatasetColumn[], datasetSource: DatasetSource): Promise<void>;
|
|
18
|
-
/**
|
|
19
|
-
* Execute query using VQuery DSL
|
|
20
|
-
*/
|
|
21
10
|
query<T extends Record<string, number | string>>(queryDSL: QueryDSL<T> | VQueryDSL<T>): Promise<{
|
|
22
11
|
performance: {
|
|
23
12
|
startAt: string;
|
|
@@ -27,9 +16,6 @@ export declare class Dataset {
|
|
|
27
16
|
dataset: any[];
|
|
28
17
|
table: any;
|
|
29
18
|
}>;
|
|
30
|
-
/**
|
|
31
|
-
* Execute raw SQL query
|
|
32
|
-
*/
|
|
33
19
|
queryBySQL(sql: string): Promise<{
|
|
34
20
|
performance: {
|
|
35
21
|
startAt: string;
|
|
@@ -39,10 +25,6 @@ export declare class Dataset {
|
|
|
39
25
|
dataset: any[];
|
|
40
26
|
table: any;
|
|
41
27
|
}>;
|
|
42
|
-
/**
|
|
43
|
-
* Clean up resources
|
|
44
|
-
*/
|
|
45
28
|
disconnect(): Promise<void>;
|
|
46
29
|
get datasetId(): string;
|
|
47
|
-
private buildColumnsStruct;
|
|
48
30
|
}
|
package/dist/node/cjs/node.cjs
CHANGED
|
@@ -67,7 +67,6 @@ class PostgresDialect {
|
|
|
67
67
|
return new NullIntrospector();
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
const isSelectItem = (item)=>'object' == typeof item && 'field' in item;
|
|
71
70
|
const escapeValue = (value)=>{
|
|
72
71
|
if (null === value) return 'null';
|
|
73
72
|
if ('string' == typeof value) return `'${value.replace(/'/g, "''")}'`;
|
|
@@ -89,7 +88,7 @@ const inlineParameters = (sql, params)=>{
|
|
|
89
88
|
});
|
|
90
89
|
return sql;
|
|
91
90
|
};
|
|
92
|
-
const
|
|
91
|
+
const OPERATOR_MAP = {
|
|
93
92
|
gt: '>',
|
|
94
93
|
gte: '>=',
|
|
95
94
|
lt: '<',
|
|
@@ -97,7 +96,7 @@ const operatorMap = {
|
|
|
97
96
|
eq: '=',
|
|
98
97
|
neq: '!='
|
|
99
98
|
};
|
|
100
|
-
const toSqlOperator = (op)=>
|
|
99
|
+
const toSqlOperator = (op)=>OPERATOR_MAP[op] ?? op;
|
|
101
100
|
const applyWhere = (qb, where)=>{
|
|
102
101
|
if (!where) return qb;
|
|
103
102
|
const toRaw = (w)=>{
|
|
@@ -152,15 +151,6 @@ const applyGroupBy = (qb, fields)=>{
|
|
|
152
151
|
}
|
|
153
152
|
return qb;
|
|
154
153
|
};
|
|
155
|
-
const having_operatorMap = {
|
|
156
|
-
gt: '>',
|
|
157
|
-
gte: '>=',
|
|
158
|
-
lt: '<',
|
|
159
|
-
lte: '<=',
|
|
160
|
-
eq: '=',
|
|
161
|
-
neq: '!='
|
|
162
|
-
};
|
|
163
|
-
const having_toSqlOperator = (op)=>having_operatorMap[op] ?? op;
|
|
164
154
|
const applyHaving = (qb, having)=>{
|
|
165
155
|
if (!having) return qb;
|
|
166
156
|
const toRaw = (h)=>{
|
|
@@ -172,7 +162,7 @@ const applyHaving = (qb, having)=>{
|
|
|
172
162
|
const leaf = h;
|
|
173
163
|
const field = leaf.field;
|
|
174
164
|
const value = leaf.value;
|
|
175
|
-
const op =
|
|
165
|
+
const op = toSqlOperator(leaf.op);
|
|
176
166
|
if ([
|
|
177
167
|
'sum',
|
|
178
168
|
'avg',
|
|
@@ -228,6 +218,7 @@ const applyOrder = (qb, orderBy)=>{
|
|
|
228
218
|
});
|
|
229
219
|
return qb;
|
|
230
220
|
};
|
|
221
|
+
const isSelectItem = (item)=>'object' == typeof item && 'field' in item;
|
|
231
222
|
const DATE_FORMAT_MAP = {
|
|
232
223
|
year: '%Y',
|
|
233
224
|
month: '%Y-%m',
|
|
@@ -303,6 +294,13 @@ const DATA_TYPE_MAP = {
|
|
|
303
294
|
datetime: 'TIMESTAMP',
|
|
304
295
|
timestamp: 'TIMESTAMP'
|
|
305
296
|
};
|
|
297
|
+
const buildColumnsStruct = (columns)=>{
|
|
298
|
+
const columnDefs = columns.map((c)=>{
|
|
299
|
+
const duckDBType = DATA_TYPE_MAP[c.type] || 'VARCHAR';
|
|
300
|
+
return `'${c.name}': '${duckDBType}'`;
|
|
301
|
+
});
|
|
302
|
+
return `{${columnDefs.join(', ')}}`;
|
|
303
|
+
};
|
|
306
304
|
class Dataset {
|
|
307
305
|
queryAdapter;
|
|
308
306
|
storageAdapter;
|
|
@@ -324,7 +322,7 @@ class Dataset {
|
|
|
324
322
|
const readFunction = READ_FUNCTION_MAP[datasetSource.type];
|
|
325
323
|
if (!readFunction) throw new Error(`Unsupported dataSource type: ${datasetSource.type}`);
|
|
326
324
|
await this.queryAdapter.writeFile(this._datasetId, datasetSource.blob);
|
|
327
|
-
const columnsStruct =
|
|
325
|
+
const columnsStruct = buildColumnsStruct(columns);
|
|
328
326
|
const columnNames = columns.map((c)=>`"${c.name}"`).join(', ');
|
|
329
327
|
let readSql = `${readFunction}('${this._datasetId}')`;
|
|
330
328
|
if ('csv' === datasetSource.type || 'json' === datasetSource.type) readSql = `${readFunction}('${this._datasetId}', columns=${columnsStruct})`;
|
|
@@ -354,13 +352,6 @@ class Dataset {
|
|
|
354
352
|
get datasetId() {
|
|
355
353
|
return this._datasetId;
|
|
356
354
|
}
|
|
357
|
-
buildColumnsStruct(columns) {
|
|
358
|
-
const columnDefs = columns.map((c)=>{
|
|
359
|
-
const duckDBType = DATA_TYPE_MAP[c.type] || 'VARCHAR';
|
|
360
|
-
return `'${c.name}': '${duckDBType}'`;
|
|
361
|
-
});
|
|
362
|
-
return `{${columnDefs.join(', ')}}`;
|
|
363
|
-
}
|
|
364
355
|
}
|
|
365
356
|
const isUrl = (url)=>isHttpUrl(url) || isBase64Url(url);
|
|
366
357
|
const isHttpUrl = (url)=>url.startsWith('http://') || url.startsWith('https://');
|
|
@@ -523,7 +514,7 @@ class VQuery {
|
|
|
523
514
|
const datasetSchema = {
|
|
524
515
|
datasetId,
|
|
525
516
|
datasetAlias: datasetId,
|
|
526
|
-
columns
|
|
517
|
+
columns
|
|
527
518
|
};
|
|
528
519
|
await this.storageAdapter.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
529
520
|
}
|
|
@@ -534,7 +525,7 @@ class VQuery {
|
|
|
534
525
|
const datasetSchema = {
|
|
535
526
|
datasetId,
|
|
536
527
|
datasetAlias: datasetId,
|
|
537
|
-
columns
|
|
528
|
+
columns
|
|
538
529
|
};
|
|
539
530
|
await this.storageAdapter.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
540
531
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const escapeValue: (value: unknown) => string;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const idbPut: <T>(db: IDBDatabase, storeName: string, value: T) => Promise<any>;
|
|
2
|
+
export declare const idbGet: <T>(db: IDBDatabase, storeName: string, key: any) => Promise<T | undefined>;
|
|
3
|
+
export declare const idbDelete: (db: IDBDatabase, storeName: string, key: any) => Promise<any>;
|
|
4
|
+
export declare const idbGetAll: <T>(db: IDBDatabase, storeName: string) => Promise<T[]>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DatasetSourceType, DataType } from '../types';
|
|
2
|
+
export declare const READ_FUNCTION_MAP: Record<DatasetSourceType, string>;
|
|
3
|
+
export declare const DATA_TYPE_MAP: Record<DataType, string>;
|
|
4
|
+
export declare const buildColumnsStruct: (columns: {
|
|
5
|
+
name: string;
|
|
6
|
+
type: DataType;
|
|
7
|
+
}[]) => string;
|
|
@@ -5,19 +5,8 @@ export declare class Dataset {
|
|
|
5
5
|
private storageAdapter;
|
|
6
6
|
private _datasetId;
|
|
7
7
|
constructor(queryAdapter: QueryAdapter, storageAdapter: StorageAdapter, datasetId: string);
|
|
8
|
-
/**
|
|
9
|
-
* Initialize the dataset by loading it into the query engine
|
|
10
|
-
* @param temporaryColumns Optional temporary columns to override storage schema
|
|
11
|
-
* @param temporaryDatasetSource Optional temporary data source to override storage source
|
|
12
|
-
*/
|
|
13
8
|
init(temporaryColumns?: DatasetColumn[], temporaryDatasetSource?: DatasetSource): Promise<void>;
|
|
14
|
-
/**
|
|
15
|
-
* Register file and create a view in DuckDB
|
|
16
|
-
*/
|
|
17
9
|
createOrReplaceView(columns: DatasetColumn[], datasetSource: DatasetSource): Promise<void>;
|
|
18
|
-
/**
|
|
19
|
-
* Execute query using VQuery DSL
|
|
20
|
-
*/
|
|
21
10
|
query<T extends Record<string, number | string>>(queryDSL: QueryDSL<T> | VQueryDSL<T>): Promise<{
|
|
22
11
|
performance: {
|
|
23
12
|
startAt: string;
|
|
@@ -27,9 +16,6 @@ export declare class Dataset {
|
|
|
27
16
|
dataset: any[];
|
|
28
17
|
table: any;
|
|
29
18
|
}>;
|
|
30
|
-
/**
|
|
31
|
-
* Execute raw SQL query
|
|
32
|
-
*/
|
|
33
19
|
queryBySQL(sql: string): Promise<{
|
|
34
20
|
performance: {
|
|
35
21
|
startAt: string;
|
|
@@ -39,10 +25,6 @@ export declare class Dataset {
|
|
|
39
25
|
dataset: any[];
|
|
40
26
|
table: any;
|
|
41
27
|
}>;
|
|
42
|
-
/**
|
|
43
|
-
* Clean up resources
|
|
44
|
-
*/
|
|
45
28
|
disconnect(): Promise<void>;
|
|
46
29
|
get datasetId(): string;
|
|
47
|
-
private buildColumnsStruct;
|
|
48
30
|
}
|
package/dist/node/esm/node.js
CHANGED
|
@@ -30,7 +30,15 @@ class PostgresDialect {
|
|
|
30
30
|
return new NullIntrospector();
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
const
|
|
33
|
+
const OPERATOR_MAP = {
|
|
34
|
+
gt: '>',
|
|
35
|
+
gte: '>=',
|
|
36
|
+
lt: '<',
|
|
37
|
+
lte: '<=',
|
|
38
|
+
eq: '=',
|
|
39
|
+
neq: '!='
|
|
40
|
+
};
|
|
41
|
+
const toSqlOperator = (op)=>OPERATOR_MAP[op] ?? op;
|
|
34
42
|
const escapeValue = (value)=>{
|
|
35
43
|
if (null === value) return 'null';
|
|
36
44
|
if ('string' == typeof value) return `'${value.replace(/'/g, "''")}'`;
|
|
@@ -38,6 +46,7 @@ const escapeValue = (value)=>{
|
|
|
38
46
|
if ('boolean' == typeof value) return value ? 'TRUE' : 'FALSE';
|
|
39
47
|
return `'${String(value).replace(/'/g, "''")}'`;
|
|
40
48
|
};
|
|
49
|
+
const isSelectItem = (item)=>'object' == typeof item && 'field' in item;
|
|
41
50
|
const inlineParameters = (sql, params)=>{
|
|
42
51
|
if (0 === params.length) return sql;
|
|
43
52
|
if (sql.includes('?')) {
|
|
@@ -52,15 +61,6 @@ const inlineParameters = (sql, params)=>{
|
|
|
52
61
|
});
|
|
53
62
|
return sql;
|
|
54
63
|
};
|
|
55
|
-
const operatorMap = {
|
|
56
|
-
gt: '>',
|
|
57
|
-
gte: '>=',
|
|
58
|
-
lt: '<',
|
|
59
|
-
lte: '<=',
|
|
60
|
-
eq: '=',
|
|
61
|
-
neq: '!='
|
|
62
|
-
};
|
|
63
|
-
const toSqlOperator = (op)=>operatorMap[op] ?? op;
|
|
64
64
|
const applyWhere = (qb, where)=>{
|
|
65
65
|
if (!where) return qb;
|
|
66
66
|
const toRaw = (w)=>{
|
|
@@ -115,15 +115,6 @@ const applyGroupBy = (qb, fields)=>{
|
|
|
115
115
|
}
|
|
116
116
|
return qb;
|
|
117
117
|
};
|
|
118
|
-
const having_operatorMap = {
|
|
119
|
-
gt: '>',
|
|
120
|
-
gte: '>=',
|
|
121
|
-
lt: '<',
|
|
122
|
-
lte: '<=',
|
|
123
|
-
eq: '=',
|
|
124
|
-
neq: '!='
|
|
125
|
-
};
|
|
126
|
-
const having_toSqlOperator = (op)=>having_operatorMap[op] ?? op;
|
|
127
118
|
const applyHaving = (qb, having)=>{
|
|
128
119
|
if (!having) return qb;
|
|
129
120
|
const toRaw = (h)=>{
|
|
@@ -135,7 +126,7 @@ const applyHaving = (qb, having)=>{
|
|
|
135
126
|
const leaf = h;
|
|
136
127
|
const field = leaf.field;
|
|
137
128
|
const value = leaf.value;
|
|
138
|
-
const op =
|
|
129
|
+
const op = toSqlOperator(leaf.op);
|
|
139
130
|
if ([
|
|
140
131
|
'sum',
|
|
141
132
|
'avg',
|
|
@@ -266,6 +257,13 @@ const DATA_TYPE_MAP = {
|
|
|
266
257
|
datetime: 'TIMESTAMP',
|
|
267
258
|
timestamp: 'TIMESTAMP'
|
|
268
259
|
};
|
|
260
|
+
const buildColumnsStruct = (columns)=>{
|
|
261
|
+
const columnDefs = columns.map((c)=>{
|
|
262
|
+
const duckDBType = DATA_TYPE_MAP[c.type] || 'VARCHAR';
|
|
263
|
+
return `'${c.name}': '${duckDBType}'`;
|
|
264
|
+
});
|
|
265
|
+
return `{${columnDefs.join(', ')}}`;
|
|
266
|
+
};
|
|
269
267
|
class Dataset {
|
|
270
268
|
queryAdapter;
|
|
271
269
|
storageAdapter;
|
|
@@ -287,7 +285,7 @@ class Dataset {
|
|
|
287
285
|
const readFunction = READ_FUNCTION_MAP[datasetSource.type];
|
|
288
286
|
if (!readFunction) throw new Error(`Unsupported dataSource type: ${datasetSource.type}`);
|
|
289
287
|
await this.queryAdapter.writeFile(this._datasetId, datasetSource.blob);
|
|
290
|
-
const columnsStruct =
|
|
288
|
+
const columnsStruct = buildColumnsStruct(columns);
|
|
291
289
|
const columnNames = columns.map((c)=>`"${c.name}"`).join(', ');
|
|
292
290
|
let readSql = `${readFunction}('${this._datasetId}')`;
|
|
293
291
|
if ('csv' === datasetSource.type || 'json' === datasetSource.type) readSql = `${readFunction}('${this._datasetId}', columns=${columnsStruct})`;
|
|
@@ -317,13 +315,6 @@ class Dataset {
|
|
|
317
315
|
get datasetId() {
|
|
318
316
|
return this._datasetId;
|
|
319
317
|
}
|
|
320
|
-
buildColumnsStruct(columns) {
|
|
321
|
-
const columnDefs = columns.map((c)=>{
|
|
322
|
-
const duckDBType = DATA_TYPE_MAP[c.type] || 'VARCHAR';
|
|
323
|
-
return `'${c.name}': '${duckDBType}'`;
|
|
324
|
-
});
|
|
325
|
-
return `{${columnDefs.join(', ')}}`;
|
|
326
|
-
}
|
|
327
318
|
}
|
|
328
319
|
const isUrl = (url)=>isHttpUrl(url) || isBase64Url(url);
|
|
329
320
|
const isHttpUrl = (url)=>url.startsWith('http://') || url.startsWith('https://');
|
|
@@ -484,7 +475,7 @@ class VQuery {
|
|
|
484
475
|
const datasetSchema = {
|
|
485
476
|
datasetId,
|
|
486
477
|
datasetAlias: datasetId,
|
|
487
|
-
columns
|
|
478
|
+
columns
|
|
488
479
|
};
|
|
489
480
|
await this.storageAdapter.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
490
481
|
}
|
|
@@ -495,7 +486,7 @@ class VQuery {
|
|
|
495
486
|
const datasetSchema = {
|
|
496
487
|
datasetId,
|
|
497
488
|
datasetAlias: datasetId,
|
|
498
|
-
columns
|
|
489
|
+
columns
|
|
499
490
|
};
|
|
500
491
|
await this.storageAdapter.writeDataset(datasetId, datasetSchema, datasetSource);
|
|
501
492
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const escapeValue: (value: unknown) => string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visactor/vquery",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"homepage": "https://visactor.github.io/VBI",
|
|
6
|
+
"bugs": "https://github.com/VisActor/VBI/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/VisActor/VBI",
|
|
10
|
+
"directory": "packages/vquery"
|
|
11
|
+
},
|
|
12
|
+
"author": {
|
|
13
|
+
"name": "VisActor",
|
|
14
|
+
"url": "https://www.visactor.io/"
|
|
15
|
+
},
|
|
4
16
|
"type": "module",
|
|
5
17
|
"exports": {
|
|
6
18
|
".": {
|
|
@@ -43,18 +55,6 @@
|
|
|
43
55
|
"typescript": "5.9.3",
|
|
44
56
|
"typescript-eslint": "8.48.0"
|
|
45
57
|
},
|
|
46
|
-
"license": "MIT",
|
|
47
|
-
"homepage": "https://visactor.github.io/VSeed",
|
|
48
|
-
"bugs": "https://github.com/VisActor/VSeed/issues",
|
|
49
|
-
"repository": {
|
|
50
|
-
"type": "git",
|
|
51
|
-
"url": "https://github.com/VisActor/VBI",
|
|
52
|
-
"directory": "packages/vquery"
|
|
53
|
-
},
|
|
54
|
-
"author": {
|
|
55
|
-
"name": "VisActor",
|
|
56
|
-
"url": "https://www.visactor.io/"
|
|
57
|
-
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "rslib build",
|
|
60
60
|
"build:test": "node scripts/build-tests.js",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"dev": "rslib build --watch --no-clean",
|
|
64
64
|
"lint": "eslint .",
|
|
65
65
|
"test": "rstest",
|
|
66
|
+
"format": "prettier --write .",
|
|
66
67
|
"test:update": "rstest --update",
|
|
67
68
|
"test:coverage": "rstest --coverage && node scripts/build-coverage-badge.mjs && open ./coverage/index.html",
|
|
68
69
|
"typecheck": "tsc --noEmit"
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Where, WhereClause, WhereGroup, WhereLeaf } from '../types';
|
|
2
|
-
import { SelectItem } from '../types/dsl/Select';
|
|
3
|
-
export declare const isSelectItem: <T>(item: keyof T | SelectItem<T>) => item is SelectItem<T>;
|
|
4
|
-
export declare const isWhereLeaf: <T>(where: Where<T> | WhereClause<T>) => where is WhereLeaf<T>;
|
|
5
|
-
export declare const isWhereGroup: <T>(where: Where<T> | WhereClause<T>) => where is WhereGroup<T>;
|
|
6
|
-
export declare const isStringOrNumber: (value: unknown) => value is string | number;
|
|
7
|
-
export declare const escapeLiteral: <T>(value: T[keyof T]) => T[keyof T];
|
|
8
|
-
export declare const escapeValue: (value: unknown) => string;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Where, WhereClause, WhereGroup, WhereLeaf } from '../types';
|
|
2
|
-
import { SelectItem } from '../types/dsl/Select';
|
|
3
|
-
export declare const isSelectItem: <T>(item: keyof T | SelectItem<T>) => item is SelectItem<T>;
|
|
4
|
-
export declare const isWhereLeaf: <T>(where: Where<T> | WhereClause<T>) => where is WhereLeaf<T>;
|
|
5
|
-
export declare const isWhereGroup: <T>(where: Where<T> | WhereClause<T>) => where is WhereGroup<T>;
|
|
6
|
-
export declare const isStringOrNumber: (value: unknown) => value is string | number;
|
|
7
|
-
export declare const escapeLiteral: <T>(value: T[keyof T]) => T[keyof T];
|
|
8
|
-
export declare const escapeValue: (value: unknown) => string;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Where, WhereClause, WhereGroup, WhereLeaf } from '../types';
|
|
2
|
-
import { SelectItem } from '../types/dsl/Select';
|
|
3
|
-
export declare const isSelectItem: <T>(item: keyof T | SelectItem<T>) => item is SelectItem<T>;
|
|
4
|
-
export declare const isWhereLeaf: <T>(where: Where<T> | WhereClause<T>) => where is WhereLeaf<T>;
|
|
5
|
-
export declare const isWhereGroup: <T>(where: Where<T> | WhereClause<T>) => where is WhereGroup<T>;
|
|
6
|
-
export declare const isStringOrNumber: (value: unknown) => value is string | number;
|
|
7
|
-
export declare const escapeLiteral: <T>(value: T[keyof T]) => T[keyof T];
|
|
8
|
-
export declare const escapeValue: (value: unknown) => string;
|