|
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") |
@@ -967,8 +968,10 @@ equate or compare different types will prevent compilation. |
967 | 968 | | `~=` | `(Interval, Comparable) -> Bool` | `BETWEEN` | |
968 | 969 | | `&&` | `Bool -> Bool` | `AND` | |
969 | 970 | | `\|\|`| `Bool -> Bool` | `OR` | |
| 971 | +| `===` | `Equatable -> Bool` | `IS` | |
| 972 | +| `!==` | `Equatable -> Bool` | `IS NOT` | |
970 | 973 |
|
971 | | -> *When comparing against `nil`, SQLite.swift will use `IS` and `IS NOT` |
| 974 | +> * When comparing against `nil`, SQLite.swift will use `IS` and `IS NOT` |
972 | 975 | > accordingly. |
973 | 976 |
|
974 | 977 |
|
@@ -1110,6 +1113,33 @@ let count = try db.scalar(users.filter(name != nil).count) |
1110 | 1113 | > // SELECT count(DISTINCT "name") FROM "users" |
1111 | 1114 | > ``` |
1112 | 1115 |
|
| 1116 | +## Upserting Rows |
| 1117 | + |
| 1118 | +We can upsert rows into a table by calling a [query’s](#queries) `upsert` |
| 1119 | +function with a list of [setters](#setters)—typically [typed column |
| 1120 | +expressions](#expressions) and values (which can also be expressions)—each |
| 1121 | +joined by the `<-` operator. Upserting is like inserting, except if there is a |
| 1122 | +conflict on the specified column value, SQLite will perform an update on the row instead. |
| 1123 | + |
| 1124 | +```swift |
| 1125 | +try db.run(users.upsert(email <- "alice@mac.com", name <- "Alice"), onConflictOf: email) |
| 1126 | +// INSERT INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice') ON CONFLICT (\"email\") DO UPDATE SET \"name\" = \"excluded\".\"name\" |
| 1127 | +``` |
| 1128 | + |
| 1129 | +The `upsert` function, when run successfully, returns an `Int64` representing |
| 1130 | +the inserted row’s [`ROWID`][ROWID]. |
| 1131 | + |
| 1132 | +```swift |
| 1133 | +do { |
| 1134 | + let rowid = try db.run(users.upsert(email <- "alice@mac.com", name <- "Alice", onConflictOf: email)) |
| 1135 | + print("inserted id: \(rowid)") |
| 1136 | +} catch { |
| 1137 | + print("insertion failed: \(error)") |
| 1138 | +} |
| 1139 | +``` |
| 1140 | + |
| 1141 | +The [`insert`](#inserting-rows), [`update`](#updating-rows), and [`delete`](#deleting-rows) functions |
| 1142 | +follow similar patterns. |
1113 | 1143 |
|
1114 | 1144 | ## Updating Rows |
1115 | 1145 |
|
@@ -1569,7 +1599,7 @@ Both of the above methods also have the following optional parameter: |
1569 | 1599 | There are a few restrictions on using Codable types: |
1570 | 1600 |
|
1571 | 1601 | - The encodable and decodable objects can only use the following types: |
1572 | | - - Int, Bool, Float, Double, String |
| 1602 | + - Int, Bool, Float, Double, String, Date |
1573 | 1603 | - Nested Codable types that will be encoded as JSON to a single column |
1574 | 1604 | - These methods will not handle object relationships for you. You must write |
1575 | 1605 | your own Codable and Decodable implementations if you wish to support this. |
@@ -1804,12 +1834,12 @@ let config = FTS5Config() |
1804 | 1834 | .column(subject) |
1805 | 1835 | .column(body, [.unindexed]) |
1806 | 1836 |
|
1807 | | -try db.run(emails.create(.FTS5(config)) |
| 1837 | +try db.run(emails.create(.FTS5(config))) |
1808 | 1838 | // CREATE VIRTUAL TABLE "emails" USING fts5("subject", "body" UNINDEXED) |
1809 | 1839 |
|
1810 | 1840 | // Note that FTS5 uses a different syntax to select columns, so we need to rewrite |
1811 | 1841 | // the last FTS4 query above as: |
1812 | | -let replies = emails.filter(emails.match("subject:\"Re:\"*)) |
| 1842 | +let replies = emails.filter(emails.match("subject:\"Re:\"*")) |
1813 | 1843 | // SELECT * FROM "emails" WHERE "emails" MATCH 'subject:"Re:"*' |
1814 | 1844 |
|
1815 | 1845 | // https://www.sqlite.org/fts5.html#_changes_to_select_statements_ |
|
0 commit comments