Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feature/console-chann…
Browse files Browse the repository at this point in the history
…el-picker
  • Loading branch information
samclark2015 committed Feb 19, 2025
2 parents 7497223 + 92dec46 commit 54dee73
Show file tree
Hide file tree
Showing 544 changed files with 9,316 additions and 17,031 deletions.
2 changes: 1 addition & 1 deletion .github/actions/setup-build-env/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ runs:
vim curl build-essential clang make cmake git \
libsodium-dev libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb \
libgtk-3-0 libgbm1 libnss3 libnspr4 libkrb5-dev libcairo-dev \
libsdl-pango-dev libjpeg-dev libgif-dev pandoc
libsdl-pango-dev libjpeg-dev libgif-dev pandoc libgtk-4-1
- name: Install Node packages
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-e2e-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ jobs:
env:
POSITRON_PY_VER_SEL: 3.12.3
POSITRON_R_VER_SEL: 4.4.0
POSITRON_PY_ALT_VER_SEL: 3.13.0
POSITRON_PY_ALT_VER_SEL: "3.13.0 (Pyenv)"
POSITRON_R_ALT_VER_SEL: 4.4.2
CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }}
CURRENTS_CI_BUILD_ID: ${{ github.run_id }}-${{ github.run_attempt }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-e2e-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ jobs:
env:
POSITRON_PY_VER_SEL: 3.12.3
POSITRON_R_VER_SEL: 4.4.0
POSITRON_PY_ALT_VER_SEL: 3.13.0
POSITRON_PY_ALT_VER_SEL: "3.13.0 (Pyenv)"
POSITRON_R_ALT_VER_SEL: 4.4.2
CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }}
CURRENTS_CI_BUILD_ID: ${{ github.run_id }}-${{ github.run_attempt }}
Expand Down
42 changes: 33 additions & 9 deletions .github/workflows/test-e2e-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,6 @@ jobs:
with:
python-version: "3.10.10"

- name: Cache node_modules, build, extensions, and remote
uses: ./.github/actions/cache-multi-paths

- name: Install node dependencies
env:
npm_config_arch: x64
Expand All @@ -96,8 +93,7 @@ jobs:
#
# see https://github.com/posit-dev/positron/issues/3481
run: |
corepack enable
.\scripts\run-with-retry.ps1 -maxAttempts 3 -command "npm install --fetch-timeout 120000"
.\scripts\run-with-retry.ps1 -maxAttempts 5 -command "npm clean-install --fetch-timeout 120000"
npm --prefix test/e2e ci
- name: Compile and Download
Expand All @@ -114,17 +110,43 @@ jobs:
python -m pip install -r requirements.txt
python -m pip install ipykernel trcli
- name: Set up R
uses: r-lib/actions/setup-r@v2
# Alternate python version
- name: Install Python 3.13.0
uses: actions/setup-python@v5
with:
r-version: "4.4.0"
python-version: "3.13.0"

# Ensure Python 3.13.0 is used and only install ipykernel
- name: Install ipykernel for Python 3.13.0
run: |
python --version # Verify it's 3.13.0
python -m pip install --upgrade pip
python -m pip install ipykernel
- name: Install R packages
# Install rig (R Installation Manager)
- name: Install rig
run: |
choco install rig
# Install R 4.4.0 using rig
- name: Install R 4.4.0
run: |
rig add 4.4.0
rig default 4.4.0
rig ls
- name: Install R packages for 4.4.0
run: |
curl https://raw.githubusercontent.com/posit-dev/qa-example-content/main/DESCRIPTION --output DESCRIPTION
Rscript -e "install.packages('pak')"
Rscript -e "pak::local_install_dev_deps(ask = FALSE)"
# Install R 4.4.2 using rig
- name: Install R 4.4.2
run: |
rig add 4.4.2
rig ls
- name: Setup Graphviz
uses: ts-graphviz/setup-graphviz@v2.0.2

