-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Connections: Create SQLite connection #6380
Merged
+206
−5
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
5d882e2
Add support for new SQLite connections
dfalbel 677494a
Add support for installing deps
dfalbel 45afd49
Prompt to allow installation
dfalbel 62ba4c5
Fix spaces
dfalbel 13e744f
add Python SQlite support
dfalbel fd1a68a
add path escaping
dfalbel 9a68a60
Handle failure to check for dependencies
dfalbel 2f71450
Remove whitespace
dfalbel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,12 +7,107 @@ import * as positron from 'positron'; | |
import * as vscode from 'vscode'; | ||
|
||
export function registerConnectionDrivers(context: vscode.ExtensionContext) { | ||
context.subscriptions.push( | ||
positron.connections.registerConnectionDriver(new RPostgreSQLDriver()) | ||
); | ||
for (const driver of [new RSQLiteDriver(), new RPostgreSQLDriver(), new PythonSQLiteDriver()]) { | ||
context.subscriptions.push( | ||
positron.connections.registerConnectionDriver(driver) | ||
); | ||
} | ||
} | ||
|
||
/// A generic driver implementation | ||
class RDriver implements positron.ConnectionsDriver { | ||
|
||
driverId: string = 'unknown'; | ||
metadata: positron.ConnectionsDriverMetadata = { | ||
languageId: 'r', | ||
name: 'Unknown', | ||
inputs: [] | ||
}; | ||
|
||
constructor(readonly packages: string[]) { } | ||
|
||
async connect(code: string) { | ||
const exec = await positron.runtime.executeCode( | ||
'r', | ||
code, | ||
true, | ||
false, | ||
positron.RuntimeCodeExecutionMode.Interactive, | ||
positron.RuntimeErrorBehavior.Continue | ||
); | ||
if (!exec) { | ||
throw new Error('Failed to execute code'); | ||
} | ||
return; | ||
} | ||
|
||
async checkDependencies() { | ||
// Currently we skip dependency checks if there's no active R session | ||
// in the foreground. | ||
if (this.packages.length === 0) { | ||
return true; | ||
} | ||
|
||
const session = await positron.runtime.getForegroundSession(); | ||
if (session) { | ||
|
||
if (session.runtimeMetadata.languageId !== 'r') { | ||
return true; | ||
} | ||
|
||
for (const pkg of this.packages) { | ||
const installed = await session.callMethod?.('is_installed', pkg); | ||
if (!installed) { | ||
return false; | ||
} | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
async installDependencies() { | ||
// Similar to checkDependencies, we skip dependency installation if there's | ||
// no active R session in the foreground. | ||
if (this.packages.length === 0) { | ||
return true; | ||
} | ||
const session = await positron.runtime.getForegroundSession(); | ||
if (session) { | ||
|
||
if (session.runtimeMetadata.languageId !== 'r') { | ||
return true; | ||
} | ||
|
||
const allow_install = await positron.window.showSimpleModalDialogPrompt( | ||
vscode.l10n.t("Installing dependencies"), | ||
vscode.l10n.t("The following R packages are required for this connection: {0}. Would you like to install them now?", this.packages.join(', ')) | ||
); | ||
|
||
if (!allow_install) { | ||
return false; | ||
} | ||
|
||
for (const pkg of this.packages) { | ||
const installed = await session.callMethod?.('is_installed', pkg); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As above, need exception handling here |
||
if (!installed) { | ||
const install_succeed = await session.callMethod?.('install_packages', pkg); | ||
if (!install_succeed) { | ||
throw new Error('Failed to install dependencies'); | ||
} | ||
} | ||
} | ||
} | ||
return true; | ||
} | ||
} | ||
|
||
class RPostgreSQLDriver implements positron.ConnectionsDriver { | ||
class RPostgreSQLDriver extends RDriver implements positron.ConnectionsDriver { | ||
|
||
constructor() { | ||
super(['RPostgres', 'DBI']); | ||
} | ||
|
||
driverId: string = 'postgres'; | ||
metadata: positron.ConnectionsDriverMetadata = { | ||
languageId: 'r', | ||
|
@@ -83,10 +178,66 @@ con <- dbConnect( | |
) | ||
`; | ||
} | ||
} | ||
|
||
class RSQLiteDriver extends RDriver implements positron.ConnectionsDriver { | ||
|
||
constructor() { | ||
super(['RSQLite', 'DBI', 'connections']); | ||
} | ||
|
||
driverId: string = 'sqlite'; | ||
metadata: positron.ConnectionsDriverMetadata = { | ||
languageId: 'r', | ||
name: 'SQLite', | ||
inputs: [ | ||
{ | ||
'id': 'dbname', | ||
'label': 'Database Name', | ||
'type': 'string', | ||
'value': 'database.db' | ||
}, | ||
{ | ||
'id': 'bigint', | ||
'label': 'Integer representation', | ||
'type': 'option', | ||
'options': [ | ||
{ 'identifier': 'integer64', 'title': 'integer64' }, | ||
{ 'identifier': 'integer', 'title': 'integer' }, | ||
{ 'identifier': 'numeric', 'title': 'numeric' }, | ||
{ 'identifier': 'character', 'title': 'character' } | ||
], | ||
'value': 'integer64' | ||
}, | ||
] | ||
}; | ||
|
||
generateCode(inputs: positron.ConnectionsInput[]) { | ||
const dbname = inputs.find(input => input.id === 'dbname')?.value ?? ''; | ||
const bigint = inputs.find(input => input.id === 'bigint')?.value ?? ''; | ||
|
||
return `library(DBI) | ||
con <- dbConnect( | ||
RSQLite::SQLite(), | ||
dbname = ${JSON.stringify(dbname)}, | ||
bigint = ${JSON.stringify(bigint)} | ||
) | ||
connections::connection_view(con) | ||
`; | ||
} | ||
} | ||
|
||
class PythonDriver implements positron.ConnectionsDriver { | ||
driverId: string = 'python'; | ||
metadata: positron.ConnectionsDriverMetadata = { | ||
languageId: 'python', | ||
name: 'Unknown', | ||
inputs: [] | ||
}; | ||
|
||
async connect(code: string) { | ||
const exec = await positron.runtime.executeCode( | ||
'r', | ||
'python', | ||
code, | ||
true, | ||
false, | ||
|
@@ -100,3 +251,33 @@ con <- dbConnect( | |
} | ||
} | ||
|
||
class PythonSQLiteDriver extends PythonDriver implements positron.ConnectionsDriver { | ||
driverId: string = 'py-sqlite'; | ||
metadata: positron.ConnectionsDriverMetadata = { | ||
languageId: 'python', | ||
name: 'SQLite', | ||
inputs: [ | ||
{ | ||
'id': 'dbname', | ||
'label': 'Database Name', | ||
'type': 'string', | ||
'value': 'database.db' | ||
}, | ||
{ | ||
'id': 'timeout', | ||
'label': 'Timeout', | ||
'type': 'number', | ||
'value': '5.0' | ||
}, | ||
] | ||
}; | ||
|
||
generateCode(inputs: positron.ConnectionsInput[]) { | ||
const dbname = inputs.find(input => input.id === 'dbname')?.value; | ||
|
||
return `import sqlite3 | ||
conn = sqlite3.connect(${JSON.stringify(dbname) ?? JSON.stringify('')}) | ||
%connection_show conn | ||
`; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs some exception handling; if
callMethod
throws I think the exception should be logged (and we should probably presume the dependencies to be installed since otherwise the user will be blocked as I understand it?)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory this is handled on the call site of
checkDependencies
andinstallDependencies
:positron/src/vs/workbench/contrib/positronConnections/browser/components/newConnectionModalDialog/createConnectionState.tsx
Lines 66 to 83 in 2122937
But indeed, they wouldn't be able to run
connect()
if checking for the dependencies fails.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With 2bfb463 we now presume that upon failure to check if dependencies are installed we can continue and try to connect.