From 9bc296fe0fc46c996876a8d7c98788b92aae7d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Nussbaumer?= Date: Sat, 28 Dec 2024 22:16:17 +0100 Subject: [PATCH 1/8] solution for #259 --- R/add_resource.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R/add_resource.R b/R/add_resource.R index 50a7c73..d2c5dec 100644 --- a/R/add_resource.R +++ b/R/add_resource.R @@ -120,6 +120,8 @@ add_resource <- function(package, resource_name, data, schema = NULL, ), class = "frictionless_error_resource_already_exists" ) + } else if (replace && !(resource_name %in% resources(package))) { + replace <- FALSE } # Check data (data frame or path), content of data frame is checked later From f5d22f0efb730d6312616a08c0383adfe2e5e001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Nussbaumer?= Date: Sat, 28 Dec 2024 22:16:25 +0100 Subject: [PATCH 2/8] Add a test --- tests/testthat/test-add_resource.R | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testthat/test-add_resource.R b/tests/testthat/test-add_resource.R index df91460..17e0cc2 100644 --- a/tests/testthat/test-add_resource.R +++ b/tests/testthat/test-add_resource.R @@ -276,6 +276,16 @@ test_that("add_resource() can replace an existing resource", { expect_equal(resources(p), resources(p_replaced)) }) +test_that("add_resource() can add a new resource even with replace=TRUE", { + p <- example_package() + df <- data.frame("col_1" = c(1, 2), "col_2" = c("a", "b")) + expect_no_error( + add_resource(p, "new_resource", df, replace = TRUE) + ) + p_replaced <- add_resource(p, "new_resource", df, replace = TRUE) + expect_equal(c(resources(p), "new_resource"), resources(p_replaced)) +}) + test_that("add_resource() uses provided schema (list or path) or creates one", { p <- create_package() df <- data.frame("col_1" = c(1, 2), "col_2" = c("a", "b")) From fad3d63685fc4227f18220794011b3a027953e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Nussbaumer?= Date: Sat, 28 Dec 2024 22:16:38 +0100 Subject: [PATCH 3/8] minor cosmetics --- R/add_resource.R | 6 +++--- frictionless.Rproj | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/R/add_resource.R b/R/add_resource.R index d2c5dec..235bcae 100644 --- a/R/add_resource.R +++ b/R/add_resource.R @@ -28,7 +28,7 @@ #' @param delim Single character used to separate the fields in the CSV file(s), #' e.g. `\t` for tab delimited file. #' Will be set as `delimiter` in the resource Table Dialect, so read functions -#'. know how to read the file(s). +#' know how to read the file(s). #' @param ... Additional [metadata properties]( #' https://docs.ropensci.org/frictionless/articles/data-resource.html#properties-implementation) #' to add to the resource, e.g. `title = "My title", validated = FALSE`. @@ -72,9 +72,9 @@ #' #' # Replace the resource "observations" with a file-based resource (2 TSV files) #' path_1 <- -#' system.file("extdata", "v1", "observations_1.tsv", package = "frictionless") +#' system.file("extdata", "v1", "observations_1.tsv", package = "frictionless") #' path_2 <- -#' system.file("extdata", "v1", "observations_2.tsv", package = "frictionless") +#' system.file("extdata", "v1", "observations_2.tsv", package = "frictionless") #' package <- add_resource( #' package, #' resource_name = "observations", diff --git a/frictionless.Rproj b/frictionless.Rproj index ef6fa31..7ddcd6e 100644 --- a/frictionless.Rproj +++ b/frictionless.Rproj @@ -1,4 +1,5 @@ Version: 1.0 +ProjectId: b6f8a5ef-2bc2-47c8-a75f-0603379777aa RestoreWorkspace: No SaveWorkspace: No From 66caf0fb4a36b40fce3094969796571283182c7b Mon Sep 17 00:00:00 2001 From: PietrH Date: Thu, 11 Jun 2026 16:06:56 +0200 Subject: [PATCH 4/8] Allow in place creation, fail earlier when replace is set to false. --- R/add_resource.R | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/R/add_resource.R b/R/add_resource.R index 8986d08..68308e9 100644 --- a/R/add_resource.R +++ b/R/add_resource.R @@ -120,8 +120,6 @@ add_resource <- function(package, resource_name, data, schema = NULL, ), class = "frictionless_error_resource_already_exists" ) - } else if (replace && !(resource_name %in% resources(package))) { - replace <- FALSE } # Check data (data frame or path), content of data frame is checked later @@ -212,12 +210,25 @@ add_resource <- function(package, resource_name, data, schema = NULL, attr(resource, "path") <- "added" } - # Add or replace resource (needs to be wrapped in its own list) - if (replace) { - index <- which(purrr::map(package$resources, "name") == resource_name) - package$resources[index] <- list(resource) - } else { + # Find the index of the index of the name of the resource if it exists, or 0 + # otherwise + index <- purrr::detect_index( + package$resources, + .f = \(resource) { + identical( + resource$name, + resource_name + ) + } + ) + + # Add the resource if it's missing + if (index == 0L) { package$resources <- append(package$resources, list(resource)) + } else { + # Or replace it if not, replace = FALSE on an existing resource should fail + # earlier + package$resources[[index]] <- resource } return(package) From bf7deb4a241862d4dea987544d36d006f0be6f18 Mon Sep 17 00:00:00 2001 From: Peter Desmet <600993+peterdesmet@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:15:02 +0200 Subject: [PATCH 5/8] Remove ProjectId --- frictionless.Rproj | 1 - 1 file changed, 1 deletion(-) diff --git a/frictionless.Rproj b/frictionless.Rproj index 7ddcd6e..ef6fa31 100644 --- a/frictionless.Rproj +++ b/frictionless.Rproj @@ -1,5 +1,4 @@ Version: 1.0 -ProjectId: b6f8a5ef-2bc2-47c8-a75f-0603379777aa RestoreWorkspace: No SaveWorkspace: No From 00fc2df956bc109436cd2f42d5e9f1e1ce04d1c6 Mon Sep 17 00:00:00 2001 From: Peter Desmet <600993+peterdesmet@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:49:52 +0200 Subject: [PATCH 6/8] Repharse "replace" parameter --- R/add_resource.R | 4 ++-- man/add_resource.Rd | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/add_resource.R b/R/add_resource.R index 236c8c0..c025b50 100644 --- a/R/add_resource.R +++ b/R/add_resource.R @@ -23,8 +23,8 @@ #' @param schema Either a list, or path or URL to a JSON file describing a Table #' Schema for the `data`. #' If not provided, one will be created using [create_schema()]. -#' @param replace If `TRUE`, the added resource will replace an existing -#' resource with the same name. +#' @param replace If `TRUE`, allows an existing resource of the same name to be +#' replaced. #' @param delim Delimiter for the CSV file(s) referenced in `data` (e.g. `\t` #' for a tab-separated file). #' Will be set as `delimiter` in the resource Table Dialect, so read functions diff --git a/man/add_resource.Rd b/man/add_resource.Rd index b14f82b..6e9fd35 100644 --- a/man/add_resource.Rd +++ b/man/add_resource.Rd @@ -36,8 +36,8 @@ and properties. Schema for the \code{data}. If not provided, one will be created using \code{\link[=create_schema]{create_schema()}}.} -\item{replace}{If \code{TRUE}, the added resource will replace an existing -resource with the same name.} +\item{replace}{If \code{TRUE}, allows an existing resource of the same name to be +replaced.} \item{delim}{Delimiter for the CSV file(s) referenced in \code{data} (e.g. \verb{\\t} for a tab-separated file). From b89f423ca1cf8204d754f332bbfc22672874c4fd Mon Sep 17 00:00:00 2001 From: Peter Desmet <600993+peterdesmet@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:50:35 +0200 Subject: [PATCH 7/8] Use resource_names in test --- tests/testthat/test-add_resource.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-add_resource.R b/tests/testthat/test-add_resource.R index c8efe12..fcc8244 100644 --- a/tests/testthat/test-add_resource.R +++ b/tests/testthat/test-add_resource.R @@ -276,14 +276,14 @@ test_that("add_resource() can replace an existing resource", { expect_equal(resource_names(p), resource_names(p_replaced)) }) -test_that("add_resource() can add a new resource even with replace=TRUE", { +test_that("add_resource() can add a new resource even with replace = TRUE", { p <- example_package() df <- data.frame("col_1" = c(1, 2), "col_2" = c("a", "b")) expect_no_error( add_resource(p, "new_resource", df, replace = TRUE) ) p_replaced <- add_resource(p, "new_resource", df, replace = TRUE) - expect_equal(c(resources(p), "new_resource"), resources(p_replaced)) + expect_equal(c(resource_names(p), "new_resource"), resource_names(p_replaced)) }) test_that("add_resource() uses provided schema (list or path) or creates one", { From 5a97f1015706b1bb03fe97905ae4bbc067979b2c Mon Sep 17 00:00:00 2001 From: Peter Desmet <600993+peterdesmet@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:54:23 +0200 Subject: [PATCH 8/8] Use more readable approach for add/replace Use which() on resource_names --- R/add_resource.R | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/R/add_resource.R b/R/add_resource.R index c025b50..8d9e1e6 100644 --- a/R/add_resource.R +++ b/R/add_resource.R @@ -211,24 +211,13 @@ add_resource <- function(package, resource_name, data, schema = NULL, attr(resource, "path") <- "added" } - # Find the index of the index of the name of the resource if it exists, or 0 - # otherwise - index <- purrr::detect_index( - package$resources, - .f = \(resource) { - identical( - resource$name, - resource_name - ) - } - ) - - # Add the resource if it's missing - if (index == 0L) { + # Add or replace resource + index <- which(resource_names(package) == resource_name) + if (length(index) == 0) { + # Add resource if it does not exist (also for replace = TRUE) package$resources <- append(package$resources, list(resource)) } else { - # Or replace it if not, replace = FALSE on an existing resource should fail - # earlier + # Replace existing resource (not done for replace = FALSE, see higher) package$resources[[index]] <- resource }