Expand All @@ -150,6 +172,8 @@ jobs:
env:
POSITRON_PY_VER_SEL: 3.10.10
POSITRON_R_VER_SEL: 4.4.0
POSITRON_PY_ALT_VER_SEL: 3.13.0
POSITRON_R_ALT_VER_SEL: 4.4.2
CURRENTS_PROJECT_ID: ZOs5z2
CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }}
CURRENTS_CI_BUILD_ID: ${{ github.run_id }}-${{ github.run_attempt }}
Expand Down
2 changes: 2 additions & 0 deletions build/darwin/create-universal-app.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions build/darwin/create-universal-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const stashPatterns = [
'**/html.icns',
// Exclusions from Python language pack (positron-python)
'**/pydevd/**', // Cython pre-built binaries for Python debugging
'**/lib/ipykernel/**', // Bundled IPyKernel dependencies
'**/lib/ipykernel/**/.dylibs/**', // Bundled IPyKernel dependency dylibs
// Exclusions from R language pack (positron-r)
'**/ark', // Compiled R kernel and LSP
// Exclusions from Kallichore Jupyter supervisor
Expand Down
8 changes: 8 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ export default tseslint.config(
// Make react-hooks/exhaustive-deps an error. Bad dependencies leads invariably to hard
// to find bugs.
'react-hooks/exhaustive-deps': 'error',
'react/jsx-sort-props': [
'error',
{
'callbacksLast': true,
'reservedFirst': true,
'shorthandFirst': true
}
]
},
},
// --- End Positron ---
Expand Down
157 changes: 152 additions & 5 deletions extensions/positron-duckdb/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ import {
DataExplorerResponse,
DataExplorerRpc,
DataExplorerUiEvent,
DataSelectionCellRange,
DataSelectionIndices,
DataSelectionRange,
DataSelectionSingleCell,
ExportDataSelectionParams,
ExportedData,
ExportFormat,
FilterBetween,
FilterComparison,
FilterComparisonOp,
Expand All @@ -48,14 +53,15 @@ import {
TableData,
TableRowLabels,
TableSchema,
TableSelectionKind,
TextSearchType
} from './interfaces';
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 { Schema, StructRow, Table, Vector } from 'apache-arrow';
import { pathToFileURL } from 'url';

// Set to true when doing development for better console logging
Expand Down Expand Up @@ -1090,8 +1096,12 @@ END`;
},
set_sort_columns: { support_status: SupportStatus.Supported, },
export_data_selection: {
support_status: SupportStatus.Unsupported,
supported_formats: []
support_status: SupportStatus.Supported,
supported_formats: [
ExportFormat.Csv,
ExportFormat.Tsv,
ExportFormat.Html
]
}
}
};
Expand Down Expand Up @@ -1173,9 +1183,146 @@ END`;
}

async exportDataSelection(params: ExportDataSelectionParams): RpcResponse<ExportedData> {
return 'not implemented';
}
const kind = params.selection.kind;

const exportQueryOutput = async (query: string,
columns: Array<SchemaEntry>): Promise<ExportedData> => {
const result = await this.db.runQuery(query);
const unboxed = [
columns.map(s => s.column_name),
// TODO: maybe this can be made more efficient
...result.toArray().map(row => result.schema.names.map(name => row[name]))
];

let data;
switch (params.format) {
case ExportFormat.Csv:
data = unboxed.map(row => row.join(',')).join('\n');
break;
case ExportFormat.Tsv:
data = unboxed.map(row => row.join('\t')).join('\n');
break;
case ExportFormat.Html:
data = unboxed.map(row => `<tr><td>${row.join('</td><td>')}</td></tr>`).join('\n');
break;
default:
throw new Error(`Unknown export format: ${params.format}`);
}

return {
data,
format: params.format,
};
};

const formatColumnNames = (columns: Array<SchemaEntry>) => {
return columns.map(s => quoteIdentifier(s.column_name)).join(', ');
}

