wrapper function in odbc/dbplyr, doesn't produce connections pane ("connections contract")

Hi all, I am developing an R package (lets call it dbr) at work so users can easily connect via ODBC to a database without having to remember any boilerplate. The workflow would be to assign a variable to dbr::connect_database.

The Issue:

While all it does is wrap/abstract away a standard odbc call, it does not pass the "Connections Contract" that produces the Connections pane information in RStudio. Given that odbc already has this code, I'm guessing I am missing some quirk of R that is preventing this from being passed.

What I Found:

I did some research on this and found information about the Connections Contract. Given that odbc already has this built in, and I am simply wrapping the function, it seems that I shouldn't have to rewrite this from scratch.

https://db.rstudio.com/advanced/contract/

My Code

This code is reproducible if you have set up an ODBC connection. When connecting to DB via the wrapper function, everything works except the Connections Pane. When calling the exact code outside of the function, the Connections Pane reappears.

connect_database <- function(dsn = "database") {

  DBI::dbConnect(odbc::odbc(),
                 dsn = dsn,
                 username = keyring::key_list("database")[1,2],
                 password = keyring::key_get("database"))

}

Has anybody dealt with this? Why is the odbc Connections Contract not passed when wrapped inside of a function call? I am having trouble googling around for it. My idea was that the outcome of calling the code should work exactly the same whether or not its called within a function. Assigning a variable such as con to both types of executions (inside a function and outside a function) produce a global environment variable with identical attributes.

Thanks!

1 Like

I think this is not working as you expect because of this code

The notification to the connection pane is done only if dbConnect() is called at the top level on an odbc object. When you encapsulate in a function it is not more top level.

You can follow the documentation and obdc example to try implement connection pane in your own package
https://rstudio.github.io/rstudio-extensions/connections-contract.html

or you can try to create a new method for dbConnect in your package following DBI standard I guess...

Hope it helps.

1 Like

Thank you @cderv

Is there any resource to understand the behind-the-scenes difference when calling something in a function vs top-level?

I understand that I can implement my own "Connections Contract", (albeit it is probably easier to tell analysts to remember the DBI::dbConnect call), but given that odbc and dbConnect already have it implemented, and I am using a vanilla version of both, is there not a way I can bring that execution back to the top-level?

Again, thanks! This is a small topic to google about, and I appreciate the time.

Here's a somewhat outside-of-the-box suggestion. Your package could provide a small RStudio addin that generates the correct DBI::dbConnect() code using a small shiny app with options relevant to your users' situation. The code can then be written directly into the open source document or run in the console. This idea was completely inspired by Hao Zhu's rstudio::conf talk https://resources.rstudio.com/rstudio-conf-2019/empowering-a-data-team-with-rstudio-addins

1 Like

Not that I know of. I stumble upon this code once, so it is how I know.

Also, we included connection contract into our own function at my company in a :package:.

1 Like

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.