From 83d9d15c8a92f0a6a19fdd8898d5ef6bf7803f5b Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Thu, 3 Feb 2022 17:21:51 +0000 Subject: [PATCH 01/23] Converted code for new platform. --- .Rbuildignore | 4 + .circleci/config.yml | 53 ---- .gitignore | 2 + DESCRIPTION | 10 +- LICENSE | 2 + LICENSE.md | 21 ++ NAMESPACE | 23 +- R/get_athena_query_response.R | 40 --- R/get_data_conversion.R | 41 --- R/read.R | 113 ++++++++ R/read_sql.R | 78 ------ R/utils-pipe.R | 14 + R/utils.R | 34 --- R/wrap.R | 200 +++++++++++++++ R/zzz.R | 9 +- inst/extdata/boto_utils.py | 17 -- man/convert_athena_type_to_arrow.Rd | 17 ++ man/create_temp_table.Rd | 24 ++ man/delete_database_and_data.Rd | 14 + man/delete_object.Rd | 25 -- man/delete_partitions_and_data.Rd | 23 ++ man/delete_table_and_data.Rd | 19 ++ man/describe_table.Rd | 22 ++ man/get_athena_query_response.Rd | 39 --- man/get_query_columns_types.Rd | 20 ++ man/get_query_execution.Rd | 20 ++ man/get_sql_from_file.Rd | 21 ++ man/pipe.Rd | 20 ++ man/read_sql.Rd | 31 --- man/read_sql_query.Rd | 17 ++ man/render_sql_template.Rd | 16 ++ man/repair_table.Rd | 26 ++ man/show_create_table.Rd | 22 ++ man/start_query_execution.Rd | 19 ++ man/start_query_execution_and_wait.Rd | 20 ++ man/stop_query_execution.Rd | 14 + man/wait_query.Rd | 20 ++ renv.lock | 354 ++++++++++++++++++++++++++ requirements.txt | 40 +++ 39 files changed, 1132 insertions(+), 372 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 LICENSE create mode 100644 LICENSE.md delete mode 100644 R/get_athena_query_response.R delete mode 100644 R/get_data_conversion.R create mode 100644 R/read.R delete mode 100644 R/read_sql.R create mode 100644 R/utils-pipe.R delete mode 100644 R/utils.R create mode 100644 R/wrap.R delete mode 100644 inst/extdata/boto_utils.py create mode 100644 man/convert_athena_type_to_arrow.Rd create mode 100644 man/create_temp_table.Rd create mode 100644 man/delete_database_and_data.Rd delete mode 100644 man/delete_object.Rd create mode 100644 man/delete_partitions_and_data.Rd create mode 100644 man/delete_table_and_data.Rd create mode 100644 man/describe_table.Rd delete mode 100644 man/get_athena_query_response.Rd create mode 100644 man/get_query_columns_types.Rd create mode 100644 man/get_query_execution.Rd create mode 100644 man/get_sql_from_file.Rd create mode 100644 man/pipe.Rd delete mode 100644 man/read_sql.Rd create mode 100644 man/read_sql_query.Rd create mode 100644 man/render_sql_template.Rd create mode 100644 man/repair_table.Rd create mode 100644 man/show_create_table.Rd create mode 100644 man/start_query_execution.Rd create mode 100644 man/start_query_execution_and_wait.Rd create mode 100644 man/stop_query_execution.Rd create mode 100644 man/wait_query.Rd create mode 100644 renv.lock create mode 100644 requirements.txt diff --git a/.Rbuildignore b/.Rbuildignore index 91114bf..176897e 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,2 +1,6 @@ +^requirements\.txt$ +^renv$ +^renv\.lock$ ^.*\.Rproj$ ^\.Rproj\.user$ +^LICENSE\.md$ diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index fb25e1f..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,53 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: continuumio/miniconda3 - steps: - - run: mkdir -p ~/.ssh/ && ssh-keyscan github.com > ~/.ssh/known_hosts 2>/dev/null - - run: conda install conda-build CacheControl lockfile - - run: conda skeleton cran $CIRCLE_REPOSITORY_URL --git-tag $CIRCLE_SHA1 - - run: | - for channel in r conda-forge bioconda moj-analytical-services; do - conda config --add channels "$channel" - done - - run: conda build r-$CIRCLE_PROJECT_REPONAME --R 3.5.1 - - persist_to_workspace: - root: /opt/conda/conda-bld/linux-64/ - paths: - - "*.tar.bz2" - publish: - docker: - - image: continuumio/miniconda3 - steps: - - attach_workspace: - at: /opt/conda/conda-bld/linux-64/ - - run: conda install anaconda-client - - run: - name: "Publish to Conda" - command: anaconda -t $CONDA_UPLOAD_TOKEN upload -u moj-analytical-services /opt/conda/conda-bld/linux-64/*.tar.bz2 - -workflows: - version: 2 - build-only: - jobs: - - build: - filters: - tags: - ignore: /^v.*/ - build-and-publish: - jobs: - - build: - filters: - tags: - only: /^v.*/ - branches: - ignore: /.*/ - - publish: - filters: - tags: - only: /^v.*/ - branches: - ignore: /.*/ - requires: - - build diff --git a/.gitignore b/.gitignore index 5b6a065..deabf39 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .Rhistory .RData .Ruserdata +renv +.Rprofile diff --git a/DESCRIPTION b/DESCRIPTION index 701792d..a501b3f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -5,16 +5,14 @@ Version: 2.0.3 Author: Karik Isichei Maintainer: The package maintainer Description: See title. -License: What license is it under? +License: MIT + file LICENSE Encoding: UTF-8 LazyData: true -RoxygenNote: 6.0.1 +RoxygenNote: 7.1.1 Imports: - reticulate (>= 1.10), - s3tools, - readr + magrittr, + reticulate Suggests: data.table (>= 1.11.8) Remotes: moj-analytical-services/s3tools - diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6f9d947 --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +YEAR: 2022 +COPYRIGHT HOLDER: Ministry of Justice diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..1eeca5e --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2022 dbtools authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NAMESPACE b/NAMESPACE index 87c0573..027d69a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,7 +1,22 @@ # Generated by roxygen2: do not edit by hand -export(get_athena_query_response) +export("%>%") +export(convert_athena_type_to_arrow) +export(create_temp_table) +export(delete_database_and_data) +export(delete_partitions_and_data) +export(delete_table_and_data) +export(describe_table) +export(get_query_columns_types) +export(get_query_execution) +export(get_sql_from_file) export(read_sql) -import(readr) -import(reticulate) -import(s3tools) +export(read_sql_query) +export(render_sql_template) +export(repair_table) +export(show_create_table) +export(start_query_execution) +export(start_query_execution_and_wait) +export(stop_query_execution) +export(wait_query) +importFrom(magrittr,"%>%") diff --git a/R/get_athena_query_response.R b/R/get_athena_query_response.R deleted file mode 100644 index 6547ac1..0000000 --- a/R/get_athena_query_response.R +++ /dev/null @@ -1,40 +0,0 @@ -#' get_athena_query_response -#' -#'@description uses boto3 (in python) to send an sql query to athena and return the resulting data's path in s3 and meta data -#' -#'@import reticulate s3tools -#' -#'@export -#' -#'@details Will send an SQL query to athena and wait for it to complete. Once the query has completed the funtion will return a list containing the s3 path to your athena query and meta data about the output data -#' -#'@param sql_query A string specifying the SQL query you want to send to athena. See packages github readme for info on the flavour of SQL Athena uses. -#' -#'@param return_athena_types Specifies if the list describing the data's meta data types should be defined using athena datatypes (TRUE) or using the data engineering team's generic metadata types (FALSE). If not specified the default value of this input parameter is set to FALSE. -#' -#'@param timeout Specifies How long you want your sql query to wait before it gives up (in seconds). Default parameter is NULL which will mean SQL query will not timeout and could wait forever if an issue occured. -#' -#'@return A list with two keys. [1] s3_path : a string pointing to the s3 path of the athena query. [2] meta : a list that has the name and type of each column in of the data in the s3_path. Can be used to get correct data types of your output when read in to R (note the order of the columns matches the order they appear in the data). -#' -#'@examples -#'# Read an sql query using readr::read_csv -#'response <- dbtools::get_athena_query_response("SELECT * from crest_v1.flatfile limit 10000") -#' -#'# print out path to athena query output (as a csv) -#'print(response$s3_path) -#' -#'# print out meta data -#'print(response$meta) -#' -#'# Read in data using whatever csv reader you want -#'s3_path_stripped = gsub("s3://", "", response$s3_path) -#'df <- s3tools::read_using(FUN = read.csv, s3_path=s3_path_stripped) - -get_athena_query_response <- function(sql_query, return_athena_types=FALSE, timeout = NULL){ - - pydbtools <- reticulate::import("pydbtools") - s3tools::get_credentials() - response <- pydbtools$get_athena_query_response(sql_query=sql_query, return_athena_types=return_athena_types, timeout=timeout, force_ec2=TRUE) - return(response) -} - diff --git a/R/get_data_conversion.R b/R/get_data_conversion.R deleted file mode 100644 index a3d3eef..0000000 --- a/R/get_data_conversion.R +++ /dev/null @@ -1,41 +0,0 @@ -get_data_conversion <- function(df_type){ - - if(df_type == 'tibble'){ - # Note how 64 bit integers (long) are read in as double - conversion <- list( - "character" = readr::col_character(), - "int" = readr::col_integer(), - "long" = readr::col_double(), - "date" = readr::col_date(), - "datetime" = readr::col_datetime(), - "boolean" = readr::col_logical(), - "float" = readr::col_double(), - "double" = readr::col_double() - ) - } else if(df_type == 'data.table'){ - # Note that dates/datetimes are read in as characters - conversion <- list( - "character" = "character", - "int" = "integer", - "long" = "integer64", - "date" = "character", - "datetime" = "character", - "boolean" = "logical", - "float" = "double", - "double" = "double" - ) - } else { - # have to read in everything as character see readme - conversion <- list( - "character" = "character", - "int" = "character", - "long" = "character", - "date" = "character", - "datetime" = "character", - "boolean" = "character", - "float" = "character", - "double" = "character" - ) - } - return(conversion) -} diff --git a/R/read.R b/R/read.R new file mode 100644 index 0000000..8f4f241 --- /dev/null +++ b/R/read.R @@ -0,0 +1,113 @@ +#' Convert an Athena type to an Arrow type +#' +#' @param t A string giving an Athena type +#' +#' @return An Arrow type +#' @export +#' +#' @see https://docs.aws.amazon.com/athena/latest/ug/data-types.html +#' @see https://arrow.apache.org/docs/r/reference/data-type.html +convert_athena_type_to_arrow <- function(t) { + # Regular expression matches either e.g. decimal(10) or decimal(10, 5) + decimal_match <- stringr::str_match( + t, + "decimal\\(([:digit:]+)(\\s*,\\s*([:digit:]+))?\\)" + ) + if (!is.na(decimal_match[1])) { + precision <- as.numeric(decimal_match[2]) + # Set scale to default 0 if not present + scale <- ifelse(is.na(decimal_match[4]), 0, as.numeric(decimal_match[4])) + return(arrow::decimal(precision, scale)) + } + + switch( + t, + "boolean" = arrow::bool(), + "tinyint" = arrow::int8(), + "smallint" = arrow::int16(), + "int" = arrow::int32(), + "integer" = arrow::int32(), + "bigint" = arrow::int64(), + "double" = arrow::float64(), + "float" = arrow::float32(), + "char" = arrow::string(), + "string" = arrow::string(), + "binary" = arrow::binary(), + "date" = arrow::date32(), + "timestamp" = arrow::timestamp(unit="ms", timezone="UTC"), + arrow::string() + ) %>% return +} + + +#' Send an SQL query to Athena and receive a data frame. +#' +#' @param sql An SQL query +#' +#' @return Dataframe +#' @export +#' +#' @examples +#' `df <- dbtools::read_sql_query('select * from my_db.my_table)` +read_sql_query <- function(sql) { + query_id <- dbtools.env$pydb$start_query_execution(sql) + dbtools.env$pydb$wait_query(query_id) + athena_status <- dbtools.env$pydb$get_query_execution(query_id) + athena_client <- dbtools.env$boto3$client('athena') + response <- dbtools.env$athena_client$get_query_results( + QueryExecutionId=query_id + ) + + if (athena_status$Status$State == 'FAILED') { + stop('SQL query failed with response error;\n', + athena_status$Status$StateChangeReason) + } + + # Create arrow schema as a list of arrow::Fields + schema <- list() + for (col_info in response$ResultSet$ResultSetMetadata$ColumnInfo) { + schema <- append( + schema, + list(arrow::field(col_info$Name, + convert_athena_type_to_arrow(col_info$Type))) + ) + } + + df <- arrow::read_csv_arrow( + athena_status$ResultConfiguration$OutputLocation, + schema=schema, + convert_options=arrow::CsvConvertOptions$create(strings_can_be_null=TRUE) + ) + return(df) +} + +#' @description Uses boto3 (in python) to send an sql query to athena and return an R dataframe, tibble or data.table based on user preference. +#' +#' @export +#' +#' @details Will send an SQL query to Athena and wait for it to complete. Once the query has completed the resulting sql query will be read using arrow. +#' Function returns dataframe. If needing more a more bespoke or self defined data reading function and arguments use dbtools::start_query_and_wait to send an SQL query and return the s3 path to data in csv format. +#' +#' @param sql_query A string specifying the SQL query you want to send to athena. See packages github readme for info on the flavour of SQL Athena uses. +#' @param return_df_as String specifying what the table should be returned as i.e. 'dataframe', 'tibble' (converts data using tibble::as_tibble) or 'data.table' (converts data using data.table::as.data.table). Default is 'tibble'. Not all tables returned are a DataFrame class. +#' +#' @return A table as a dataframe, tibble or data.table +#' +#' @examples +#' # Read an sql query returning a tibble +#' ``` +#' df <- dbtools::read_sql( +#' "SELECT * from crest_v1.flatfile limit 10000", +#' return_df_as="tibble" +#' ) +#' ``` +read_sql <- function(sql_query, return_df_as="tibble") { + df <- read_sql_query(sql_query) + if (return_df_as == "tibble") { + return(tibble::as_tibble(df)) + } else if (return_df_as == "data.table") { + return(data.table::as.data.table(df)) + } else { + return(df) + } +} diff --git a/R/read_sql.R b/R/read_sql.R deleted file mode 100644 index adc314b..0000000 --- a/R/read_sql.R +++ /dev/null @@ -1,78 +0,0 @@ -#' read_sql -#' -#'@description uses boto3 (in python) to send an sql query to athena and return an R dataframe, tibble or data.table based on user preference. -#' -#'@import reticulate s3tools readr -#' -#'@export -#' -#'@details Will send an SQL query to athena and wait for it to complete. Once the query has completed the resulting sql query will be read using read.csv (base R), read_csv (readr) or fread (data.table). -#' Function returns dataframe. If needing more a more bespoke or self defined data reading function and arguments use dbtools::get_athena_query_response to send an SQL query and return the s3 path to data in csv format. -#' -#'@param sql_query A string specifying the SQL query you want to send to athena. See packages github readme for info on the flavour of SQL Athena uses. -#' -#'@param return_df_as String specifying what the table should be returned as i.e. 'dataframe' (reads data using read.csv), 'tibble' (reads data using readr::read_csv) or 'data.table' (reads data using data.table::fread). Default is 'tibble'. Not all tables returned are a DataFrame class. -#' Only return_df_as set to 'tibble' maintains date and datetime formats. dataframe and data.table will convert date and datetimes to characters. -#' -#'@param timeout Specifies How long you want your sql query to wait before it gives up (in seconds). Default parameter is NULL which will mean SQL query will not timeout and could wait forever if an issue occured. -#' -#'@return A table as a dataframe, tibble or data.table -#' -#'@examples -#'# Read an sql query using readr::read_csv i.e. returning a Tibble -#'df <- dbtools::read_sql("SELECT * from crest_v1.flatfile limit 10000") -#'df - -read_sql <- function(sql_query, return_df_as='tibble', timeout = NULL){ - - # Annoyingly I think you have to pull it in as the source_python function doesn't seem to be exported properly - # require(reticulate) - - return_df_as <- tolower(return_df_as) - if(!return_df_as %in% c('dataframe', 'tibble', 'data.table')){ - stop("input var return_df_as must be one of the following 'dataframe', 'tibble' or 'data.table'") - } - - response <- dbtools::get_athena_query_response(sql_query=sql_query, return_athena_types=FALSE, timeout=timeout) - s3_path_stripped <- gsub("s3://", "", response$s3_path) - bucket <- unlist(strsplit(s3_path_stripped, '/'))[1] - s3_key <- gsub(paste0(bucket,"/"), "", s3_path_stripped) - - # Check if text output - if(endsWith(s3_path_stripped, ".txt")){ - if(return_df_as == 'tibble'){ - df <- s3tools::read_using(FUN=readr::read_csv, s3_path=s3_path_stripped, col_names=FALSE, col_types=list(readr::col_character())) - } else if(return_df_as == 'data.table'){ - df <- s3tools::read_using(FUN=data.table::fread, s3_path=s3_path_stripped, header=FALSE, colClasses=c("character")) - } else { - df <- s3tools::read_using(FUN=read.csv, s3_path=s3_path_stripped, header=FALSE, colClasses=c("character")) - } - colnames(df) <- c("output") - } else { - # Get meta Ddata conversion - data_conversion <- dbtools:::get_data_conversion(return_df_as) - col_classes = list() - for(m in response$meta){ - col_classes[[m$name]] = data_conversion[[m$type]] - } - col_classes_vec = unlist(col_classes) - - if(return_df_as == 'tibble'){ - #This is the best R work arround I could find to replicate Python's **kwargs... - col_types = do.call(readr::cols, col_classes) - df <- s3tools::read_using(FUN=readr::read_csv, s3_path=s3_path_stripped, col_names=TRUE, col_types=col_types) - - } else if(return_df_as == 'data.table'){ - dt_ver <- packageVersion("data.table") - if(dt_ver < '1.11.8'){ - warning("Your version of data.table must be 1.11.8 or above please install a new version otherwise your outputs of type data.table may not convert data types properly.") - } - df <- s3tools::read_using(FUN=data.table::fread, s3_path=s3_path_stripped, header=TRUE, colClasses=col_classes_vec) - } else { - df <- s3tools::read_using(FUN=read.csv, s3_path=s3_path_stripped, header=TRUE, colClasses=col_classes_vec) - } - } - dbtools:::delete_object(bucket, s3_key) - dbtools:::delete_object(bucket, paste0(s3_key, ".metadata")) - return(df) -} diff --git a/R/utils-pipe.R b/R/utils-pipe.R new file mode 100644 index 0000000..fd0b1d1 --- /dev/null +++ b/R/utils-pipe.R @@ -0,0 +1,14 @@ +#' Pipe operator +#' +#' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. +#' +#' @name %>% +#' @rdname pipe +#' @keywords internal +#' @export +#' @importFrom magrittr %>% +#' @usage lhs \%>\% rhs +#' @param lhs A value or the magrittr placeholder. +#' @param rhs A function call using the magrittr semantics. +#' @return The result of calling `rhs(lhs)`. +NULL diff --git a/R/utils.R b/R/utils.R deleted file mode 100644 index 2829e88..0000000 --- a/R/utils.R +++ /dev/null @@ -1,34 +0,0 @@ -#' delete_object -#' -#'@description uses boto3 (in python) to delete an S3 object (used by read_sql function to clean up after itself) -#' -#'@import reticulate -#' -#'@details Will send an SQL query to athena and wait for it to complete. Once the query has completed the resulting sql query will be read using read.csv (base R), read_csv (readr) or fread (data.table). -#' Function returns dataframe. If needing more a more bespoke or self defined data reading function and arguments use dbtools::get_athena_query_response to send an SQL query and return the s3 path to data in csv format. -#' -#'@param bucket A string specifying the s3 bucket name -#' -#'@param key File path to the s3 object - -#'@examples -#'# delete a file from S3 -#'# (note this is not exported so have to use tripple colon) -#'dbtools:::delete_object('my_bucket', 'path/to/file.csv') - -delete_object <- function(bucket, key){ - python_script <- system.file("extdata", "boto_utils.py", package = "dbtools") - reticulate::source_python(python_script) - s3tools::get_credentials() - delete_object(bucket=bucket, key=key) -} - -get_iam_role <- function(){ - user <- Sys.getenv("USER") - if(user==""){ - stop("Error could not find username in env vars. Please raise an issue on the Github repo for dbtools.") - } - iam_role <- paste0("alpha_user_", user) - return(iam_role) -} - diff --git a/R/wrap.R b/R/wrap.R new file mode 100644 index 0000000..56f92e8 --- /dev/null +++ b/R/wrap.R @@ -0,0 +1,200 @@ +#' Create a temporary table +#' +#' @param sql: The SQL table you want to create a temp table out of. Should +#' be a table that starts with a WITH or SELECT clause. +#' @param table_name The name of the temp table you wish to create +#' @param region_name Name of the AWS region you want to run queries on. +#' Defaults to pydbtools.utils.aws_default_region (which if left unset is +#' "eu-west-1"). +#' +#' @export +#' +#' @examples +#' `dbtools::create_temp_table("SELECT a_col, count(*) as n FROM a_database.table GROUP BY a_col", table_name="temp_table_1")` +create_temp_table <- function(sql, table_name, region_name) { + dbtools.env$pydb$create_temp_table(sql, table_name, region_name=region_name) +} + +#' Show the list of columns, including partition columns: 'DESCRIBE table;'. +#' +#' @param table Table name +#' @param database AWS Glue/Athena database name +#' +#' @return DataFrame filled by formatted infos. +#' @export +#' +#' @examples +#' `df_table = dbtools::describe_table(table='my_table', database='my_db')` +describe_table <- function(table, database) { + dbtools.env$pydb$describe_table(table, database) +} + +#' Get the data type of all columns queried. +#' +#' @param query_id Athena query execution ID +#' +#' @return List with all data types +#' @export +#' +#' @examples +#' `dbtools::get_query_columns_types('query-execution-id')` +get_query_columns_types <- function(query_id) { + dbtools.env$pydb$get_query_columns_types(query_id) +} + +#' Fetch query execution details. +#' +#' @param query_id Athena query execution ID +#' +#' @return List with the get_query_execution response. +#' @export +#' +#' @examples +#' `res <- dbtools::get_query_execution(query_id='query-execution-id')` +get_query_execution <- function(query_id) { + dbtools.env$pydb$get_query_execution(query_id) +} + + +#' Run the Hive's metastore consistency check: 'MSCK REPAIR TABLE table;'. +#' +#' Recovers partitions and data associated with partitions. +#' Use this statement when you add partitions to the catalog. +#' It is possible it will take some time to add all partitions. +#' If this operation times out, it will be in an incomplete state +#' where only a few partitions are added to the catalog. +#' +#' @param table Table name +#' @param database AWS Glue/Athena database name +#' +#' @return Query final state ('SUCCEEDED', 'FAILED', 'CANCELLED') +#' @export +#' +#' @examples +#' `query_final_state = dbtools::repair_table(table='...', database='...')` +repair_table <- function(table, database) { + dbtools.env$pydb$repair_table(table, database) +} + +#' Generate the query that created a table: 'SHOW CREATE TABLE table;'. +#' +#' @param table Table name +#' @param database AWS Glue/Athena database name +#' +#' @return The query that created the table +#' @export +#' +#' @examples +#' `df_table = dbtools::show_create_table(table='my_table', database='my_db')` +show_create_table <- function(table, database) { + dbtools.env$pydb$show_create_table(table, database) +} + +#' Start a SQL Query against AWS Athena +#' +#' @param sql SQL query +#' @param wait Default FALSE, indicates whether to wait for the query to finish and return a dictionary with the query execution response. +#' +#' @return Query execution ID if `wait` is set to `False`, list with the get_query_execution response otherwise. +#' @export +start_query_execution <- function(sql, wait=FALSE) { + dbtools.env$pydb$start_query_execution(sql, wait) +} + +#' Stop a query execution +#' +#' @param query_id Athena query execution ID +#' +#' @export +stop_query_execution <- function(query_id) { + dbtools.env$pydb$stop_query_execution(query_id) +} + +#' Wait for a query to end. +#' +#' @param query_id Athena query execution ID +#' +#' @return List with the get_query_execution response +#' @export +#' +#' @examples +#' `res <- dbtools::wait_query(query_id)` +wait_query <- function(query_id) { + dbtools.env$pydb$wait_query(query_id) +} + +#' Calls start_query_execution followed by wait_query. +#' +#' @param sql An SQL string. Which works with __TEMP__ references. +#' +#' @return List with the get_query_execution response. +#' @export +#' +#' @examples +#' `res <- dbtools::start_query_execution_and_wait('select * from __temp__.my_table')` +start_query_execution_and_wait <- function(sql) { + dbtools.env$pydb$start_query_execution_and_wait(sql) +} + +#' Deletes partitions and the underlying data on S3 from an Athena +#' database table matching an expression. +#' +#' @param database The database name. +#' @param table The table name. +#' @param expression The expression to match. +#' +#' @see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_partitions +#' @export +#' +#' @examples +#' `dbtools::delete_partitions_and_data("my_database", "my_table", "year = 2020 and month = 5")` +delete_partitions_and_data <- function(database, table, expression) { + dbtools.env$pydb$delete_partitions_and_data(database, table, expression) +} + +#' Deletes both a table from an Athena database and the underlying data on S3. +#' +#' @param database The database name. +#' @param table The table name. +#' +#' @export +#' +#' @examples +#' `dbtools::delete_table_and_data("__temp__", "my_table")` +delete_table_and_data <- function(database, table) { + dbtools.env$pydb$delete_table_and_data(database, table) +} + +#' Deletes both an Athena database and the underlying data on S3. +#' +#' @param database Database name +#' +#' @export +delete_database_and_data <- function(database) { + dbtools.env$pydb$delete_database_and_data(database) +} + +#' Read in an SQL file and inject arguments with Jinja (if given params). +#' +#' @param filepath A filepath to your SQL file. +#' @param jinja_args If not NULL, will pass the read +#' in SQL file through a jinja template to render the template. +#' Otherwise will just return the SQL file as is. Defaults to NULL. +#' +#' @return +#' @export +#' +#' @examples +get_sql_from_file <- function(filepath, jinja_args=NULL) { + dbtools.env$pydb$get_sql_from_file(filepath, jinja_args) +} + +#' Takes an SQL query and injects arguments with Jinja. +#' +#' @param sql An SQL query +#' @param jinja_args Arguments that are referenced in the SQL file +#' +#' @export +render_sql_template <- function(sql, jinja_args) { + dbtools.env$pydb$render_sql_template(sql, jinja_args) +} diff --git a/R/zzz.R b/R/zzz.R index 8b88e50..49830e3 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,6 +1,7 @@ +dbtools.env <- new.env(parent=emptyenv()) .onLoad <- function(libname, pkgname) { - # Construct Python path and pass it to reticulate - base_path <- strsplit(Sys.getenv("PATH"), ":")[[1]][1] - python_path <- paste(base_path, "/python", sep = "") - reticulate::use_python(python_path) + # import Python packages on package load + boto3 <- reticulate::import('boto3') + assign('pydb', reticulate::import('pydbtools'), dbtools.env) + assign('athena_client', boto3$client('athena'), dbtools.env) } diff --git a/inst/extdata/boto_utils.py b/inst/extdata/boto_utils.py deleted file mode 100644 index 2527bbd..0000000 --- a/inst/extdata/boto_utils.py +++ /dev/null @@ -1,17 +0,0 @@ -import boto3 -from botocore.credentials import InstanceMetadataProvider, InstanceMetadataFetcher - -def delete_object(bucket, key): - rn = "eu-west-1" - provider = InstanceMetadataProvider( - iam_role_fetcher=InstanceMetadataFetcher(timeout=1000, num_attempts=2) - ) - creds = provider.load().get_frozen_credentials() - s3_client = boto3.client( - "s3", - region_name=rn, - aws_access_key_id=creds.access_key, - aws_secret_access_key=creds.secret_key, - aws_session_token=creds.token, - ) - s3_client.delete_object(Bucket=bucket, Key=key) diff --git a/man/convert_athena_type_to_arrow.Rd b/man/convert_athena_type_to_arrow.Rd new file mode 100644 index 0000000..2522848 --- /dev/null +++ b/man/convert_athena_type_to_arrow.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read.R +\name{convert_athena_type_to_arrow} +\alias{convert_athena_type_to_arrow} +\title{Convert an Athena type to an Arrow type} +\usage{ +convert_athena_type_to_arrow(t) +} +\arguments{ +\item{t}{A string giving an Athena type} +} +\value{ +An Arrow type +} +\description{ +Convert an Athena type to an Arrow type +} diff --git a/man/create_temp_table.Rd b/man/create_temp_table.Rd new file mode 100644 index 0000000..5b3cb78 --- /dev/null +++ b/man/create_temp_table.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{create_temp_table} +\alias{create_temp_table} +\title{Create a temporary table} +\usage{ +create_temp_table(sql, table_name, region_name) +} +\arguments{ +\item{table_name}{The name of the temp table you wish to create} + +\item{region_name}{Name of the AWS region you want to run queries on. +Defaults to pydbtools.utils.aws_default_region (which if left unset is +"eu-west-1").} + +\item{sql:}{The SQL table you want to create a temp table out of. Should +be a table that starts with a WITH or SELECT clause.} +} +\description{ +Create a temporary table +} +\examples{ +`dbtools::create_temp_table("SELECT a_col, count(*) as n FROM a_database.table GROUP BY a_col", table_name="temp_table_1")` +} diff --git a/man/delete_database_and_data.Rd b/man/delete_database_and_data.Rd new file mode 100644 index 0000000..447fa89 --- /dev/null +++ b/man/delete_database_and_data.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{delete_database_and_data} +\alias{delete_database_and_data} +\title{Deletes both an Athena database and the underlying data on S3.} +\usage{ +delete_database_and_data(database) +} +\arguments{ +\item{database}{Database name} +} +\description{ +Deletes both an Athena database and the underlying data on S3. +} diff --git a/man/delete_object.Rd b/man/delete_object.Rd deleted file mode 100644 index d35c13e..0000000 --- a/man/delete_object.Rd +++ /dev/null @@ -1,25 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils.R -\name{delete_object} -\alias{delete_object} -\title{delete_object} -\usage{ -delete_object(bucket, key) -} -\arguments{ -\item{bucket}{A string specifying the s3 bucket name} - -\item{key}{File path to the s3 object} -} -\description{ -uses boto3 (in python) to delete an S3 object (used by read_sql function to clean up after itself) -} -\details{ -Will send an SQL query to athena and wait for it to complete. Once the query has completed the resulting sql query will be read using read.csv (base R), read_csv (readr) or fread (data.table). -Function returns dataframe. If needing more a more bespoke or self defined data reading function and arguments use dbtools::get_athena_query_response to send an SQL query and return the s3 path to data in csv format. -} -\examples{ -# delete a file from S3 -# (note this is not exported so have to use tripple colon) -dbtools:::delete_object('my_bucket', 'path/to/file.csv') -} diff --git a/man/delete_partitions_and_data.Rd b/man/delete_partitions_and_data.Rd new file mode 100644 index 0000000..e7109e5 --- /dev/null +++ b/man/delete_partitions_and_data.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{delete_partitions_and_data} +\alias{delete_partitions_and_data} +\title{Deletes partitions and the underlying data on S3 from an Athena +database table matching an expression.} +\usage{ +delete_partitions_and_data(database, table, expression) +} +\arguments{ +\item{database}{The database name.} + +\item{table}{The table name.} + +\item{expression}{The expression to match.} +} +\description{ +Deletes partitions and the underlying data on S3 from an Athena +database table matching an expression. +} +\examples{ +`dbtools::delete_partitions_and_data("my_database", "my_table", "year = 2020 and month = 5")` +} diff --git a/man/delete_table_and_data.Rd b/man/delete_table_and_data.Rd new file mode 100644 index 0000000..4e82a67 --- /dev/null +++ b/man/delete_table_and_data.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{delete_table_and_data} +\alias{delete_table_and_data} +\title{Deletes both a table from an Athena database and the underlying data on S3.} +\usage{ +delete_table_and_data(database, table) +} +\arguments{ +\item{database}{The database name.} + +\item{table}{The table name.} +} +\description{ +Deletes both a table from an Athena database and the underlying data on S3. +} +\examples{ +`dbtools::delete_table_and_data("__temp__", "my_table")` +} diff --git a/man/describe_table.Rd b/man/describe_table.Rd new file mode 100644 index 0000000..9bbd20f --- /dev/null +++ b/man/describe_table.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{describe_table} +\alias{describe_table} +\title{Show the list of columns, including partition columns: 'DESCRIBE table;'.} +\usage{ +describe_table(table, database) +} +\arguments{ +\item{table}{Table name} + +\item{database}{AWS Glue/Athena database name} +} +\value{ +DataFrame filled by formatted infos. +} +\description{ +Show the list of columns, including partition columns: 'DESCRIBE table;'. +} +\examples{ +`df_table = dbtools::describe_table(table='my_table', database='my_db')` +} diff --git a/man/get_athena_query_response.Rd b/man/get_athena_query_response.Rd deleted file mode 100644 index 436fb77..0000000 --- a/man/get_athena_query_response.Rd +++ /dev/null @@ -1,39 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/get_athena_query_response.R -\name{get_athena_query_response} -\alias{get_athena_query_response} -\title{get_athena_query_response} -\usage{ -get_athena_query_response(sql_query, return_athena_types = FALSE, - timeout = NULL) -} -\arguments{ -\item{sql_query}{A string specifying the SQL query you want to send to athena. See packages github readme for info on the flavour of SQL Athena uses.} - -\item{return_athena_types}{Specifies if the list describing the data's meta data types should be defined using athena datatypes (TRUE) or using the data engineering team's generic metadata types (FALSE). If not specified the default value of this input parameter is set to FALSE.} - -\item{timeout}{Specifies How long you want your sql query to wait before it gives up (in seconds). Default parameter is NULL which will mean SQL query will not timeout and could wait forever if an issue occured.} -} -\value{ -A list with two keys. [1] s3_path : a string pointing to the s3 path of the athena query. [2] meta : a list that has the name and type of each column in of the data in the s3_path. Can be used to get correct data types of your output when read in to R (note the order of the columns matches the order they appear in the data). -} -\description{ -uses boto3 (in python) to send an sql query to athena and return the resulting data's path in s3 and meta data -} -\details{ -Will send an SQL query to athena and wait for it to complete. Once the query has completed the funtion will return a list containing the s3 path to your athena query and meta data about the output data -} -\examples{ -# Read an sql query using readr::read_csv -response <- dbtools::get_athena_query_response("SELECT * from crest_v1.flatfile limit 10000") - -# print out path to athena query output (as a csv) -print(response$s3_path) - -# print out meta data -print(response$meta) - -# Read in data using whatever csv reader you want -s3_path_stripped = gsub("s3://", "", response$s3_path) -df <- s3tools::read_using(FUN = read.csv, s3_path=s3_path_stripped) -} diff --git a/man/get_query_columns_types.Rd b/man/get_query_columns_types.Rd new file mode 100644 index 0000000..6e3697e --- /dev/null +++ b/man/get_query_columns_types.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{get_query_columns_types} +\alias{get_query_columns_types} +\title{Get the data type of all columns queried.} +\usage{ +get_query_columns_types(query_id) +} +\arguments{ +\item{query_id}{Athena query execution ID} +} +\value{ +List with all data types +} +\description{ +Get the data type of all columns queried. +} +\examples{ +`dbtools::get_query_columns_types('query-execution-id')` +} diff --git a/man/get_query_execution.Rd b/man/get_query_execution.Rd new file mode 100644 index 0000000..7a3f112 --- /dev/null +++ b/man/get_query_execution.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{get_query_execution} +\alias{get_query_execution} +\title{Fetch query execution details.} +\usage{ +get_query_execution(query_id) +} +\arguments{ +\item{query_id}{Athena query execution ID} +} +\value{ +List with the get_query_execution response. +} +\description{ +Fetch query execution details. +} +\examples{ +`res <- dbtools::get_query_execution(query_id='query-execution-id')` +} diff --git a/man/get_sql_from_file.Rd b/man/get_sql_from_file.Rd new file mode 100644 index 0000000..9836ee1 --- /dev/null +++ b/man/get_sql_from_file.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{get_sql_from_file} +\alias{get_sql_from_file} +\title{Read in an SQL file and inject arguments with Jinja (if given params).} +\usage{ +get_sql_from_file(filepath, jinja_args = NULL) +} +\arguments{ +\item{filepath}{A filepath to your SQL file.} + +\item{jinja_args}{If not NULL, will pass the read +in SQL file through a jinja template to render the template. +Otherwise will just return the SQL file as is. Defaults to NULL.} +} +\value{ + +} +\description{ +Read in an SQL file and inject arguments with Jinja (if given params). +} diff --git a/man/pipe.Rd b/man/pipe.Rd new file mode 100644 index 0000000..1f8f237 --- /dev/null +++ b/man/pipe.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-pipe.R +\name{\%>\%} +\alias{\%>\%} +\title{Pipe operator} +\usage{ +lhs \%>\% rhs +} +\arguments{ +\item{lhs}{A value or the magrittr placeholder.} + +\item{rhs}{A function call using the magrittr semantics.} +} +\value{ +The result of calling `rhs(lhs)`. +} +\description{ +See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. +} +\keyword{internal} diff --git a/man/read_sql.Rd b/man/read_sql.Rd deleted file mode 100644 index 73d8feb..0000000 --- a/man/read_sql.Rd +++ /dev/null @@ -1,31 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/read_sql.R -\name{read_sql} -\alias{read_sql} -\title{read_sql} -\usage{ -read_sql(sql_query, return_df_as = "tibble", timeout = NULL) -} -\arguments{ -\item{sql_query}{A string specifying the SQL query you want to send to athena. See packages github readme for info on the flavour of SQL Athena uses.} - -\item{return_df_as}{String specifying what the table should be returned as i.e. 'dataframe' (reads data using read.csv), 'tibble' (reads data using readr::read_csv) or 'data.table' (reads data using data.table::fread). Default is 'tibble'. Not all tables returned are a DataFrame class. -Only return_df_as set to 'tibble' maintains date and datetime formats. dataframe and data.table will convert date and datetimes to characters.} - -\item{timeout}{Specifies How long you want your sql query to wait before it gives up (in seconds). Default parameter is NULL which will mean SQL query will not timeout and could wait forever if an issue occured.} -} -\value{ -A table as a Dataframe, tibble or data.table -} -\description{ -uses boto3 (in python) to send an sql query to athena and return an R dataframe, tibble or data.table based on user preference. -} -\details{ -Will send an SQL query to athena and wait for it to complete. Once the query has completed the resulting sql query will be read using read.csv (base R), read_csv (readr) or fread (data.table). -Function returns dataframe. If needing more a more bespoke or self defined data reading function and arguments use dbtools::get_athena_query_response to send an SQL query and return the s3 path to data in csv format. -} -\examples{ -# Read an sql query using readr::read_csv i.e. returning a Tibble -df <- dbtools::read_sql("SELECT * from crest_v1.flatfile limit 10000") -df -} diff --git a/man/read_sql_query.Rd b/man/read_sql_query.Rd new file mode 100644 index 0000000..9438ac8 --- /dev/null +++ b/man/read_sql_query.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read.R +\name{read_sql_query} +\alias{read_sql_query} +\title{Send an SQL query to Athena and receive a data frame.} +\usage{ +read_sql_query(sql) +} +\arguments{ +\item{sql}{An SQL query} +} +\value{ +Dataframe +} +\description{ +Send an SQL query to Athena and receive a data frame. +} diff --git a/man/render_sql_template.Rd b/man/render_sql_template.Rd new file mode 100644 index 0000000..4983c84 --- /dev/null +++ b/man/render_sql_template.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{render_sql_template} +\alias{render_sql_template} +\title{Takes an SQL query and injects arguments with Jinja.} +\usage{ +render_sql_template(sql, jinja_args) +} +\arguments{ +\item{sql}{An SQL query} + +\item{jinja_args}{Arguments that are referenced in the SQL file} +} +\description{ +Takes an SQL query and injects arguments with Jinja. +} diff --git a/man/repair_table.Rd b/man/repair_table.Rd new file mode 100644 index 0000000..6df1f42 --- /dev/null +++ b/man/repair_table.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{repair_table} +\alias{repair_table} +\title{Run the Hive's metastore consistency check: 'MSCK REPAIR TABLE table;'.} +\usage{ +repair_table(table, database) +} +\arguments{ +\item{table}{Table name} + +\item{database}{AWS Glue/Athena database name} +} +\value{ +Query final state ('SUCCEEDED', 'FAILED', 'CANCELLED') +} +\description{ +Recovers partitions and data associated with partitions. +Use this statement when you add partitions to the catalog. +It is possible it will take some time to add all partitions. +If this operation times out, it will be in an incomplete state +where only a few partitions are added to the catalog. +} +\examples{ +`query_final_state = dbtools::repair_table(table='...', database='...')` +} diff --git a/man/show_create_table.Rd b/man/show_create_table.Rd new file mode 100644 index 0000000..e98640f --- /dev/null +++ b/man/show_create_table.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{show_create_table} +\alias{show_create_table} +\title{Generate the query that created a table: 'SHOW CREATE TABLE table;'.} +\usage{ +show_create_table(table, database) +} +\arguments{ +\item{table}{Table name} + +\item{database}{AWS Glue/Athena database name} +} +\value{ +The query that created the table +} +\description{ +Generate the query that created a table: 'SHOW CREATE TABLE table;'. +} +\examples{ +`df_table = dbtools::show_create_table(table='my_table', database='my_db')` +} diff --git a/man/start_query_execution.Rd b/man/start_query_execution.Rd new file mode 100644 index 0000000..eebda6c --- /dev/null +++ b/man/start_query_execution.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{start_query_execution} +\alias{start_query_execution} +\title{Start a SQL Query against AWS Athena} +\usage{ +start_query_execution(sql, wait = FALSE) +} +\arguments{ +\item{sql}{SQL query} + +\item{wait}{Default FALSE, indicates whether to wait for the query to finish and return a dictionary with the query execution response.} +} +\value{ +Query execution ID if `wait` is set to `False`, list with the get_query_execution response otherwise. +} +\description{ +Start a SQL Query against AWS Athena +} diff --git a/man/start_query_execution_and_wait.Rd b/man/start_query_execution_and_wait.Rd new file mode 100644 index 0000000..a5e2924 --- /dev/null +++ b/man/start_query_execution_and_wait.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{start_query_execution_and_wait} +\alias{start_query_execution_and_wait} +\title{Calls start_query_execution followed by wait_query.} +\usage{ +start_query_execution_and_wait(sql) +} +\arguments{ +\item{sql}{An SQL string. Which works with __TEMP__ references.} +} +\value{ +List with the get_query_execution response. +} +\description{ +Calls start_query_execution followed by wait_query. +} +\examples{ +`res <- dbtools::start_query_execution_and_wait('select * from __temp__.my_table')` +} diff --git a/man/stop_query_execution.Rd b/man/stop_query_execution.Rd new file mode 100644 index 0000000..da0af78 --- /dev/null +++ b/man/stop_query_execution.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{stop_query_execution} +\alias{stop_query_execution} +\title{Stop a query execution} +\usage{ +stop_query_execution(query_id) +} +\arguments{ +\item{query_id}{Athena query execution ID} +} +\description{ +Stop a query execution +} diff --git a/man/wait_query.Rd b/man/wait_query.Rd new file mode 100644 index 0000000..3c427a8 --- /dev/null +++ b/man/wait_query.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wrap.R +\name{wait_query} +\alias{wait_query} +\title{Wait for a query to end.} +\usage{ +wait_query(query_id) +} +\arguments{ +\item{query_id}{Athena query execution ID} +} +\value{ +List with the get_query_execution response +} +\description{ +Wait for a query to end. +} +\examples{ +`res <- dbtools::wait_query(query_id)` +} diff --git a/renv.lock b/renv.lock new file mode 100644 index 0000000..a37a940 --- /dev/null +++ b/renv.lock @@ -0,0 +1,354 @@ +{ + "R": { + "Version": "4.1.2", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://packagemanager.rstudio.com/cran/2021-05-17" + } + ] + }, + "Python": { + "Version": "3.8.10", + "Type": "virtualenv", + "Name": null + }, + "Packages": { + "Matrix": { + "Package": "Matrix", + "Version": "1.3-4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4ed05e9c9726267e4a5872e09c04587c" + }, + "R6": { + "Package": "R6", + "Version": "2.5.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "b203113193e70978a696b2809525649d" + }, + "Rcpp": { + "Package": "Rcpp", + "Version": "1.0.7", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "dab19adae4440ae55aa8a9d238b246bb" + }, + "arrow": { + "Package": "arrow", + "Version": "4.0.0.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "366f5c066a920a1dc8d52d8bac1f33f7" + }, + "assertthat": { + "Package": "assertthat", + "Version": "0.2.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "50c838a310445e954bc13f26f26a6ecf" + }, + "bit": { + "Package": "bit", + "Version": "4.0.4", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "f36715f14d94678eea9933af927bc15d" + }, + "bit64": { + "Package": "bit64", + "Version": "4.0.5", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "9fe98599ca456d6552421db0d6772d8f" + }, + "brio": { + "Package": "brio", + "Version": "1.1.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "2f01e16ff9571fe70381c7b9ae560dc4" + }, + "callr": { + "Package": "callr", + "Version": "3.7.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "461aa75a11ce2400245190ef5d3995df" + }, + "cli": { + "Package": "cli", + "Version": "2.5.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "a94ba44cee3ea571e813721e64184172" + }, + "cpp11": { + "Package": "cpp11", + "Version": "0.2.7", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "730eebcc741a5c36761f7d4d0f5e37b8" + }, + "crayon": { + "Package": "crayon", + "Version": "1.4.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "e75525c55c70e5f4f78c9960a4b402e9" + }, + "data.table": { + "Package": "data.table", + "Version": "1.14.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "d1b8b1a821ee564a3515fa6c6d5c52dc" + }, + "desc": { + "Package": "desc", + "Version": "1.3.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "b6963166f7f10b970af1006c462ce6cd" + }, + "diffobj": { + "Package": "diffobj", + "Version": "0.3.4", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "feb5b7455eba422a2c110bb89852e6a3" + }, + "digest": { + "Package": "digest", + "Version": "0.6.27", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "a0cbe758a531d054b537d16dff4d58a1" + }, + "ellipsis": { + "Package": "ellipsis", + "Version": "0.3.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "bb0eec2fe32e88d9e2836c2f73ea2077" + }, + "evaluate": { + "Package": "evaluate", + "Version": "0.14", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "ec8ca05cffcc70569eaaad8469d2a3a7" + }, + "fansi": { + "Package": "fansi", + "Version": "0.4.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "fea074fb67fe4c25d47ad09087da847d" + }, + "glue": { + "Package": "glue", + "Version": "1.4.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "6efd734b14c6471cfe443345f3e35e29" + }, + "jsonlite": { + "Package": "jsonlite", + "Version": "1.7.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "98138e0994d41508c7a6b84a0600cfcb" + }, + "lattice": { + "Package": "lattice", + "Version": "0.20-45", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "b64cdbb2b340437c4ee047a1f4c4377b" + }, + "lifecycle": { + "Package": "lifecycle", + "Version": "1.0.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "3471fb65971f1a7b2d4ae7848cf2db8d" + }, + "magrittr": { + "Package": "magrittr", + "Version": "2.0.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "41287f1ac7d28a92f0a286ed507928d3" + }, + "pillar": { + "Package": "pillar", + "Version": "1.6.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "8672ae02bd20f6479bce2d06c7ff1401" + }, + "pkgconfig": { + "Package": "pkgconfig", + "Version": "2.0.3", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "01f28d4278f15c76cddbea05899c5d6f" + }, + "pkgload": { + "Package": "pkgload", + "Version": "1.2.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "463642747f81879e6752485aefb831cf" + }, + "png": { + "Package": "png", + "Version": "0.1-7", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "03b7076c234cb3331288919983326c55" + }, + "praise": { + "Package": "praise", + "Version": "1.0.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "a555924add98c99d2f411e37e7d25e9f" + }, + "processx": { + "Package": "processx", + "Version": "3.5.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "0cbca2bc4d16525d009c4dbba156b37c" + }, + "ps": { + "Package": "ps", + "Version": "1.6.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "32620e2001c1dce1af49c49dccbb9420" + }, + "purrr": { + "Package": "purrr", + "Version": "0.3.4", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "97def703420c8ab10d8f0e6c72101e02" + }, + "rappdirs": { + "Package": "rappdirs", + "Version": "0.3.3", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "5e3c5dc0b071b21fa128676560dbe94d" + }, + "rematch2": { + "Package": "rematch2", + "Version": "2.1.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "76c9e04c712a05848ae7a23d2f170a40" + }, + "renv": { + "Package": "renv", + "Version": "0.13.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "079cb1f03ff972b30401ed05623cbe92" + }, + "reticulate": { + "Package": "reticulate", + "Version": "1.20", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "30ab0ea8c8d3dd16a3fa06903449bbfb" + }, + "rlang": { + "Package": "rlang", + "Version": "0.4.11", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "515f341d3affe0de9e4a7f762efb0456" + }, + "rprojroot": { + "Package": "rprojroot", + "Version": "2.0.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "249d8cd1e74a8f6a26194a91b47f21d1" + }, + "rstudioapi": { + "Package": "rstudioapi", + "Version": "0.13", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "06c85365a03fdaf699966cc1d3cf53ea" + }, + "stringi": { + "Package": "stringi", + "Version": "1.6.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "3b9a9c9454b864b08713715396689b9e" + }, + "stringr": { + "Package": "stringr", + "Version": "1.4.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "0759e6b6c0957edb1311028a49a35e76" + }, + "testthat": { + "Package": "testthat", + "Version": "3.0.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "495e0434d9305716b6a87031570ce109" + }, + "tibble": { + "Package": "tibble", + "Version": "3.1.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "349b40a9f144516d537c875e786ec8b8" + }, + "tidyselect": { + "Package": "tidyselect", + "Version": "1.1.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "7243004a708d06d4716717fa1ff5b2fe" + }, + "utf8": { + "Package": "utf8", + "Version": "1.2.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "c3ad47dc6da0751f18ed53c4613e3ac7" + }, + "vctrs": { + "Package": "vctrs", + "Version": "0.3.8", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "ecf749a1b39ea72bd9b51b76292261f1" + }, + "waldo": { + "Package": "waldo", + "Version": "0.2.5", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "20c45f1d511a3f730b7b469f4d11e104" + }, + "withr": { + "Package": "withr", + "Version": "2.4.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "ad03909b44677f930fa156d47d7a3aeb" + } + } +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..dbe1b97 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,40 @@ +asn1crypto==1.4.0 +awswrangler==2.13.0 +beautifulsoup4==4.10.0 +boto3==1.20.39 +botocore==1.23.39 +certifi==2021.10.8 +charset-normalizer==2.0.10 +decorator==5.1.1 +et-xmlfile==1.1.0 +idna==3.3 +Jinja2==3.0.3 +jmespath==0.10.0 +jsonpath-ng==1.5.3 +lxml==4.7.1 +MarkupSafe==2.0.1 +numpy==1.22.1 +openpyxl==3.0.9 +opensearch-py==1.0.0 +packaging==21.3 +pandas==1.2.5 +pg8000==1.22.1 +ply==3.11 +progressbar2==3.55.0 +pyarrow==6.0.1 +pydbtools==5.0.0 +PyMySQL==1.0.2 +pyparsing==3.0.6 +python-dateutil==2.8.2 +python-utils==3.1.0 +pytz==2021.3 +redshift-connector==2.0.903 +requests==2.27.1 +requests-aws4auth==1.1.1 +s3transfer==0.5.0 +scramp==1.4.1 +six==1.16.0 +soupsieve==2.3.1 +sql-metadata==2.3.0 +sqlparse==0.4.2 +urllib3==1.26.8 From 4655260f45c0d57257495d81440b5240a2cd8f4e Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Thu, 3 Feb 2022 17:35:12 +0000 Subject: [PATCH 02/23] Corrected license --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 1eeca5e..b20a52f 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # MIT License -Copyright (c) 2022 dbtools authors +Copyright (c) 2022 Ministry of Justice Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 7b4270faf8053cf05eecf6de9a39ba498096c156 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Fri, 4 Feb 2022 08:47:46 +0000 Subject: [PATCH 03/23] Version and docs --- .gitignore | 1 + DESCRIPTION | 7 +++++-- README.md | 39 +++++++++++++++++++++++++++++++++++++++ vignettes/.gitignore | 2 ++ vignettes/dbtools.Rmd | 19 +++++++++++++++++++ 5 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 vignettes/.gitignore create mode 100644 vignettes/dbtools.Rmd diff --git a/.gitignore b/.gitignore index deabf39..23d9330 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ .Ruserdata renv .Rprofile +inst/doc diff --git a/DESCRIPTION b/DESCRIPTION index a501b3f..2d588be 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: dbtools Type: Package Title: Uses R wrapper function to send queries to athena. -Version: 2.0.3 +Version: 3.0.0 Author: Karik Isichei Maintainer: The package maintainer Description: See title. @@ -13,6 +13,9 @@ Imports: magrittr, reticulate Suggests: - data.table (>= 1.11.8) + knitr, + data.table (>= 1.11.8), + rmarkdown Remotes: moj-analytical-services/s3tools +VignetteBuilder: knitr diff --git a/README.md b/README.md index 6d114b1..0a4ce71 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,39 @@ # dbtools +Users who have yet to migrate to the newer version of the Analytical +Platform should refer to the [Legacy](#legacy) section below. + +## About + +A package that is used to run SQL queries configured for the +Analytical Platform. This packages is a [reticulated](https://rstudio.github.io/reticulate/) +wrapper around [pydbtools](https://github.com/moj-analytical-services/pydbtools) +which uses AWS Wrangler's Athena module but adds additional functionality +(like Jinja templating, creating temporary tables) and alters some configuration +to our specification. + +## Installation + +Run the following commands in the R console. + +```R +# Set up the project to use renv, if not already done +renv::init() +# Tell renv that Python will be used +renv::use_python() +# Install the reticulate library to interface with Python +renv::install("reticulate") +# Install the Python library pydbtools +reticulate::py_install("pydbtools") +# Install dbtools +renv::install("moj-analytical-services/dbtools") +``` + +# Legacy + +The information below applies to versions <3.0.0, and should be used by anyone +on the older version of the Analytical Platform i.e. anyone using R3.*. + This is a simple package that lets you query databases using Amazon Athena and get the s3 path to the athena output (as a csv). This is significantly faster than using database drivers provided by Amazon, so might be a good option when pulling in large data. Note: this package works alongside user IAM policies on the Analytical-Platform and requires you to be added to be given a standard database access. If in our github organisation you will be able to access the repo to request standard database access [here](https://github.com/moj-analytical-services/data-engineering-database-access). @@ -141,6 +175,11 @@ When you run a query in SQL against our databases you are using Athena. When Ath #### Changelog: +## 3.0.0 - 2022-02-03 + +- No longer dependent on s3tools +- Wraps `pydbtools` functions + ## 2.0.3 - 2020-04-29 - Fixes prompts to install miniconda - now automatically uses main Analytical Platform Conda Python, based on sys path diff --git a/vignettes/.gitignore b/vignettes/.gitignore new file mode 100644 index 0000000..097b241 --- /dev/null +++ b/vignettes/.gitignore @@ -0,0 +1,2 @@ +*.html +*.R diff --git a/vignettes/dbtools.Rmd b/vignettes/dbtools.Rmd new file mode 100644 index 0000000..3cc2e16 --- /dev/null +++ b/vignettes/dbtools.Rmd @@ -0,0 +1,19 @@ +--- +title: "dbtools" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{dbtools} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} +library(dbtools) +``` From 67b47c711cc60247a9e6c3de25077a1e3710b23d Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 9 Feb 2022 17:41:57 +0000 Subject: [PATCH 04/23] Rewrite because of reticulate problems and write vignette. --- .Rbuildignore | 2 + .gitignore | 2 + DESCRIPTION | 3 +- R/read.R | 72 ++++---- R/wrap.R | 9 +- R/zzz.R | 7 +- README.md | 54 ++++++ inst/python/read_sql_query_py.py | 22 +++ vignettes/dbtools.Rmd | 281 ++++++++++++++++++++++++++++++- 9 files changed, 412 insertions(+), 40 deletions(-) create mode 100644 inst/python/read_sql_query_py.py diff --git a/.Rbuildignore b/.Rbuildignore index 176897e..cbdc128 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -4,3 +4,5 @@ ^.*\.Rproj$ ^\.Rproj\.user$ ^LICENSE\.md$ +^doc$ +^Meta$ diff --git a/.gitignore b/.gitignore index 23d9330..16a22ab 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ renv .Rprofile inst/doc +/doc/ +/Meta/ diff --git a/DESCRIPTION b/DESCRIPTION index 2d588be..f20605d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -15,7 +15,8 @@ Imports: Suggests: knitr, data.table (>= 1.11.8), - rmarkdown + rmarkdown, + tibble Remotes: moj-analytical-services/s3tools VignetteBuilder: knitr diff --git a/R/read.R b/R/read.R index 8f4f241..be8e82f 100644 --- a/R/read.R +++ b/R/read.R @@ -40,7 +40,7 @@ convert_athena_type_to_arrow <- function(t) { } -#' Send an SQL query to Athena and receive a data frame. +#' Send an SQL query to Athena and receive a tibble. #' #' @param sql An SQL query #' @@ -50,34 +50,48 @@ convert_athena_type_to_arrow <- function(t) { #' @examples #' `df <- dbtools::read_sql_query('select * from my_db.my_table)` read_sql_query <- function(sql) { - query_id <- dbtools.env$pydb$start_query_execution(sql) - dbtools.env$pydb$wait_query(query_id) - athena_status <- dbtools.env$pydb$get_query_execution(query_id) - athena_client <- dbtools.env$boto3$client('athena') - response <- dbtools.env$athena_client$get_query_results( - QueryExecutionId=query_id - ) + # This approach doesn't work because for some reason pydbtools and boto3 + # stopped playing well together under reticulate, with boto3 throwing a + # permissions error which doesn't occur in pure Python. Leaving this code here + # in case it gets fixed as it would be much quicker. + # + # query_id <- dbtools.env$pydb$start_query_execution(sql) + # dbtools.env$pydb$wait_query(query_id) + # athena_status <- dbtools.env$pydb$get_query_execution(query_id) + # + # if (athena_status$Status$State == 'FAILED') { + # stop('SQL query failed with response error;\n', + # athena_status$Status$StateChangeReason) + # } + # + # response <- dbtools.env$boto3$client('athena')$get_query_results( + # QueryExecutionId=athena_status$QueryExecutionId + # ) + # + # # Create arrow schema as a list of arrow::Fields + # schema <- list() + # for (col_info in response$ResultSet$ResultSetMetadata$ColumnInfo) { + # schema <- append( + # schema, + # list(arrow::field(col_info$Name, + # convert_athena_type_to_arrow(col_info$Type))) + # ) + # } + # + # df <- arrow::read_csv_arrow( + # athena_status$ResultConfiguration$OutputLocation, + # schema=schema, + # convert_options=arrow::CsvConvertOptions$create(strings_can_be_null=TRUE) + # ) - if (athena_status$Status$State == 'FAILED') { - stop('SQL query failed with response error;\n', - athena_status$Status$StateChangeReason) - } - # Create arrow schema as a list of arrow::Fields - schema <- list() - for (col_info in response$ResultSet$ResultSetMetadata$ColumnInfo) { - schema <- append( - schema, - list(arrow::field(col_info$Name, - convert_athena_type_to_arrow(col_info$Type))) - ) - } - - df <- arrow::read_csv_arrow( - athena_status$ResultConfiguration$OutputLocation, - schema=schema, - convert_options=arrow::CsvConvertOptions$create(strings_can_be_null=TRUE) - ) + # Download the dataframe result to a parquet temporary file as pandas and + # reticulate are frequently incompatible, and load the data into R using + # arrow. + tmp_location <- tempfile(fileext=".parquet") + read_sql_query_py(sql, tmp_location) + df <- arrow::read_parquet(tmp_location) + unlink(tmp_location) return(df) } @@ -103,8 +117,8 @@ read_sql_query <- function(sql) { #' ``` read_sql <- function(sql_query, return_df_as="tibble") { df <- read_sql_query(sql_query) - if (return_df_as == "tibble") { - return(tibble::as_tibble(df)) + if (return_df_as == "dataframe") { + return(as.data.frame(df)) } else if (return_df_as == "data.table") { return(data.table::as.data.table(df)) } else { diff --git a/R/wrap.R b/R/wrap.R index 56f92e8..bd5b828 100644 --- a/R/wrap.R +++ b/R/wrap.R @@ -3,16 +3,13 @@ #' @param sql: The SQL table you want to create a temp table out of. Should #' be a table that starts with a WITH or SELECT clause. #' @param table_name The name of the temp table you wish to create -#' @param region_name Name of the AWS region you want to run queries on. -#' Defaults to pydbtools.utils.aws_default_region (which if left unset is -#' "eu-west-1"). #' #' @export #' #' @examples #' `dbtools::create_temp_table("SELECT a_col, count(*) as n FROM a_database.table GROUP BY a_col", table_name="temp_table_1")` -create_temp_table <- function(sql, table_name, region_name) { - dbtools.env$pydb$create_temp_table(sql, table_name, region_name=region_name) +create_temp_table <- function(sql, table_name) { + dbtools.env$pydb$create_temp_table(sql, table_name) } #' Show the list of columns, including partition columns: 'DESCRIBE table;'. @@ -162,7 +159,7 @@ delete_partitions_and_data <- function(database, table, expression) { #' @examples #' `dbtools::delete_table_and_data("__temp__", "my_table")` delete_table_and_data <- function(database, table) { - dbtools.env$pydb$delete_table_and_data(database, table) + dbtools.env$pydb$delete_table_and_data(table, database) } #' Deletes both an Athena database and the underlying data on S3. diff --git a/R/zzz.R b/R/zzz.R index 49830e3..909b7ee 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,7 +1,8 @@ +reticulate::source_python( + system.file("python", "read_sql_query_py.py", package = "dbtools")) + dbtools.env <- new.env(parent=emptyenv()) .onLoad <- function(libname, pkgname) { - # import Python packages on package load - boto3 <- reticulate::import('boto3') + # import Python package on package load assign('pydb', reticulate::import('pydbtools'), dbtools.env) - assign('athena_client', boto3$client('athena'), dbtools.env) } diff --git a/README.md b/README.md index 0a4ce71..5919df2 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,60 @@ reticulate::py_install("pydbtools") renv::install("moj-analytical-services/dbtools") ``` +## Quickstart guide + +### Read an SQL Athena query into an R dataframe + +```r +library(dbtools) + +df <- read_sql_query("SELECT * from a_database.table LIMIT 10") +``` + +### Run a query in Athena + +```r +response <- dbtools::start_query_execution_and_wait( + "CREATE DATABASE IF NOT EXISTS my_test_database" +) +``` + +### Create temporary tables to do further separate SQL queries on later + +```r +dbtools::create_temp_table( + "SELECT a_col, count(*) as n FROM a_database.table GROUP BY a_col", + table_name="temp_table_1" +) +df <- dbtools::read_sql_query("SELECT * FROM __temp__.temp_table_1 WHERE n < 10") +``` + +### Delete databases, tables and partitions together with the data on S3 + +```r +dbtools::delete_partitions_and_data( + database='my_database', + table='my_table', + expression='year = 2020 or year = 2021' +) +dbtools::delete_table_and_data(database='my_database', table='my_table') +dbtools::delete_database('my_database') + +# These can be used for temporary databases and tables. +dbtools::delete_table_and_data(database='__temp__', table='my_temp_table') +``` + +### Use Jinja templating to inject arguments into your SQL + +```r +sql_template <- "SELECT * FROM {{ db_name }}.{{ table }}" +sql <- dbtools::render_sql_template(sql_template, {"db_name": db_name, "table": "department"}) +df <- dbtools::read_sql_query(sql) + +cat("SELECT * FROM {{ db_name }}.{{ table_name }}", file="tempfile.sql") +sql <- pydb.get_sql_from_file("tempfile.sql", jinja_args={"db_name": db_name, "table_name": "department"}) +pydb.read_sql_query(sql) + # Legacy The information below applies to versions <3.0.0, and should be used by anyone diff --git a/inst/python/read_sql_query_py.py b/inst/python/read_sql_query_py.py new file mode 100644 index 0000000..8fafd6b --- /dev/null +++ b/inst/python/read_sql_query_py.py @@ -0,0 +1,22 @@ +import pydbtools as pydb +import tempfile + +def read_sql_query_py(sql: str, file_location: str) -> None: + """Downloads the data frame generated by an SQL query and saves it as a + parquet file in a given location. + This needs to be in a pure Python function to prevent reticulate calling a + pandas dataframe conversion, which often fails in one way or another. + + Arguments: + sql (str) -- An Athena SQL query + file_location (str) -- The file location where the query result will be + saved + + Returns: + None + """ + + df = pydb.read_sql_query(sql) + df.to_parquet(file_location) + + diff --git a/vignettes/dbtools.Rmd b/vignettes/dbtools.Rmd index 3cc2e16..4824bfa 100644 --- a/vignettes/dbtools.Rmd +++ b/vignettes/dbtools.Rmd @@ -1,5 +1,5 @@ --- -title: "dbtools" +title: "Introduction to dbtools" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{dbtools} @@ -12,8 +12,287 @@ knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) +devtools::load_all() ``` +```{python, include=FALSE} +import os +import pandas as pd +import awswrangler as wr +import pydbtools as pydb + +# setup your own testing area (set foldername = GH username) +foldername = "mratford" # GH username +foldername = foldername.lower().replace("-","_") + +bucketname = "alpha-everyone" +s3_base_path = f"s3://{bucketname}/{foldername}/" + +db_name = f"aws_example_dbtools" +source_db_base_path = f"s3://{bucketname}/{foldername}/source_db/" + +# Delete all the s3 files in a given path +if wr.s3.list_objects(s3_base_path): + print("deleting objs") + wr.s3.delete_objects(s3_base_path) + +# Delete the database if it exists +df_dbs = wr.catalog.databases(None) +if db_name in df_dbs["Database"].to_list(): + print(f"{db_name} found deleting") + wr.catalog.delete_database( + name=db_name + ) + +# Setup source database +# Create the database +wr.catalog.create_database(db_name) + +# Iterate through the tables in data/ and write them to our db using awswrangler +for table_name in ["department", "employees", "sales"]: + df = pd.read_csv(f"data/{table_name}.csv") + table_path = os.path.join(source_db_base_path, table_name) + wr.s3.to_parquet( + df=df, + path=table_path, + index=False, + dataset=True, # True allows the other params below i.e. overwriting to db.table + database=db_name, + table=table_name, + mode="overwrite", + ) +``` + +`dbtools` is a library used to query AWS Athena databases from R on the +Ministry of Justice's Analytical Platform. It uses the Python library +`pydbtools` and inherits much of its functionality, including creating +and querying temporary tables and injecting SQL queries +with template arguments. + ```{r setup} library(dbtools) ``` + +## Reading SQL queries + +The `read_sql_query` function is used to obtain R tibbles from SQL queries +sent to Athena. + +```{r} +read_sql_query("select * from aws_example_dbtools.employees limit 5") +``` + +If a standard data frame is preferred the `read_sql` function is provided + +```{r} +read_sql("select * from aws_example_dbtools.department limit 5", + return_df_as="dataframe") +``` + +or for a `data.table` + +```{r} +read_sql("select * from aws_example_dbtools.sales limit 5", + return_df_as="data.table") +``` + +## Creating temporary SQL tables + +The `create_temp_table` function allows you to create tables which can be +referred to in subsequent queries from the `__temp__` database. For example, +to create a table showing total sales per employee from the tables above create +a temporary total sales table. + +```{r} +sql <- " +SELECT employee_id, sum(sales) as total_sales +FROM aws_example_dbtools.sales +GROUP BY employee_id +" +create_temp_table(sql, table_name="total_sales") +``` + +Then create a table of employees from the sales department. + +```{r} +sql <- " +SELECT e.employee_id, e.forename, e.surname, d.department_name +FROM aws_example_dbtools.employees AS e +LEFT JOIN aws_example_dbtools.department AS d +ON e.department_id = d.department_id +WHERE e.department_id = 1 +" +create_temp_table(sql, table_name="sales_employees") +``` + +The two temporary tables can then be joined to provide the final table. + +```{r} +sql <- " +SELECT se.*, ts.total_sales +FROM __temp__.sales_employees AS se +INNER JOIN __temp__.total_sales AS ts +ON se.employee_id = ts.employee_id +" +read_sql_query(sql) +``` + +## SQL templating + +Sometimes you will want to run similar SQL queries which differ only by, +for example, table or column names. In these cases +SQL templates can be created to SQL queries populated by templated variables, +using Jinja templating. For example, + +```{r} +sql_template = "select * from {{ db_name }}.{{ table }} limit 10" +sql <- render_sql_template(sql_template, + list(db_name="aws_example_dbtools", + table="department")) +sql +``` + +The rendered SQL can then be used to query Athena as usual. + +```{r} +read_sql_query(sql) +``` + +The same template can be used to read a different table. + +```{r} +sql <- render_sql_template(sql_template, + list(db_name="aws_example_dbtools", + table="sales")) +read_sql_query(sql) +``` + +Perhaps more usefully we can use SQL templates saved as a file, which means we +can make use of our editors' and IDEs' SQL capabilities. + +```{r} +cat("SELECT * FROM {{ db_name }}.{{ table_name }}", file="tempfile.sql") + +sql <- get_sql_from_file("tempfile.sql", + jinja_args=list(db_name="aws_example_dbtools", + table_name="department")) +read_sql_query(sql) +``` + +## Advanced usage +### Creating and maintaining database tables in Athena + +In this section we will create a new database from our existing database in +Athena. Use the `start_query_execution_and_wait` function +to run the SQL creating the database. + +```{r} +sql <- " +CREATE DATABASE IF NOT EXISTS new_db_dbtools +COMMENT 'Example of running queries and insert into' +LOCATION 's3://alpha-everyone/dbtools/new_db/' +" + +response <- start_query_execution_and_wait(sql) +response$Status$State +``` + +Create a derived table in the new database with a CTAS query that both +generates the output into S3 and creates the schema of the table. Note that +this only inserts the data from quarters 1 and 2. + +```{r} +sql <- " +CREATE TABLE new_db_dbtools.sales_report WITH +( + external_location='s3://alpha-everyone/dbtools/new_db/sales_report' +) AS +SELECT qtr as sales_quarter, sum(sales) AS total_sales +FROM aws_example_dbtools.sales +WHERE qtr IN (1,2) +GROUP BY qtr +" + +response <- start_query_execution_and_wait(sql) +response$Status$State +``` + +We can now use an insert into query to add the data from quarters 3 and 4 as +the schema has already been created. + +```{r} +sql <- " +INSERT INTO new_db_dbtools.sales_report +SELECT qtr as sales_quarter, sum(sales) AS total_sales +FROM aws_example_dbtools.sales +WHERE qtr IN (3,4) +GROUP BY qtr +" + +response <- start_query_execution_and_wait(sql) +read_sql_query("select * from new_db_dbtools.sales_report") +``` + +### Creating a table with partitions + +Do the same as before but partition the data based on when the report was run. + +```{r} +sql <- " +CREATE TABLE new_db_dbtools.daily_sales_report WITH +( + external_location='s3://alpha-everyone/dbtools/new_db/daily_sales_report', + partitioned_by = ARRAY['report_date'] +) AS +SELECT qtr as sales_quarter, sum(sales) AS total_sales, +date '2021-01-01' AS report_date +FROM aws_example_dbtools.sales +GROUP BY qtr, date '2021-01-01' +" + +response <- start_query_execution_and_wait(sql) +response$Status$State +``` + +Then, simulating a source database that is updated daily, add more partitioned +data. + +```{r} +sql <- " +INSERT INTO new_db_dbtools.daily_sales_report +SELECT qtr as sales_quarter, sum(sales) AS total_sales, +date '2021-01-02' AS report_date +FROM aws_example_dbtools.sales +GROUP BY qtr, date '2021-01-02' +" + +response <- start_query_execution_and_wait(sql) +read_sql_query("select * from new_db_dbtools.daily_sales_report") +``` + +We can remove a partition and its underlying data using +`delete_partitions_and_data` which uses an expression to match partitions - +see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_partitions +for more details. + +```{r} +delete_partitions_and_data("new_db_dbtools", "daily_sales_report", + "report_date = '2021-01-02'") +read_sql_query("select * from new_db_dbtools.daily_sales_report") +``` + +Similarly we can remove a table and its data, + +```{r} +delete_table_and_data("new_db_dbtools", "daily_sales_report") +``` + +or the whole database. + +```{r} +delete_database_and_data("new_db_dbtools") +``` + +```{r, include=FALSE} +delete_database_and_data("aws_example_dbtools") +``` From 2f9464e6658348ff2611bce7b9ed324cc903f7b4 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 9 Feb 2022 17:43:17 +0000 Subject: [PATCH 05/23] Docs --- .gitignore | 2 - doc/dbtools.R | 151 ++++++++++++++++++ doc/dbtools.Rmd | 298 +++++++++++++++++++++++++++++++++++ doc/dbtools.html | 395 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 844 insertions(+), 2 deletions(-) create mode 100644 doc/dbtools.R create mode 100644 doc/dbtools.Rmd create mode 100644 doc/dbtools.html diff --git a/.gitignore b/.gitignore index 16a22ab..1f0272a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,4 @@ .Ruserdata renv .Rprofile -inst/doc -/doc/ /Meta/ diff --git a/doc/dbtools.R b/doc/dbtools.R new file mode 100644 index 0000000..12a45ed --- /dev/null +++ b/doc/dbtools.R @@ -0,0 +1,151 @@ +## ---- include = FALSE--------------------------------------------------------- +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +devtools::load_all() + +## ----setup-------------------------------------------------------------------- +library(dbtools) + +## ----------------------------------------------------------------------------- +read_sql_query("select * from aws_example_dbtools.employees limit 5") + +## ----------------------------------------------------------------------------- +read_sql("select * from aws_example_dbtools.department limit 5", + return_df_as="dataframe") + +## ----------------------------------------------------------------------------- +read_sql("select * from aws_example_dbtools.sales limit 5", + return_df_as="data.table") + +## ----------------------------------------------------------------------------- +sql <- " +SELECT employee_id, sum(sales) as total_sales +FROM aws_example_dbtools.sales +GROUP BY employee_id +" +create_temp_table(sql, table_name="total_sales") + +## ----------------------------------------------------------------------------- +sql <- " +SELECT e.employee_id, e.forename, e.surname, d.department_name +FROM aws_example_dbtools.employees AS e +LEFT JOIN aws_example_dbtools.department AS d +ON e.department_id = d.department_id +WHERE e.department_id = 1 +" +create_temp_table(sql, table_name="sales_employees") + +## ----------------------------------------------------------------------------- +sql <- " +SELECT se.*, ts.total_sales +FROM __temp__.sales_employees AS se +INNER JOIN __temp__.total_sales AS ts +ON se.employee_id = ts.employee_id +" +read_sql_query(sql) + +## ----------------------------------------------------------------------------- +sql_template = "select * from {{ db_name }}.{{ table }} limit 10" +sql <- render_sql_template(sql_template, + list(db_name="aws_example_dbtools", + table="department")) +sql + +## ----------------------------------------------------------------------------- +read_sql_query(sql) + +## ----------------------------------------------------------------------------- +sql <- render_sql_template(sql_template, + list(db_name="aws_example_dbtools", + table="sales")) +read_sql_query(sql) + +## ----------------------------------------------------------------------------- +cat("SELECT * FROM {{ db_name }}.{{ table_name }}", file="tempfile.sql") + +sql <- get_sql_from_file("tempfile.sql", + jinja_args=list(db_name="aws_example_dbtools", + table_name="department")) +read_sql_query(sql) + +## ----------------------------------------------------------------------------- +sql <- " +CREATE DATABASE IF NOT EXISTS new_db_dbtools +COMMENT 'Example of running queries and insert into' +LOCATION 's3://alpha-everyone/dbtools/new_db/' +" + +response <- start_query_execution_and_wait(sql) +response$Status$State + +## ----------------------------------------------------------------------------- +sql <- " +CREATE TABLE new_db_dbtools.sales_report WITH +( + external_location='s3://alpha-everyone/dbtools/new_db/sales_report' +) AS +SELECT qtr as sales_quarter, sum(sales) AS total_sales +FROM aws_example_dbtools.sales +WHERE qtr IN (1,2) +GROUP BY qtr +" + +response <- start_query_execution_and_wait(sql) +response$Status$State + +## ----------------------------------------------------------------------------- +sql <- " +INSERT INTO new_db_dbtools.sales_report +SELECT qtr as sales_quarter, sum(sales) AS total_sales +FROM aws_example_dbtools.sales +WHERE qtr IN (3,4) +GROUP BY qtr +" + +response <- start_query_execution_and_wait(sql) +read_sql_query("select * from new_db_dbtools.sales_report") + +## ----------------------------------------------------------------------------- +sql <- " +CREATE TABLE new_db_dbtools.daily_sales_report WITH +( + external_location='s3://alpha-everyone/dbtools/new_db/daily_sales_report', + partitioned_by = ARRAY['report_date'] +) AS +SELECT qtr as sales_quarter, sum(sales) AS total_sales, +date '2021-01-01' AS report_date +FROM aws_example_dbtools.sales +GROUP BY qtr, date '2021-01-01' +" + +response <- start_query_execution_and_wait(sql) +response$Status$State + +## ----------------------------------------------------------------------------- +sql <- " +INSERT INTO new_db_dbtools.daily_sales_report +SELECT qtr as sales_quarter, sum(sales) AS total_sales, +date '2021-01-02' AS report_date +FROM aws_example_dbtools.sales +GROUP BY qtr, date '2021-01-02' +" + +response <- start_query_execution_and_wait(sql) +read_sql_query("select * from new_db_dbtools.daily_sales_report") + +## ----------------------------------------------------------------------------- +delete_partitions_and_data("new_db_dbtools", "daily_sales_report", + "report_date = '2021-01-02'") +read_sql_query("select * from new_db_dbtools.daily_sales_report") + +## ----------------------------------------------------------------------------- +delete_table_and_data("new_db_dbtools", "daily_sales_report") + +## ----------------------------------------------------------------------------- +delete_database_and_data("new_db_dbtools") + +## ---- include=FALSE----------------------------------------------------------- +delete_database_and_data("aws_example_dbtools") + diff --git a/doc/dbtools.Rmd b/doc/dbtools.Rmd new file mode 100644 index 0000000..4824bfa --- /dev/null +++ b/doc/dbtools.Rmd @@ -0,0 +1,298 @@ +--- +title: "Introduction to dbtools" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{dbtools} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +devtools::load_all() +``` + +```{python, include=FALSE} +import os +import pandas as pd +import awswrangler as wr +import pydbtools as pydb + +# setup your own testing area (set foldername = GH username) +foldername = "mratford" # GH username +foldername = foldername.lower().replace("-","_") + +bucketname = "alpha-everyone" +s3_base_path = f"s3://{bucketname}/{foldername}/" + +db_name = f"aws_example_dbtools" +source_db_base_path = f"s3://{bucketname}/{foldername}/source_db/" + +# Delete all the s3 files in a given path +if wr.s3.list_objects(s3_base_path): + print("deleting objs") + wr.s3.delete_objects(s3_base_path) + +# Delete the database if it exists +df_dbs = wr.catalog.databases(None) +if db_name in df_dbs["Database"].to_list(): + print(f"{db_name} found deleting") + wr.catalog.delete_database( + name=db_name + ) + +# Setup source database +# Create the database +wr.catalog.create_database(db_name) + +# Iterate through the tables in data/ and write them to our db using awswrangler +for table_name in ["department", "employees", "sales"]: + df = pd.read_csv(f"data/{table_name}.csv") + table_path = os.path.join(source_db_base_path, table_name) + wr.s3.to_parquet( + df=df, + path=table_path, + index=False, + dataset=True, # True allows the other params below i.e. overwriting to db.table + database=db_name, + table=table_name, + mode="overwrite", + ) +``` + +`dbtools` is a library used to query AWS Athena databases from R on the +Ministry of Justice's Analytical Platform. It uses the Python library +`pydbtools` and inherits much of its functionality, including creating +and querying temporary tables and injecting SQL queries +with template arguments. + +```{r setup} +library(dbtools) +``` + +## Reading SQL queries + +The `read_sql_query` function is used to obtain R tibbles from SQL queries +sent to Athena. + +```{r} +read_sql_query("select * from aws_example_dbtools.employees limit 5") +``` + +If a standard data frame is preferred the `read_sql` function is provided + +```{r} +read_sql("select * from aws_example_dbtools.department limit 5", + return_df_as="dataframe") +``` + +or for a `data.table` + +```{r} +read_sql("select * from aws_example_dbtools.sales limit 5", + return_df_as="data.table") +``` + +## Creating temporary SQL tables + +The `create_temp_table` function allows you to create tables which can be +referred to in subsequent queries from the `__temp__` database. For example, +to create a table showing total sales per employee from the tables above create +a temporary total sales table. + +```{r} +sql <- " +SELECT employee_id, sum(sales) as total_sales +FROM aws_example_dbtools.sales +GROUP BY employee_id +" +create_temp_table(sql, table_name="total_sales") +``` + +Then create a table of employees from the sales department. + +```{r} +sql <- " +SELECT e.employee_id, e.forename, e.surname, d.department_name +FROM aws_example_dbtools.employees AS e +LEFT JOIN aws_example_dbtools.department AS d +ON e.department_id = d.department_id +WHERE e.department_id = 1 +" +create_temp_table(sql, table_name="sales_employees") +``` + +The two temporary tables can then be joined to provide the final table. + +```{r} +sql <- " +SELECT se.*, ts.total_sales +FROM __temp__.sales_employees AS se +INNER JOIN __temp__.total_sales AS ts +ON se.employee_id = ts.employee_id +" +read_sql_query(sql) +``` + +## SQL templating + +Sometimes you will want to run similar SQL queries which differ only by, +for example, table or column names. In these cases +SQL templates can be created to SQL queries populated by templated variables, +using Jinja templating. For example, + +```{r} +sql_template = "select * from {{ db_name }}.{{ table }} limit 10" +sql <- render_sql_template(sql_template, + list(db_name="aws_example_dbtools", + table="department")) +sql +``` + +The rendered SQL can then be used to query Athena as usual. + +```{r} +read_sql_query(sql) +``` + +The same template can be used to read a different table. + +```{r} +sql <- render_sql_template(sql_template, + list(db_name="aws_example_dbtools", + table="sales")) +read_sql_query(sql) +``` + +Perhaps more usefully we can use SQL templates saved as a file, which means we +can make use of our editors' and IDEs' SQL capabilities. + +```{r} +cat("SELECT * FROM {{ db_name }}.{{ table_name }}", file="tempfile.sql") + +sql <- get_sql_from_file("tempfile.sql", + jinja_args=list(db_name="aws_example_dbtools", + table_name="department")) +read_sql_query(sql) +``` + +## Advanced usage +### Creating and maintaining database tables in Athena + +In this section we will create a new database from our existing database in +Athena. Use the `start_query_execution_and_wait` function +to run the SQL creating the database. + +```{r} +sql <- " +CREATE DATABASE IF NOT EXISTS new_db_dbtools +COMMENT 'Example of running queries and insert into' +LOCATION 's3://alpha-everyone/dbtools/new_db/' +" + +response <- start_query_execution_and_wait(sql) +response$Status$State +``` + +Create a derived table in the new database with a CTAS query that both +generates the output into S3 and creates the schema of the table. Note that +this only inserts the data from quarters 1 and 2. + +```{r} +sql <- " +CREATE TABLE new_db_dbtools.sales_report WITH +( + external_location='s3://alpha-everyone/dbtools/new_db/sales_report' +) AS +SELECT qtr as sales_quarter, sum(sales) AS total_sales +FROM aws_example_dbtools.sales +WHERE qtr IN (1,2) +GROUP BY qtr +" + +response <- start_query_execution_and_wait(sql) +response$Status$State +``` + +We can now use an insert into query to add the data from quarters 3 and 4 as +the schema has already been created. + +```{r} +sql <- " +INSERT INTO new_db_dbtools.sales_report +SELECT qtr as sales_quarter, sum(sales) AS total_sales +FROM aws_example_dbtools.sales +WHERE qtr IN (3,4) +GROUP BY qtr +" + +response <- start_query_execution_and_wait(sql) +read_sql_query("select * from new_db_dbtools.sales_report") +``` + +### Creating a table with partitions + +Do the same as before but partition the data based on when the report was run. + +```{r} +sql <- " +CREATE TABLE new_db_dbtools.daily_sales_report WITH +( + external_location='s3://alpha-everyone/dbtools/new_db/daily_sales_report', + partitioned_by = ARRAY['report_date'] +) AS +SELECT qtr as sales_quarter, sum(sales) AS total_sales, +date '2021-01-01' AS report_date +FROM aws_example_dbtools.sales +GROUP BY qtr, date '2021-01-01' +" + +response <- start_query_execution_and_wait(sql) +response$Status$State +``` + +Then, simulating a source database that is updated daily, add more partitioned +data. + +```{r} +sql <- " +INSERT INTO new_db_dbtools.daily_sales_report +SELECT qtr as sales_quarter, sum(sales) AS total_sales, +date '2021-01-02' AS report_date +FROM aws_example_dbtools.sales +GROUP BY qtr, date '2021-01-02' +" + +response <- start_query_execution_and_wait(sql) +read_sql_query("select * from new_db_dbtools.daily_sales_report") +``` + +We can remove a partition and its underlying data using +`delete_partitions_and_data` which uses an expression to match partitions - +see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_partitions +for more details. + +```{r} +delete_partitions_and_data("new_db_dbtools", "daily_sales_report", + "report_date = '2021-01-02'") +read_sql_query("select * from new_db_dbtools.daily_sales_report") +``` + +Similarly we can remove a table and its data, + +```{r} +delete_table_and_data("new_db_dbtools", "daily_sales_report") +``` + +or the whole database. + +```{r} +delete_database_and_data("new_db_dbtools") +``` + +```{r, include=FALSE} +delete_database_and_data("aws_example_dbtools") +``` diff --git a/doc/dbtools.html b/doc/dbtools.html new file mode 100644 index 0000000..ebc3b00 --- /dev/null +++ b/doc/dbtools.html @@ -0,0 +1,395 @@ + + + + + + + + + + + + + + +Introduction to dbtools + + + + + + + + + + + + + + + + + + + + + + + + + +