const getColumnSelectors = (columns: Array<SchemaEntry>) => {
const columnSelectors = [];
for (const column of columns) {
const quotedName = quoteIdentifier(column.column_name);

// Build column selector. Just casting to string for now
let columnSelector;
switch (column.column_type) {
case 'FLOAT':
case 'DOUBLE': {
columnSelector = `CASE WHEN isinf(${quotedName}) AND ${quotedName} > 0 THEN 'Inf'
WHEN isinf(${quotedName}) AND ${quotedName} < 0 THEN '-Inf'
WHEN isnan(${quotedName}) THEN 'NaN'
ELSE CAST(${quotedName} AS VARCHAR)
END`;
break;
}
case 'TIMESTAMP':
columnSelector = `strftime(${quotedName} AT TIME ZONE 'UTC', '%Y-%m-%d %H:%M:%S')`;
break;
case 'TIMESTAMP WITH TIME ZONE':
columnSelector = `strftime(${quotedName}, '%Y-%m-%d %H:%M:%S%z')`;
break;
case 'VARCHAR':
case 'TINYINT':
case 'SMALLINT':
case 'INTEGER':
case 'BIGINT':
case 'DATE':
case 'TIME':
default:
columnSelector = `CAST(${quotedName} AS VARCHAR)`;
break;
}
columnSelectors.push(
`CASE WHEN ${quotedName} IS NULL THEN 'NULL' ELSE ${columnSelector} END
AS formatted_${columnSelectors.length} `);
}
return columnSelectors;
};

let data: string;
switch (kind) {
case TableSelectionKind.SingleCell: {
const selection = params.selection.selection as DataSelectionSingleCell;
const rowIndex = selection.row_index;
const columnIndex = selection.column_index;
const schema = this.fullSchema[columnIndex];
const selector = getColumnSelectors([schema])[0];
const query = `SELECT ${selector} FROM ${this.tableName} LIMIT 1 OFFSET ${rowIndex};`;
const result = await this.db.runQuery(query);
return {
data: result.toArray()[0][result.schema.names[0]],
format: params.format
}
}
case TableSelectionKind.CellRange: {
const selection = params.selection.selection as DataSelectionCellRange;
const rowStart = selection.first_row_index;
const rowEnd = selection.last_row_index;
const columnStart = selection.first_column_index;
const columnEnd = selection.last_column_index;
const columns = this.fullSchema.slice(columnStart, columnEnd + 1);
const query = `SELECT ${getColumnSelectors(columns).join(',')}
FROM ${this.tableName}
LIMIT ${rowEnd - rowStart + 1} OFFSET ${rowStart};`;
return await exportQueryOutput(query, columns);
}
case TableSelectionKind.RowRange: {
const selection = params.selection.selection as DataSelectionRange;
const rowStart = selection.first_index;
const rowEnd = selection.last_index;
const query = `SELECT ${getColumnSelectors(this.fullSchema).join(',')}
FROM ${this.tableName}
LIMIT ${rowEnd - rowStart + 1} OFFSET ${rowStart};`;
return await exportQueryOutput(query, this.fullSchema);
}
case TableSelectionKind.ColumnRange: {
const selection = params.selection.selection as DataSelectionRange;
const columnStart = selection.first_index;
const columnEnd = selection.last_index;
const columns = this.fullSchema.slice(columnStart, columnEnd + 1);
const query = `SELECT ${getColumnSelectors(columns).join(',')}
FROM ${this.tableName}`;
return await exportQueryOutput(query, columns);
}
case TableSelectionKind.RowIndices: {
const selection = params.selection.selection as DataSelectionIndices;
const indices = selection.indices;
const query = `SELECT ${getColumnSelectors(this.fullSchema).join(',')}
FROM ${this.tableName}
WHERE rowid IN (${indices.join(', ')})`;
return await exportQueryOutput(query, this.fullSchema);
}
case TableSelectionKind.ColumnIndices: {
const selection = params.selection.selection as DataSelectionIndices;
const indices = selection.indices;
const columns = indices.map(i => this.fullSchema[i]);
const query = `SELECT ${getColumnSelectors(columns).join(',')}
FROM ${this.tableName}`;
return await exportQueryOutput(query, columns);
}
}
}
private async _getShape(whereClause: string = ''): Promise<[number, number]> {
const numColumns = this.fullSchema.length;
const countStar = `SELECT count(*) AS num_rows
Expand Down
Loading

0 comments on commit 54dee73

Please sign in to comment.