Skip to content

Commit 8c93679

Browse files
authored
Merge pull request #55 from luusluus/53-suggest-adjust-date-type-display-format
53 suggest adjust date type display format
2 parents 1654445 + d7b20df commit 8c93679

File tree

12 files changed

+126
-48
lines changed

12 files changed

+126
-48
lines changed

.vscode/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@
1414
"parquet-visualizer.backend": "duckdb",
1515
"parquet-visualizer.defaultQuery": "SELECT *\r\nFROM data\r\nLIMIT 1000;",
1616
"parquet-visualizer.RunQueryKeyBinding": "Ctrl-Enter",
17+
"parquet-visualizer.dateTimeFormat": "RFC2822",
18+
"parquet-visualizer.outputDateTimeFormatInUTC": true
1719
}

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ The following configuration options are available:
5454
|`parquet-visualizer.backend`|`duckdb`| Backend for reading the parquet file. Options: `duckdb`, `parquet-wasm`|
5555
|`parquet-visualizer.defaultPageSizes`|`[20, 50, 100, 500]`|Set the default page size for data and query tab.|
5656
|`parquet-visualizer.defaultQuery`|`SELECT *\r\nFROM data\r\nLIMIT 1000;`|Default SQL query for parquet file. The table `data` should remain the same.|
57+
|`parquet-visualizer.RunQueryKeyBinding`|`Ctrl-Enter`|Default Key Binding for running queries. If Ctrl is written, it will be translated to Command for mac and vica versa. E.g., Ctrl-E will be synonymous to Command-E.|
58+
|`parquet-visualizer.dateTimeFormat`|`ISO8601`|Set datetime format for columns of timestamp type. Defaults to ISO8601. You can set a custom format like `YYYY-MM-DD HH:mm:ss.SSS Z`. Find rules for formatting [here](https://www.npmjs.com/package/date-and-time#formatdateobj-arg-utc).|
59+
|`parquet-visualizer.outputDateTimeFormatInUTC`|`true`|Outputs the datetime format for timestamp columns in UTC or in local time.|
5760

5861

5962
## Parquet backends

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@
7979
100,
8080
500
8181
]
82+
},
83+
"parquet-visualizer.dateTimeFormat": {
84+
"markdownDescription": "Set datetime format for columns of timestamp type. Defaults to ISO8601. You can set a custom format like `YYYY-MM-DD HH:mm:ss.SSS Z`. Find rules for formatting [here](https://www.npmjs.com/package/date-and-time#formatdateobj-arg-utc).",
85+
"type": "string",
86+
"enumDescriptions": [
87+
"ISO8601",
88+
"RFC2822"
89+
],
90+
"default": "ISO8601"
91+
},
92+
"parquet-visualizer.outputDateTimeFormatInUTC": {
93+
"type": "boolean",
94+
"markdownDescription": "Outputs the datetime format for timestamp columns in UTC or in local time.",
95+
"default": true
8296
}
8397
}
8498
},
@@ -127,6 +141,7 @@
127141
},
128142
"dependencies": {
129143
"apache-arrow": "^15.0.0",
144+
"date-and-time": "^3.6.0",
130145
"duckdb-async": "^1.0.0",
131146
"parquet-wasm": "^0.6.0"
132147
},

src/backend.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
import { Schema, Field, Type } from "apache-arrow";
22

33
import { convertBigIntToString, convertObjectsToJSONStrings } from './util';
4-
4+
import { DateTimeFormatSettings } from './types';
55

66
export abstract class Backend {
77
public filePath: string;
88
protected arrowSchema: Schema;
99
protected metadata: any;
1010

11-
public constructor(filePath: string) {
11+
private dateTimeFormat: DateTimeFormatSettings;
12+
13+
public constructor(filePath: string, dateTimeFormat: DateTimeFormatSettings) {
1214
this.filePath = filePath;
15+
this.dateTimeFormat = dateTimeFormat;
1316
}
1417

15-
static createAsync(filePath: string): Promise<any> {
18+
static createAsync(filePath: string, dateTimeFormat: DateTimeFormatSettings): Promise<any> {
1619
throw new Error("Method not implemented");
1720
};
1821

@@ -107,7 +110,7 @@ export abstract class Backend {
107110
key: 'footer_signing_key_metadata',
108111
value: Number(this.metadata[0]["footer_signing_key_metadata"])
109112
},
110-
]
113+
];
111114
};
112115

