|
35 | 35 | - [Sorting Rows](#sorting-rows) |
36 | 36 | - [Limiting and Paging Results](#limiting-and-paging-results) |
37 | 37 | - [Aggregation](#aggregation) |
| 38 | + - [Upserting Rows](#upserting-rows) |
38 | 39 | - [Updating Rows](#updating-rows) |
39 | 40 | - [Deleting Rows](#deleting-rows) |
40 | 41 | - [Transactions and Savepoints](#transactions-and-savepoints) |
@@ -266,8 +267,8 @@ var path = NSSearchPathForDirectoriesInDomains( |
266 | 267 | ).first! + "/" + Bundle.main.bundleIdentifier! |
267 | 268 |
|
268 | 269 | // create parent directory iff it doesn’t exist |
269 | | -try FileManager.default.createDirectoryAtPath( |
270 | | - path, withIntermediateDirectories: true, attributes: nil |
| 270 | +try FileManager.default.createDirectory( |
| 271 | +atPath: path, withIntermediateDirectories: true, attributes: nil |
271 | 272 | ) |
272 | 273 |
|
273 | 274 | let db = try Connection("\(path)/db.sqlite3") |
@@ -955,8 +956,10 @@ equate or compare different types will prevent compilation. |
955 | 956 | | `~=` | `(Interval, Comparable) -> Bool` | `BETWEEN` | |
956 | 957 | | `&&` | `Bool -> Bool` | `AND` | |
957 | 958 | | `\|\|`| `Bool -> Bool` | `OR` | |
| 959 | +| `===` | `Equatable -> Bool` | `IS` | |
| 960 | +| `!==` | `Equatable -> Bool` | `IS NOT` | |
958 | 961 |
|
959 | | -> *When comparing against `nil`, SQLite.swift will use `IS` and `IS NOT` |
| 962 | +> * When comparing against `nil`, SQLite.swift will use `IS` and `IS NOT` |
960 | 963 | > accordingly. |
961 | 964 |
|
962 | 965 |
|
@@ -1098,6 +1101,33 @@ let count = try db.scalar(users.filter(name != nil).count) |
1098 | 1101 | > // SELECT count(DISTINCT "name") FROM "users" |
1099 | 1102 | > ``` |
1100 | 1103 |
|
| 1104 | +## Upserting Rows |
| 1105 | + |
| 1106 | +We can upsert rows into a table by calling a [query’s](#queries) `upsert` |
| 1107 | +function with a list of [setters](#setters)—typically [typed column |
| 1108 | +expressions](#expressions) and values (which can also be expressions)—each |
| 1109 | +joined by the `<-` operator. Upserting is like inserting, except if there is a |
| 1110 | +conflict on the specified column value, SQLite will perform an update on the row instead. |
| 1111 | + |
| 1112 | +```swift |
| 1113 | +try db.run(users.upsert(email <- "alice@mac.com", name <- "Alice"), onConflictOf: email) |
| 1114 | +// INSERT INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice') ON CONFLICT (\"email\") DO UPDATE SET \"name\" = \"excluded\".\"name\" |
| 1115 | +``` |
| 1116 | + |
| 1117 | +The `upsert` function, when run successfully, returns an `Int64` representing |
| 1118 | +the inserted row’s [`ROWID`][ROWID]. |
| 1119 | + |
| 1120 | +```swift |
| 1121 | +do { |
| 1122 | + let rowid = try db.run(users.upsert(email <- "alice@mac.com", name <- "Alice", onConflictOf: email)) |
| 1123 | + print("inserted id: \(rowid)") |
| 1124 | +} catch { |
| 1125 | + print("insertion failed: \(error)") |
| 1126 | +} |
| 1127 | +``` |
| 1128 | + |
| 1129 | +The [`insert`](#inserting-rows), [`update`](#updating-rows), and [`delete`](#deleting-rows) functions |
| 1130 | +follow similar patterns. |
1101 | 1131 |
|
1102 | 1132 | ## Updating Rows |
1103 | 1133 |
|
@@ -1557,7 +1587,7 @@ Both of the above methods also have the following optional parameter: |
1557 | 1587 | There are a few restrictions on using Codable types: |
1558 | 1588 |
|
1559 | 1589 | - The encodable and decodable objects can only use the following types: |
1560 | | - - Int, Bool, Float, Double, String |
| 1590 | + - Int, Bool, Float, Double, String, Date |
1561 | 1591 | - Nested Codable types that will be encoded as JSON to a single column |
1562 | 1592 | - These methods will not handle object relationships for you. You must write |
1563 | 1593 | your own Codable and Decodable implementations if you wish to support this. |
@@ -1792,12 +1822,12 @@ let config = FTS5Config() |
1792 | 1822 | .column(subject) |
1793 | 1823 | .column(body, [.unindexed]) |
1794 | 1824 |
|
1795 | | -try db.run(emails.create(.FTS5(config)) |
| 1825 | +try db.run(emails.create(.FTS5(config))) |
1796 | 1826 | // CREATE VIRTUAL TABLE "emails" USING fts5("subject", "body" UNINDEXED) |
1797 | 1827 |
|
1798 | 1828 | // Note that FTS5 uses a different syntax to select columns, so we need to rewrite |
1799 | 1829 | // the last FTS4 query above as: |
1800 | | -let replies = emails.filter(emails.match("subject:\"Re:\"*)) |
| 1830 | +let replies = emails.filter(emails.match("subject:\"Re:\"*")) |
1801 | 1831 | // SELECT * FROM "emails" WHERE "emails" MATCH 'subject:"Re:"*' |
1802 | 1832 |
|
1803 | 1833 | // https://www.sqlite.org/fts5.html#_changes_to_select_statements_ |
|
0 commit comments