R/filter_out.R

Defines functions duckplyr_filter_out filter_out.duckplyr_df

Documented in filter_out.duckplyr_df

# Generated by 02-duckplyr_df-methods.R
#' @rdname filter.duckplyr_df
#' @export
filter_out.duckplyr_df <- function(.data, ..., .by = NULL, .preserve = FALSE) {
  force(.data)

  dots <- dplyr_quosures(...)
  check_filter(dots)

  by <- enquo(.by)

  duckplyr_error <- rel_try(list(name = "filter_out", x = .data, args = try_list(dots = dots, by = by, preserve = .preserve)),
    #' @section Fallbacks:
    #' There is no DuckDB translation in `filter_out.duckplyr_df()`
    #' - with no filter conditions,
    #' - nor for a grouped operation (if `.by` is set).
    #'
    #' These features fall back to [dplyr::filter_out()], see `vignette("fallback")` for details.
    "Can't use relational without filter conditions." = (length(dots) == 0),
    "{.code filter_out(.by = ...)} not implemented, try {.code mutate(.by = ...)} followed by a simple {.code filter_out()}." = (!quo_is_null(by)),
    {
      rel <- duckdb_rel_from_df(.data)
      exprs <- rel_translate_dots(dots, .data)

      rel <- oo_prep(rel)

      # Negate the filter: filter_out keeps rows where NOT ALL conditions are TRUE.
      # For each expression, wrap in COALESCE(expr, FALSE) to treat NA as FALSE,
      # then negate the conjunction. This is equivalent to:
      # NOT (COALESCE(expr1, FALSE) AND COALESCE(expr2, FALSE) AND ...)
      false_expr <- relexpr_constant(FALSE)
      coalesced <- lapply(exprs, function(expr) {
        relexpr_function("___coalesce", list(expr, false_expr))
      })
      conjunction <- Reduce(function(a, b) {
        relexpr_function("&", list(a, b))
      }, coalesced)
      negated <- relexpr_function("!", list(conjunction))

      rel <- rel_filter(rel, list(negated))

      out_rel <- oo_restore(rel)

      out <- duckplyr_reconstruct(out_rel, .data)
      return(out)
    }
  )

  # dplyr forward
  check_prudence(.data, duckplyr_error)

  filter_out <- dplyr$filter_out.data.frame
  out <- filter_out(.data, ..., .by = {{ .by }}, .preserve = .preserve)
  return(out)

  # dplyr implementation
  filter_impl(
    .data = .data,
    ...,
    .by = {{ .by }},
    .preserve = .preserve,
    .verb = "filter_out"
  )
}

duckplyr_filter_out <- function(.data, ...) {
  try_fetch(
    .data <- as_duckplyr_df_impl(.data),
    error = function(e) {
      testthat::skip(conditionMessage(e))
    }
  )
  out <- filter_out(.data, ...)
  class(out) <- setdiff(class(out), "duckplyr_df")
  out
}

Try the duckplyr package in your browser

Any scripts or data that you put into this service are public.

duckplyr documentation built on March 10, 2026, 9:06 a.m.