Introduction to dbtools

+ + + +

dbtools is a library used to query AWS Athena databases from R on the Ministry of Justice’s Analytical Platform. It uses the Python library pydbtools and inherits much of its functionality, including creating and querying temporary tables and injecting SQL queries with template arguments.

+
library(dbtools)
+
+

Reading SQL queries

+

The read_sql_query function is used to obtain R tibbles from SQL queries sent to Athena.

+
read_sql_query("select * from aws_example_dbtools.employees limit 5")
+#> # A tibble: 5 x 6
+#>   employee_id sex   forename surname  department_id manager_id
+#>         <int> <chr> <chr>    <chr>            <dbl>      <dbl>
+#> 1           1 M     Dexter   Mitchell             1         17
+#> 2           2 F     Summer   Bennett              1         17
+#> 3           3 M     Pip      Carter               1         17
+#> 4           4 F     Bella    Long                 1         17
+#> 5           5 F     Lexie    Perry               NA         17
+

If a standard data frame is preferred the read_sql function is provided

+
read_sql("select * from aws_example_dbtools.department limit 5",
+         return_df_as="dataframe")
+#>   department_id department_name
+#> 1             1           Sales
+#> 2             2           Admin
+#> 3             3      Management
+#> 4             4       Technical
+#> 5             5     Maintenance
+

