diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index d9fced24..135b7a19 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -40,7 +40,7 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 diff --git a/.github/workflows/live-api.yml b/.github/workflows/live-api.yml index 2daf0b07..19750021 100644 --- a/.github/workflows/live-api.yml +++ b/.github/workflows/live-api.yml @@ -21,7 +21,7 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 82450331..19c9692b 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -22,7 +22,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 diff --git a/.github/workflows/pr-commands.yaml b/.github/workflows/pr-commands.yaml index 71f335b3..eea58c5c 100644 --- a/.github/workflows/pr-commands.yaml +++ b/.github/workflows/pr-commands.yaml @@ -14,7 +14,7 @@ jobs: env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/pr-fetch@v2 with: @@ -51,7 +51,7 @@ jobs: env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/pr-fetch@v2 with: diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 27d45283..960234cd 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -15,7 +15,7 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-r@v2 with: @@ -44,7 +44,7 @@ jobs: - name: Upload test results if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: coverage-test-failures path: ${{ runner.temp }}/package diff --git a/R/bq-download.R b/R/bq-download.R index 2a9c5213..c325729c 100644 --- a/R/bq-download.R +++ b/R/bq-download.R @@ -287,6 +287,21 @@ parse_postprocess <- function(df, bigint) { function(x) hms::parse_hms(x) ) + # Fix for issue #624: Ensure NUMERIC/FLOAT columns remain as doubles + # Some BigQuery configurations may incorrectly return NUMERIC columns as INTEGER type + df <- col_apply( + df, + function(x) { + # Check if this is a NUMERIC or BIGNUMERIC column that got parsed as integer64 + bq_type <- attr(x, "bq_type") + !is.null(bq_type) && bq_type %in% c("NUMERIC", "BIGNUMERIC") && bit64::is.integer64(x) + }, + function(x) { + # Convert back to double to preserve decimal precision + as.numeric(x) + } + ) + if (bigint != "integer64") { as_bigint <- switch( bigint, @@ -294,7 +309,10 @@ parse_postprocess <- function(df, bigint) { numeric = as.numeric, character = as.character ) - df <- col_apply(df, bit64::is.integer64, as_bigint) + # Only apply bigint conversion to true INTEGER columns, not NUMERIC/FLOAT + df <- col_apply(df, function(x) { + bit64::is.integer64(x) && !attr(x, "bq_type") %in% c("NUMERIC", "BIGNUMERIC", "FLOAT") + }, as_bigint) } df diff --git a/tests/testthat/test-bq-download.R b/tests/testthat/test-bq-download.R index 68fa317b..9088cb74 100644 --- a/tests/testthat/test-bq-download.R +++ b/tests/testthat/test-bq-download.R @@ -396,3 +396,27 @@ test_that("can convert bytes type", { ) ) }) + +test_that("NUMERIC columns preserve double precision (issue #624)", { + # Test that NUMERIC/BIGNUMERIC columns are not converted to integers + # even when bigint = "integer" is used + + # Create test data that simulates NUMERIC columns incorrectly parsed as integer64 + test_data <- data.frame( + value = bit64::as.integer64(c(123, 456, 789)), + count = bit64::as.integer64(c(1, 2, 3)) + ) + attr(test_data$value, "bq_type") <- "NUMERIC" # Should remain double + attr(test_data$count, "bq_type") <- "INTEGER" # Should be converted to int + + # Apply post-processing with bigint = "integer" + result <- parse_postprocess(test_data, bigint = "integer") + + # NUMERIC column should remain as double + expect_type(result$value, "double") + expect_equal(result$value, c(123, 456, 789)) + + # INTEGER column should be converted to integer + expect_type(result$count, "integer") + expect_equal(result$count, c(1L, 2L, 3L)) +})