skip_if_not_installed("DBI")
skip_if_not_installed("RSQLite")

describe("glue_sql", {
  con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
  on.exit(DBI::dbDisconnect(con))

  it("errors if no connection given", {
    var <- "foo"
    expect_snapshot(glue_sql("{var}"), error = TRUE)
  })
  it("returns the string if no substations needed", {
    expect_identical(glue_sql("foo", .con = con), DBI::SQL("foo"))
  })
  it("quotes string values", {
    var <- "foo"
    expect_identical(glue_sql("{var}", .con = con), DBI::SQL("'foo'"))
  })
  it("quotes identifiers", {
    var <- "foo"
    expect_identical(glue_sql("{`var`}", .con = con), DBI::SQL("`foo`"))
  })
  it("quotes Id identifiers", {
    var <- DBI::Id(schema = "foo", table = "bar", column = "baz")
    expect_identical(
      glue_sql("{`var`}", .con = con),
      DBI::SQL("`foo`.`bar`.`baz`")
    )
  })
  it("quotes lists of Id identifiers", {
    var <- c(
      DBI::Id(schema = "foo", table = "bar", column = "baz"),
      DBI::Id(schema = "foo", table = "bar", column = "baz2")
    )
    expect_identical(
      glue_sql("{`var`*}", .con = con),
      DBI::SQL("`foo`.`bar`.`baz`, `foo`.`bar`.`baz2`")
    )
  })
  it("Does not quote numbers", {
    var <- 1
    expect_identical(glue_sql("{var}", .con = con), DBI::SQL("1"))
  })
  it("Does not quote DBI::SQL()", {
    var <- DBI::SQL("foo")
    expect_identical(glue_sql("{var}", .con = con), DBI::SQL("foo"))
  })
  it("collapses values if succeeded by a *", {
    expect_identical(glue_sql("{var*}", .con = con, var = 1), DBI::SQL(1))
    expect_identical(
      glue_sql("{var*}", .con = con, var = 1:5),
      DBI::SQL("1, 2, 3, 4, 5")
    )

    expect_identical(glue_sql("{var*}", .con = con, var = "a"), DBI::SQL("'a'"))
    expect_identical(
      glue_sql("{var*}", .con = con, var = letters[1:5]),
      DBI::SQL("'a', 'b', 'c', 'd', 'e'")
    )
  })
  it('collapses empty values to NULL', {
    expect_identical(
      glue_sql("{var*}", .con = con, var = character()),
      DBI::SQL("NULL")
    )
    expect_identical(
      glue_sql("{var*}", .con = con, var = DBI::SQL(character())),
      DBI::SQL("NULL")
    )
  })
  it("mimics glue() when not collapsing", {
    expect_equal(
      glue_sql("{var}", .con = con, var = NULL),
      DBI::SQL(glue("{var}", var = NULL))
    )
  })

  it("should return an SQL NULL by default for missing values", {
    var <- list(NA, NA_character_, NA_real_, NA_integer_)
    expect_identical(
      glue_sql("x = {var}", .con = con),
      rep(DBI::SQL("x = NULL"), 4)
    )
  })

  it("should preserve the type of the even with missing values (#130)", {
    expect_identical(
      glue_sql("x = {c(1L, NA)}", .con = con),
      DBI::SQL(c(paste0("x = ", c(1, "NULL"))))
    )
    expect_identical(
      glue_sql("x = {c(1, NA)}", .con = con),
      DBI::SQL(c(paste0("x = ", c(1, "NULL"))))
    )
    expect_identical(
      glue_sql("x = {c('1', NA)}", .con = con),
      DBI::SQL(c(paste0("x = ", c("'1'", "NULL"))))
    )
    expect_identical(
      glue_sql("x = {c(TRUE, NA)}", .con = con),
      DBI::SQL(c(paste0("x = ", c("1", "NULL"))))
    )
  })

  it("should return NA for missing values quote strings", {
    var <- c("C", NA)
    expect_identical(
      glue_sql("x = {var}", .con = con),
      DBI::SQL(c("x = 'C'", "x = NULL"))
    )
  })

  it("should return a quoted date for Dates", {
    var <- as.Date("2019-01-01")
    expect_identical(
      glue_sql("x = {var}", .con = con),
      DBI::SQL("x = '2019-01-01'")
    )
  })

  it("should quote values from lists properly", {
    var <- list(1, 2, "three")
    expect_identical(
      glue_sql("x = {var}", .con = con),
      DBI::SQL(c("x = 1", "x = 2", "x = 'three'"))
    )
  })

  it("should handle NA when collapsing (#185)", {
    expect_identical(
      glue_sql("x IN ({c(NA, 'A')*})", .con = con),
      DBI::SQL(paste0("x IN (NULL, 'A')"))
    )
    expect_identical(
      glue_sql("x IN ({c(NA, 1)*})", .con = con),
      DBI::SQL(paste0("x IN (NULL, 1)"))
    )
    expect_identical(
      glue_sql("x IN ({c(NA, 1L)*})", .con = con),
      DBI::SQL(paste0("x IN (NULL, 1)"))
    )
    expect_identical(
      glue_sql("x IN ({c(NA, TRUE)*})", .con = con),
      DBI::SQL(paste0("x IN (NULL, 1)"))
    )
  })

  it("should handle DBI::SQL() elements correctly when collapsing (#191)", {
    expect_identical(
      glue_sql("x IN ({DBI::SQL(c('a','b'))*})", .con = con),
      DBI::SQL(paste0("x IN (a, b)"))
    )
  })

  it("should allow whitespace after the *", {
    x <- 1:3
    expect_identical(
      glue_sql(.con = con, "{x* }"),
      DBI::SQL(paste0("1, 2, 3"))
    )
  })
})

describe("glue_data_sql", {
  con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
  on.exit(DBI::dbDisconnect(con))

  it("errors if no connection given", {
    expect_snapshot(glue_data_sql(mtcars, "{head(gear)*}"), error = TRUE)
  })
  it("collapses values if succeeded by a *", {
    var <- "foo"
    expect_identical(
      glue_data_sql(mtcars, "{head(gear)*}", .con = con),
      DBI::SQL("4, 4, 4, 3, 3, 3")
    )
  })
})

describe("glue_sql_collapse", {
  it("returns an SQL object", {
    expect_identical(
      glue_sql_collapse(character()),
      DBI::SQL("")
    )

    expect_identical(
      glue_sql_collapse(c("foo", "bar", "baz")),
      DBI::SQL("foobarbaz")
    )
  })
})

test_that("get nice errors if rlang installed", {
  con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
  on.exit(DBI::dbDisconnect(con))

  expect_snapshot(error = TRUE, {
    glue_sql("{x + }", .con = con)
    glue_sql("{NOTFOUND}", .con = con)
  })
})
