I am trying to build a reference implementation of our internal tooling for database connection boilerplate coding in R for other data scientists and data analyst
Our software developers made something similar to this in python:
class DataRepository:
def __init__(self):
if user is not None and account is not None and password is not None and warehouse is not None and role is not None and database is not None and schema is not None:
self.ctx = snowflake.connector.connect(
user=user,
password=password,
account=account,
role=role,
database=database,
schema=schema,
warehouse=warehouse,
login_timeout=login_timeout,
ocsp_fail_open=ocsp_fail_open
)
else:
secret_str = self.get_secrets()
self.ctx = snowflake.connector.connect(
user=secret_str['user'],
password=secret_str['password'],
account=secret_str['account'],
role=secret_str['role'],
database=secret_str['database'],
schema=secret_str['schema'],
warehouse=secret_str['warehouse'],
login_timeout=login_timeout,
ocsp_fail_open=ocsp_fail_open
)
def get_secrets(self):
my_session = boto3.session.Session(region_name=AWS_DEFAULT_REGION)
client = my_session.client(
service_name='secretsmanager',
region_name=AWS_DEFAULT_REGION,
)
get_secret_value_response = client.get_secret_value(
SecretId=SECRET_NAME
)
secret_str = json.loads(get_secret_value_response['SecretString'])
return secret_str
I was trying to reproduce this with S3 as:
DataRepository <-
R6Class(
classname = "DataRepository",
public = list(
ctx = NULL,
secrets = NULL,
initialize = function() {
if (length(user) == 1 &
length(account) == 1 & length(password) == 1
&
length(warehouse) == 1 &
length(role) == 1 & length(database) == 1) {
self$ctx <- dbConnect(
odbc::odbc(),
Driver = "SnowflakeDSIIDriver",
Database = database,
Uid = user,
Pwd = password,
Server = paste0(account, ".snowflakecomputing.com"),
role = role
)
} else {
secret_dict <- self$getSecrets()
self$ctx <- dbConnect(
odbc::odbc(),
Driver = secret_dict$user,
Database = secret_dict$database,
Uid = secret_dict$user,
Pwd = secret_dict$password,
Server = paste0(secret_dict$account, ".snowflakecomputing.com"),
role = secret_dict$account
)
}
},
getSecrets = function() {
secrets_client <- paws::secretsmanager(config =
list(region = AWS_REGION))
get_secret_value_response <- secrets_client$get_secret_value(SecretId = SECRETS_NAME)
secrets_str <-
get_secret_value_response$SecretString %>% fromJSON()
return(secrets_str)
}
)
)
However it seems that I am not able to access the get_secrets function within the initializer as opposite as my colleagues do in python.
Is there any simple solution to this?
PS: I am not so familiar with the R6 system and I believe that my confusion is probably due to a conceptual error but I would more than happy to learn more :)
Your code is fine in the getSecrets regard, but you forgot to define your constructor arguments.
Consider this:
DataRepository <-
R6Class(
classname = "DataRepository",
public = list(
ctx = NULL,
secrets = NULL,
initialize = function(user, account,password,warehouse,role,database) {
if ( !missing(database) &&
length(user) == 1 &&
length(account) == 1 && length(password) == 1 &&
length(warehouse) == 1 &&
length(role) == 1 && length(database) == 1) {
self$ctx <- dbConnect(
odbc::odbc(),
Driver = "SnowflakeDSIIDriver",
Database = database,
Uid = user,
Pwd = password,
Server = paste0(account, ".snowflakecomputing.com"),
role = role
)
} else {
secret_dict <- self$getSecrets()
## self$ctx <- dbConnect(
## odbc::odbc(),
## Driver = secret_dict$user,
## Database = secret_dict$database,
## Uid = secret_dict$user,
## Pwd = secret_dict$password,
## Server = paste0(secret_dict$account, ".snowflakecomputing.com"),
## role = secret_dict$account
## )
}
},
getSecrets = function() {
cat( "I am in the getSecrets method!\n")
## secrets_client <- paws::secretsmanager(config =
## list(region = AWS_REGION))
## get_secret_value_response <- secrets_client$get_secret_value(SecretId = SECRETS_NAME)
## secrets_str <-
## get_secret_value_response$SecretString %>% fromJSON()
## return(secrets_str)
}
)
)
dr = DataRepository$new()
Output:
> dr = DataRepository$new()
I am in the getSecrets method!
Check if your arguments are missing (Above I checked just the last one, which works if you are doing positional arguments only, for which there is no guarantee), or set defaults that you handle meaningfully, or just write a function that checks input arguments and returns FALSE if they won't suffice and you should go get the secrets instead.
Also do use double amperasands, eg. &&
and not &
, the latter is a vectorized AND operator. You should have only one value here, and you would welcome a warning if that wisn't the case.