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

Adds multirow insert method #153

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

NeedleInAJayStack
Copy link
Contributor

@NeedleInAJayStack NeedleInAJayStack commented Jul 29, 2022

This adds functionality to do a multi-row inserts with a single values method call.

Previously, to insert multiple rows a user had to call values repeatedly:

db.insert(into: "planets")
    .columns(["name", "color"])
    .values([SQLBind("Jupiter"), SQLBind("orange")])
    .values([SQLBind("Mars"), SQLBind("red")])
    .run()

This was a bit awkward when inserting rows from an array, where an instance of the builder had to be saved off and edited:

let rows: [[SQLExpression]]  = [[...], [...], ...]
let builder = db.insert(into: "planets")
    .columns(["name", "color"])
for row in rows {
    builder.values(row)
}
builder.run()

This MR simplifies the mutli-row insert situation by adding a values method overload that accepts a nested array:

db.insert(into: "planets")
    .columns(["name", "color"])
    .values([[SQLBind("Jupiter"), SQLBind("orange")], [SQLBind("Mars"), SQLBind("red")]])
    .run()

let rows  = [[...], [...], ...]
db.insert(into: "planets")
    .columns(["name", "color"])
    .values(rows)
    .run()

NOTE

This functionality was only added to the SQLExpression version of values, NOT the Encodable version of values. There are known issues with [Encodable] conforming to Encodable that prevent adequate type checks.

For example, if a values(_ rows: [[Encodable]]) is defined, it is undeterministic since the same call would also match values(_ rows: [Encodable]). If instead we change values(_ rows: [Encodable]) to detect [[Encodable]] cases at runtime, then it is difficult to guarantee that a caller hasn't mixed Encodable and [Encodable] values.

@NeedleInAJayStack NeedleInAJayStack changed the title feature: Adds multirow insert method DRAFT: Adds multirow insert method Jul 29, 2022
@codecov-commenter
Copy link

codecov-commenter commented Jul 30, 2022

Codecov Report

Merging #153 (c5b1f51) into main (a5c3df4) will increase coverage by 0.00%.
The diff coverage is 100.00%.

❗ Current head c5b1f51 differs from pull request most recent head e2ad748. Consider uploading reports for the commit e2ad748 to get more accurate results

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #153   +/-   ##
=======================================
  Coverage   69.27%   69.28%           
=======================================
  Files          94       94           
  Lines        3486     3487    +1     
=======================================
+ Hits         2415     2416    +1     
  Misses       1071     1071           
Flag Coverage Δ
unittests 69.28% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
Sources/SQLKit/Builders/SQLInsertBuilder.swift 81.18% <100.00%> (+0.77%) ⬆️
Sources/SQLKit/Query/SQLQueryString.swift 89.65% <0.00%> (-0.51%) ⬇️

@NeedleInAJayStack NeedleInAJayStack changed the title DRAFT: Adds multirow insert method Adds multirow insert method Jul 30, 2022
@0xTim 0xTim requested a review from gwynne August 1, 2022 09:45
Copy link
Member

@gwynne gwynne left a comment

Choose a reason for hiding this comment

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

I've been meaning to upstream basically this exact helper myself! 🙂 I have two nits:

  1. I'd rather it not be just another overload of values(_:), but have a unique name - consider an attempt to insert into a table with a single column of array type. I named my version multiValues(_:), but I'm not at all convinced that's an ideal name either and would actually welcome a bit of bikeshedding on the matter.
  2. My implementation is a bit more generic:
    extension SQLInsertBuilder {
        @discardableResult
        public func multiValues<S1, S2>(_ valueSets: S1) -> Self
            where S1: Sequence, S2: Sequence,
                  S1.Element == S2, S2.Element == SQLExpression
        {
            valueSets.reduce(self) { $0.values(Array($1)) }
        }
    }
    Even though the input gets converted back to Array in the end regardless, accepting generic sequences allows for cleaner syntax when using, for example, the methods from swift-algorithms to process the data to be inserted.

@NeedleInAJayStack
Copy link
Contributor Author

welcome a bit of bikeshedding on the matter

I think multiValues(_:) is a fine name. Along the same vein, allValues seems like a reasonable option. However, I think I prefer rows(_:) or rowValues(_:), since I feel like they imply that all sequences should have equal length and correspond to the column ordering.

@NeedleInAJayStack
Copy link
Contributor Author

@gwynne Sorry it took so long to get back to this one. I've adjusted it to use your implementation (which is great!), and named it rows. Again, I'm happy to switch to multiValues if you prefer that. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants