Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support returning in rows_*.tbl_dbi() #607

Merged
merged 21 commits into from
Aug 31, 2021

Conversation

mgirlich
Copy link
Contributor

@mgirlich mgirlich commented Aug 17, 2021

Closes #593.

@krlmlr
Copy link
Collaborator

krlmlr commented Aug 18, 2021

Thanks. Should we discuss conditional updates and mutating joins separately?

Copy link
Collaborator

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is a good start.

I think type stability for the return values is really important here. Can we return the inserted rows in an attribute to the returned table?

@krlmlr
Copy link
Collaborator

krlmlr commented Aug 18, 2021

Please also run devtools::document() to avoid check errors.

@mgirlich
Copy link
Contributor Author

mgirlich commented Aug 18, 2021

I think type stability for the return values is really important here. Can we return the inserted rows in an attribute to the returned table?

You mean something like

returned_rows <- dbGetQuery(con, sql, immediate = TRUE)
attr(x, "returned_rows") <- returned_rows
invisible(x)

and then have a helper function e.g. get_returned_rows(x) to get the returned rows?

I can do that and I think type stability is important. On the other hand it also seems a bit counterintuitive to me. The x argument can only be a table that wasn't modified (otherwise remote_table() doesn't work and also doesn't really make sense). And using returning seems to be a very good indicator that one wants to use the result.

In case you have a pipeline of insert/update/upsert operations in mind, i.e.

x %>% 
  dm::rows_insert(y, returning = "id") %>% 
  dm::rows_insert(y2, returning = "id") %>% 
  dm::rows_update(z, returning = "id")

it might make sense that the user could choose the name of the attribute so that all results from returning can still be accessed.

Copy link
Collaborator

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Can we simplify further?

R/rows-db.R Outdated Show resolved Hide resolved
R/rows-db.R Outdated Show resolved Hide resolved
R/rows-db.R Outdated
sql <- sql_rows_insert(x, y)
dbExecute(con, sql, immediate = TRUE)
invisible(x)
sql <- sql_rows_insert(x, y, returning = returning)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to pass returning to the sql_() methods?

Suggested change
sql <- sql_rows_insert(x, y, returning = returning)
sql <- paste0(
sql_rows_insert(x, y, returning = returning)
if (!is.null(returning)) paste0("\n", sql_returning(...))
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If returning is not an argument of the sql_() methods then I would rather have something like

sql_rows_insert(x, y, returning = returning) %>%
  sql_add_returning(x, returning)

and export sql_add_returning() (this should be exported to complete the other sql functions). To me this feels like a more user-friendly interface. What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need an sql_returning() generic anyway -- to special-case both the clause and the way column expressions are constructed (to work around that RSQLite bug). I don't mind sql_add_returning() as an equivalent to the paste0() call in my proposal.

@krlmlr
Copy link
Collaborator

krlmlr commented Aug 19, 2021

Thanks, the attribute looks good.

Regarding stacking of "returning" data, I think it's dangerous to use the pipe for functions that have side effects:

x %>% 
  dm::rows_insert(y, returning = "id", in_place = TRUE) %>% 
  dm::rows_insert(y2, returning = "id", in_place = TRUE) %>% 
  dm::rows_update(z, returning = "id", in_place = TRUE)

If the first call succeeds but the second call fails, you might be tempted to re-run the pipe, which might now also fail the first call. It's safer to un-pipe this and consume return values implicitly. I don't think we need to act here.

Copy link
Collaborator

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, a few final nitpicks.

For tests of this feature, we can use persistent tables, referring to the blocking issue. If you could add them, I'll start the CI run and merge.

R/rows-db.R Outdated Show resolved Hide resolved
R/rows-db.R Show resolved Hide resolved
R/rows-db.R Outdated Show resolved Hide resolved
@mgirlich
Copy link
Contributor Author

For tests of this feature, we can use persistent tables, referring to the blocking issue. If you could add them, I'll start the CI run and merge.

I think it should be sufficient to rely on the dev version of RSQLite as the bug is fixed in there.

@krlmlr
Copy link
Collaborator

krlmlr commented Aug 21, 2021

RSQLite 2.2.8 is on CRAN now.

Copy link
Collaborator

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks great! Running checks now, one last question.

R/rows-db.R Show resolved Hide resolved
@krlmlr
Copy link
Collaborator

krlmlr commented Aug 26, 2021

We need has_returned_rows() in pkgdown: https://github.com/cynkra/dm/runs/3428475709#step:17:55.

krlmlr
krlmlr previously approved these changes Aug 31, 2021
Copy link
Collaborator

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is huge! Looking forward to using it.

@krlmlr
Copy link
Collaborator

krlmlr commented Aug 31, 2021

I love SQL Server...

@krlmlr krlmlr enabled auto-merge August 31, 2021 04:25
@krlmlr krlmlr merged commit 5be3627 into cynkra:main Aug 31, 2021
@krlmlr
Copy link
Collaborator

krlmlr commented Aug 31, 2021

Thanks!

@mgirlich mgirlich deleted the rows-insert-returning branch September 13, 2021 09:02
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 14, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

rows_insert() et al. with option to return modified rows
2 participants