or for a data.table

+
read_sql("select * from aws_example_dbtools.sales limit 5",
+         return_df_as="data.table")
+#>    employee_id qtr  sales
+#> 1:           1   1 768.17
+#> 2:           2   1 391.98
+#> 3:           3   1 406.36
+#> 4:           4   1 816.25
+#> 5:           5   1 437.05
+
+
+

Creating temporary SQL tables

+

The create_temp_table function allows you to create tables which can be referred to in subsequent queries from the __temp__ database. For example, to create a table showing total sales per employee from the tables above create a temporary total sales table.

+
sql <- "
+SELECT employee_id, sum(sales) as total_sales
+FROM aws_example_dbtools.sales
+GROUP BY employee_id
+"
+create_temp_table(sql, table_name="total_sales")
+

Then create a table of employees from the sales department.

+
sql <- "
+SELECT e.employee_id, e.forename, e.surname, d.department_name
+FROM aws_example_dbtools.employees AS e
+LEFT JOIN aws_example_dbtools.department AS d
+ON e.department_id = d.department_id
+WHERE e.department_id = 1
+"
+create_temp_table(sql, table_name="sales_employees")
+

The two temporary tables can then be joined to provide the final table.

+
sql <- "
+SELECT se.*, ts.total_sales
+FROM __temp__.sales_employees AS se
+INNER JOIN __temp__.total_sales AS ts
+ON se.employee_id = ts.employee_id
+"
+read_sql_query(sql)
+#> # A tibble: 41 x 5
+#>    employee_id forename surname   department_name total_sales
+#>          <int> <chr>    <chr>     <chr>                 <dbl>
+#>  1           1 Dexter   Mitchell  Sales                 2912.
+#>  2           2 Summer   Bennett   Sales                 1786.
+#>  3           3 Pip      Carter    Sales                 2591.
+#>  4           4 Bella    Long      Sales                 2997.
+#>  5           6 Robert   Roberts   Sales                 2208.
+#>  6           7 Iris     Alexander Sales                 2465.
+#>  7           9 Evan     Carter    Sales                 2280.
+#>  8          10 Lauren   Powell    Sales                 1936.
+#>  9          11 Alice    James     Sales                 3093.
+#> 10          12 Owen     Scott     Sales                 2286.
+#> # … with 31 more rows
+
+
+

