diff --git a/R/data-model-helpers.R b/R/data-model-helpers.R index f83cd58eef..4d350a9649 100644 --- a/R/data-model-helpers.R +++ b/R/data-model-helpers.R @@ -16,34 +16,3 @@ new_data_model <- function(tables, columns, references) { class = "data_model" ) } - -get_datamodel_from_overview <- function(overview) { - new_data_model( - tables = datamodel_tables_from_overview(overview), - columns = datamodel_columns_from_overview(overview), - references = datamodel_references_from_overview(overview) - ) -} - -datamodel_tables_from_overview <- function(overview) { - overview %>% - distinct(table) %>% - add_column(segment = NA_character_, display = NA_character_) %>% - as.data.frame(stringsAsFactors = FALSE) -} - -datamodel_columns_from_overview <- function(overview) { - overview %>% - select(column, type, table, key, ref, ref_col) %>% - mutate(key = as.numeric(key)) %>% - as.data.frame(stringsAsFactors = FALSE) -} - -datamodel_references_from_overview <- function(overview) { - overview %>% - filter(!is.na(ref)) %>% - select(table, column, ref, ref_col) %>% - mutate(ref_id = as.numeric(row_number())) %>% - add_column(ref_col_num = 1) %>% - as.data.frame(stringsAsFactors = FALSE) -} diff --git a/R/datamodelr-code.R b/R/datamodelr-code.R index 8445cc2e19..e9b384df46 100644 --- a/R/datamodelr-code.R +++ b/R/datamodelr-code.R @@ -1,10 +1,6 @@ # data_model code directly from {datamodelr} -------------------------------------- -is.data_model <- function(x) { - inherits(x, "data_model") -} - bdm_create_references <- function(col_table) { if (!inherits(col_table, "data.frame")) stop("Input must be a data frame.") diff --git a/R/db-helpers.R b/R/db-helpers.R index 177f8e7547..27fc9ece6c 100644 --- a/R/db-helpers.R +++ b/R/db-helpers.R @@ -3,16 +3,19 @@ unique_db_table_name <- local({ function(table_name) { i <<- i + 1 - glue("{table_name}_", systime_convenient(), "_", get_pid(), "_", as.character(i)) + glue("{table_name}_", as.character(i), "_", systime_convenient(), "_", get_pid()) } }) systime_convenient <- function() { + # FIXME: Race condition here, but fast enough + local_options(digits.secs = 6) + if (Sys.getenv("IN_PKGDOWN") != "") { "2020_08_28_07_13_03" } else { time <- as.character(Sys.time()) - gsub("[-: ]", "_", time) + gsub("[-:. ]", "_", time) } } diff --git a/R/dm-from-src.R b/R/dm-from-src.R index 9092b7c6d6..17408f888a 100644 --- a/R/dm-from-src.R +++ b/R/dm-from-src.R @@ -65,32 +65,36 @@ dm_from_src <- function(src = NULL, table_names = NULL, learn_keys = NULL, # FIXME: Get rid of legacy method once it works for all if (is.null(learn_keys) || isTRUE(learn_keys)) { - dm_learned <- dm_learn_from_db(src, ...) - - if (is.null(dm_learned)) { - if (isTRUE(learn_keys)) { - abort_learn_keys() - } - - inform("Keys could not be queried, use `learn_keys = FALSE` to mute this message.") - } else { - if (is_null(learn_keys)) { - inform("Keys queried successfully, use `learn_keys = TRUE` to mute this message.") + # FIXME: Try to make it work everywhere + tryCatch( + { + dm_learned <- dm_learn_from_db(src, ...) + if (is_null(learn_keys)) { + inform("Keys queried successfully, use `learn_keys = TRUE` to mute this message.") + } + + if (is_null(table_names)) { + return(dm_learned) + } + + tbls_in_dm <- src_tbls_impl(dm_learned) + + if (!all(table_names %in% tbls_in_dm)) { + abort_tbl_access(setdiff(table_names, tbls_in_dm)) + } + tbls_req <- intersect(tbls_in_dm, table_names) + + return(dm_learned %>% dm_select_tbl(!!!tbls_req)) + }, + error = function(e) { + if (isTRUE(learn_keys)) { + abort_learn_keys(conditionMessage(e)) + } + # FIXME: Use new-style error messages. + inform(paste0("Keys could not be queried: ", conditionMessage(e), ". Use `learn_keys = FALSE` to mute this message.")) + NULL } - - if (is_null(table_names)) { - return(dm_learned) - } - - tbls_in_dm <- src_tbls_impl(dm_learned) - - if (!all(table_names %in% tbls_in_dm)) { - abort_tbl_access(setdiff(table_names, tbls_in_dm)) - } - tbls_req <- intersect(tbls_in_dm, table_names) - - return(dm_learned %>% dm_select_tbl(!!!tbls_req)) - } + ) } if (is_null(table_names)) { @@ -144,12 +148,16 @@ quote_ids <- function(x, con, schema = NULL) { # Errors ------------------------------------------------------------------ -abort_learn_keys <- function() { - abort(error_txt_learn_keys(), class = dm_error_full("learn_keys")) +abort_learn_keys <- function(reason) { + abort(error_txt_learn_keys(reason), class = dm_error_full("learn_keys")) } -error_txt_learn_keys <- function() { - "Failed to learn keys from database. Use `learn_keys = FALSE` to work around." +error_txt_learn_keys <- function(reason) { + # FIXME: Use new-style error messages. + paste0( + "Failed to learn keys from database: ", reason, + ". Use `learn_keys = FALSE` to work around." + ) } abort_tbl_access <- function(bad) { diff --git a/R/learn.R b/R/learn.R index 015f656222..ed5235f48c 100644 --- a/R/learn.R +++ b/R/learn.R @@ -41,10 +41,6 @@ dm_learn_from_db <- function(dest, dbname = NA, ...) { return() } - if (!is_mssql(con)) { - return(dm_learn_from_db_legacy(con, dbname, ...)) - } - dm_learn_from_db_meta(con, catalog = dbname, ...) } @@ -111,7 +107,10 @@ dm_learn_from_db_meta <- function(con, catalog = NULL, schema = NULL, name_forma left_join(columns, select = c(column_name, dm_name, table_catalog, table_schema, table_name)) %>% dm_update_zoomed() %>% dm_zoom_to(constraint_column_usage) %>% - left_join(columns, select = c(column_name, dm_name, table_catalog, table_schema, table_name)) %>% + # + # inner_join(): Matching column sometimes not found on Postgres + inner_join(columns, select = c(column_name, dm_name, table_catalog, table_schema, table_name)) %>% + # dm_update_zoomed() %>% dm_select_tbl(-columns) %>% dm_rename(constraint_column_usage, constraint_column_usage.table_catalog = table_catalog) %>% @@ -164,38 +163,6 @@ dm_learn_from_db_meta <- function(con, catalog = NULL, schema = NULL, name_forma new_dm2(tables, pks_df, fks_df) } -dm_learn_from_db_legacy <- function(con, dbname, ...) { - sql <- db_learn_query(con, dbname = dbname, ...) - if (is.null(sql)) { - return() - } - - overview <- - dbGetQuery(con, sql) %>% - as_tibble() - - if (nrow(overview) == 0) { - return() - } - - table_names <- - overview %>% - arrange(table) %>% - distinct(schema, table) %>% - transmute( - name = table, - value = schema_if(schema = schema, table = table, con = con, dbname = dbname) - ) %>% - deframe() - - # FIXME: Use tbl_sql(vars = ...) - tables <- map(table_names, ~ tbl(con, dbplyr::ident_q(.x))) - - data_model <- get_datamodel_from_overview(overview) - - legacy_new_dm(tables, data_model) -} - schema_if <- function(schema, table, con, dbname = NULL) { table_sql <- DBI::dbQuoteIdentifier(con, table) if (is_null(dbname) || is.na(dbname) || dbname == "") { @@ -213,184 +180,3 @@ schema_if <- function(schema, table, con, dbname = NULL) { SQL(paste0(DBI::dbQuoteIdentifier(con, dbname), ".", DBI::dbQuoteIdentifier(con, schema), ".", table_sql)) } } - -db_learn_query <- function(dest, dbname, ...) { - if (is_postgres(dest)) { - return(postgres_learn_query(dest, ...)) - } -} - -postgres_learn_query <- function(con, schema = "public", table_type = "BASE TABLE") { - sprintf( - "SELECT - t.table_schema as schema, - t.table_name as table, - c.column_name as column, - case when pk.column_name is null then 0 else 1 end as key, - fk.ref, - fk.ref_col, - case c.is_nullable when 'YES' then 0 else 1 end as mandatory, - c.data_type as type, - c.ordinal_position as column_order - - from - information_schema.columns c - inner join information_schema.tables t on - t.table_name = c.table_name - and t.table_schema = c.table_schema - and t.table_catalog = c.table_catalog - - left join -- primary keys - ( SELECT DISTINCT - tc.constraint_name, tc.table_name, tc.table_schema, tc.table_catalog, kcu.column_name - FROM - information_schema.table_constraints AS tc - JOIN information_schema.key_column_usage AS kcu ON - tc.constraint_name = kcu.constraint_name - WHERE constraint_type = 'PRIMARY KEY' - ) pk on - pk.table_name = c.table_name - and pk.column_name = c.column_name - and pk.table_schema = c.table_schema - and pk.table_catalog = c.table_catalog - - left join -- foreign keys - ( SELECT DISTINCT - tc.constraint_name, kcu.table_name, kcu.table_schema, kcu.table_catalog, kcu.column_name, - ccu.table_name as ref, - ccu.column_name as ref_col - FROM - information_schema.table_constraints AS tc - JOIN information_schema.key_column_usage AS kcu ON - tc.constraint_name = kcu.constraint_name - JOIN information_schema.constraint_column_usage AS ccu ON - ccu.constraint_name = tc.constraint_name - WHERE tc.constraint_type = 'FOREIGN KEY' - ) fk on - fk.table_name = c.table_name - and fk.table_schema = c.table_schema - and fk.table_catalog = c.table_catalog - and fk.column_name = c.column_name - - where - c.table_schema = %s - and t.table_type = %s", - dbQuoteString(con, schema), - dbQuoteString(con, table_type) - ) -} - -# FIXME: only needed for `dm_learn_from_db()` <- needs to be implemented in a different manner -legacy_new_dm <- function(tables = NULL, data_model = NULL) { - if (is_null(tables) && is_null(data_model)) { - return(empty_dm()) - } - - if (!all_same_source(tables)) abort_not_same_src() - stopifnot(is.data_model(data_model)) - - columns <- as_tibble(data_model$columns) - - data_model_tables <- data_model$tables - - stopifnot(all(names(tables) %in% data_model_tables$table)) - stopifnot(all(data_model_tables$table %in% names(tables))) - - pks <- - columns %>% - select(column, table, key) %>% - filter(key > 0) %>% - select(-key) - - if (is.null(data_model$references) || nrow(data_model$references) == 0) { - fks <- tibble( - table = character(), - column = character(), - ref = character(), - ref_column = character(), - on_delete = character() - ) - } else { - fks <- - data_model$references %>% - transmute(table, column, ref, ref_column = ref_col, on_delete = "no_action") %>% - as_tibble() - } - - # Legacy - data <- unname(tables[data_model_tables$table]) - - table <- data_model_tables$table - segment <- data_model_tables$segment - # would be logical NA otherwise, but if set, it is class `character` - display <- as.character(data_model_tables$display) - zoom <- new_zoom() - col_tracker_zoom <- new_col_tracker_zoom() - - pks <- - pks %>% - # Legacy compatibility - mutate(column = as.list(column, list())) %>% - nest_compat(pks = -table) - - pks <- - tibble( - table = setdiff(table, pks$table), - pks = list_of(new_pk()) - ) %>% - vec_rbind(pks) - - # Legacy compatibility - fks$column <- as.list(fks$column) - fks$ref_column <- as.list(fks$ref_column) - - fks <- - fks %>% - nest_compat(fks = -ref) %>% - rename(table = ref) - - fks <- - tibble( - table = setdiff(table, fks$table), - fks = list_of(new_fk()) - ) %>% - vec_rbind(fks) - - # there are no filters at this stage - filters <- - tibble( - table = table, - filters = list_of(new_filter()) - ) - - def <- - tibble(table, data, segment, display) %>% - left_join(pks, by = "table") %>% - left_join(fks, by = "table") %>% - left_join(filters, by = "table") %>% - left_join(zoom, by = "table") %>% - left_join(col_tracker_zoom, by = "table") - - new_dm3(def) -} - -nest_compat <- function(.data, ...) { - # `...` has to be name-variable pair (see `?nest()`) of length 1 - quos <- enquos(...) - stopifnot(length(quos) == 1) - new_col <- names(quos) - if (nrow(.data) == 0) { - remove <- eval_select_indices(quo(c(...)), colnames(.data)) - keep <- setdiff(seq_along(.data), remove) - - nest <- new_list_of(list(), ptype = .data %>% select(!!!remove)) - - .data %>% - select(!!!keep) %>% - mutate(!!new_col := !!nest) - } else { - .data %>% - nest(...) %>% - mutate_at(vars(!!!new_col), as_list_of) - } -} diff --git a/R/meta.R b/R/meta.R index 3826c94514..fce70084c4 100644 --- a/R/meta.R +++ b/R/meta.R @@ -68,19 +68,22 @@ dm_meta_raw <- function(con, catalog) { )) if (is_postgres(src)) { - info_fkc <- + info_pkc <- table_constraints %>% select(constraint_catalog, constraint_schema, constraint_name, constraint_type) %>% - filter(constraint_type == "FOREIGN KEY") + filter(constraint_type %in% c("PRIMARY KEY", "FOREIGN KEY")) - constraint_column_usage <- - tbl_lc(src, dbplyr::ident_q("information_schema.constraint_column_usage")) %>% - group_by(constraint_catalog, constraint_schema, constraint_name) %>% - mutate(ordinal_position = row_number()) %>% - ungroup() %>% - semi_join(info_fkc, by = c("constraint_catalog", "constraint_schema", "constraint_name")) + key_column_usage <- + key_column_usage %>% + semi_join(info_pkc, by = c("constraint_catalog", "constraint_schema", "constraint_name")) - # FIXME: Also has `position_in_unique_constraint`, used elsewhere? + # Need hand-crafted query for now + constraint_column_usage <- + tbl(src, sql(postgres_column_constraints), vars = c( + "table_catalog", "table_schema", "table_name", "column_name", + "constraint_catalog", "constraint_schema", "constraint_name", + "ordinal_position" + )) } else if (is_mssql(src)) { constraint_column_usage <- mssql_constraint_column_usage(src, table_constraints, catalog) } diff --git a/R/postgres.R b/R/postgres.R new file mode 100644 index 0000000000..4f36caa83e --- /dev/null +++ b/R/postgres.R @@ -0,0 +1,48 @@ +# From \d+ information_schema.constraint_column_usage, adapted to include colnum +postgres_column_constraints <- "SELECT current_database()::information_schema.sql_identifier AS table_catalog, + x.tblschema::information_schema.sql_identifier AS table_schema, + x.tblname::information_schema.sql_identifier AS table_name, + x.colname::information_schema.sql_identifier AS column_name, + current_database()::information_schema.sql_identifier AS constraint_catalog, + x.cstrschema::information_schema.sql_identifier AS constraint_schema, + x.cstrname::information_schema.sql_identifier AS constraint_name, + x.colnum::information_schema.cardinal_number AS ordinal_position + + FROM ( SELECT DISTINCT nr.nspname, + r.relname, + r.relowner, + a.attname, + NULL::smallint AS attnum, + nc.nspname, + c.conname + FROM pg_namespace nr, + pg_class r, + pg_attribute a, + pg_depend d, + pg_namespace nc, + pg_constraint c + WHERE nr.oid = r.relnamespace AND r.oid = a.attrelid AND d.refclassid = 'pg_class'::regclass::oid AND d.refobjid = r.oid AND d.refobjsubid = a.attnum AND d.classid = 'pg_constraint'::regclass::oid AND d.objid = c.oid AND c.connamespace = nc.oid AND c.contype = 'c'::\"char\" AND (r.relkind = ANY (ARRAY['r'::\"char\", 'p'::\"char\"])) AND NOT a.attisdropped + UNION ALL + SELECT nr.nspname, + r.relname, + r.relowner, + a.attname, + a.attnum, + nc.nspname, + c.conname + FROM pg_namespace nr, + pg_class r, + pg_attribute a, + pg_namespace nc, + pg_constraint c + WHERE nr.oid = r.relnamespace AND r.oid = a.attrelid AND nc.oid = c.connamespace AND r.oid = + CASE c.contype + WHEN 'f'::\"char\" THEN c.confrelid + ELSE c.conrelid + END AND (a.attnum = ANY ( + CASE c.contype + WHEN 'f'::\"char\" THEN c.confkey + ELSE c.conkey + END)) AND NOT a.attisdropped AND (c.contype = ANY (ARRAY['f'::\"char\"])) AND (r.relkind = ANY (ARRAY['r'::\"char\", 'p'::\"char\"]))) x(tblschema, tblname, tblowner, colname, colnum, cstrschema, cstrname) + WHERE pg_has_role(x.tblowner, 'USAGE'::text) +" diff --git a/tests/testthat/_snaps/error-helpers.md b/tests/testthat/_snaps/error-helpers.md index b65c0741d6..89fab2ad12 100644 --- a/tests/testthat/_snaps/error-helpers.md +++ b/tests/testthat/_snaps/error-helpers.md @@ -206,10 +206,10 @@ Error in `abort_only_possible_w_zoom()`: ! You can't call `dm_update_zoomed()` on an unzoomed `dm`. Consider using `dm_zoom_to()` first. Code - abort_learn_keys() + abort_learn_keys("some reason") Condition Error in `abort_learn_keys()`: - ! Failed to learn keys from database. Use `learn_keys = FALSE` to work around. + ! Failed to learn keys from database: some reason. Use `learn_keys = FALSE` to work around. Code abort_tbl_access("accessdenied") Condition diff --git a/tests/testthat/_snaps/learn.md b/tests/testthat/_snaps/learn.md index 065e3c5b2d..f615bde7f9 100644 --- a/tests/testthat/_snaps/learn.md +++ b/tests/testthat/_snaps/learn.md @@ -1,40 +1,9 @@ -# dm_meta() data model +# Standard learning from MSSQL (schema 'dbo') or Postgres (schema 'public') and get_src_tbl_names() works? Code - dm_meta(my_test_src()) %>% dm_paste(options = c("select", "keys", "color")) + dm_from_src(src_db)[integer()] Message - dm::dm( - schemata, - tables, - columns, - table_constraints, - key_column_usage, - constraint_column_usage, - ) %>% - dm::dm_select(schemata, catalog_name, schema_name) %>% - dm::dm_select(tables, table_catalog, table_schema, table_name, table_type) %>% - dm::dm_select(columns, table_catalog, table_schema, table_name, column_name, ordinal_position, column_default, is_nullable) %>% - dm::dm_select(table_constraints, constraint_catalog, constraint_schema, constraint_name, table_catalog, table_schema, table_name, constraint_type) %>% - dm::dm_select(key_column_usage, constraint_catalog, constraint_schema, constraint_name, table_catalog, table_schema, table_name, column_name, ordinal_position) %>% - dm::dm_select(constraint_column_usage, table_catalog, table_schema, table_name, column_name, constraint_catalog, constraint_schema, constraint_name, ordinal_position) %>% - dm::dm_add_pk(schemata, c(catalog_name, schema_name)) %>% - dm::dm_add_pk(tables, c(table_catalog, table_schema, table_name)) %>% - dm::dm_add_pk(columns, c(table_catalog, table_schema, table_name, column_name)) %>% - dm::dm_add_pk(table_constraints, c(constraint_catalog, constraint_schema, constraint_name)) %>% - dm::dm_add_pk(key_column_usage, c(constraint_catalog, constraint_schema, constraint_name, ordinal_position)) %>% - dm::dm_add_pk(constraint_column_usage, c(constraint_catalog, constraint_schema, constraint_name, ordinal_position)) %>% - dm::dm_add_fk(tables, c(table_catalog, table_schema), schemata) %>% - dm::dm_add_fk(columns, c(table_catalog, table_schema, table_name), tables) %>% - dm::dm_add_fk(table_constraints, c(table_catalog, table_schema, table_name), tables) %>% - dm::dm_add_fk(key_column_usage, c(table_catalog, table_schema, table_name, column_name), columns) %>% - dm::dm_add_fk(constraint_column_usage, c(table_catalog, table_schema, table_name, column_name), columns) %>% - dm::dm_add_fk(key_column_usage, c(constraint_catalog, constraint_schema, constraint_name), table_constraints) %>% - dm::dm_add_fk(constraint_column_usage, c(constraint_catalog, constraint_schema, constraint_name), table_constraints) %>% - dm::dm_add_fk(constraint_column_usage, c(constraint_catalog, constraint_schema, constraint_name, ordinal_position), key_column_usage) %>% - dm::dm_set_colors(`#0000FFFF` = schemata) %>% - dm::dm_set_colors(`#A52A2AFF` = tables) %>% - dm::dm_set_colors(`#A52A2AFF` = columns) %>% - dm::dm_set_colors(`#008B00FF` = table_constraints) %>% - dm::dm_set_colors(`#FFA500FF` = key_column_usage) %>% - dm::dm_set_colors(`#FFA500FF` = constraint_column_usage) + Keys queried successfully, use `learn_keys = TRUE` to mute this message. + Output + dm() diff --git a/tests/testthat/_snaps/meta.md b/tests/testthat/_snaps/meta.md new file mode 100644 index 0000000000..66f0f1c4c5 --- /dev/null +++ b/tests/testthat/_snaps/meta.md @@ -0,0 +1,47 @@ +# dummy + + Code + TRUE + Output + [1] TRUE + +# dm_meta() data model + + Code + dm_meta(my_test_src()) %>% dm_paste(options = c("select", "keys", "color")) + Message + dm::dm( + schemata, + tables, + columns, + table_constraints, + key_column_usage, + constraint_column_usage, + ) %>% + dm::dm_select(schemata, catalog_name, schema_name) %>% + dm::dm_select(tables, table_catalog, table_schema, table_name, table_type) %>% + dm::dm_select(columns, table_catalog, table_schema, table_name, column_name, ordinal_position, column_default, is_nullable) %>% + dm::dm_select(table_constraints, constraint_catalog, constraint_schema, constraint_name, table_catalog, table_schema, table_name, constraint_type) %>% + dm::dm_select(key_column_usage, constraint_catalog, constraint_schema, constraint_name, table_catalog, table_schema, table_name, column_name, ordinal_position) %>% + dm::dm_select(constraint_column_usage, table_catalog, table_schema, table_name, column_name, constraint_catalog, constraint_schema, constraint_name, ordinal_position) %>% + dm::dm_add_pk(schemata, c(catalog_name, schema_name)) %>% + dm::dm_add_pk(tables, c(table_catalog, table_schema, table_name)) %>% + dm::dm_add_pk(columns, c(table_catalog, table_schema, table_name, column_name)) %>% + dm::dm_add_pk(table_constraints, c(constraint_catalog, constraint_schema, constraint_name)) %>% + dm::dm_add_pk(key_column_usage, c(constraint_catalog, constraint_schema, constraint_name, ordinal_position)) %>% + dm::dm_add_pk(constraint_column_usage, c(constraint_catalog, constraint_schema, constraint_name, ordinal_position)) %>% + dm::dm_add_fk(tables, c(table_catalog, table_schema), schemata) %>% + dm::dm_add_fk(columns, c(table_catalog, table_schema, table_name), tables) %>% + dm::dm_add_fk(table_constraints, c(table_catalog, table_schema, table_name), tables) %>% + dm::dm_add_fk(key_column_usage, c(table_catalog, table_schema, table_name, column_name), columns) %>% + dm::dm_add_fk(constraint_column_usage, c(table_catalog, table_schema, table_name, column_name), columns) %>% + dm::dm_add_fk(key_column_usage, c(constraint_catalog, constraint_schema, constraint_name), table_constraints) %>% + dm::dm_add_fk(constraint_column_usage, c(constraint_catalog, constraint_schema, constraint_name), table_constraints) %>% + dm::dm_add_fk(constraint_column_usage, c(constraint_catalog, constraint_schema, constraint_name, ordinal_position), key_column_usage) %>% + dm::dm_set_colors(`#0000FFFF` = schemata) %>% + dm::dm_set_colors(`#A52A2AFF` = tables) %>% + dm::dm_set_colors(`#A52A2AFF` = columns) %>% + dm::dm_set_colors(`#008B00FF` = table_constraints) %>% + dm::dm_set_colors(`#FFA500FF` = key_column_usage) %>% + dm::dm_set_colors(`#FFA500FF` = constraint_column_usage) + diff --git a/tests/testthat/test-error-helpers.R b/tests/testthat/test-error-helpers.R index b8a65364c6..95912a0df6 100644 --- a/tests/testthat/test-error-helpers.R +++ b/tests/testthat/test-error-helpers.R @@ -42,7 +42,7 @@ test_that("output", { abort_con_only_for_dbi() abort_only_possible_wo_zoom("dm_zoom_to") abort_only_possible_w_zoom("dm_update_zoomed") - abort_learn_keys() + abort_learn_keys("some reason") abort_tbl_access("accessdenied") abort_unnamed_table_list() abort_need_unique_names("clone") diff --git a/tests/testthat/test-learn.R b/tests/testthat/test-learn.R index 1a617e5598..70be4a761a 100644 --- a/tests/testthat/test-learn.R +++ b/tests/testthat/test-learn.R @@ -1,21 +1,8 @@ # FIXME: #313: learn only from current source -# produces a randomized schema name with a length of 4-10 characters -# consisting of the symbols in `reservoir` -random_schema <- function() { - reservoir <- c(letters, LETTERS, "'", "-", "_", as.character(0:9)) - how_long <- sample(4:10, 1) - paste0(reservoir[sample(seq_len(length(reservoir)), how_long, replace = TRUE)], collapse = "") -} - -schema_name <- random_schema() - test_that("Standard learning from MSSQL (schema 'dbo') or Postgres (schema 'public') and get_src_tbl_names() works?", { skip_if_src_not(c("mssql", "postgres")) - # FIXME: Enable when fixed - skip_if_src("postgres") - # dm_learn_from_mssql() -------------------------------------------------- src_db <- my_test_src() @@ -49,7 +36,40 @@ test_that("Standard learning from MSSQL (schema 'dbo') or Postgres (schema 'publ sort(dbQuoteIdentifier(src_db$con, remote_tbl_names)) ) - expect_message(dm_db_learned_all <- dm_from_src(src_db)) + expect_snapshot({ + dm_from_src(src_db)[integer()] + }) +}) + +test_that("Standard learning from MSSQL (schema 'dbo') or Postgres (schema 'public') and get_src_tbl_names() works?", { + skip_if_src_not(c("mssql", "postgres")) + + # dm_learn_from_mssql() -------------------------------------------------- + src_db <- my_test_src() + + # create an object on the MSSQL-DB that can be learned + withr::defer( + try(walk( + remote_tbl_names, + ~ try(dbExecute(src_db$con, paste0("DROP TABLE ", .x))) + )) + ) + + dm_for_filter_copied <- copy_dm_to(src_db, dm_for_filter(), temporary = FALSE, table_names = ~ DBI::SQL(unique_db_table_name(.x))) + order_of_deletion <- c("tf_2", "tf_1", "tf_5", "tf_6", "tf_4", "tf_3") + + remote_tbl_names <- + map_chr( + dm_get_tables(dm_for_filter_copied)[order_of_deletion], + dbplyr::remote_name + ) %>% + SQL() %>% + DBI::dbUnquoteIdentifier(conn = src_db$con) %>% + map_chr(~ .x@name[["table"]]) + + remote_tbl_map <- set_names(remote_tbl_names, gsub("^(tf_.).*$", "\\1", remote_tbl_names)) + + expect_silent(dm_db_learned_all <- dm_from_src(src_db, learn_keys = TRUE)) # Select and fix table names dm_db_learned <- @@ -91,6 +111,16 @@ test_that("Standard learning from MSSQL (schema 'dbo') or Postgres (schema 'publ test_that("Learning from specific schema on MSSQL or Postgres works?", { skip_if_src_not(c("mssql", "postgres")) + # produces a randomized schema name with a length of 4-10 characters + # consisting of the symbols in `reservoir` + random_schema <- function() { + reservoir <- c(letters, LETTERS, "'", "-", "_", as.character(0:9)) + how_long <- sample(4:10, 1) + paste0(reservoir[sample(seq_len(length(reservoir)), how_long, replace = TRUE)], collapse = "") + } + + schema_name <- random_schema() + src_db <- my_test_src() con_db <- src_db$con @@ -371,12 +401,3 @@ test_that("Learning from a specific schema in another DB for MSSQL works?", { dm_local_no_keys ) }) - -test_that("dm_meta() data model", { - skip_if_src_not("mssql") - - expect_snapshot({ - dm_meta(my_test_src()) %>% - dm_paste(options = c("select", "keys", "color")) - }) -}) diff --git a/tests/testthat/test-meta.R b/tests/testthat/test-meta.R new file mode 100644 index 0000000000..f6a2ebb426 --- /dev/null +++ b/tests/testthat/test-meta.R @@ -0,0 +1,15 @@ +test_that("dummy", { + # To avoid deletion of file + expect_snapshot({ + TRUE + }) +}) + +test_that("dm_meta() data model", { + skip_if_src_not(c("mssql", "postgres")) + + expect_snapshot({ + dm_meta(my_test_src()) %>% + dm_paste(options = c("select", "keys", "color")) + }) +})