You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The fact that `insert()`, `update()`, and `delete()` have a number of
overloads that can only be disambiguated by specifying a type, a tuple
member, or `!` is a big point of confusion for new users of
SQLite.swift. The overloads add some interesting patterns to the mix,
but aren't worth the pain points.
If we eliminate the overloads, we can insert/update/delete in place.
This allows for subtle bugs to be introduced into apps (where the
developer doesn't check for a rowid or that an update/delete was
successful), but is a tradeoff we'll have to make. It doesn't make sense
to enforce a different kind of interface/access at the expense of
confusion.
Given:
let user = email <- "alice@mac.com")
The old way:
users.insert(user)!
let rowid = users.insert(user)!
if let rowid = users.insert(user) { /* ... */ }
let (rowid, statement) = users.insert(user)
// etc.
The new way:
users.insert(user)
let rowid = users.insert(user).rowid!
if let rowid = users.insert(user).rowid { /* ... */ }
let (rowid, statement) = users.insert(user)
// etc.
Slightly and rarely more verbose and readable, with less confusing
compiler errors and hand-holding.
Signed-off-by: Stephen Celis <stephen@stephencelis.com>
Copy file name to clipboardExpand all lines: Documentation/Index.md
+46-90Lines changed: 46 additions & 90 deletions
Original file line number
Diff line number
Diff line change
@@ -393,62 +393,33 @@ Additional constraints may be provided outside the scope of a single column usin
393
393
394
394
## Inserting Rows
395
395
396
-
We can insert rows into a table by calling a [query’s](#queries) `insert` function with a list of [setters](#setters), typically [typed column expressions](#expressions) and values (which can also be expressions), each joined by the `<-` operator.
396
+
We can insert rows into a table by calling a [query’s](#queries) `insert` function with a list of [setters](#setters)—typically [typed column expressions](#expressions) and values (which can also be expressions)—each joined by the `<-` operator.
397
397
398
398
``` swift
399
-
users.insert(email <-"alice@mac.com", name <-"Alice")?
399
+
users.insert(email <-"alice@mac.com", name <-"Alice")
400
400
// INSERT INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice')
401
401
402
402
users.insert(or: .Replace, email <-"alice@mac.com", name <-"Alice B.")
403
403
// INSERT OR REPLACE INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice B.')
404
404
```
405
405
406
-
The `insert` function can return several different types that are useful in different contexts.
406
+
The `insert` function returns a tuple with an `Int64?` representing the inserted row’s [`ROWID`][ROWID] (or `nil` on failure) and the associated `Statement`.
407
407
408
-
- An `Int64?` representing the inserted row’s [`ROWID`][ROWID] (or `nil` on failure), for simplicity.
The [`update`](#updating-rows) and [`delete`](#deleting-rows) functions follow similar patterns.
447
418
448
419
> _Note:_ If `insert` is called without any arguments, the statement will run with a `DEFAULT VALUES` clause. The table must not have any constraints that aren’t fulfilled by default values.
We can update a table’s rows by calling a [query’s](#queries) `update` function with a list of [setters](#setters), typically [typed column expressions](#expressions) and values (which can also be expressions), each joined by the `<-` operator.
790
+
We can update a table’s rows by calling a [query’s](#queries) `update` function with a list of [setters](#setters)—typically [typed column expressions](#expressions) and values (which can also be expressions)—each joined by the `<-` operator.
820
791
821
792
When an unscoped query calls `update`, it will update _every_ row in the table.
822
793
823
794
``` swift
824
-
users.update(email <-"alice@me.com")?
795
+
users.update(email <-"alice@me.com")
825
796
// UPDATE "users" SET "email" = 'alice@me.com'
826
797
```
827
798
828
799
Be sure to scope `UPDATE` statements beforehand using [the `filter` function](#filtering-rows).
829
800
830
801
``` swift
831
802
let alice = users.filter(id ==1)
832
-
alice.update(email <-"alice@me.com")?
803
+
alice.update(email <-"alice@me.com")
833
804
// UPDATE "users" SET "email" = 'alice@me.com' WHERE ("id" = 1)
834
805
```
835
806
836
-
Like [`insert`](#inserting-rows) (and [`delete`](#updating-rows)), `update` can return several different types that are useful in different contexts.
837
-
838
-
- An `Int?` representing the number of updated rows (or `nil` on failure), for simplicity.
839
-
840
-
``` swift
841
-
if alice.update(email <-"alice@me.com") >0 {
842
-
println("updated Alice")
843
-
}
844
-
```
807
+
The `update` function returns a tuple with an `Int?` representing the number of updates (or `nil` on failure) and the associated `Statement`.
845
808
846
-
If a value is always expected, we can disambiguate with a `!`.
847
-
848
-
``` swift
849
-
alice.update(email <-"alice@me.com")!
850
-
```
851
-
852
-
- A `Statement`, for [the transaction and savepoint helpers](#transactions-and-savepoints) that take a list of statements.
853
-
854
-
- A tuple of the above number of updated rows and statement: `(changes: Int?, Statement)`, for flexibility.
Using the `transaction` and `savepoint` functions, we can run a series of statements, committing the changes to the database if they all succeed. If a single statement fails, we can bail out early and roll back.
852
+
Using the `transaction` and `savepoint` functions, we can run a series of statements chained together (using `&&`). If a single statement fails, we can short-circuit the series (using `||`) and roll back the changes.
900
853
901
854
``` swift
902
855
db.transaction()
@@ -905,18 +858,21 @@ db.transaction()
905
858
&& db.commit() || db.rollback()
906
859
```
907
860
908
-
The former statement can also be written as
861
+
> _Note:_ Each statement is captured in an auto-closure and won’t execute till the preceding statement succeeds. This is why we can use the `lastInsertRowid` property on `Database` to reference the previous statement’s insert [`ROWID`][ROWID].
862
+
863
+
For more complex transactions and savepoints, block helpers exist. Using a block helper, the former statement can be written (more verbosely) as follows:
if users.insert(email <-"cathy@icloud.com", manager_id <- db.lastInsertRowid).rowid !=nil {
869
+
return .Commit
870
+
}
913
871
}
914
-
return .Commit|| .Rollback
872
+
return .Rollback
915
873
}
916
874
```
917
875
918
-
> _Note:_ Each statement is captured in an auto-closure and won’t execute till the preceding statement succeeds. This means we can use the `lastInsertRowid` property on `Database` to reference the previous statement’s insert [`ROWID`][ROWID].
0 commit comments