SQL templating

+

Sometimes you will want to run similar SQL queries which differ only by, for example, table or column names. In these cases SQL templates can be created to SQL queries populated by templated variables, using Jinja templating. For example,

+
sql_template = "select * from {{ db_name }}.{{ table }} limit 10"
+sql <- render_sql_template(sql_template, 
+                           list(db_name="aws_example_dbtools",
+                                table="department"))
+sql
+#> [1] "select * from aws_example_dbtools.department limit 10"
+

The rendered SQL can then be used to query Athena as usual.

+
read_sql_query(sql)
+#> # A tibble: 6 x 2
+#>   department_id department_name
+#>           <int> <chr>          
+#> 1             1 Sales          
+#> 2             2 Admin          
+#> 3             3 Management     
+#> 4             4 Technical      
+#> 5             5 Maintenance    
+#> 6             6 HR
+

The same template can be used to read a different table.

+
sql <- render_sql_template(sql_template, 
+                           list(db_name="aws_example_dbtools",
+                                table="sales"))
+read_sql_query(sql)
+#> # A tibble: 10 x 3
+#>    employee_id   qtr sales
+#>          <int> <int> <dbl>
+#>  1           1     1  768.
+#>  2           2     1  392.
+#>  3           3     1  406.
+#>  4           4     1  816.
+#>  5           5     1  437.
+#>  6           6     1  385.
+#>  7           7     1  821.
+#>  8           8     1  398.
+#>  9           9     1  899.
+#> 10          10     1  439.
+

