diff --git a/extensions/positron-duckdb/src/extension.ts b/extensions/positron-duckdb/src/extension.ts index d6fb2118a44..adbfa63231e 100644 --- a/extensions/positron-duckdb/src/extension.ts +++ b/extensions/positron-duckdb/src/extension.ts @@ -53,6 +53,7 @@ import { import * as duckdb from '@duckdb/duckdb-wasm'; import * as path from 'path'; import * as fs from 'fs'; +import * as zlib from 'zlib'; import Worker from 'web-worker'; import { Table, Vector } from 'apache-arrow'; import { pathToFileURL } from 'url'; @@ -417,6 +418,7 @@ class ColumnProfileEvaluator { const numRows = Number(stats.get('num_rows')); const nullCount = Number(stats.get(`null_count_${field}`)); + return { values, counts, @@ -1243,6 +1245,12 @@ export class DataExplorerRpcHandler { * @param catalogName The table name to use in the DuckDB catalog. */ async createTableFromFilePath(filePath: string, catalogName: string) { + let fileExt = path.extname(filePath); + const isGzipped = fileExt === '.gz'; + + if (isGzipped) { + fileExt = path.extname(filePath.slice(0, -3)); + } const getCsvImportQuery = (_filePath: string, options: Array) => { return `CREATE OR REPLACE TABLE ${catalogName} AS @@ -1273,15 +1281,22 @@ export class DataExplorerRpcHandler { } }; - const fileExt = path.extname(filePath); - // Read the entire contents and register it as a temp file // to avoid file handle caching in duckdb-wasm - const fileContents = fs.readFileSync(filePath, { encoding: null }); - const virtualPath = path.basename(filePath); + let fileContents = fs.readFileSync(filePath, { encoding: null }); + if (isGzipped) { + fileContents = zlib.gunzipSync(fileContents); + } + + // For gzipped files, use the base name without the .gz extension + const virtualPath = isGzipped ? + path.basename(filePath, '.gz') : + path.basename(filePath); + await this.db.db.registerFileBuffer(virtualPath, fileContents); try { - if (fileExt === '.parquet' || fileExt === '.parq') { + const baseExt = path.extname(virtualPath); + if (baseExt === '.parquet' || baseExt === '.parq') { // Always create a view for Parquet files const query = `CREATE OR REPLACE TABLE ${catalogName} AS SELECT * FROM parquet_scan('${virtualPath}');`; diff --git a/src/vs/workbench/contrib/positronDataExplorerEditor/browser/positronDataExplorerEditor.contribution.ts b/src/vs/workbench/contrib/positronDataExplorerEditor/browser/positronDataExplorerEditor.contribution.ts index 47d3c10a7da..809a818c30e 100644 --- a/src/vs/workbench/contrib/positronDataExplorerEditor/browser/positronDataExplorerEditor.contribution.ts +++ b/src/vs/workbench/contrib/positronDataExplorerEditor/browser/positronDataExplorerEditor.contribution.ts @@ -17,6 +17,7 @@ import { PositronDataExplorerEditor } from './positronDataExplorerEditor.js'; import { PositronDataExplorerEditorInput } from './positronDataExplorerEditorInput.js'; import { registerPositronDataExplorerActions } from './positronDataExplorerActions.js'; import { extname } from '../../../../base/common/resources.js'; +import { posix } from '../../../../base/common/path.js'; import { IPositronDataExplorerService } from '../../../services/positronDataExplorer/browser/interfaces/positronDataExplorerService.js'; import { PositronDataExplorerUri } from '../../../services/positronDataExplorer/common/positronDataExplorerUri.js'; @@ -76,7 +77,7 @@ class PositronDataExplorerContribution extends Disposable { } )); - const DUCKDB_SUPPORTED_EXTENSIONS = ['parquet', 'parq', 'csv', 'tsv']; + const DUCKDB_SUPPORTED_EXTENSIONS = ['parquet', 'parq', 'csv', 'tsv', 'gz']; this._register(editorResolverService.registerEditor( `*.{${DUCKDB_SUPPORTED_EXTENSIONS.join(',')}}`, @@ -84,7 +85,12 @@ class PositronDataExplorerContribution extends Disposable { { singlePerResource: true, canSupportResource: resource => { - return DUCKDB_SUPPORTED_EXTENSIONS.includes(extname(resource).substring(1)); + let fileExt = extname(resource).substring(1); + if (fileExt === 'gz') { + // Strip the .gz and get the actual extension + fileExt = posix.extname(resource.path.slice(0, -3)).substring(1); + } + return DUCKDB_SUPPORTED_EXTENSIONS.includes(fileExt); } }, {