@@ -14,7 +14,7 @@ library (e.g., Android, Windows).
1414## Features
1515
1616 - A pure-Swift interface
17- - Embeds a modern and consistent sqlite ([ 3.49.1] ( https://www.sqlite.org/releaselog/3_49_1.html ) ) and sqlcipher ([ 4.7 .0] ( https://github.com/sqlcipher/sqlcipher/releases/tag/v4.7 .0 ) ) build in the library
17+ - Embeds a modern and consistent sqlite ([ 3.49.1] ( https://www.sqlite.org/releaselog/3_49_1.html ) ) and sqlcipher ([ 4.8 .0] ( https://github.com/sqlcipher/sqlcipher/releases/tag/v4.8 .0 ) ) build in the library
1818 - Works on iOS, macOS, Android, Windows, and Linux
1919 - A type-safe, optional-aware SQL expression builder
2020 - A flexible, chainable, lazy-executing query layer
@@ -120,7 +120,8 @@ library (e.g., Android, Windows).
120120 - [ Online Database Backup] ( #online-database-backup )
121121 - [ Attaching and detaching databases] ( #attaching-and-detaching-databases )
122122 - [ Logging] ( #logging )
123- - [ Vacuum] ( #vacuum )
123+ - [ Database Middleware Packages] ( #database-middleware-packages )
124+ - [ Communication] ( #communication )
124125
125126[ ↩ ] : #sqliteswift-documentation
126127
@@ -136,7 +137,7 @@ process of downloading, compiling, and linking dependencies.
136137
137138 ``` swift
138139 dependencies: [
139- .package (url : " https://github.com/skiptools/swift-sqlcipher.git" , from : " 1.3 .0" )
140+ .package (url : " https://github.com/skiptools/swift-sqlcipher.git" , from : " 1.4 .0" )
140141 ]
141142 ```
142143
@@ -150,22 +151,41 @@ process of downloading, compiling, and linking dependencies.
150151
151152## Getting Started
152153
154+ If you just want to use the low-level SQLCipher functions instead of SQLite3,
155+ you can conditionally import the package:
156+
157+ ``` swift
158+ #if canImport (SQLCipher )
159+ import SQLCipher
160+ #else
161+ import SQLite3
162+ #endif
163+ ```
164+
165+ SQLCipher is API-compatible with the SQLite3 framework that is included on many platforms,
166+ including iOS and Android.
167+
168+ The remainder of this document assumes you want to use the higher-level SQLiteDB
169+ interface atop the SQLCipher package. This interface is based on the
170+ [ SQLite.swift] ( https://github.com/stephencelis/SQLite.swift ) package, but
171+ uses SQLCipher rather than SQLite3 and enables various features like encryption,
172+ FTS5, and JSON support.
173+
153174To use SQLiteDB classes or structures in your target’s source file, first
154175import the ` SQLiteDB ` module.
155176
156177``` swift
157178import SQLiteDB
158179```
159180
160-
161181### Connecting to a Database
162182
163183Database connections are established using the ` Connection ` class. A
164184connection is initialized with a path to a database. SQLite will attempt to
165185create the database file if it does not already exist.
166186
167187``` swift
168- let db = try Connection (" path/to/db.sqlite3 " )
188+ let db = try Connection (" path/to/database.db " )
169189```
170190
171191
@@ -178,7 +198,7 @@ directory.
178198let path = URL.applicationSupportDirectory
179199// create parent directory inside application support if it doesn’t exist
180200try FileManager.default .createDirectory (atPath : path, withIntermediateDirectories : true , attributes : nil )
181- let db = try Connection (dbURL.appendingPathComponent (" db.sqlite3 " ).path )
201+ let db = try Connection (dbURL.appendingPathComponent (" database.db " ).path )
182202```
183203
184204#### Read-Only Databases
@@ -193,7 +213,7 @@ let path = Bundle.main.path(forResource: "db", ofType: "sqlite3")!
193213let db = try Connection (path, readonly : true )
194214```
195215
196- > [ !NOTE ]
216+ > [ !WARNING ]
197217> Signed applications cannot modify their bundle resources. If you
198218> bundle a database file with your app for the purpose of bootstrapping, copy
199219> it to a writable location _ before_ establishing a connection (see
@@ -2112,15 +2132,90 @@ try db.vacuum()
21122132[ROWID]: https: // sqlite.org/lang_createtable.html#rowid
21132133[SQLiteMigrationManager.swift ]: https: // github.com/garriguv/SQLiteMigrationManager.swift
21142134
2135+ ## Database Middleware Packages
2136+
2137+ If you have a Swift package that acts as database middleware, such as an ORM
2138+ or other database access layer, that uses the SQLite3 C API directly, you can expose a
2139+ [SwiftPM 6.1 trait](https :// github.com/swiftlang/swift-evolution/blob/main/proposals/0450-swiftpm-package-traits.md)
2140+ in your `Package.swift ` to enable dependent packages to enable using SQLCipher rather than SQLite3.
2141+
2142+ ```swift
2143+ // swift-tools-version:6.1
2144+ import PackageDescription
2145+
2146+ let package = Package (name : " your-middleware" ,
2147+ products : [
2148+ .library (name : " NeatORM" , targets : [" NeatORM" ])
2149+ ],
2150+ traits : [
2151+ .trait (name : " SQLCipher" , description : " Use the SQLCipher library rather than the vendored SQLite" )
2152+ ],
2153+ depedencies : [
2154+ .package (url : " https://github.com/skiptools/swift-sqlcipher.git" , from : " 1.4.0" )
2155+ ],
2156+ targets : [
2157+ .target (name : " NeatORM" , dependencies : [
2158+ // target only depends on SQLCipher when the "SQLCipher" trait is activated by a dependent package
2159+ // otherwise it will default to using the system "SQLite3" framework
2160+ .product (name : " SQLCipher" , package : " swift-sqlcipher" , condition : .when (traits : [" SQLCipher" ]))
2161+ ])
2162+ ]
2163+ )
2164+ ```
2165+
2166+ Then throughout your package 's code, wherever you `import SQLite3`,
2167+ you would change this to conditionally `import SQLCipher` if it is available
2168+ (i.e ., if the trait is activated by the client package ):
2169+
2170+ ```swift
2171+ #if canImport (SQLCipher)
2172+ import SQLCipher
2173+ #else
2174+ import SQLite3
2175+ #endif
2176+ ```
2177+
2178+ Since the C API surface of the SQLCipher package is a superset of the SQLite3 framework,
2179+ all the same `sqlite3_* ` functions will behave identically. However, you may want to also
2180+ create additional conditionally- enabled functionality in your own package , such as
2181+ for key management or FTS5 search index handling. For example:
2182+
2183+ ```swift
2184+ #if canImport (SQLCipher)
2185+ import SQLCipher
2186+
2187+ extension Connection {
2188+ func updateEncryptionKey (newKey : String ) throws {
2189+ try checkError (sqlite3_rekey_v2 (dbHandle, newKey, Int32 (newKey.utf8 .count )))
2190+ }
2191+ }
2192+ ```
2193+
2194+ Clients of your package would then enable the SQLCipher trait in their
2195+ Package.swift 's dependencies:
2196+
2197+ ```swift
2198+ dependencies: [
2199+ // turn on SQLCipher support for NeatORM
2200+ .package (url : " https://github.com/your-middleware/NeatORM.git" , from : " 1.2.3" , traits : [" SQLCipher" ])
2201+ ]
2202+ ```
2203+
2204+ In this way, your package can be parameterized to work with either the
2205+ built- in vendored SQLite3 package or with the SQLCipher package
2206+ depending on the needs of the developer.
21152207
21162208## Communication
21172209
2118- [Open an issue]: https: // github.com/skiptools/swift-sqlcipher/issues/new
2119- [Submit a pull request]: https: // github.com/skiptools/swift-sqlcipher/pulls
2210+ - [Browse discussions](https :// github.com/skiptools/swift-sqlcipher/discussions)
2211+ - [Open an issue](https :// github.com/skiptools/swift-sqlcipher/issues/new)
2212+ - [Submit a pull request](https :// github.com/skiptools/swift-sqlcipher/pulls)
21202213
21212214## License
21222215
2123- MIT license. See [the LICENSE file](./ LICENSE.txt ) for more information.
2216+ - This swift- sqlcipher package uses the MIT license. See [the LICENSE file](./ LICENSE.txt ) for more information.
2217+ - The BSD- style sqlcipher license is available at [https :// www.zetetic.net/sqlcipher/license/](https://www.zetetic.net/sqlcipher/license/).
2218+ - SQLite3 itself is in the public domain. Its license is available at [https :// sqlite.org/purchase/license](https://sqlite.org/purchase/license).
21242219
21252220## Alternatives
21262221
0 commit comments