Perhaps more usefully we can use SQL templates saved as a file, which means we can make use of our editors’ and IDEs’ SQL capabilities.

+
cat("SELECT * FROM {{ db_name }}.{{ table_name }}", file="tempfile.sql")
+
+sql <- get_sql_from_file("tempfile.sql",
+                         jinja_args=list(db_name="aws_example_dbtools",
+                                         table_name="department"))
+read_sql_query(sql)
+#> # A tibble: 6 x 2
+#>   department_id department_name
+#>           <int> <chr>          
+#> 1             1 Sales          
+#> 2             2 Admin          
+#> 3             3 Management     
+#> 4             4 Technical      
+#> 5             5 Maintenance    
+#> 6             6 HR
+
+
+

Advanced usage

+
+

Creating and maintaining database tables in Athena

+

In this section we will create a new database from our existing database in Athena. Use the start_query_execution_and_wait function to run the SQL creating the database.

+
sql <- "
+CREATE DATABASE IF NOT EXISTS new_db_dbtools
+COMMENT 'Example of running queries and insert into'
+LOCATION 's3://alpha-everyone/dbtools/new_db/'
+"
+
+response <- start_query_execution_and_wait(sql)
+response$Status$State
+#> [1] "SUCCEEDED"
+

Create a derived table in the new database with a CTAS query that both generates the output into S3 and creates the schema of the table. Note that this only inserts the data from quarters 1 and 2.

+
sql <- "
+CREATE TABLE new_db_dbtools.sales_report WITH
+(
+    external_location='s3://alpha-everyone/dbtools/new_db/sales_report'
+) AS
+SELECT qtr as sales_quarter, sum(sales) AS total_sales
+FROM aws_example_dbtools.sales
+WHERE qtr IN (1,2)
+GROUP BY qtr
+"
+
+response <- start_query_execution_and_wait(sql)
+response$Status$State
+#> [1] "SUCCEEDED"
+

We can now use an insert into query to add the data from quarters 3 and 4 as the schema has already been created.

+
sql <- "
+INSERT INTO new_db_dbtools.sales_report
+SELECT qtr as sales_quarter, sum(sales) AS total_sales
+FROM aws_example_dbtools.sales
+WHERE qtr IN (3,4)
+GROUP BY qtr
+"
+
+response <- start_query_execution_and_wait(sql)
+read_sql_query("select * from new_db_dbtools.sales_report") 
+#> # A tibble: 4 x 2
+#>   sales_quarter total_sales
+#>           <int>       <dbl>
+#> 1             1      28168.
+#> 2             2      30697.
+#> 3             4      27559.
+#> 4             3      26419.
+
+
+

Creating a table with partitions

+

Do the same as before but partition the data based on when the report was run.

+
sql <- "
+CREATE TABLE new_db_dbtools.daily_sales_report WITH
+(
+    external_location='s3://alpha-everyone/dbtools/new_db/daily_sales_report',
+    partitioned_by = ARRAY['report_date']
+) AS
+SELECT qtr as sales_quarter, sum(sales) AS total_sales,
+date '2021-01-01' AS report_date
+FROM aws_example_dbtools.sales
+GROUP BY qtr, date '2021-01-01'
+"
+
+response <- start_query_execution_and_wait(sql)
+response$Status$State
+#> [1] "SUCCEEDED"
+

Then, simulating a source database that is updated daily, add more partitioned data.

+
sql <- "
+INSERT INTO new_db_dbtools.daily_sales_report
+SELECT qtr as sales_quarter, sum(sales) AS total_sales,
+date '2021-01-02' AS report_date
+FROM aws_example_dbtools.sales
+GROUP BY qtr, date '2021-01-02'
+"
+
+response <- start_query_execution_and_wait(sql)
+read_sql_query("select * from new_db_dbtools.daily_sales_report")
+#> # A tibble: 8 x 3
+#>   sales_quarter total_sales report_date
+#>           <int>       <dbl> <date>     
+#> 1             4      27559. 2021-01-01 
+#> 2             2      30697. 2021-01-01 
+#> 3             3      26419. 2021-01-01 
+#> 4             1      28168. 2021-01-01 
+#> 5             2      30697. 2021-01-02 
+#> 6             3      26419. 2021-01-02 
+#> 7             1      28168. 2021-01-02 
+#> 8             4      27559. 2021-01-02
+

We can remove a partition and its underlying data using delete_partitions_and_data which uses an expression to match partitions - see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_partitions for more details.

+
delete_partitions_and_data("new_db_dbtools", "daily_sales_report",
+                           "report_date = '2021-01-02'")
+read_sql_query("select * from new_db_dbtools.daily_sales_report")
+#> # A tibble: 4 x 3
+#>   sales_quarter total_sales report_date
+#>           <int>       <dbl> <date>     
+#> 1             4      27559. 2021-01-01 
+#> 2             2      30697. 2021-01-01 
+#> 3             3      26419. 2021-01-01 
+#> 4             1      28168. 2021-01-01
+

Similarly we can remove a table and its data,

+
delete_table_and_data("new_db_dbtools", "daily_sales_report")
+

or the whole database.