113116
abstract getMetaDataImpl(): Promise<any>;
@@ -119,7 +122,9 @@ export abstract class Backend {
119122

120123
const queryResult = await this.queryImpl(query);
121124
const result = queryResult.map(v => {
122-
return convertObjectsToJSONStrings(convertBigIntToString(v));
125+
return convertObjectsToJSONStrings(
126+
convertBigIntToString(v, this.dateTimeFormat)
127+
);
123128
});
124129

125130
const endTime = performance.now();

src/duckdb-backend.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
1-
import * as fs from 'fs';
2-
31
import * as duckdb from "duckdb-async";
4-
import { Backend } from "./backend";
52

63
import { tableFromIPC, Schema } from "apache-arrow";
74

5+
import { Backend } from "./backend";
6+
import { DateTimeFormatSettings } from './types';
7+
88
export class DuckDBBackend extends Backend{
99
private db: duckdb.Database;
1010
public arrowSchema: Schema<any>;
1111
public metadata: any;
1212

13-
constructor(filePath: string, db: duckdb.Database){
14-
super(filePath);
13+
constructor(filePath: string, dateTimeFormatSettings: DateTimeFormatSettings, db: duckdb.Database){
14+
super(filePath, dateTimeFormatSettings);
1515
this.db = db;
1616
}
1717

18-
public static override async createAsync (path: string){
18+
public static override async createAsync (path: string, dateTimeFormatSettings: DateTimeFormatSettings){
1919
const db = await duckdb.Database.create(":memory:");
2020
// const splitted = path.split('/');
2121
// const filename = splitted[splitted.length - 1];
2222
// const filePath = `${__dirname}/${filename}.duckdb`;
2323
// const db = await duckdb.Database.create(filePath);
24-
return new DuckDBBackend(path, db);
24+
return new DuckDBBackend(path, dateTimeFormatSettings, db);
2525
}
2626

2727
dispose() {

src/parquet-editor.ts

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import { DuckDBBackend } from './duckdb-backend';
1212
import { DuckDBPaginator } from './duckdb-paginator';
1313
import { ParquetWasmBackend } from './parquet-wasm-backend';
1414
import { ParquetWasmPaginator } from './parquet-wasm-paginator';
15-
import { affectsDocument, defaultPageSizes, defaultQuery, defaultBackend, defaultRunQueryKeyBinding } from './settings';
15+
import { affectsDocument, defaultPageSizes, defaultQuery, defaultBackend, defaultRunQueryKeyBinding, dateTimeFormat, outputDateTimeFormatInUTC } from './settings';
16+
import { DateTimeFormatSettings } from './types';
1617

1718
// import { getLogger } from './logger';
1819

@@ -30,10 +31,14 @@ class CustomParquetDocument extends Disposable implements vscode.CustomDocument
3031
static async create(
3132
uri: vscode.Uri
3233
): Promise<CustomParquetDocument | PromiseLike<CustomParquetDocument>> {
34+
const dateTimeFormatSettings: DateTimeFormatSettings = {
35+
format: dateTimeFormat(),
36+
useUTC: outputDateTimeFormatInUTC()
37+
};
3338
try{
3439
switch (defaultBackend()) {
3540
case 'duckdb': {
36-
const backend = await DuckDBBackend.createAsync(uri.fsPath);
41+
const backend = await DuckDBBackend.createAsync(uri.fsPath, dateTimeFormatSettings);
3742
await backend.initialize();
3843
const totalItems = backend.getRowCount();
3944
const table = 'data';
@@ -42,7 +47,7 @@ class CustomParquetDocument extends Disposable implements vscode.CustomDocument
4247
return new CustomParquetDocument(uri, backend, paginator);
4348
}
4449
case 'parquet-wasm': {
45-
const backend = await ParquetWasmBackend.createAsync(uri.fsPath);
50+
const backend = await ParquetWasmBackend.createAsync(uri.fsPath, dateTimeFormatSettings);
4651
const paginator = new ParquetWasmPaginator(backend);
4752
return new CustomParquetDocument(uri, backend, paginator);
4853
}
@@ -53,7 +58,7 @@ class CustomParquetDocument extends Disposable implements vscode.CustomDocument
5358
} catch (err: any){
5459
console.log(err);
5560

56-
const backend = await ParquetWasmBackend.createAsync(uri.fsPath);
61+
const backend = await ParquetWasmBackend.createAsync(uri.fsPath, dateTimeFormatSettings);
5762
const paginator = new ParquetWasmPaginator(backend);
5863
return new CustomParquetDocument(uri, backend, paginator);
5964
}
@@ -73,28 +78,34 @@ class CustomParquetDocument extends Disposable implements vscode.CustomDocument
7378
if (this.backend instanceof DuckDBBackend) {
7479
this.isQueryAble = true;
7580

81+
const dateTimeFormatSettings: DateTimeFormatSettings = {
82+
format: dateTimeFormat(),
83+
useUTC: outputDateTimeFormatInUTC()
84+
};
85+
7686
this.worker = new Worker(__dirname + "/worker.js", {
77-
workerData: {
78-
pathParquetFile: this.uri.fsPath
79-
}
80-
});
81-
82-
this.worker.on('message', (message) => {
83-
if (message.type === 'query'){
84-
this.emitQueryResult(message);
85-
} else if (message.type === 'paginator') {
86-
this.fireDataPaginatorEvent(
87-
message.result,
88-
message.rowCount,
89-
message.pageSize,
90-
message.pageNumber,
91-
message.pageCount,
92-
requestSourceQueryTab
93-
);
94-
} else if (message.type === 'exportQueryResults') {
95-
vscode.window.showInformationMessage(`Exported query result to ${message.path}`);
96-
}
97-
});
87+
workerData: {
88+
pathParquetFile: this.uri.fsPath,
89+
dateTimeFormatSettings: dateTimeFormatSettings,
90+
}
91+
});
92+
93+
this.worker.on('message', (message) => {
94+
if (message.type === 'query'){
95+
this.emitQueryResult(message);
96+
} else if (message.type === 'paginator') {
97+
this.fireDataPaginatorEvent(
98+
message.result,
99+
message.rowCount,
100+
message.pageSize,
101+
message.pageNumber,
102+
message.pageCount,
103+
requestSourceQueryTab
104+
);
105+
} else if (message.type === 'exportQueryResults') {
106+
vscode.window.showInformationMessage(`Exported query result to ${message.path}`);
107+
}
108+
});
98109
}
99110
}
100111

src/parquet-wasm-backend.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,25 @@ import { ParquetFile } from 'parquet-wasm';
1111
import { Backend } from './backend';
1212
import { Table } from 'apache-arrow/table';
1313
import { tableFromIPC } from 'apache-arrow';
14+
import { DateTimeFormatSettings } from './types';
1415

1516
export class ParquetWasmBackend extends Backend {
1617
public parquetFile: ParquetFile;
1718

1819

1920
private constructor(
2021
filePath: string,
22+
dateTimeFormat: DateTimeFormatSettings,
2123
parquetFile: ParquetFile,
2224
table: Table<any>
2325
) {
24-
super(filePath);
26+
super(filePath, dateTimeFormat);
2527
this.parquetFile = parquetFile;
2628
this.arrowSchema = table.schema;
2729
this.metadata = this.getMetaDataImpl();
2830
}
2931

30-
public static override async createAsync (path: string) {
32+
public static override async createAsync (path: string, dateTimeFormat: DateTimeFormatSettings) {
3133
const buffer = fs.readFileSync(path);
3234
const file = new File([buffer], "fileName", {
3335
type: "application/vnd.apache.parquet",
@@ -43,6 +45,7 @@ export class ParquetWasmBackend extends Backend {
4345

4446
return new ParquetWasmBackend(
4547
path,
48+
dateTimeFormat,
4649
parquetFile,
4750
table
4851
);

src/settings.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ export function defaultBackend(): string {
2121
export function defaultRunQueryKeyBinding(): string {
2222
return settings().get('RunQueryKeyBinding');
2323
}
24+
25+
export function dateTimeFormat(): string {
26+
return settings().get('dateTimeFormat') as string;
27+
}
28+
29+
export function outputDateTimeFormatInUTC(): boolean {
30+
return settings().get<boolean>('outputDateTimeFormatInUTC') as boolean;
31+
}
2432

2533
function settingsChanged(e: vscode.ConfigurationChangeEvent, sections: string[]): boolean {
2634
return sections.map(s => `${name}.${s}`).some(s => e.affectsConfiguration(s));

src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
export interface DateTimeFormatSettings {
3+
format: string;
4+
useUTC: boolean;
5+
}

src/util.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import date from 'date-and-time';
2+
3+
import { DateTimeFormatSettings } from './types';
4+
15
export function getNonce() {
26
let text = '';
37
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -17,21 +21,33 @@ export function convertToTabulatorData(array: any[]) {
1721
});
1822
}
1923

20-
export function convertBigIntToString(obj: any): any {
24+
export function convertBigIntToString(obj: any, dateTimeFormatSettings: DateTimeFormatSettings): any {
2125
if (Array.isArray(obj)) {
22-
return obj.map(item => convertBigIntToString(item));
26+
return obj.map(item => convertBigIntToString(item, dateTimeFormatSettings));
2327
}
2428
else if (obj instanceof Uint8Array) {
2529
return Array.from(obj.values());
2630
}
2731
else if (obj !== null && typeof obj === 'object') {
2832
if (obj instanceof Date) {
29-
return obj.toUTCString();
33+
if (dateTimeFormatSettings.format === "ISO8601") {
34+
return obj.toISOString();
35+
}
36+
else if (dateTimeFormatSettings.format === "RFC2822") {
37+
return obj.toUTCString();
38+
}
39+
else {
40+
return date.format(
41+
obj,
42+
dateTimeFormatSettings.format,
43+
dateTimeFormatSettings.useUTC
44+
);
45+
}
3046
}
3147
const newObj: { [key: string]: any } = {};
3248
for (const key in obj) {
3349
if (obj.hasOwnProperty(key)) {
34-
newObj[key] = convertBigIntToString(obj[key]);
50+
newObj[key] = convertBigIntToString(obj[key], dateTimeFormatSettings);
3551
}
3652
}
3753
return newObj;
@@ -95,7 +111,7 @@ export function createHeadersFromData(data: any) {
95111
}
96112

97113
export function replacePeriodWithUnderscoreInKey(data: any) {
98-
return data.map(obj => {
114+
return data.map((obj: { [x: string]: any; }) => {
99115
const newObj: { [key: string]: any } = {};
100116

101117
Object.keys(obj).forEach(key => {

src/worker.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { Paginator } from './paginator';
1212
import { DuckDBBackend } from './duckdb-backend';
1313
import { DuckDBPaginator } from './duckdb-paginator';
1414
import { createHeadersFromData, replacePeriodWithUnderscoreInKey } from './util';
15-
15+
import { DateTimeFormatSettings } from './types';
1616

1717
class BackendWorker {
1818
paginator: Paginator;
@@ -23,8 +23,8 @@ class BackendWorker {
2323
this.backend = backend;
2424
}
2525

26-
static async create(path: string) {
27-
const backend = await DuckDBBackend.createAsync(path);
26+
static async create(path: string, dateTimeFormatSettings: DateTimeFormatSettings) {
27+
const backend = await DuckDBBackend.createAsync(path, dateTimeFormatSettings);
2828
await backend.initialize();
2929
return new BackendWorker(backend);
3030
}
@@ -140,7 +140,10 @@ class BackendWorker {
140140
}
141141

142142
(async () => {
143-
const worker = await BackendWorker.create(workerData.pathParquetFile);
143+
const worker = await BackendWorker.create(
144+
workerData.pathParquetFile,
145+
workerData.dateTimeFormatSettings
146+
);
144147

145148
parentPort.on('message', async (message: any) => {
146149
switch (message.source) {

0 commit comments

Comments
 (0)