+
delete_database_and_data("new_db_dbtools")
+
+
+ + + + + + + + + + + From 440dda29cd95cff842a133c6cf1bccfd513d0125 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Thu, 10 Feb 2022 10:06:45 +0000 Subject: [PATCH 06/23] Updated README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 5919df2..dc04d35 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,11 @@ which uses AWS Wrangler's Athena module but adds additional functionality (like Jinja templating, creating temporary tables) and alters some configuration to our specification. +Alternatively you might want to use +[Rdbtools](https://github.com/moj-analytical-services/Rdbtools), which has the +advantages of being R-native, so no messing with `reticulate` and Python, and +supporting `dbplyr`. Please note the caveat about support, though. + ## Installation Run the following commands in the R console. @@ -31,6 +36,9 @@ renv::install("moj-analytical-services/dbtools") ## Quickstart guide +There is a [vignette](doc/dbtools.html) with more details but the following +describes the basics of the package. + ### Read an SQL Athena query into an R dataframe ```r From efe164e918f9edce69496ac7fc9a320818125d61 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Fri, 11 Feb 2022 14:24:30 +0000 Subject: [PATCH 07/23] Try returning None in case something else is being converted by reticulate. --- inst/python/read_sql_query_py.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inst/python/read_sql_query_py.py b/inst/python/read_sql_query_py.py index 8fafd6b..61daa81 100644 --- a/inst/python/read_sql_query_py.py +++ b/inst/python/read_sql_query_py.py @@ -19,4 +19,6 @@ def read_sql_query_py(sql: str, file_location: str) -> None: df = pydb.read_sql_query(sql) df.to_parquet(file_location) + return None + From 5e376a3b5099431c1f4676a44e0e82e9560e7c06 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Fri, 11 Feb 2022 15:39:25 +0000 Subject: [PATCH 08/23] Use pydbtools function to save parquet, minimising reticulate interference. --- R/read.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/read.R b/R/read.R index be8e82f..63256b5 100644 --- a/R/read.R +++ b/R/read.R @@ -89,7 +89,7 @@ read_sql_query <- function(sql) { # reticulate are frequently incompatible, and load the data into R using # arrow. tmp_location <- tempfile(fileext=".parquet") - read_sql_query_py(sql, tmp_location) + dbtools.env$pydb$save_query_to_parquet(sql, tmp_location) df <- arrow::read_parquet(tmp_location) unlink(tmp_location) return(df) From 6a5eb4c0564baecf602c6fe95ff401618afb0253 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Fri, 11 Feb 2022 16:18:35 +0000 Subject: [PATCH 09/23] Add arrow to dependencies. --- DESCRIPTION | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index f20605d..7d9baa5 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -11,7 +11,8 @@ LazyData: true RoxygenNote: 7.1.1 Imports: magrittr, - reticulate + reticulate, + arrow Suggests: knitr, data.table (>= 1.11.8), From 8cafee31c1bc15fec8c858af44c8e39afa4cf97f Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Mon, 14 Feb 2022 15:55:21 +0000 Subject: [PATCH 10/23] Markdown version of vignette --- doc/dbtools.md | 379 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 doc/dbtools.md diff --git a/doc/dbtools.md b/doc/dbtools.md new file mode 100644 index 0000000..4d6f46f --- /dev/null +++ b/doc/dbtools.md @@ -0,0 +1,379 @@ +# Introduction to dbtools {#introduction-to-dbtools .title .toc-ignore} + +`dbtools` is a library used to query AWS Athena databases from R on the +Ministry of Justice's Analytical Platform. It uses the Python library +`pydbtools` and inherits much of its functionality, including creating +and querying temporary tables and injecting SQL queries with template +arguments. + +::: {#cb1 .sourceCode} +``` {.sourceCode .r} +library(dbtools) +``` +::: + +::: {#reading-sql-queries .section .level2} +## Reading SQL queries + +The `read_sql_query` function is used to obtain R tibbles from SQL +queries sent to Athena. + +::: {#cb2 .sourceCode} +``` {.sourceCode .r} +read_sql_query("select * from aws_example_dbtools.employees limit 5") +#> # A tibble: 5 x 6 +#> employee_id sex forename surname department_id manager_id +#> +#> 1 1 M Dexter Mitchell 1 17 +#> 2 2 F Summer Bennett 1 17 +#> 3 3 M Pip Carter 1 17 +#> 4 4 F Bella Long 1 17 +#> 5 5 F Lexie Perry NA 17 +``` +::: + +If a standard data frame is preferred the `read_sql` function is +provided + +::: {#cb3 .sourceCode} +``` {.sourceCode .r} +read_sql("select * from aws_example_dbtools.department limit 5", + return_df_as="dataframe") +#> department_id department_name +#> 1 1 Sales +#> 2 2 Admin +#> 3 3 Management +#> 4 4 Technical +#> 5 5 Maintenance +``` +::: + +or for a `data.table` + +::: {#cb4 .sourceCode} +``` {.sourceCode .r} +read_sql("select * from aws_example_dbtools.sales limit 5", + return_df_as="data.table") +#> employee_id qtr sales +#> 1: 1 1 768.17 +#> 2: 2 1 391.98 +#> 3: 3 1 406.36 +#> 4: 4 1 816.25 +#> 5: 5 1 437.05 +``` +::: +::: + +::: {#creating-temporary-sql-tables .section .level2} +## Creating temporary SQL tables + +The `create_temp_table` function allows you to create tables which can +be referred to in subsequent queries from the `__temp__` database. For +example, to create a table showing total sales per employee from the +tables above create a temporary total sales table. + +::: {#cb5 .sourceCode} +``` {.sourceCode .r} +sql <- " +SELECT employee_id, sum(sales) as total_sales +FROM aws_example_dbtools.sales +GROUP BY employee_id +" +create_temp_table(sql, table_name="total_sales") +``` +::: + +Then create a table of employees from the sales department. + +::: {#cb6 .sourceCode} +``` {.sourceCode .r} +sql <- " +SELECT e.employee_id, e.forename, e.surname, d.department_name +FROM aws_example_dbtools.employees AS e +LEFT JOIN aws_example_dbtools.department AS d +ON e.department_id = d.department_id +WHERE e.department_id = 1 +" +create_temp_table(sql, table_name="sales_employees") +``` +::: + +The two temporary tables can then be joined to provide the final table. + +::: {#cb7 .sourceCode} +``` {.sourceCode .r} +sql <- " +SELECT se.*, ts.total_sales +FROM __temp__.sales_employees AS se +INNER JOIN __temp__.total_sales AS ts +ON se.employee_id = ts.employee_id +" +read_sql_query(sql) +#> # A tibble: 41 x 5 +#> employee_id forename surname department_name total_sales +#> +#> 1 1 Dexter Mitchell Sales 2912. +#> 2 2 Summer Bennett Sales 1786. +#> 3 3 Pip Carter Sales 2591. +#> 4 4 Bella Long Sales 2997. +#> 5 6 Robert Roberts Sales 2208. +#> 6 7 Iris Alexander Sales 2465. +#> 7 9 Evan Carter Sales 2280. +#> 8 10 Lauren Powell Sales 1936. +#> 9 11 Alice James Sales 3093. +#> 10 12 Owen Scott Sales 2286. +#> # … with 31 more rows +``` +::: +::: + +::: {#sql-templating .section .level2} +## SQL templating + +Sometimes you will want to run similar SQL queries which differ only by, +for example, table or column names. In these cases SQL templates can be +created to SQL queries populated by templated variables, using Jinja +templating. For example, + +::: {#cb8 .sourceCode} +``` {.sourceCode .r} +sql_template = "select * from {{ db_name }}.{{ table }} limit 10" +sql <- render_sql_template(sql_template, + list(db_name="aws_example_dbtools", + table="department")) +sql +#> [1] "select * from aws_example_dbtools.department limit 10" +``` +::: + +The rendered SQL can then be used to query Athena as usual. + +::: {#cb9 .sourceCode} +``` {.sourceCode .r} +read_sql_query(sql) +#> # A tibble: 6 x 2 +#> department_id department_name +#> +#> 1 1 Sales +#> 2 2 Admin +#> 3 3 Management +#> 4 4 Technical +#> 5 5 Maintenance +#> 6 6 HR +``` +::: + +The same template can be used to read a different table. + +::: {#cb10 .sourceCode} +``` {.sourceCode .r} +sql <- render_sql_template(sql_template, + list(db_name="aws_example_dbtools", + table="sales")) +read_sql_query(sql) +#> # A tibble: 10 x 3 +#> employee_id qtr sales +#> +#> 1 1 1 768. +#> 2 2 1 392. +#> 3 3 1 406. +#> 4 4 1 816. +#> 5 5 1 437. +#> 6 6 1 385. +#> 7 7 1 821. +#> 8 8 1 398. +#> 9 9 1 899. +#> 10 10 1 439. +``` +::: + +Perhaps more usefully we can use SQL templates saved as a file, which +means we can make use of our editors' and IDEs' SQL capabilities. + +::: {#cb11 .sourceCode} +``` {.sourceCode .r} +cat("SELECT * FROM {{ db_name }}.{{ table_name }}", file="tempfile.sql") + +sql <- get_sql_from_file("tempfile.sql", + jinja_args=list(db_name="aws_example_dbtools", + table_name="department")) +read_sql_query(sql) +#> # A tibble: 6 x 2 +#> department_id department_name +#> +#> 1 1 Sales +#> 2 2 Admin +#> 3 3 Management +#> 4 4 Technical +#> 5 5 Maintenance +#> 6 6 HR +``` +::: +::: + +::: {#advanced-usage .section .level2} +## Advanced usage + +::: {#creating-and-maintaining-database-tables-in-athena .section .level3} +### Creating and maintaining database tables in Athena + +In this section we will create a new database from our existing database +in Athena. Use the `start_query_execution_and_wait` function to run the +SQL creating the database. + +::: {#cb12 .sourceCode} +``` {.sourceCode .r} +sql <- " +CREATE DATABASE IF NOT EXISTS new_db_dbtools +COMMENT 'Example of running queries and insert into' +LOCATION 's3://alpha-everyone/dbtools/new_db/' +" + +response <- start_query_execution_and_wait(sql) +response$Status$State +#> [1] "SUCCEEDED" +``` +::: + +Create a derived table in the new database with a CTAS query that both +generates the output into S3 and creates the schema of the table. Note +that this only inserts the data from quarters 1 and 2. + +::: {#cb13 .sourceCode} +``` {.sourceCode .r} +sql <- " +CREATE TABLE new_db_dbtools.sales_report WITH +( + external_location='s3://alpha-everyone/dbtools/new_db/sales_report' +) AS +SELECT qtr as sales_quarter, sum(sales) AS total_sales +FROM aws_example_dbtools.sales +WHERE qtr IN (1,2) +GROUP BY qtr +" + +response <- start_query_execution_and_wait(sql) +response$Status$State +#> [1] "SUCCEEDED" +``` +::: + +We can now use an insert into query to add the data from quarters 3 and +4 as the schema has already been created. + +::: {#cb14 .sourceCode} +``` {.sourceCode .r} +sql <- " +INSERT INTO new_db_dbtools.sales_report +SELECT qtr as sales_quarter, sum(sales) AS total_sales +FROM aws_example_dbtools.sales +WHERE qtr IN (3,4) +GROUP BY qtr +" + +response <- start_query_execution_and_wait(sql) +read_sql_query("select * from new_db_dbtools.sales_report") +#> # A tibble: 4 x 2 +#> sales_quarter total_sales +#> +#> 1 1 28168. +#> 2 2 30697. +#> 3 4 27559. +#> 4 3 26419. +``` +::: +::: + +::: {#creating-a-table-with-partitions .section .level3} +### Creating a table with partitions + +Do the same as before but partition the data based on when the report +was run. + +::: {#cb15 .sourceCode} +``` {.sourceCode .r} +sql <- " +CREATE TABLE new_db_dbtools.daily_sales_report WITH +( + external_location='s3://alpha-everyone/dbtools/new_db/daily_sales_report', + partitioned_by = ARRAY['report_date'] +) AS +SELECT qtr as sales_quarter, sum(sales) AS total_sales, +date '2021-01-01' AS report_date +FROM aws_example_dbtools.sales +GROUP BY qtr, date '2021-01-01' +" + +response <- start_query_execution_and_wait(sql) +response$Status$State +#> [1] "SUCCEEDED" +``` +::: + +Then, simulating a source database that is updated daily, add more +partitioned data. + +::: {#cb16 .sourceCode} +``` {.sourceCode .r} +sql <- " +INSERT INTO new_db_dbtools.daily_sales_report +SELECT qtr as sales_quarter, sum(sales) AS total_sales, +date '2021-01-02' AS report_date +FROM aws_example_dbtools.sales +GROUP BY qtr, date '2021-01-02' +" + +response <- start_query_execution_and_wait(sql) +read_sql_query("select * from new_db_dbtools.daily_sales_report") +#> # A tibble: 8 x 3 +#> sales_quarter total_sales report_date +#> +#> 1 4 27559. 2021-01-01 +#> 2 2 30697. 2021-01-01 +#> 3 3 26419. 2021-01-01 +#> 4 1 28168. 2021-01-01 +#> 5 2 30697. 2021-01-02 +#> 6 3 26419. 2021-01-02 +#> 7 1 28168. 2021-01-02 +#> 8 4 27559. 2021-01-02 +``` +::: + +We can remove a partition and its underlying data using +`delete_partitions_and_data` which uses an expression to match +partitions - see + +for more details. + +::: {#cb17 .sourceCode} +``` {.sourceCode .r} +delete_partitions_and_data("new_db_dbtools", "daily_sales_report", + "report_date = '2021-01-02'") +read_sql_query("select * from new_db_dbtools.daily_sales_report") +#> # A tibble: 4 x 3 +#> sales_quarter total_sales report_date +#> +#> 1 4 27559. 2021-01-01 +#> 2 2 30697. 2021-01-01 +#> 3 3 26419. 2021-01-01 +#> 4 1 28168. 2021-01-01 +``` +::: + +Similarly we can remove a table and its data, + +::: {#cb18 .sourceCode} +``` {.sourceCode .r} +delete_table_and_data("new_db_dbtools", "daily_sales_report") +``` +::: + +or the whole database. + +::: {#cb19 .sourceCode} +``` {.sourceCode .r} +delete_database_and_data("new_db_dbtools") +``` +::: +::: +::: From 2377e407b8ea9a061581be88d141b4b21a2d0375 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Tue, 15 Feb 2022 10:02:40 +0000 Subject: [PATCH 11/23] Removed redundant python function, updated requirements --- doc/dbtools.md | 379 ------------------------------- inst/python/read_sql_query_py.py | 24 -- requirements.txt | 2 +- 3 files changed, 1 insertion(+), 404 deletions(-) delete mode 100644 doc/dbtools.md delete mode 100644 inst/python/read_sql_query_py.py diff --git a/doc/dbtools.md b/doc/dbtools.md deleted file mode 100644 index 4d6f46f..0000000 --- a/doc/dbtools.md +++ /dev/null @@ -1,379 +0,0 @@ -# Introduction to dbtools {#introduction-to-dbtools .title .toc-ignore} - -`dbtools` is a library used to query AWS Athena databases from R on the -Ministry of Justice's Analytical Platform. It uses the Python library -`pydbtools` and inherits much of its functionality, including creating -and querying temporary tables and injecting SQL queries with template -arguments. - -::: {#cb1 .sourceCode} -``` {.sourceCode .r} -library(dbtools) -``` -::: - -::: {#reading-sql-queries .section .level2} -## Reading SQL queries - -The `read_sql_query` function is used to obtain R tibbles from SQL -queries sent to Athena. - -::: {#cb2 .sourceCode} -``` {.sourceCode .r} -read_sql_query("select * from aws_example_dbtools.employees limit 5") -#> # A tibble: 5 x 6 -#> employee_id sex forename surname department_id manager_id -#> -#> 1 1 M Dexter Mitchell 1 17 -#> 2 2 F Summer Bennett 1 17 -#> 3 3 M Pip Carter 1 17 -#> 4 4 F Bella Long 1 17 -#> 5 5 F Lexie Perry NA 17 -``` -::: - -If a standard data frame is preferred the `read_sql` function is -provided - -::: {#cb3 .sourceCode} -``` {.sourceCode .r} -read_sql("select * from aws_example_dbtools.department limit 5", - return_df_as="dataframe") -#> department_id department_name -#> 1 1 Sales -#> 2 2 Admin -#> 3 3 Management -#> 4 4 Technical -#> 5 5 Maintenance -``` -::: - -or for a `data.table` - -::: {#cb4 .sourceCode} -``` {.sourceCode .r} -read_sql("select * from aws_example_dbtools.sales limit 5", - return_df_as="data.table") -#> employee_id qtr sales -#> 1: 1 1 768.17 -#> 2: 2 1 391.98 -#> 3: 3 1 406.36 -#> 4: 4 1 816.25 -#> 5: 5 1 437.05 -``` -::: -::: - -::: {#creating-temporary-sql-tables .section .level2} -## Creating temporary SQL tables - -The `create_temp_table` function allows you to create tables which can -be referred to in subsequent queries from the `__temp__` database. For -example, to create a table showing total sales per employee from the -tables above create a temporary total sales table. - -::: {#cb5 .sourceCode} -``` {.sourceCode .r} -sql <- " -SELECT employee_id, sum(sales) as total_sales -FROM aws_example_dbtools.sales -GROUP BY employee_id -" -create_temp_table(sql, table_name="total_sales") -``` -::: - -Then create a table of employees from the sales department. - -::: {#cb6 .sourceCode} -``` {.sourceCode .r} -sql <- " -SELECT e.employee_id, e.forename, e.surname, d.department_name -FROM aws_example_dbtools.employees AS e -LEFT JOIN aws_example_dbtools.department AS d -ON e.department_id = d.department_id -WHERE e.department_id = 1 -" -create_temp_table(sql, table_name="sales_employees") -``` -::: - -The two temporary tables can then be joined to provide the final table. - -::: {#cb7 .sourceCode} -``` {.sourceCode .r} -sql <- " -SELECT se.*, ts.total_sales -FROM __temp__.sales_employees AS se -INNER JOIN __temp__.total_sales AS ts -ON se.employee_id = ts.employee_id -" -read_sql_query(sql) -#> # A tibble: 41 x 5 -#> employee_id forename surname department_name total_sales -#> -#> 1 1 Dexter Mitchell Sales 2912. -#> 2 2 Summer Bennett Sales 1786. -#> 3 3 Pip Carter Sales 2591. -#> 4 4 Bella Long Sales 2997. -#> 5 6 Robert Roberts Sales 2208. -#> 6 7 Iris Alexander Sales 2465. -#> 7 9 Evan Carter Sales 2280. -#> 8 10 Lauren Powell Sales 1936. -#> 9 11 Alice James Sales 3093. -#> 10 12 Owen Scott Sales 2286. -#> # … with 31 more rows -``` -::: -::: - -::: {#sql-templating .section .level2} -## SQL templating - -Sometimes you will want to run similar SQL queries which differ only by, -for example, table or column names. In these cases SQL templates can be -created to SQL queries populated by templated variables, using Jinja -templating. For example, - -::: {#cb8 .sourceCode} -``` {.sourceCode .r} -sql_template = "select * from {{ db_name }}.{{ table }} limit 10" -sql <- render_sql_template(sql_template, - list(db_name="aws_example_dbtools", - table="department")) -sql -#> [1] "select * from aws_example_dbtools.department limit 10" -``` -::: - -The rendered SQL can then be used to query Athena as usual. - -::: {#cb9 .sourceCode} -``` {.sourceCode .r} -read_sql_query(sql) -#> # A tibble: 6 x 2 -#> department_id department_name -#> -#> 1 1 Sales -#> 2 2 Admin -#> 3 3 Management -#> 4 4 Technical -#> 5 5 Maintenance -#> 6 6 HR -``` -::: - -The same template can be used to read a different table. - -::: {#cb10 .sourceCode} -``` {.sourceCode .r} -sql <- render_sql_template(sql_template, - list(db_name="aws_example_dbtools", - table="sales")) -read_sql_query(sql) -#> # A tibble: 10 x 3 -#> employee_id qtr sales -#> -#> 1 1 1 768. -#> 2 2 1 392. -#> 3 3 1 406. -#> 4 4 1 816. -#> 5 5 1 437. -#> 6 6 1 385. -#> 7 7 1 821. -#> 8 8 1 398. -#> 9 9 1 899. -#> 10 10 1 439. -``` -::: - -Perhaps more usefully we can use SQL templates saved as a file, which -means we can make use of our editors' and IDEs' SQL capabilities. - -::: {#cb11 .sourceCode} -``` {.sourceCode .r} -cat("SELECT * FROM {{ db_name }}.{{ table_name }}", file="tempfile.sql") - -sql <- get_sql_from_file("tempfile.sql", - jinja_args=list(db_name="aws_example_dbtools", - table_name="department")) -read_sql_query(sql) -#> # A tibble: 6 x 2 -#> department_id department_name -#> -#> 1 1 Sales -#> 2 2 Admin -#> 3 3 Management -#> 4 4 Technical -#> 5 5 Maintenance -#> 6 6 HR -``` -::: -::: - -::: {#advanced-usage .section .level2} -## Advanced usage - -::: {#creating-and-maintaining-database-tables-in-athena .section .level3} -### Creating and maintaining database tables in Athena - -In this section we will create a new database from our existing database -in Athena. Use the `start_query_execution_and_wait` function to run the -SQL creating the database. - -::: {#cb12 .sourceCode} -``` {.sourceCode .r} -sql <- " -CREATE DATABASE IF NOT EXISTS new_db_dbtools -COMMENT 'Example of running queries and insert into' -LOCATION 's3://alpha-everyone/dbtools/new_db/' -" - -response <- start_query_execution_and_wait(sql) -response$Status$State -#> [1] "SUCCEEDED" -``` -::: - -Create a derived table in the new database with a CTAS query that both -generates the output into S3 and creates the schema of the table. Note -that this only inserts the data from quarters 1 and 2. - -::: {#cb13 .sourceCode} -``` {.sourceCode .r} -sql <- " -CREATE TABLE new_db_dbtools.sales_report WITH -( - external_location='s3://alpha-everyone/dbtools/new_db/sales_report' -) AS -SELECT qtr as sales_quarter, sum(sales) AS total_sales -FROM aws_example_dbtools.sales -WHERE qtr IN (1,2) -GROUP BY qtr -" - -response <- start_query_execution_and_wait(sql) -response$Status$State -#> [1] "SUCCEEDED" -``` -::: - -We can now use an insert into query to add the data from quarters 3 and -4 as the schema has already been created. - -::: {#cb14 .sourceCode} -``` {.sourceCode .r} -sql <- " -INSERT INTO new_db_dbtools.sales_report -SELECT qtr as sales_quarter, sum(sales) AS total_sales -FROM aws_example_dbtools.sales -WHERE qtr IN (3,4) -GROUP BY qtr -" - -response <- start_query_execution_and_wait(sql) -read_sql_query("select * from new_db_dbtools.sales_report") -#> # A tibble: 4 x 2 -#> sales_quarter total_sales -#> -#> 1 1 28168. -#> 2 2 30697. -#> 3 4 27559. -#> 4 3 26419. -``` -::: -::: - -::: {#creating-a-table-with-partitions .section .level3} -### Creating a table with partitions - -Do the same as before but partition the data based on when the report -was run. - -::: {#cb15 .sourceCode} -``` {.sourceCode .r} -sql <- " -CREATE TABLE new_db_dbtools.daily_sales_report WITH -( - external_location='s3://alpha-everyone/dbtools/new_db/daily_sales_report', - partitioned_by = ARRAY['report_date'] -) AS -SELECT qtr as sales_quarter, sum(sales) AS total_sales, -date '2021-01-01' AS report_date -FROM aws_example_dbtools.sales -GROUP BY qtr, date '2021-01-01' -" - -response <- start_query_execution_and_wait(sql) -response$Status$State -#> [1] "SUCCEEDED" -``` -::: - -Then, simulating a source database that is updated daily, add more -partitioned data. - -::: {#cb16 .sourceCode} -``` {.sourceCode .r} -sql <- " -INSERT INTO new_db_dbtools.daily_sales_report -SELECT qtr as sales_quarter, sum(sales) AS total_sales, -date '2021-01-02' AS report_date -FROM aws_example_dbtools.sales -GROUP BY qtr, date '2021-01-02' -" - -response <- start_query_execution_and_wait(sql) -read_sql_query("select * from new_db_dbtools.daily_sales_report") -#> # A tibble: 8 x 3 -#> sales_quarter total_sales report_date -#> -#> 1 4 27559. 2021-01-01 -#> 2 2 30697. 2021-01-01 -#> 3 3 26419. 2021-01-01 -#> 4 1 28168. 2021-01-01 -#> 5 2 30697. 2021-01-02 -#> 6 3 26419. 2021-01-02 -#> 7 1 28168. 2021-01-02 -#> 8 4 27559. 2021-01-02 -``` -::: - -We can remove a partition and its underlying data using -`delete_partitions_and_data` which uses an expression to match -partitions - see - -for more details. - -::: {#cb17 .sourceCode} -``` {.sourceCode .r} -delete_partitions_and_data("new_db_dbtools", "daily_sales_report", - "report_date = '2021-01-02'") -read_sql_query("select * from new_db_dbtools.daily_sales_report") -#> # A tibble: 4 x 3 -#> sales_quarter total_sales report_date -#> -#> 1 4 27559. 2021-01-01 -#> 2 2 30697. 2021-01-01 -#> 3 3 26419. 2021-01-01 -#> 4 1 28168. 2021-01-01 -``` -::: - -Similarly we can remove a table and its data, - -::: {#cb18 .sourceCode} -``` {.sourceCode .r} -delete_table_and_data("new_db_dbtools", "daily_sales_report") -``` -::: - -or the whole database. - -::: {#cb19 .sourceCode} -``` {.sourceCode .r} -delete_database_and_data("new_db_dbtools") -``` -::: -::: -::: diff --git a/inst/python/read_sql_query_py.py b/inst/python/read_sql_query_py.py deleted file mode 100644 index 61daa81..0000000 --- a/inst/python/read_sql_query_py.py +++ /dev/null @@ -1,24 +0,0 @@ -import pydbtools as pydb -import tempfile - -def read_sql_query_py(sql: str, file_location: str) -> None: - """Downloads the data frame generated by an SQL query and saves it as a - parquet file in a given location. - This needs to be in a pure Python function to prevent reticulate calling a - pandas dataframe conversion, which often fails in one way or another. - - Arguments: - sql (str) -- An Athena SQL query - file_location (str) -- The file location where the query result will be - saved - - Returns: - None - """ - - df = pydb.read_sql_query(sql) - df.to_parquet(file_location) - - return None - - diff --git a/requirements.txt b/requirements.txt index dbe1b97..bd83923 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,7 @@ pg8000==1.22.1 ply==3.11 progressbar2==3.55.0 pyarrow==6.0.1 -pydbtools==5.0.0 +pydbtools==5.1.0 PyMySQL==1.0.2 pyparsing==3.0.6 python-dateutil==2.8.2 From 94de1dd8d403961cbc03d2081eec92074e6ed786 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Tue, 15 Feb 2022 10:27:12 +0000 Subject: [PATCH 12/23] Added pdf vignette --- doc/dbtools.pdf | Bin 0 -> 169142 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/dbtools.pdf diff --git a/doc/dbtools.pdf b/doc/dbtools.pdf new file mode 100644 index 0000000000000000000000000000000000000000..017eeb6b774db3bf83768dfd734ca558faf682a4 GIT binary patch literal 169142 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

Xa#!}@j{cCU3-vue14M!Vvic`}u2r@$BG|0{8 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

-67fo{nGlGerF*`AoOm;fH4$gN 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 z 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�X$t|M#^?veW*rITJ&WunR+|t(!{pvgX1% zap9tt1?JRbXTfUv%FyD>tae#TQPb1k>Eq>*wLvDw$kY;gxr$H{^XSz?G1vd?+*JF= z=CQLRcmN<+3Z4)Gbc6z72&6LrV&xS|U=INhTc9HhhycP^LQ5(&fF)!#p8;C3Jv^wa z8T%k+&oDs8b1*#vCxoBQyPryzy>3x{9Yy=f?{fb4%&*<;P8gEeUS(i$^VT!gSsW3JD`$!Ly%4 z@!Ih$hpl!*RP7ehWo1_Bi6I3O{nZvAPHQ=Q85i2;*t5x4;WvMPzUgX-=$y`p{W)n; zsPlC3m*;gGZGth-3>{F0u8MW>RyFcev~h8acX700jb5&C{l^4){vq6ZZeL=IJ2Bxn zF`7cON(>)~37U;En~mXI*8_xF7hol&qvY0gwR!a<60C6$B#KuS3b2KKzgdlvy2j%W zHiOMBczVR7g||$KAUaK4z^^^gxuWe5Ctn{=P>(sO9(TzuHgF`$bi^_-_(K*s^EI_3 z$hu0~X5q1ibm^!SbGORdwGoqliOYu%^=D(z*7TbMS;|4qYH`DpdW| tr13zQ=|0yQ(`=6e%dLFqpNqvmz|Aip#E-Q)U`TZ}Bpe_wZ(wc+_!nNApIQI_ literal 0 HcmV?d00001 From 7b1663e8b120fda40242fa7afd21fe2fb5ae92ea Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Tue, 15 Feb 2022 11:42:52 +0000 Subject: [PATCH 13/23] Closed R code markdown block. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dc04d35..1e467a4 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ df <- dbtools::read_sql_query(sql) cat("SELECT * FROM {{ db_name }}.{{ table_name }}", file="tempfile.sql") sql <- pydb.get_sql_from_file("tempfile.sql", jinja_args={"db_name": db_name, "table_name": "department"}) pydb.read_sql_query(sql) +``` # Legacy From 8cb57252acb6a213e9263f7059b059b562775e16 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Tue, 15 Feb 2022 11:43:46 +0000 Subject: [PATCH 14/23] Linked to pdf version of vignette. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e467a4..6be72c2 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ renv::install("moj-analytical-services/dbtools") ## Quickstart guide -There is a [vignette](doc/dbtools.html) with more details but the following +There is a [vignette](doc/dbtools.pdf) with more details but the following describes the basics of the package. ### Read an SQL Athena query into an R dataframe From e9e3a1c029b75457f9fba8f10775bfc1bdf5902b Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Tue, 15 Feb 2022 11:57:00 +0000 Subject: [PATCH 15/23] Removed s3tools from dependencies --- DESCRIPTION | 2 -- 1 file changed, 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 7d9baa5..b7330de 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -18,6 +18,4 @@ Suggests: data.table (>= 1.11.8), rmarkdown, tibble -Remotes: - moj-analytical-services/s3tools VignetteBuilder: knitr From 6a15a558723692001b1a68fd113abcdd933167a5 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Tue, 15 Feb 2022 11:57:58 +0000 Subject: [PATCH 16/23] Removed maintainer field --- DESCRIPTION | 1 - 1 file changed, 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index b7330de..da8ae4f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -3,7 +3,6 @@ Type: Package Title: Uses R wrapper function to send queries to athena. Version: 3.0.0 Author: Karik Isichei -Maintainer: The package maintainer Description: See title. License: MIT + file LICENSE Encoding: UTF-8 From a9314056680ba0b18454cb03ebcc64437d445732 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Tue, 15 Feb 2022 13:52:14 +0000 Subject: [PATCH 17/23] Remove load of python function --- R/zzz.R | 3 --- 1 file changed, 3 deletions(-) diff --git a/R/zzz.R b/R/zzz.R index 909b7ee..fa4b998 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,6 +1,3 @@ -reticulate::source_python( - system.file("python", "read_sql_query_py.py", package = "dbtools")) - dbtools.env <- new.env(parent=emptyenv()) .onLoad <- function(libname, pkgname) { # import Python package on package load From 648acc9112822fbd7a26dae1ebea01add4235d81 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Tue, 15 Feb 2022 14:00:45 +0000 Subject: [PATCH 18/23] Roxygenised --- R/read.R | 12 +++++------ R/wrap.R | 4 +--- man/convert_athena_type_to_arrow.Rd | 5 +++++ man/create_temp_table.Rd | 6 +----- man/delete_partitions_and_data.Rd | 3 +++ man/read_sql.Rd | 32 +++++++++++++++++++++++++++++ man/read_sql_query.Rd | 7 +++++-- 7 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 man/read_sql.Rd diff --git a/R/read.R b/R/read.R index 63256b5..2124ab7 100644 --- a/R/read.R +++ b/R/read.R @@ -5,8 +5,8 @@ #' @return An Arrow type #' @export #' -#' @see https://docs.aws.amazon.com/athena/latest/ug/data-types.html -#' @see https://arrow.apache.org/docs/r/reference/data-type.html +#' @seealso https://docs.aws.amazon.com/athena/latest/ug/data-types.html +#' @seealso https://arrow.apache.org/docs/r/reference/data-type.html convert_athena_type_to_arrow <- function(t) { # Regular expression matches either e.g. decimal(10) or decimal(10, 5) decimal_match <- stringr::str_match( @@ -40,7 +40,7 @@ convert_athena_type_to_arrow <- function(t) { } -#' Send an SQL query to Athena and receive a tibble. +#' Send an SQL query to Athena and receive a dataframe. #' #' @param sql An SQL query #' @@ -48,7 +48,7 @@ convert_athena_type_to_arrow <- function(t) { #' @export #' #' @examples -#' `df <- dbtools::read_sql_query('select * from my_db.my_table)` +#' `df <- dbtools::read_sql_query('select * from my_db.my_table')` read_sql_query <- function(sql) { # This approach doesn't work because for some reason pydbtools and boto3 # stopped playing well together under reticulate, with boto3 throwing a @@ -95,7 +95,7 @@ read_sql_query <- function(sql) { return(df) } -#' @description Uses boto3 (in python) to send an sql query to athena and return an R dataframe, tibble or data.table based on user preference. +#' Uses boto3 (in python) to send an sql query to athena and return an R dataframe, tibble or data.table based on user preference. #' #' @export #' @@ -122,6 +122,6 @@ read_sql <- function(sql_query, return_df_as="tibble") { } else if (return_df_as == "data.table") { return(data.table::as.data.table(df)) } else { - return(df) + return(tibble::as_tibble(df)) } } diff --git a/R/wrap.R b/R/wrap.R index bd5b828..764ed6f 100644 --- a/R/wrap.R +++ b/R/wrap.R @@ -140,7 +140,7 @@ start_query_execution_and_wait <- function(sql) { #' @param table The table name. #' @param expression The expression to match. #' -#' @see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_partitions +#' @seealso https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_partitions #' @export #' #' @examples @@ -180,8 +180,6 @@ delete_database_and_data <- function(database) { #' #' @return #' @export -#' -#' @examples get_sql_from_file <- function(filepath, jinja_args=NULL) { dbtools.env$pydb$get_sql_from_file(filepath, jinja_args) } diff --git a/man/convert_athena_type_to_arrow.Rd b/man/convert_athena_type_to_arrow.Rd index 2522848..1e794d7 100644 --- a/man/convert_athena_type_to_arrow.Rd +++ b/man/convert_athena_type_to_arrow.Rd @@ -15,3 +15,8 @@ An Arrow type \description{ Convert an Athena type to an Arrow type } +\seealso{ +https://docs.aws.amazon.com/athena/latest/ug/data-types.html + +https://arrow.apache.org/docs/r/reference/data-type.html +} diff --git a/man/create_temp_table.Rd b/man/create_temp_table.Rd index 5b3cb78..298679c 100644 --- a/man/create_temp_table.Rd +++ b/man/create_temp_table.Rd @@ -4,15 +4,11 @@ \alias{create_temp_table} \title{Create a temporary table} \usage{ -create_temp_table(sql, table_name, region_name) +create_temp_table(sql, table_name) } \arguments{ \item{table_name}{The name of the temp table you wish to create} -\item{region_name}{Name of the AWS region you want to run queries on. -Defaults to pydbtools.utils.aws_default_region (which if left unset is -"eu-west-1").} - \item{sql:}{The SQL table you want to create a temp table out of. Should be a table that starts with a WITH or SELECT clause.} } diff --git a/man/delete_partitions_and_data.Rd b/man/delete_partitions_and_data.Rd index e7109e5..4f16f48 100644 --- a/man/delete_partitions_and_data.Rd +++ b/man/delete_partitions_and_data.Rd @@ -21,3 +21,6 @@ database table matching an expression. \examples{ `dbtools::delete_partitions_and_data("my_database", "my_table", "year = 2020 and month = 5")` } +\seealso{ +https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_partitions +} diff --git a/man/read_sql.Rd b/man/read_sql.Rd new file mode 100644 index 0000000..0313d74 --- /dev/null +++ b/man/read_sql.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read.R +\name{read_sql} +\alias{read_sql} +\title{Uses boto3 (in python) to send an sql query to athena and return an R dataframe, tibble or data.table based on user preference.} +\usage{ +read_sql(sql_query, return_df_as = "tibble") +} +\arguments{ +\item{sql_query}{A string specifying the SQL query you want to send to athena. See packages github readme for info on the flavour of SQL Athena uses.} + +\item{return_df_as}{String specifying what the table should be returned as i.e. 'dataframe', 'tibble' (converts data using tibble::as_tibble) or 'data.table' (converts data using data.table::as.data.table). Default is 'tibble'. Not all tables returned are a DataFrame class.} +} +\value{ +A table as a dataframe, tibble or data.table +} +\description{ +Uses boto3 (in python) to send an sql query to athena and return an R dataframe, tibble or data.table based on user preference. +} +\details{ +Will send an SQL query to Athena and wait for it to complete. Once the query has completed the resulting sql query will be read using arrow. +Function returns dataframe. If needing more a more bespoke or self defined data reading function and arguments use dbtools::start_query_and_wait to send an SQL query and return the s3 path to data in csv format. +} +\examples{ +# Read an sql query returning a tibble +``` +df <- dbtools::read_sql( + "SELECT * from crest_v1.flatfile limit 10000", + return_df_as="tibble" +) +``` +} diff --git a/man/read_sql_query.Rd b/man/read_sql_query.Rd index 9438ac8..96222af 100644 --- a/man/read_sql_query.Rd +++ b/man/read_sql_query.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/read.R \name{read_sql_query} \alias{read_sql_query} -\title{Send an SQL query to Athena and receive a data frame.} +\title{Send an SQL query to Athena and receive a dataframe.} \usage{ read_sql_query(sql) } @@ -13,5 +13,8 @@ read_sql_query(sql) Dataframe } \description{ -Send an SQL query to Athena and receive a data frame. +Send an SQL query to Athena and receive a dataframe. +} +\examples{ +`df <- dbtools::read_sql_query('select * from my_db.my_table')` } From 2442a1f69d650786eaa7445c05f395eda6773bca Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 16 Feb 2022 14:57:21 +0000 Subject: [PATCH 19/23] Documentation changes --- R/read.R | 2 +- R/wrap.R | 4 ++++ doc/dbtools.R | 2 +- doc/dbtools.Rmd | 15 ++++++++----- doc/dbtools.html | 52 ++++++++++++++++++++++--------------------- vignettes/dbtools.Rmd | 15 ++++++++----- 6 files changed, 53 insertions(+), 37 deletions(-) diff --git a/R/read.R b/R/read.R index 2124ab7..9f50c82 100644 --- a/R/read.R +++ b/R/read.R @@ -44,7 +44,7 @@ convert_athena_type_to_arrow <- function(t) { #' #' @param sql An SQL query #' -#' @return Dataframe +#' @return Dataframe or tibble if the tibble library is loaded. #' @export #' #' @examples diff --git a/R/wrap.R b/R/wrap.R index 764ed6f..c3cd938 100644 --- a/R/wrap.R +++ b/R/wrap.R @@ -44,6 +44,7 @@ get_query_columns_types <- function(query_id) { #' @param query_id Athena query execution ID #' #' @return List with the get_query_execution response. +#' @seealso https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/athena.html#Athena.Client.get_query_execution #' @export #' #' @examples @@ -93,6 +94,7 @@ show_create_table <- function(table, database) { #' @param wait Default FALSE, indicates whether to wait for the query to finish and return a dictionary with the query execution response. #' #' @return Query execution ID if `wait` is set to `False`, list with the get_query_execution response otherwise. +#' @seealso https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/athena.html#Athena.Client.get_query_execution #' @export start_query_execution <- function(sql, wait=FALSE) { dbtools.env$pydb$start_query_execution(sql, wait) @@ -112,6 +114,7 @@ stop_query_execution <- function(query_id) { #' @param query_id Athena query execution ID #' #' @return List with the get_query_execution response +#' @seealso https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/athena.html#Athena.Client.get_query_execution #' @export #' #' @examples @@ -125,6 +128,7 @@ wait_query <- function(query_id) { #' @param sql An SQL string. Which works with __TEMP__ references. #' #' @return List with the get_query_execution response. +#' @seealso https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/athena.html#Athena.Client.get_query_execution #' @export #' #' @examples diff --git a/doc/dbtools.R b/doc/dbtools.R index 12a45ed..f8710e6 100644 --- a/doc/dbtools.R +++ b/doc/dbtools.R @@ -13,7 +13,7 @@ read_sql_query("select * from aws_example_dbtools.employees limit 5") ## ----------------------------------------------------------------------------- read_sql("select * from aws_example_dbtools.department limit 5", - return_df_as="dataframe") + return_df_as="tibble") ## ----------------------------------------------------------------------------- read_sql("select * from aws_example_dbtools.sales limit 5", diff --git a/doc/dbtools.Rmd b/doc/dbtools.Rmd index 4824bfa..440fe09 100644 --- a/doc/dbtools.Rmd +++ b/doc/dbtools.Rmd @@ -75,18 +75,18 @@ library(dbtools) ## Reading SQL queries -The `read_sql_query` function is used to obtain R tibbles from SQL queries +The `read_sql_query` function is used to obtain R dataframes from SQL queries sent to Athena. ```{r} read_sql_query("select * from aws_example_dbtools.employees limit 5") ``` -If a standard data frame is preferred the `read_sql` function is provided +If a tibble is preferred the `read_sql` function is provided ```{r} read_sql("select * from aws_example_dbtools.department limit 5", - return_df_as="dataframe") + return_df_as="tibble") ``` or for a `data.table` @@ -96,6 +96,7 @@ read_sql("select * from aws_example_dbtools.sales limit 5", return_df_as="data.table") ``` + ## Creating temporary SQL tables The `create_temp_table` function allows you to create tables which can be @@ -142,7 +143,8 @@ read_sql_query(sql) Sometimes you will want to run similar SQL queries which differ only by, for example, table or column names. In these cases SQL templates can be created to SQL queries populated by templated variables, -using Jinja templating. For example, +using Jinja2 templating (https://jinja2docs.readthedocs.io/en/stable/index.html). +For example, ```{r} sql_template = "select * from {{ db_name }}.{{ table }} limit 10" @@ -235,7 +237,10 @@ read_sql_query("select * from new_db_dbtools.sales_report") ### Creating a table with partitions -Do the same as before but partition the data based on when the report was run. +Do the same as before but partition the data based on when the report was run. +This can make queries more efficient as filtering on the partition columns +reduces the amount of data scanned, plus makes incrementally adding data +easier. ```{r} sql <- " diff --git a/doc/dbtools.html b/doc/dbtools.html index ebc3b00..2e645e6 100644 --- a/doc/dbtools.html +++ b/doc/dbtools.html @@ -145,7 +145,7 @@

Introduction to dbtools

library(dbtools)

Reading SQL queries

-

The read_sql_query function is used to obtain R tibbles from SQL queries sent to Athena.

+

The read_sql_query function is used to obtain R dataframes from SQL queries sent to Athena.

read_sql_query("select * from aws_example_dbtools.employees limit 5")
 #> # A tibble: 5 x 6
 #>   employee_id sex   forename surname  department_id manager_id
@@ -155,15 +155,17 @@ 

Reading SQL queries

#> 3 3 M Pip Carter 1 17 #> 4 4 F Bella Long 1 17 #> 5 5 F Lexie Perry NA 17
-

If a standard data frame is preferred the read_sql function is provided

+

If a tibble is preferred the read_sql function is provided

read_sql("select * from aws_example_dbtools.department limit 5",
-         return_df_as="dataframe")
-#>   department_id department_name
-#> 1             1           Sales
-#> 2             2           Admin
-#> 3             3      Management
-#> 4             4       Technical
-#> 5             5     Maintenance
+ return_df_as="tibble") +#> # A tibble: 5 x 2 +#> department_id department_name +#> <int> <chr> +#> 1 1 Sales +#> 2 2 Admin +#> 3 3 Management +#> 4 4 Technical +#> 5 5 Maintenance

or for a data.table

read_sql("select * from aws_example_dbtools.sales limit 5",
          return_df_as="data.table")
@@ -217,7 +219,7 @@ 

Creating temporary SQL tables

SQL templating

-

Sometimes you will want to run similar SQL queries which differ only by, for example, table or column names. In these cases SQL templates can be created to SQL queries populated by templated variables, using Jinja templating. For example,

+

Sometimes you will want to run similar SQL queries which differ only by, for example, table or column names. In these cases SQL templates can be created to SQL queries populated by templated variables, using Jinja2 templating (https://jinja2docs.readthedocs.io/en/stable/index.html). For example,

sql_template = "select * from {{ db_name }}.{{ table }} limit 10"
 sql <- render_sql_template(sql_template, 
                            list(db_name="aws_example_dbtools",
@@ -313,14 +315,14 @@ 

Creating and maintaining database tables in Athena

#> # A tibble: 4 x 2 #> sales_quarter total_sales #> <int> <dbl> -#> 1 1 28168. -#> 2 2 30697. -#> 3 4 27559. -#> 4 3 26419.
+#> 1 2 30697. +#> 2 1 28168. +#> 3 3 26419. +#> 4 4 27559.

Creating a table with partitions

-

Do the same as before but partition the data based on when the report was run.

+

Do the same as before but partition the data based on when the report was run. This can make queries more efficient as filtering on the partition columns reduces the amount of data scanned, plus makes incrementally adding data easier.

sql <- "
 CREATE TABLE new_db_dbtools.daily_sales_report WITH
 (
@@ -350,12 +352,12 @@ 

Creating a table with partitions

#> # A tibble: 8 x 3 #> sales_quarter total_sales report_date #> <int> <dbl> <date> -#> 1 4 27559. 2021-01-01 -#> 2 2 30697. 2021-01-01 -#> 3 3 26419. 2021-01-01 -#> 4 1 28168. 2021-01-01 -#> 5 2 30697. 2021-01-02 -#> 6 3 26419. 2021-01-02 +#> 1 3 26419. 2021-01-01 +#> 2 1 28168. 2021-01-01 +#> 3 2 30697. 2021-01-01 +#> 4 4 27559. 2021-01-01 +#> 5 3 26419. 2021-01-02 +#> 6 2 30697. 2021-01-02 #> 7 1 28168. 2021-01-02 #> 8 4 27559. 2021-01-02

We can remove a partition and its underlying data using delete_partitions_and_data which uses an expression to match partitions - see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_partitions for more details.

@@ -365,10 +367,10 @@

Creating a table with partitions

#> # A tibble: 4 x 3 #> sales_quarter total_sales report_date #> <int> <dbl> <date> -#> 1 4 27559. 2021-01-01 -#> 2 2 30697. 2021-01-01 -#> 3 3 26419. 2021-01-01 -#> 4 1 28168. 2021-01-01
+#> 1 3 26419. 2021-01-01 +#> 2 1 28168. 2021-01-01 +#> 3 2 30697. 2021-01-01 +#> 4 4 27559. 2021-01-01

Similarly we can remove a table and its data,

delete_table_and_data("new_db_dbtools", "daily_sales_report")

or the whole database.

diff --git a/vignettes/dbtools.Rmd b/vignettes/dbtools.Rmd index 4824bfa..440fe09 100644 --- a/vignettes/dbtools.Rmd +++ b/vignettes/dbtools.Rmd @@ -75,18 +75,18 @@ library(dbtools) ## Reading SQL queries -The `read_sql_query` function is used to obtain R tibbles from SQL queries +The `read_sql_query` function is used to obtain R dataframes from SQL queries sent to Athena. ```{r} read_sql_query("select * from aws_example_dbtools.employees limit 5") ``` -If a standard data frame is preferred the `read_sql` function is provided +If a tibble is preferred the `read_sql` function is provided ```{r} read_sql("select * from aws_example_dbtools.department limit 5", - return_df_as="dataframe") + return_df_as="tibble") ``` or for a `data.table` @@ -96,6 +96,7 @@ read_sql("select * from aws_example_dbtools.sales limit 5", return_df_as="data.table") ``` + ## Creating temporary SQL tables The `create_temp_table` function allows you to create tables which can be @@ -142,7 +143,8 @@ read_sql_query(sql) Sometimes you will want to run similar SQL queries which differ only by, for example, table or column names. In these cases SQL templates can be created to SQL queries populated by templated variables, -using Jinja templating. For example, +using Jinja2 templating (https://jinja2docs.readthedocs.io/en/stable/index.html). +For example, ```{r} sql_template = "select * from {{ db_name }}.{{ table }} limit 10" @@ -235,7 +237,10 @@ read_sql_query("select * from new_db_dbtools.sales_report") ### Creating a table with partitions -Do the same as before but partition the data based on when the report was run. +Do the same as before but partition the data based on when the report was run. +This can make queries more efficient as filtering on the partition columns +reduces the amount of data scanned, plus makes incrementally adding data +easier. ```{r} sql <- " From 2ae0bf565e446eaba537c2284c3eea09b846a725 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 16 Feb 2022 15:43:06 +0000 Subject: [PATCH 20/23] Removed unnecessary code, roxygenised. --- NAMESPACE | 1 - R/read.R | 77 --------------------------- man/convert_athena_type_to_arrow.Rd | 22 -------- man/get_query_execution.Rd | 3 ++ man/read_sql_query.Rd | 2 +- man/start_query_execution.Rd | 3 ++ man/start_query_execution_and_wait.Rd | 3 ++ man/wait_query.Rd | 3 ++ 8 files changed, 13 insertions(+), 101 deletions(-) delete mode 100644 man/convert_athena_type_to_arrow.Rd diff --git a/NAMESPACE b/NAMESPACE index 027d69a..12be57e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,7 +1,6 @@ # Generated by roxygen2: do not edit by hand export("%>%") -export(convert_athena_type_to_arrow) export(create_temp_table) export(delete_database_and_data) export(delete_partitions_and_data) diff --git a/R/read.R b/R/read.R index 9f50c82..e21cb4d 100644 --- a/R/read.R +++ b/R/read.R @@ -1,45 +1,3 @@ -#' Convert an Athena type to an Arrow type -#' -#' @param t A string giving an Athena type -#' -#' @return An Arrow type -#' @export -#' -#' @seealso https://docs.aws.amazon.com/athena/latest/ug/data-types.html -#' @seealso https://arrow.apache.org/docs/r/reference/data-type.html -convert_athena_type_to_arrow <- function(t) { - # Regular expression matches either e.g. decimal(10) or decimal(10, 5) - decimal_match <- stringr::str_match( - t, - "decimal\\(([:digit:]+)(\\s*,\\s*([:digit:]+))?\\)" - ) - if (!is.na(decimal_match[1])) { - precision <- as.numeric(decimal_match[2]) - # Set scale to default 0 if not present - scale <- ifelse(is.na(decimal_match[4]), 0, as.numeric(decimal_match[4])) - return(arrow::decimal(precision, scale)) - } - - switch( - t, - "boolean" = arrow::bool(), - "tinyint" = arrow::int8(), - "smallint" = arrow::int16(), - "int" = arrow::int32(), - "integer" = arrow::int32(), - "bigint" = arrow::int64(), - "double" = arrow::float64(), - "float" = arrow::float32(), - "char" = arrow::string(), - "string" = arrow::string(), - "binary" = arrow::binary(), - "date" = arrow::date32(), - "timestamp" = arrow::timestamp(unit="ms", timezone="UTC"), - arrow::string() - ) %>% return -} - - #' Send an SQL query to Athena and receive a dataframe. #' #' @param sql An SQL query @@ -50,41 +8,6 @@ convert_athena_type_to_arrow <- function(t) { #' @examples #' `df <- dbtools::read_sql_query('select * from my_db.my_table')` read_sql_query <- function(sql) { - # This approach doesn't work because for some reason pydbtools and boto3 - # stopped playing well together under reticulate, with boto3 throwing a - # permissions error which doesn't occur in pure Python. Leaving this code here - # in case it gets fixed as it would be much quicker. - # - # query_id <- dbtools.env$pydb$start_query_execution(sql) - # dbtools.env$pydb$wait_query(query_id) - # athena_status <- dbtools.env$pydb$get_query_execution(query_id) - # - # if (athena_status$Status$State == 'FAILED') { - # stop('SQL query failed with response error;\n', - # athena_status$Status$StateChangeReason) - # } - # - # response <- dbtools.env$boto3$client('athena')$get_query_results( - # QueryExecutionId=athena_status$QueryExecutionId - # ) - # - # # Create arrow schema as a list of arrow::Fields - # schema <- list() - # for (col_info in response$ResultSet$ResultSetMetadata$ColumnInfo) { - # schema <- append( - # schema, - # list(arrow::field(col_info$Name, - # convert_athena_type_to_arrow(col_info$Type))) - # ) - # } - # - # df <- arrow::read_csv_arrow( - # athena_status$ResultConfiguration$OutputLocation, - # schema=schema, - # convert_options=arrow::CsvConvertOptions$create(strings_can_be_null=TRUE) - # ) - - # Download the dataframe result to a parquet temporary file as pandas and # reticulate are frequently incompatible, and load the data into R using # arrow. diff --git a/man/convert_athena_type_to_arrow.Rd b/man/convert_athena_type_to_arrow.Rd deleted file mode 100644 index 1e794d7..0000000 --- a/man/convert_athena_type_to_arrow.Rd +++ /dev/null @@ -1,22 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/read.R -\name{convert_athena_type_to_arrow} -\alias{convert_athena_type_to_arrow} -\title{Convert an Athena type to an Arrow type} -\usage{ -convert_athena_type_to_arrow(t) -} -\arguments{ -\item{t}{A string giving an Athena type} -} -\value{ -An Arrow type -} -\description{ -Convert an Athena type to an Arrow type -} -\seealso{ -https://docs.aws.amazon.com/athena/latest/ug/data-types.html - -https://arrow.apache.org/docs/r/reference/data-type.html -} diff --git a/man/get_query_execution.Rd b/man/get_query_execution.Rd index 7a3f112..189e754 100644 --- a/man/get_query_execution.Rd +++ b/man/get_query_execution.Rd @@ -18,3 +18,6 @@ Fetch query execution details. \examples{ `res <- dbtools::get_query_execution(query_id='query-execution-id')` } +\seealso{ +https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/athena.html#Athena.Client.get_query_execution +} diff --git a/man/read_sql_query.Rd b/man/read_sql_query.Rd index 96222af..0f3937e 100644 --- a/man/read_sql_query.Rd +++ b/man/read_sql_query.Rd @@ -10,7 +10,7 @@ read_sql_query(sql) \item{sql}{An SQL query} } \value{ -Dataframe +Dataframe or tibble if the tibble library is loaded. } \description{ Send an SQL query to Athena and receive a dataframe. diff --git a/man/start_query_execution.Rd b/man/start_query_execution.Rd index eebda6c..ab494ba 100644 --- a/man/start_query_execution.Rd +++ b/man/start_query_execution.Rd @@ -17,3 +17,6 @@ Query execution ID if `wait` is set to `False`, list with the get_query_executio \description{ Start a SQL Query against AWS Athena } +\seealso{ +https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/athena.html#Athena.Client.get_query_execution +} diff --git a/man/start_query_execution_and_wait.Rd b/man/start_query_execution_and_wait.Rd index a5e2924..1631eb2 100644 --- a/man/start_query_execution_and_wait.Rd +++ b/man/start_query_execution_and_wait.Rd @@ -18,3 +18,6 @@ Calls start_query_execution followed by wait_query. \examples{ `res <- dbtools::start_query_execution_and_wait('select * from __temp__.my_table')` } +\seealso{ +https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/athena.html#Athena.Client.get_query_execution +} diff --git a/man/wait_query.Rd b/man/wait_query.Rd index 3c427a8..af3c311 100644 --- a/man/wait_query.Rd +++ b/man/wait_query.Rd @@ -18,3 +18,6 @@ Wait for a query to end. \examples{ `res <- dbtools::wait_query(query_id)` } +\seealso{ +https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/athena.html#Athena.Client.get_query_execution +} From da6a7dec9a1ca15ef1bac44c26e1f5ee65b28ef4 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 16 Feb 2022 16:29:09 +0000 Subject: [PATCH 21/23] More documentation --- R/dbtools.R | 22 ++++++++++++++++++++++ README.md | 2 +- man/dbtools.Rd | 26 ++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 R/dbtools.R create mode 100644 man/dbtools.Rd diff --git a/R/dbtools.R b/R/dbtools.R new file mode 100644 index 0000000..7337dc0 --- /dev/null +++ b/R/dbtools.R @@ -0,0 +1,22 @@ +#' dbtools: A package for accessing AWS Athena from the Analytical Platform. +#' +#' @section About: +#' The dbtools package is used to run SQL queries configured for the +#' Analytical Platform. This package is a reticulated +#' wrapper around the Python library pydbtools +#' which uses AWS Wrangler's Athena module but adds additional functionality +#' (like Jinja templating, creating temporary tables) and alters some configuration +#' to our specification. +#' +#' Alternatively you might want to use +#' Rdbtools, which has the +#' advantages of being R-native, so no messing with `reticulate` and Python, and +#' supporting `dbplyr`. Please note the caveat about support, though. +#' +#' @seealso \url{https://github.com/moj-analytical-services/pydbtools} +#' @seealso \url{https://github.com/moj-analytical-services/Rdbtools} +#' +#' @docType package +#' @name dbtools +NULL +#> NULL diff --git a/README.md b/README.md index 6be72c2..9a0ea67 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Platform should refer to the [Legacy](#legacy) section below. ## About A package that is used to run SQL queries configured for the -Analytical Platform. This packages is a [reticulated](https://rstudio.github.io/reticulate/) +Analytical Platform. This package is a [reticulated](https://rstudio.github.io/reticulate/) wrapper around [pydbtools](https://github.com/moj-analytical-services/pydbtools) which uses AWS Wrangler's Athena module but adds additional functionality (like Jinja templating, creating temporary tables) and alters some configuration diff --git a/man/dbtools.Rd b/man/dbtools.Rd new file mode 100644 index 0000000..c45cab0 --- /dev/null +++ b/man/dbtools.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/dbtools.R +\docType{package} +\name{dbtools} +\alias{dbtools} +\title{dbtools: A package for accessing AWS Athena from the Analytical Platform.} +\section{About}{ + +The dbtools package is used to run SQL queries configured for the +Analytical Platform. This package is a reticulated +wrapper around the Python library pydbtools +which uses AWS Wrangler's Athena module but adds additional functionality +(like Jinja templating, creating temporary tables) and alters some configuration +to our specification. + +Alternatively you might want to use +Rdbtools, which has the +advantages of being R-native, so no messing with `reticulate` and Python, and +supporting `dbplyr`. Please note the caveat about support, though. +} + +\seealso{ +\url{https://github.com/moj-analytical-services/pydbtools} + +\url{https://github.com/moj-analytical-services/Rdbtools} +} From 8ac5f98383fcb5b65c1fa83c1b1049fa84ac53a4 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 16 Feb 2022 16:37:04 +0000 Subject: [PATCH 22/23] Vignette rerun --- doc/dbtools.html | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/dbtools.html b/doc/dbtools.html index 2e645e6..b764281 100644 --- a/doc/dbtools.html +++ b/doc/dbtools.html @@ -315,10 +315,10 @@

Creating and maintaining database tables in Athena

#> # A tibble: 4 x 2 #> sales_quarter total_sales #> <int> <dbl> -#> 1 2 30697. -#> 2 1 28168. -#> 3 3 26419. -#> 4 4 27559. +#> 1 3 26419. +#> 2 4 27559. +#> 3 1 28168. +#> 4 2 30697.

Creating a table with partitions

@@ -352,10 +352,10 @@

Creating a table with partitions

#> # A tibble: 8 x 3 #> sales_quarter total_sales report_date #> <int> <dbl> <date> -#> 1 3 26419. 2021-01-01 -#> 2 1 28168. 2021-01-01 -#> 3 2 30697. 2021-01-01 -#> 4 4 27559. 2021-01-01 +#> 1 1 28168. 2021-01-01 +#> 2 2 30697. 2021-01-01 +#> 3 4 27559. 2021-01-01 +#> 4 3 26419. 2021-01-01 #> 5 3 26419. 2021-01-02 #> 6 2 30697. 2021-01-02 #> 7 1 28168. 2021-01-02 @@ -367,10 +367,10 @@

Creating a table with partitions

#> # A tibble: 4 x 3 #> sales_quarter total_sales report_date #> <int> <dbl> <date> -#> 1 3 26419. 2021-01-01 -#> 2 1 28168. 2021-01-01 -#> 3 2 30697. 2021-01-01 -#> 4 4 27559. 2021-01-01
+#> 1 1 28168. 2021-01-01 +#> 2 2 30697. 2021-01-01 +#> 3 4 27559. 2021-01-01 +#> 4 3 26419. 2021-01-01

Similarly we can remove a table and its data,

delete_table_and_data("new_db_dbtools", "daily_sales_report")

or the whole database.

From aa08f9ef6bb943c0669cfa0dc7b36cea4a2db0af Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 16 Feb 2022 16:38:04 +0000 Subject: [PATCH 23/23] pdf vignette" --- doc/dbtools.pdf | Bin 169142 -> 169941 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/dbtools.pdf b/doc/dbtools.pdf index 017eeb6b774db3bf83768dfd734ca558faf682a4..320d03670dabf33ec3fed4c41dcf77e9070d525d 100644 GIT binary patch delta 37130 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 UTZX0KzoPh$vrJS}+gJziFNHN;3;+NC