Push from command line

This commit is contained in:
Deniz Duezgoeren
2019-08-12 11:20:21 +02:00
parent 3a919dcb23
commit f1345eac14
512 changed files with 103288 additions and 1930 deletions
+21
View File
@@ -0,0 +1,21 @@
(The MIT License)
Copyright (c) 2014-2015 Stephen Celis (<stephen@stephencelis.com>)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+293
View File
@@ -0,0 +1,293 @@
# SQLite.swift
[![Build Status][TravisBadge]][TravisLink] [![CocoaPods Version][CocoaPodsVersionBadge]][CocoaPodsVersionLink] [![Swift5 compatible][Swift5Badge]][Swift5Link] [![Platform][PlatformBadge]][PlatformLink] [![Carthage compatible][CartagheBadge]][CarthageLink] [![Join the chat at https://gitter.im/stephencelis/SQLite.swift][GitterBadge]][GitterLink]
A type-safe, [Swift][]-language layer over [SQLite3][].
[SQLite.swift][] provides compile-time confidence in SQL statement
syntax _and_ intent.
## Features
- A pure-Swift interface
- A type-safe, optional-aware SQL expression builder
- A flexible, chainable, lazy-executing query layer
- Automatically-typed data access
- A lightweight, uncomplicated query and parameter binding interface
- Developer-friendly error handling and debugging
- [Full-text search][] support
- [Well-documented][See Documentation]
- Extensively tested
- [SQLCipher][] support via CocoaPods
- Active support at
[StackOverflow](http://stackoverflow.com/questions/tagged/sqlite.swift),
and [Gitter Chat Room](https://gitter.im/stephencelis/SQLite.swift)
(_experimental_)
[SQLCipher]: https://www.zetetic.net/sqlcipher/
[Full-text search]: Documentation/Index.md#full-text-search
[See Documentation]: Documentation/Index.md#sqliteswift-documentation
## Usage
```swift
import SQLite
let db = try Connection("path/to/db.sqlite3")
let users = Table("users")
let id = Expression<Int64>("id")
let name = Expression<String?>("name")
let email = Expression<String>("email")
try db.run(users.create { t in
t.column(id, primaryKey: true)
t.column(name)
t.column(email, unique: true)
})
// CREATE TABLE "users" (
// "id" INTEGER PRIMARY KEY NOT NULL,
// "name" TEXT,
// "email" TEXT NOT NULL UNIQUE
// )
let insert = users.insert(name <- "Alice", email <- "alice@mac.com")
let rowid = try db.run(insert)
// INSERT INTO "users" ("name", "email") VALUES ('Alice', 'alice@mac.com')
for user in try db.prepare(users) {
print("id: \(user[id]), name: \(user[name]), email: \(user[email])")
// id: 1, name: Optional("Alice"), email: alice@mac.com
}
// SELECT * FROM "users"
let alice = users.filter(id == rowid)
try db.run(alice.update(email <- email.replace("mac.com", with: "me.com")))
// UPDATE "users" SET "email" = replace("email", 'mac.com', 'me.com')
// WHERE ("id" = 1)
try db.run(alice.delete())
// DELETE FROM "users" WHERE ("id" = 1)
try db.scalar(users.count) // 0
// SELECT count(*) FROM "users"
```
SQLite.swift also works as a lightweight, Swift-friendly wrapper over the C
API.
```swift
let stmt = try db.prepare("INSERT INTO users (email) VALUES (?)")
for email in ["betty@icloud.com", "cathy@icloud.com"] {
try stmt.run(email)
}
db.totalChanges // 3
db.changes // 1
db.lastInsertRowid // 3
for row in try db.prepare("SELECT id, email FROM users") {
print("id: \(row[0]), email: \(row[1])")
// id: Optional(2), email: Optional("betty@icloud.com")
// id: Optional(3), email: Optional("cathy@icloud.com")
}
try db.scalar("SELECT count(*) FROM users") // 2
```
[Read the documentation][See Documentation] or explore more,
interactively, from the Xcode projects playground.
![SQLite.playground Screen Shot](Documentation/Resources/playground@2x.png)
For a more comprehensive example, see
[this article][Create a Data Access Layer with SQLite.swift and Swift 2]
and the [companion repository][SQLiteDataAccessLayer2].
[Create a Data Access Layer with SQLite.swift and Swift 2]: http://masteringswift.blogspot.com/2015/09/create-data-access-layer-with.html
[SQLiteDataAccessLayer2]: https://github.com/hoffmanjon/SQLiteDataAccessLayer2/tree/master
## Installation
> _Note:_ Version 0.12 requires Swift 5 (and [Xcode](https://developer.apple.com/xcode/downloads/) 10.2) or greater. Version 0.11.6 requires Swift 4.2 (and [Xcode](https://developer.apple.com/xcode/downloads/) 10.1) or greater.
### Carthage
[Carthage][] is a simple, decentralized dependency manager for Cocoa. To
install SQLite.swift with Carthage:
1. Make sure Carthage is [installed][Carthage Installation].
2. Update your Cartfile to include the following:
```ruby
github "stephencelis/SQLite.swift" ~> 0.12.0
```
3. Run `carthage update` and
[add the appropriate framework][Carthage Usage].
[Carthage]: https://github.com/Carthage/Carthage
[Carthage Installation]: https://github.com/Carthage/Carthage#installing-carthage
[Carthage Usage]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
### CocoaPods
[CocoaPods][] is a dependency manager for Cocoa projects. To install
SQLite.swift with CocoaPods:
1. Make sure CocoaPods is [installed][CocoaPods Installation]. (SQLite.swift
requires version 1.6.1 or greater.)
```sh
# Using the default Ruby install will require you to use sudo when
# installing and updating gems.
[sudo] gem install cocoapods
```
2. Update your Podfile to include the following:
```ruby
use_frameworks!
target 'YourAppTargetName' do
pod 'SQLite.swift', '~> 0.12.0'
end
```
3. Run `pod install --repo-update`.
[CocoaPods]: https://cocoapods.org
[CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started
### Swift Package Manager
The [Swift Package Manager][] is a tool for managing the distribution of
Swift code.
1. Add the following to your `Package.swift` file:
```swift
dependencies: [
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.12.0")
]
```
2. Build your project:
```sh
$ swift build
```
[Swift Package Manager]: https://swift.org/package-manager
### Manual
To install SQLite.swift as an Xcode sub-project:
1. Drag the **SQLite.xcodeproj** file into your own project.
([Submodule][], clone, or [download][] the project first.)
![Installation Screen Shot](Documentation/Resources/installation@2x.png)
2. In your targets **General** tab, click the **+** button under **Linked
Frameworks and Libraries**.
3. Select the appropriate **SQLite.framework** for your platform.
4. **Add**.
Some additional steps are required to install the application on an actual
device:
5. In the **General** tab, click the **+** button under **Embedded
Binaries**.
6. Select the appropriate **SQLite.framework** for your platform.
7. **Add**.
[Xcode]: https://developer.apple.com/xcode/downloads/
[Submodule]: http://git-scm.com/book/en/Git-Tools-Submodules
[download]: https://github.com/stephencelis/SQLite.swift/archive/master.zip
## Communication
[See the planning document] for a roadmap and existing feature requests.
[Read the contributing guidelines][]. The _TL;DR_ (but please; _R_):
- Need **help** or have a **general question**? [Ask on Stack
Overflow][] (tag `sqlite.swift`).
- Found a **bug** or have a **feature request**? [Open an issue][].
- Want to **contribute**? [Submit a pull request][].
[See the planning document]: /Documentation/Planning.md
[Read the contributing guidelines]: ./CONTRIBUTING.md#contributing
[Ask on Stack Overflow]: http://stackoverflow.com/questions/tagged/sqlite.swift
[Open an issue]: https://github.com/stephencelis/SQLite.swift/issues/new
[Submit a pull request]: https://github.com/stephencelis/SQLite.swift/fork
## Author
- [Stephen Celis](mailto:stephen@stephencelis.com)
([@stephencelis](https://twitter.com/stephencelis))
## License
SQLite.swift is available under the MIT license. See [the LICENSE
file](./LICENSE.txt) for more information.
## Related
These projects enhance or use SQLite.swift:
- [SQLiteMigrationManager.swift][] (inspired by
[FMDBMigrationManager][])
## Alternatives
Looking for something else? Try another Swift wrapper (or [FMDB][]):
- [Camembert](https://github.com/remirobert/Camembert)
- [GRDB](https://github.com/groue/GRDB.swift)
- [SQLiteDB](https://github.com/FahimF/SQLiteDB)
- [Squeal](https://github.com/nerdyc/Squeal)
- [SwiftData](https://github.com/ryanfowler/SwiftData)
- [SwiftSQLite](https://github.com/chrismsimpson/SwiftSQLite)
[Swift]: https://swift.org/
[SQLite3]: http://www.sqlite.org
[SQLite.swift]: https://github.com/stephencelis/SQLite.swift
[TravisBadge]: https://img.shields.io/travis/stephencelis/SQLite.swift/master.svg?style=flat
[TravisLink]: https://travis-ci.org/stephencelis/SQLite.swift
[CocoaPodsVersionBadge]: https://cocoapod-badges.herokuapp.com/v/SQLite.swift/badge.png
[CocoaPodsVersionLink]: http://cocoadocs.org/docsets/SQLite.swift
[PlatformBadge]: https://cocoapod-badges.herokuapp.com/p/SQLite.swift/badge.png
[PlatformLink]: http://cocoadocs.org/docsets/SQLite.swift
[CartagheBadge]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat
[CarthageLink]: https://github.com/Carthage/Carthage
[GitterBadge]: https://badges.gitter.im/stephencelis/SQLite.swift.svg
[GitterLink]: https://gitter.im/stephencelis/SQLite.swift
[Swift5Badge]: https://img.shields.io/badge/swift-5-orange.svg?style=flat
[Swift5Link]: https://developer.apple.com/swift/
[SQLiteMigrationManager.swift]: https://github.com/garriguv/SQLiteMigrationManager.swift
[FMDB]: https://github.com/ccgus/fmdb
[FMDBMigrationManager]: https://github.com/layerhq/FMDBMigrationManager
+60
View File
@@ -0,0 +1,60 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
public struct Blob {
public let bytes: [UInt8]
public init(bytes: [UInt8]) {
self.bytes = bytes
}
public init(bytes: UnsafeRawPointer, length: Int) {
let i8bufptr = UnsafeBufferPointer(start: bytes.assumingMemoryBound(to: UInt8.self), count: length)
self.init(bytes: [UInt8](i8bufptr))
}
public func toHex() -> String {
return bytes.map {
($0 < 16 ? "0" : "") + String($0, radix: 16, uppercase: false)
}.joined(separator: "")
}
}
extension Blob : CustomStringConvertible {
public var description: String {
return "x'\(toHex())'"
}
}
extension Blob : Equatable {
}
public func ==(lhs: Blob, rhs: Blob) -> Bool {
return lhs.bytes == rhs.bytes
}
+750
View File
@@ -0,0 +1,750 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
import Dispatch
#if SQLITE_SWIFT_STANDALONE
import sqlite3
#elseif SQLITE_SWIFT_SQLCIPHER
import SQLCipher
#elseif os(Linux)
import CSQLite
#else
import SQLite3
#endif
/// A connection to SQLite.
public final class Connection {
/// The location of a SQLite database.
public enum Location {
/// An in-memory database (equivalent to `.uri(":memory:")`).
///
/// See: <https://www.sqlite.org/inmemorydb.html#sharedmemdb>
case inMemory
/// A temporary, file-backed database (equivalent to `.uri("")`).
///
/// See: <https://www.sqlite.org/inmemorydb.html#temp_db>
case temporary
/// A database located at the given URI filename (or path).
///
/// See: <https://www.sqlite.org/uri.html>
///
/// - Parameter filename: A URI filename
case uri(String)
}
/// An SQL operation passed to update callbacks.
public enum Operation {
/// An INSERT operation.
case insert
/// An UPDATE operation.
case update
/// A DELETE operation.
case delete
fileprivate init(rawValue:Int32) {
switch rawValue {
case SQLITE_INSERT:
self = .insert
case SQLITE_UPDATE:
self = .update
case SQLITE_DELETE:
self = .delete
default:
fatalError("unhandled operation code: \(rawValue)")
}
}
}
public var handle: OpaquePointer { return _handle! }
fileprivate var _handle: OpaquePointer? = nil
/// Initializes a new SQLite connection.
///
/// - Parameters:
///
/// - location: The location of the database. Creates a new database if it
/// doesnt already exist (unless in read-only mode).
///
/// Default: `.inMemory`.
///
/// - readonly: Whether or not to open the database in a read-only state.
///
/// Default: `false`.
///
/// - Returns: A new database connection.
public init(_ location: Location = .inMemory, readonly: Bool = false) throws {
let flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE
try check(sqlite3_open_v2(location.description, &_handle, flags | SQLITE_OPEN_FULLMUTEX, nil))
queue.setSpecific(key: Connection.queueKey, value: queueContext)
}
/// Initializes a new connection to a database.
///
/// - Parameters:
///
/// - filename: The location of the database. Creates a new database if
/// it doesnt already exist (unless in read-only mode).
///
/// - readonly: Whether or not to open the database in a read-only state.
///
/// Default: `false`.
///
/// - Throws: `Result.Error` iff a connection cannot be established.
///
/// - Returns: A new database connection.
public convenience init(_ filename: String, readonly: Bool = false) throws {
try self.init(.uri(filename), readonly: readonly)
}
deinit {
sqlite3_close(handle)
}
// MARK: -
/// Whether or not the database was opened in a read-only state.
public var readonly: Bool { return sqlite3_db_readonly(handle, nil) == 1 }
/// The last rowid inserted into the database via this connection.
public var lastInsertRowid: Int64 {
return sqlite3_last_insert_rowid(handle)
}
/// The last number of changes (inserts, updates, or deletes) made to the
/// database via this connection.
public var changes: Int {
return Int(sqlite3_changes(handle))
}
/// The total number of changes (inserts, updates, or deletes) made to the
/// database via this connection.
public var totalChanges: Int {
return Int(sqlite3_total_changes(handle))
}
// MARK: - Execute
/// Executes a batch of SQL statements.
///
/// - Parameter SQL: A batch of zero or more semicolon-separated SQL
/// statements.
///
/// - Throws: `Result.Error` if query execution fails.
public func execute(_ SQL: String) throws {
_ = try sync { try self.check(sqlite3_exec(self.handle, SQL, nil, nil, nil)) }
}
// MARK: - Prepare
/// Prepares a single SQL statement (with optional parameter bindings).
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Returns: A prepared statement.
public func prepare(_ statement: String, _ bindings: Binding?...) throws -> Statement {
if !bindings.isEmpty { return try prepare(statement, bindings) }
return try Statement(self, statement)
}
/// Prepares a single SQL statement and binds parameters to it.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Returns: A prepared statement.
public func prepare(_ statement: String, _ bindings: [Binding?]) throws -> Statement {
return try prepare(statement).bind(bindings)
}
/// Prepares a single SQL statement and binds parameters to it.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A dictionary of named parameters to bind to the statement.
///
/// - Returns: A prepared statement.
public func prepare(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement {
return try prepare(statement).bind(bindings)
}
// MARK: - Run
/// Runs a single SQL statement (with optional parameter bindings).
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement.
@discardableResult public func run(_ statement: String, _ bindings: Binding?...) throws -> Statement {
return try run(statement, bindings)
}
/// Prepares, binds, and runs a single SQL statement.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement.
@discardableResult public func run(_ statement: String, _ bindings: [Binding?]) throws -> Statement {
return try prepare(statement).run(bindings)
}
/// Prepares, binds, and runs a single SQL statement.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A dictionary of named parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement.
@discardableResult public func run(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement {
return try prepare(statement).run(bindings)
}
// MARK: - Scalar
/// Runs a single SQL statement (with optional parameter bindings),
/// returning the first value of the first row.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ statement: String, _ bindings: Binding?...) throws -> Binding? {
return try scalar(statement, bindings)
}
/// Runs a single SQL statement (with optional parameter bindings),
/// returning the first value of the first row.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ statement: String, _ bindings: [Binding?]) throws -> Binding? {
return try prepare(statement).scalar(bindings)
}
/// Runs a single SQL statement (with optional parameter bindings),
/// returning the first value of the first row.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A dictionary of named parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ statement: String, _ bindings: [String: Binding?]) throws -> Binding? {
return try prepare(statement).scalar(bindings)
}
// MARK: - Transactions
/// The mode in which a transaction acquires a lock.
public enum TransactionMode : String {
/// Defers locking the database till the first read/write executes.
case deferred = "DEFERRED"
/// Immediately acquires a reserved lock on the database.
case immediate = "IMMEDIATE"
/// Immediately acquires an exclusive lock on all databases.
case exclusive = "EXCLUSIVE"
}
// TODO: Consider not requiring a throw to roll back?
/// Runs a transaction with the given mode.
///
/// - Note: Transactions cannot be nested. To nest transactions, see
/// `savepoint()`, instead.
///
/// - Parameters:
///
/// - mode: The mode in which a transaction acquires a lock.
///
/// Default: `.deferred`
///
/// - block: A closure to run SQL statements within the transaction.
/// The transaction will be committed when the block returns. The block
/// must throw to roll the transaction back.
///
/// - Throws: `Result.Error`, and rethrows.
public func transaction(_ mode: TransactionMode = .deferred, block: () throws -> Void) throws {
try transaction("BEGIN \(mode.rawValue) TRANSACTION", block, "COMMIT TRANSACTION", or: "ROLLBACK TRANSACTION")
}
// TODO: Consider not requiring a throw to roll back?
// TODO: Consider removing ability to set a name?
/// Runs a transaction with the given savepoint name (if omitted, it will
/// generate a UUID).
///
/// - SeeAlso: `transaction()`.
///
/// - Parameters:
///
/// - savepointName: A unique identifier for the savepoint (optional).
///
/// - block: A closure to run SQL statements within the transaction.
/// The savepoint will be released (committed) when the block returns.
/// The block must throw to roll the savepoint back.
///
/// - Throws: `SQLite.Result.Error`, and rethrows.
public func savepoint(_ name: String = UUID().uuidString, block: () throws -> Void) throws {
let name = name.quote("'")
let savepoint = "SAVEPOINT \(name)"
try transaction(savepoint, block, "RELEASE \(savepoint)", or: "ROLLBACK TO \(savepoint)")
}
fileprivate func transaction(_ begin: String, _ block: () throws -> Void, _ commit: String, or rollback: String) throws {
return try sync {
try self.run(begin)
do {
try block()
try self.run(commit)
} catch {
try self.run(rollback)
throw error
}
}
}
/// Interrupts any long-running queries.
public func interrupt() {
sqlite3_interrupt(handle)
}
// MARK: - Handlers
/// The number of seconds a connection will attempt to retry a statement
/// after encountering a busy signal (lock).
public var busyTimeout: Double = 0 {
didSet {
sqlite3_busy_timeout(handle, Int32(busyTimeout * 1_000))
}
}
/// Sets a handler to call after encountering a busy signal (lock).
///
/// - Parameter callback: This block is executed during a lock in which a
/// busy error would otherwise be returned. Its passed the number of
/// times its been called for this lock. If it returns `true`, it will
/// try again. If it returns `false`, no further attempts will be made.
public func busyHandler(_ callback: ((_ tries: Int) -> Bool)?) {
guard let callback = callback else {
sqlite3_busy_handler(handle, nil, nil)
busyHandler = nil
return
}
let box: BusyHandler = { callback(Int($0)) ? 1 : 0 }
sqlite3_busy_handler(handle, { callback, tries in
unsafeBitCast(callback, to: BusyHandler.self)(tries)
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
busyHandler = box
}
fileprivate typealias BusyHandler = @convention(block) (Int32) -> Int32
fileprivate var busyHandler: BusyHandler?
/// Sets a handler to call when a statement is executed with the compiled
/// SQL.
///
/// - Parameter callback: This block is invoked when a statement is executed
/// with the compiled SQL as its argument.
///
/// db.trace { SQL in print(SQL) }
public func trace(_ callback: ((String) -> Void)?) {
#if SQLITE_SWIFT_SQLCIPHER || os(Linux)
trace_v1(callback)
#else
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
trace_v2(callback)
} else {
trace_v1(callback)
}
#endif
}
fileprivate func trace_v1(_ callback: ((String) -> Void)?) {
guard let callback = callback else {
sqlite3_trace(handle, nil /* xCallback */, nil /* pCtx */)
trace = nil
return
}
let box: Trace = { (pointer: UnsafeRawPointer) in
callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self)))
}
sqlite3_trace(handle,
{
(C: UnsafeMutableRawPointer?, SQL: UnsafePointer<Int8>?) in
if let C = C, let SQL = SQL {
unsafeBitCast(C, to: Trace.self)(SQL)
}
},
unsafeBitCast(box, to: UnsafeMutableRawPointer.self)
)
trace = box
}
fileprivate typealias Trace = @convention(block) (UnsafeRawPointer) -> Void
fileprivate var trace: Trace?
/// Registers a callback to be invoked whenever a row is inserted, updated,
/// or deleted in a rowid table.
///
/// - Parameter callback: A callback invoked with the `Operation` (one of
/// `.Insert`, `.Update`, or `.Delete`), database name, table name, and
/// rowid.
public func updateHook(_ callback: ((_ operation: Operation, _ db: String, _ table: String, _ rowid: Int64) -> Void)?) {
guard let callback = callback else {
sqlite3_update_hook(handle, nil, nil)
updateHook = nil
return
}
let box: UpdateHook = {
callback(
Operation(rawValue: $0),
String(cString: $1),
String(cString: $2),
$3
)
}
sqlite3_update_hook(handle, { callback, operation, db, table, rowid in
unsafeBitCast(callback, to: UpdateHook.self)(operation, db!, table!, rowid)
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
updateHook = box
}
fileprivate typealias UpdateHook = @convention(block) (Int32, UnsafePointer<Int8>, UnsafePointer<Int8>, Int64) -> Void
fileprivate var updateHook: UpdateHook?
/// Registers a callback to be invoked whenever a transaction is committed.
///
/// - Parameter callback: A callback invoked whenever a transaction is
/// committed. If this callback throws, the transaction will be rolled
/// back.
public func commitHook(_ callback: (() throws -> Void)?) {
guard let callback = callback else {
sqlite3_commit_hook(handle, nil, nil)
commitHook = nil
return
}
let box: CommitHook = {
do {
try callback()
} catch {
return 1
}
return 0
}
sqlite3_commit_hook(handle, { callback in
unsafeBitCast(callback, to: CommitHook.self)()
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
commitHook = box
}
fileprivate typealias CommitHook = @convention(block) () -> Int32
fileprivate var commitHook: CommitHook?
/// Registers a callback to be invoked whenever a transaction rolls back.
///
/// - Parameter callback: A callback invoked when a transaction is rolled
/// back.
public func rollbackHook(_ callback: (() -> Void)?) {
guard let callback = callback else {
sqlite3_rollback_hook(handle, nil, nil)
rollbackHook = nil
return
}
let box: RollbackHook = { callback() }
sqlite3_rollback_hook(handle, { callback in
unsafeBitCast(callback, to: RollbackHook.self)()
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
rollbackHook = box
}
fileprivate typealias RollbackHook = @convention(block) () -> Void
fileprivate var rollbackHook: RollbackHook?
/// Creates or redefines a custom SQL function.
///
/// - Parameters:
///
/// - function: The name of the function to create or redefine.
///
/// - argumentCount: The number of arguments that the function takes. If
/// `nil`, the function may take any number of arguments.
///
/// Default: `nil`
///
/// - deterministic: Whether or not the function is deterministic (_i.e._
/// the function always returns the same result for a given input).
///
/// Default: `false`
///
/// - block: A block of code to run when the function is called. The block
/// is called with an array of raw SQL values mapped to the functions
/// parameters and should return a raw SQL value (or nil).
public func createFunction(_ function: String, argumentCount: UInt? = nil, deterministic: Bool = false, _ block: @escaping (_ args: [Binding?]) -> Binding?) {
let argc = argumentCount.map { Int($0) } ?? -1
let box: Function = { context, argc, argv in
let arguments: [Binding?] = (0..<Int(argc)).map { idx in
let value = argv![idx]
switch sqlite3_value_type(value) {
case SQLITE_BLOB:
return Blob(bytes: sqlite3_value_blob(value), length: Int(sqlite3_value_bytes(value)))
case SQLITE_FLOAT:
return sqlite3_value_double(value)
case SQLITE_INTEGER:
return sqlite3_value_int64(value)
case SQLITE_NULL:
return nil
case SQLITE_TEXT:
return String(cString: UnsafePointer(sqlite3_value_text(value)))
case let type:
fatalError("unsupported value type: \(type)")
}
}
let result = block(arguments)
if let result = result as? Blob {
sqlite3_result_blob(context, result.bytes, Int32(result.bytes.count), nil)
} else if let result = result as? Double {
sqlite3_result_double(context, result)
} else if let result = result as? Int64 {
sqlite3_result_int64(context, result)
} else if let result = result as? String {
sqlite3_result_text(context, result, Int32(result.count), SQLITE_TRANSIENT)
} else if result == nil {
sqlite3_result_null(context)
} else {
fatalError("unsupported result type: \(String(describing: result))")
}
}
var flags = SQLITE_UTF8
#if !os(Linux)
if deterministic {
flags |= SQLITE_DETERMINISTIC
}
#endif
sqlite3_create_function_v2(handle, function, Int32(argc), flags, unsafeBitCast(box, to: UnsafeMutableRawPointer.self), { context, argc, value in
let function = unsafeBitCast(sqlite3_user_data(context), to: Function.self)
function(context, argc, value)
}, nil, nil, nil)
if functions[function] == nil { self.functions[function] = [:] }
functions[function]?[argc] = box
}
fileprivate typealias Function = @convention(block) (OpaquePointer?, Int32, UnsafeMutablePointer<OpaquePointer?>?) -> Void
fileprivate var functions = [String: [Int: Function]]()
/// Defines a new collating sequence.
///
/// - Parameters:
///
/// - collation: The name of the collation added.
///
/// - block: A collation function that takes two strings and returns the
/// comparison result.
public func createCollation(_ collation: String, _ block: @escaping (_ lhs: String, _ rhs: String) -> ComparisonResult) throws {
let box: Collation = { (lhs: UnsafeRawPointer, rhs: UnsafeRawPointer) in
let lstr = String(cString: lhs.assumingMemoryBound(to: UInt8.self))
let rstr = String(cString: rhs.assumingMemoryBound(to: UInt8.self))
return Int32(block(lstr, rstr).rawValue)
}
try check(sqlite3_create_collation_v2(handle, collation, SQLITE_UTF8,
unsafeBitCast(box, to: UnsafeMutableRawPointer.self),
{ (callback: UnsafeMutableRawPointer?, _, lhs: UnsafeRawPointer?, _, rhs: UnsafeRawPointer?) in /* xCompare */
if let lhs = lhs, let rhs = rhs {
return unsafeBitCast(callback, to: Collation.self)(lhs, rhs)
} else {
fatalError("sqlite3_create_collation_v2 callback called with NULL pointer")
}
}, nil /* xDestroy */))
collations[collation] = box
}
fileprivate typealias Collation = @convention(block) (UnsafeRawPointer, UnsafeRawPointer) -> Int32
fileprivate var collations = [String: Collation]()
// MARK: - Error Handling
func sync<T>(_ block: () throws -> T) rethrows -> T {
if DispatchQueue.getSpecific(key: Connection.queueKey) == queueContext {
return try block()
} else {
return try queue.sync(execute: block)
}
}
@discardableResult func check(_ resultCode: Int32, statement: Statement? = nil) throws -> Int32 {
guard let error = Result(errorCode: resultCode, connection: self, statement: statement) else {
return resultCode
}
throw error
}
fileprivate var queue = DispatchQueue(label: "SQLite.Database", attributes: [])
fileprivate static let queueKey = DispatchSpecificKey<Int>()
fileprivate lazy var queueContext: Int = unsafeBitCast(self, to: Int.self)
}
extension Connection : CustomStringConvertible {
public var description: String {
return String(cString: sqlite3_db_filename(handle, nil))
}
}
extension Connection.Location : CustomStringConvertible {
public var description: String {
switch self {
case .inMemory:
return ":memory:"
case .temporary:
return ""
case .uri(let URI):
return URI
}
}
}
public enum Result : Error {
fileprivate static let successCodes: Set = [SQLITE_OK, SQLITE_ROW, SQLITE_DONE]
/// Represents a SQLite specific [error code](https://sqlite.org/rescode.html)
///
/// - message: English-language text that describes the error
///
/// - code: SQLite [error code](https://sqlite.org/rescode.html#primary_result_code_list)
///
/// - statement: the statement which produced the error
case error(message: String, code: Int32, statement: Statement?)
init?(errorCode: Int32, connection: Connection, statement: Statement? = nil) {
guard !Result.successCodes.contains(errorCode) else { return nil }
let message = String(cString: sqlite3_errmsg(connection.handle))
self = .error(message: message, code: errorCode, statement: statement)
}
}
extension Result : CustomStringConvertible {
public var description: String {
switch self {
case let .error(message, errorCode, statement):
if let statement = statement {
return "\(message) (\(statement)) (code: \(errorCode))"
} else {
return "\(message) (code: \(errorCode))"
}
}
}
}
#if !SQLITE_SWIFT_SQLCIPHER && !os(Linux)
@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)
extension Connection {
fileprivate func trace_v2(_ callback: ((String) -> Void)?) {
guard let callback = callback else {
// If the X callback is NULL or if the M mask is zero, then tracing is disabled.
sqlite3_trace_v2(handle, 0 /* mask */, nil /* xCallback */, nil /* pCtx */)
trace = nil
return
}
let box: Trace = { (pointer: UnsafeRawPointer) in
callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self)))
}
sqlite3_trace_v2(handle,
UInt32(SQLITE_TRACE_STMT) /* mask */,
{
// A trace callback is invoked with four arguments: callback(T,C,P,X).
// The T argument is one of the SQLITE_TRACE constants to indicate why the
// callback was invoked. The C argument is a copy of the context pointer.
// The P and X arguments are pointers whose meanings depend on T.
(T: UInt32, C: UnsafeMutableRawPointer?, P: UnsafeMutableRawPointer?, X: UnsafeMutableRawPointer?) in
if let P = P,
let expandedSQL = sqlite3_expanded_sql(OpaquePointer(P)) {
unsafeBitCast(C, to: Trace.self)(expandedSQL)
sqlite3_free(expandedSQL)
}
return Int32(0) // currently ignored
},
unsafeBitCast(box, to: UnsafeMutableRawPointer.self) /* pCtx */
)
trace = box
}
}
#endif
+21
View File
@@ -0,0 +1,21 @@
import Foundation
public enum QueryError: Error, CustomStringConvertible {
case noSuchTable(name: String)
case noSuchColumn(name: String, columns: [String])
case ambiguousColumn(name: String, similar: [String])
case unexpectedNullValue(name: String)
public var description: String {
switch self {
case .noSuchTable(let name):
return "No such table: \(name)"
case .noSuchColumn(let name, let columns):
return "No such column `\(name)` in columns \(columns)"
case .ambiguousColumn(let name, let similar):
return "Ambiguous column `\(name)` (please disambiguate: \(similar))"
case .unexpectedNullValue(let name):
return "Unexpected null value for column `\(name)`"
}
}
}
+317
View File
@@ -0,0 +1,317 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if SQLITE_SWIFT_STANDALONE
import sqlite3
#elseif SQLITE_SWIFT_SQLCIPHER
import SQLCipher
#elseif os(Linux)
import CSQLite
#else
import SQLite3
#endif
/// A single SQL statement.
public final class Statement {
fileprivate var handle: OpaquePointer? = nil
fileprivate let connection: Connection
init(_ connection: Connection, _ SQL: String) throws {
self.connection = connection
try connection.check(sqlite3_prepare_v2(connection.handle, SQL, -1, &handle, nil))
}
deinit {
sqlite3_finalize(handle)
}
public lazy var columnCount: Int = Int(sqlite3_column_count(self.handle))
public lazy var columnNames: [String] = (0..<Int32(self.columnCount)).map {
String(cString: sqlite3_column_name(self.handle, $0))
}
/// A cursor pointing to the current row.
public lazy var row: Cursor = Cursor(self)
/// Binds a list of parameters to a statement.
///
/// - Parameter values: A list of parameters to bind to the statement.
///
/// - Returns: The statement object (useful for chaining).
public func bind(_ values: Binding?...) -> Statement {
return bind(values)
}
/// Binds a list of parameters to a statement.
///
/// - Parameter values: A list of parameters to bind to the statement.
///
/// - Returns: The statement object (useful for chaining).
public func bind(_ values: [Binding?]) -> Statement {
if values.isEmpty { return self }
reset()
guard values.count == Int(sqlite3_bind_parameter_count(handle)) else {
fatalError("\(sqlite3_bind_parameter_count(handle)) values expected, \(values.count) passed")
}
for idx in 1...values.count { bind(values[idx - 1], atIndex: idx) }
return self
}
/// Binds a dictionary of named parameters to a statement.
///
/// - Parameter values: A dictionary of named parameters to bind to the
/// statement.
///
/// - Returns: The statement object (useful for chaining).
public func bind(_ values: [String: Binding?]) -> Statement {
reset()
for (name, value) in values {
let idx = sqlite3_bind_parameter_index(handle, name)
guard idx > 0 else {
fatalError("parameter not found: \(name)")
}
bind(value, atIndex: Int(idx))
}
return self
}
fileprivate func bind(_ value: Binding?, atIndex idx: Int) {
if value == nil {
sqlite3_bind_null(handle, Int32(idx))
} else if let value = value as? Blob {
sqlite3_bind_blob(handle, Int32(idx), value.bytes, Int32(value.bytes.count), SQLITE_TRANSIENT)
} else if let value = value as? Double {
sqlite3_bind_double(handle, Int32(idx), value)
} else if let value = value as? Int64 {
sqlite3_bind_int64(handle, Int32(idx), value)
} else if let value = value as? String {
sqlite3_bind_text(handle, Int32(idx), value, -1, SQLITE_TRANSIENT)
} else if let value = value as? Int {
self.bind(value.datatypeValue, atIndex: idx)
} else if let value = value as? Bool {
self.bind(value.datatypeValue, atIndex: idx)
} else if let value = value {
fatalError("tried to bind unexpected value \(value)")
}
}
/// - Parameter bindings: A list of parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement object (useful for chaining).
@discardableResult public func run(_ bindings: Binding?...) throws -> Statement {
guard bindings.isEmpty else {
return try run(bindings)
}
reset(clearBindings: false)
repeat {} while try step()
return self
}
/// - Parameter bindings: A list of parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement object (useful for chaining).
@discardableResult public func run(_ bindings: [Binding?]) throws -> Statement {
return try bind(bindings).run()
}
/// - Parameter bindings: A dictionary of named parameters to bind to the
/// statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement object (useful for chaining).
@discardableResult public func run(_ bindings: [String: Binding?]) throws -> Statement {
return try bind(bindings).run()
}
/// - Parameter bindings: A list of parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ bindings: Binding?...) throws -> Binding? {
guard bindings.isEmpty else {
return try scalar(bindings)
}
reset(clearBindings: false)
_ = try step()
return row[0]
}
/// - Parameter bindings: A list of parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ bindings: [Binding?]) throws -> Binding? {
return try bind(bindings).scalar()
}
/// - Parameter bindings: A dictionary of named parameters to bind to the
/// statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ bindings: [String: Binding?]) throws -> Binding? {
return try bind(bindings).scalar()
}
public func step() throws -> Bool {
return try connection.sync { try self.connection.check(sqlite3_step(self.handle)) == SQLITE_ROW }
}
fileprivate func reset(clearBindings shouldClear: Bool = true) {
sqlite3_reset(handle)
if (shouldClear) { sqlite3_clear_bindings(handle) }
}
}
extension Statement : Sequence {
public func makeIterator() -> Statement {
reset(clearBindings: false)
return self
}
}
public protocol FailableIterator : IteratorProtocol {
func failableNext() throws -> Self.Element?
}
extension FailableIterator {
public func next() -> Element? {
return try! failableNext()
}
}
extension Array {
public init<I: FailableIterator>(_ failableIterator: I) throws where I.Element == Element {
self.init()
while let row = try failableIterator.failableNext() {
append(row)
}
}
}
extension Statement : FailableIterator {
public typealias Element = [Binding?]
public func failableNext() throws -> [Binding?]? {
return try step() ? Array(row) : nil
}
}
extension Statement : CustomStringConvertible {
public var description: String {
return String(cString: sqlite3_sql(handle))
}
}
public struct Cursor {
fileprivate let handle: OpaquePointer
fileprivate let columnCount: Int
fileprivate init(_ statement: Statement) {
handle = statement.handle!
columnCount = statement.columnCount
}
public subscript(idx: Int) -> Double {
return sqlite3_column_double(handle, Int32(idx))
}
public subscript(idx: Int) -> Int64 {
return sqlite3_column_int64(handle, Int32(idx))
}
public subscript(idx: Int) -> String {
return String(cString: UnsafePointer(sqlite3_column_text(handle, Int32(idx))))
}
public subscript(idx: Int) -> Blob {
if let pointer = sqlite3_column_blob(handle, Int32(idx)) {
let length = Int(sqlite3_column_bytes(handle, Int32(idx)))
return Blob(bytes: pointer, length: length)
} else {
// The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
// https://www.sqlite.org/c3ref/column_blob.html
return Blob(bytes: [])
}
}
// MARK: -
public subscript(idx: Int) -> Bool {
return Bool.fromDatatypeValue(self[idx])
}
public subscript(idx: Int) -> Int {
return Int.fromDatatypeValue(self[idx])
}
}
/// Cursors provide direct access to a statements current row.
extension Cursor : Sequence {
public subscript(idx: Int) -> Binding? {
switch sqlite3_column_type(handle, Int32(idx)) {
case SQLITE_BLOB:
return self[idx] as Blob
case SQLITE_FLOAT:
return self[idx] as Double
case SQLITE_INTEGER:
return self[idx] as Int64
case SQLITE_NULL:
return nil
case SQLITE_TEXT:
return self[idx] as String
case let type:
fatalError("unsupported column type: \(type)")
}
}
public func makeIterator() -> AnyIterator<Binding?> {
var idx = 0
return AnyIterator {
if idx >= self.columnCount {
return Optional<Binding?>.none
} else {
idx += 1
return self[idx - 1]
}
}
}
}
+132
View File
@@ -0,0 +1,132 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
/// - Warning: `Binding` is a protocol that SQLite.swift uses internally to
/// directly map SQLite types to Swift types.
///
/// Do not conform custom types to the Binding protocol. See the `Value`
/// protocol, instead.
public protocol Binding {}
public protocol Number : Binding {}
public protocol Value : Expressible { // extensions cannot have inheritance clauses
associatedtype ValueType = Self
associatedtype Datatype : Binding
static var declaredDatatype: String { get }
static func fromDatatypeValue(_ datatypeValue: Datatype) -> ValueType
var datatypeValue: Datatype { get }
}
extension Double : Number, Value {
public static let declaredDatatype = "REAL"
public static func fromDatatypeValue(_ datatypeValue: Double) -> Double {
return datatypeValue
}
public var datatypeValue: Double {
return self
}
}
extension Int64 : Number, Value {
public static let declaredDatatype = "INTEGER"
public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int64 {
return datatypeValue
}
public var datatypeValue: Int64 {
return self
}
}
extension String : Binding, Value {
public static let declaredDatatype = "TEXT"
public static func fromDatatypeValue(_ datatypeValue: String) -> String {
return datatypeValue
}
public var datatypeValue: String {
return self
}
}
extension Blob : Binding, Value {
public static let declaredDatatype = "BLOB"
public static func fromDatatypeValue(_ datatypeValue: Blob) -> Blob {
return datatypeValue
}
public var datatypeValue: Blob {
return self
}
}
// MARK: -
extension Bool : Binding, Value {
public static var declaredDatatype = Int64.declaredDatatype
public static func fromDatatypeValue(_ datatypeValue: Int64) -> Bool {
return datatypeValue != 0
}
public var datatypeValue: Int64 {
return self ? 1 : 0
}
}
extension Int : Number, Value {
public static var declaredDatatype = Int64.declaredDatatype
public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int {
return Int(datatypeValue)
}
public var datatypeValue: Int64 {
return Int64(self)
}
}
+352
View File
@@ -0,0 +1,352 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if SWIFT_PACKAGE
import SQLiteObjc
#endif
extension Module {
public static func FTS4(_ column: Expressible, _ more: Expressible...) -> Module {
return FTS4([column] + more)
}
public static func FTS4(_ columns: [Expressible] = [], tokenize tokenizer: Tokenizer? = nil) -> Module {
return FTS4(FTS4Config().columns(columns).tokenizer(tokenizer))
}
public static func FTS4(_ config: FTS4Config) -> Module {
return Module(name: "fts4", arguments: config.arguments())
}
}
extension VirtualTable {
/// Builds an expression appended with a `MATCH` query against the given
/// pattern.
///
/// let emails = VirtualTable("emails")
///
/// emails.filter(emails.match("Hello"))
/// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello'
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: An expression appended with a `MATCH` query against the given
/// pattern.
public func match(_ pattern: String) -> Expression<Bool> {
return "MATCH".infix(tableName(), pattern)
}
public func match(_ pattern: Expression<String>) -> Expression<Bool> {
return "MATCH".infix(tableName(), pattern)
}
public func match(_ pattern: Expression<String?>) -> Expression<Bool?> {
return "MATCH".infix(tableName(), pattern)
}
/// Builds a copy of the query with a `WHERE MATCH` clause.
///
/// let emails = VirtualTable("emails")
///
/// emails.match("Hello")
/// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello'
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A query with the given `WHERE MATCH` clause applied.
public func match(_ pattern: String) -> QueryType {
return filter(match(pattern))
}
public func match(_ pattern: Expression<String>) -> QueryType {
return filter(match(pattern))
}
public func match(_ pattern: Expression<String?>) -> QueryType {
return filter(match(pattern))
}
}
public struct Tokenizer {
public static let Simple = Tokenizer("simple")
public static let Porter = Tokenizer("porter")
public static func Unicode61(removeDiacritics: Bool? = nil, tokenchars: Set<Character> = [], separators: Set<Character> = []) -> Tokenizer {
var arguments = [String]()
if let removeDiacritics = removeDiacritics {
arguments.append("removeDiacritics=\(removeDiacritics ? 1 : 0)".quote())
}
if !tokenchars.isEmpty {
let joined = tokenchars.map { String($0) }.joined(separator: "")
arguments.append("tokenchars=\(joined)".quote())
}
if !separators.isEmpty {
let joined = separators.map { String($0) }.joined(separator: "")
arguments.append("separators=\(joined)".quote())
}
return Tokenizer("unicode61", arguments)
}
public static func Custom(_ name: String) -> Tokenizer {
return Tokenizer(Tokenizer.moduleName.quote(), [name.quote()])
}
public let name: String
public let arguments: [String]
fileprivate init(_ name: String, _ arguments: [String] = []) {
self.name = name
self.arguments = arguments
}
fileprivate static let moduleName = "SQLite.swift"
}
extension Tokenizer : CustomStringConvertible {
public var description: String {
return ([name] + arguments).joined(separator: " ")
}
}
extension Connection {
public func registerTokenizer(_ submoduleName: String, next: @escaping (String) -> (String, Range<String.Index>)?) throws {
try check(_SQLiteRegisterTokenizer(handle, Tokenizer.moduleName, submoduleName) { (
input: UnsafePointer<Int8>, offset: UnsafeMutablePointer<Int32>, length: UnsafeMutablePointer<Int32>) in
let string = String(cString: input)
guard let (token, range) = next(string) else { return nil }
let view:String.UTF8View = string.utf8
if let from = range.lowerBound.samePosition(in: view),
let to = range.upperBound.samePosition(in: view) {
offset.pointee += Int32(string[string.startIndex..<range.lowerBound].utf8.count)
length.pointee = Int32(view.distance(from: from, to: to))
return token
} else {
return nil
}
})
}
}
/// Configuration options shared between the [FTS4](https://www.sqlite.org/fts3.html) and
/// [FTS5](https://www.sqlite.org/fts5.html) extensions.
open class FTSConfig {
public enum ColumnOption {
/// [The notindexed= option](https://www.sqlite.org/fts3.html#section_6_5)
case unindexed
}
typealias ColumnDefinition = (Expressible, options: [ColumnOption])
var columnDefinitions = [ColumnDefinition]()
var tokenizer: Tokenizer?
var prefixes = [Int]()
var externalContentSchema: SchemaType?
var isContentless: Bool = false
/// Adds a column definition
@discardableResult open func column(_ column: Expressible, _ options: [ColumnOption] = []) -> Self {
self.columnDefinitions.append((column, options))
return self
}
@discardableResult open func columns(_ columns: [Expressible]) -> Self {
for column in columns {
self.column(column)
}
return self
}
/// [Tokenizers](https://www.sqlite.org/fts3.html#tokenizer)
open func tokenizer(_ tokenizer: Tokenizer?) -> Self {
self.tokenizer = tokenizer
return self
}
/// [The prefix= option](https://www.sqlite.org/fts3.html#section_6_6)
open func prefix(_ prefix: [Int]) -> Self {
self.prefixes += prefix
return self
}
/// [The content= option](https://www.sqlite.org/fts3.html#section_6_2)
open func externalContent(_ schema: SchemaType) -> Self {
self.externalContentSchema = schema
return self
}
/// [Contentless FTS4 Tables](https://www.sqlite.org/fts3.html#section_6_2_1)
open func contentless() -> Self {
self.isContentless = true
return self
}
func formatColumnDefinitions() -> [Expressible] {
return columnDefinitions.map { $0.0 }
}
func arguments() -> [Expressible] {
return options().arguments
}
func options() -> Options {
var options = Options()
options.append(formatColumnDefinitions())
if let tokenizer = tokenizer {
options.append("tokenize", value: Expression<Void>(literal: tokenizer.description))
}
options.appendCommaSeparated("prefix", values:prefixes.sorted().map { String($0) })
if isContentless {
options.append("content", value: "")
} else if let externalContentSchema = externalContentSchema {
options.append("content", value: externalContentSchema.tableName())
}
return options
}
struct Options {
var arguments = [Expressible]()
@discardableResult mutating func append(_ columns: [Expressible]) -> Options {
arguments.append(contentsOf: columns)
return self
}
@discardableResult mutating func appendCommaSeparated(_ key: String, values: [String]) -> Options {
if values.isEmpty {
return self
} else {
return append(key, value: values.joined(separator: ","))
}
}
@discardableResult mutating func append(_ key: String, value: CustomStringConvertible?) -> Options {
return append(key, value: value?.description)
}
@discardableResult mutating func append(_ key: String, value: String?) -> Options {
return append(key, value: value.map { Expression<String>($0) })
}
@discardableResult mutating func append(_ key: String, value: Expressible?) -> Options {
if let value = value {
arguments.append("=".join([Expression<Void>(literal: key), value]))
}
return self
}
}
}
/// Configuration for the [FTS4](https://www.sqlite.org/fts3.html) extension.
open class FTS4Config : FTSConfig {
/// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4)
public enum MatchInfo : CustomStringConvertible {
case fts3
public var description: String {
return "fts3"
}
}
/// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options)
public enum Order : CustomStringConvertible {
/// Data structures are optimized for returning results in ascending order by docid (default)
case asc
/// FTS4 stores its data in such a way as to optimize returning results in descending order by docid.
case desc
public var description: String {
switch self {
case .asc: return "asc"
case .desc: return "desc"
}
}
}
var compressFunction: String?
var uncompressFunction: String?
var languageId: String?
var matchInfo: MatchInfo?
var order: Order?
override public init() {
}
/// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1)
open func compress(_ functionName: String) -> Self {
self.compressFunction = functionName
return self
}
/// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1)
open func uncompress(_ functionName: String) -> Self {
self.uncompressFunction = functionName
return self
}
/// [The languageid= option](https://www.sqlite.org/fts3.html#section_6_3)
open func languageId(_ columnName: String) -> Self {
self.languageId = columnName
return self
}
/// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4)
open func matchInfo(_ matchInfo: MatchInfo) -> Self {
self.matchInfo = matchInfo
return self
}
/// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options)
open func order(_ order: Order) -> Self {
self.order = order
return self
}
override func options() -> Options {
var options = super.options()
for (column, _) in (columnDefinitions.filter { $0.options.contains(.unindexed) }) {
options.append("notindexed", value: column)
}
options.append("languageid", value: languageId)
options.append("compress", value: compressFunction)
options.append("uncompress", value: uncompressFunction)
options.append("matchinfo", value: matchInfo)
options.append("order", value: order)
return options
}
}
+97
View File
@@ -0,0 +1,97 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
extension Module {
public static func FTS5(_ config: FTS5Config) -> Module {
return Module(name: "fts5", arguments: config.arguments())
}
}
/// Configuration for the [FTS5](https://www.sqlite.org/fts5.html) extension.
///
/// **Note:** this is currently only applicable when using SQLite.swift together with a FTS5-enabled version
/// of SQLite.
open class FTS5Config : FTSConfig {
public enum Detail : CustomStringConvertible {
/// store rowid, column number, term offset
case full
/// store rowid, column number
case column
/// store rowid
case none
public var description: String {
switch self {
case .full: return "full"
case .column: return "column"
case .none: return "none"
}
}
}
var detail: Detail?
var contentRowId: Expressible?
var columnSize: Int?
override public init() {
}
/// [External Content Tables](https://www.sqlite.org/fts5.html#section_4_4_2)
open func contentRowId(_ column: Expressible) -> Self {
self.contentRowId = column
return self
}
/// [The Columnsize Option](https://www.sqlite.org/fts5.html#section_4_5)
open func columnSize(_ size: Int) -> Self {
self.columnSize = size
return self
}
/// [The Detail Option](https://www.sqlite.org/fts5.html#section_4_6)
open func detail(_ detail: Detail) -> Self {
self.detail = detail
return self
}
override func options() -> Options {
var options = super.options()
options.append("content_rowid", value: contentRowId)
if let columnSize = columnSize {
options.append("columnsize", value: Expression<Int>(value: columnSize))
}
options.append("detail", value: detail)
return options
}
override func formatColumnDefinitions() -> [Expressible] {
return columnDefinitions.map { definition in
if definition.options.contains(.unindexed) {
return " ".join([definition.0, Expression<Void>(literal: "UNINDEXED")])
} else {
return definition.0
}
}
}
}
+37
View File
@@ -0,0 +1,37 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
extension Module {
public static func RTree<T : Value, U : Value>(_ primaryKey: Expression<T>, _ pairs: (Expression<U>, Expression<U>)...) -> Module where T.Datatype == Int64, U.Datatype == Double {
var arguments: [Expressible] = [primaryKey]
for pair in pairs {
arguments.append(contentsOf: [pair.0, pair.1] as [Expressible])
}
return Module(name: "rtree", arguments: arguments)
}
}
+70
View File
@@ -0,0 +1,70 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
extension Data : Value {
public static var declaredDatatype: String {
return Blob.declaredDatatype
}
public static func fromDatatypeValue(_ dataValue: Blob) -> Data {
return Data(dataValue.bytes)
}
public var datatypeValue: Blob {
return withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Blob in
return Blob(bytes: pointer.baseAddress!, length: count)
}
}
}
extension Date : Value {
public static var declaredDatatype: String {
return String.declaredDatatype
}
public static func fromDatatypeValue(_ stringValue: String) -> Date {
return dateFormatter.date(from: stringValue)!
}
public var datatypeValue: String {
return dateFormatter.string(from: self)
}
}
/// A global date formatter used to serialize and deserialize `NSDate` objects.
/// If multiple date formats are used in an applications database(s), use a
/// custom `Value` type per additional format.
public var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()
+120
View File
@@ -0,0 +1,120 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if SQLITE_SWIFT_STANDALONE
import sqlite3
#elseif SQLITE_SWIFT_SQLCIPHER
import SQLCipher
#elseif os(Linux)
import CSQLite
#else
import SQLite3
#endif
public typealias Star = (Expression<Binding>?, Expression<Binding>?) -> Expression<Void>
public func *(_: Expression<Binding>?, _: Expression<Binding>?) -> Expression<Void> {
return Expression(literal: "*")
}
public protocol _OptionalType {
associatedtype WrappedType
}
extension Optional : _OptionalType {
public typealias WrappedType = Wrapped
}
// let SQLITE_STATIC = unsafeBitCast(0, sqlite3_destructor_type.self)
let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
extension String {
func quote(_ mark: Character = "\"") -> String {
let escaped = reduce("") { string, character in
string + (character == mark ? "\(mark)\(mark)" : "\(character)")
}
return "\(mark)\(escaped)\(mark)"
}
func join(_ expressions: [Expressible]) -> Expressible {
var (template, bindings) = ([String](), [Binding?]())
for expressible in expressions {
let expression = expressible.expression
template.append(expression.template)
bindings.append(contentsOf: expression.bindings)
}
return Expression<Void>(template.joined(separator: self), bindings)
}
func infix<T>(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression<T> {
let expression = Expression<T>(" \(self) ".join([lhs, rhs]).expression)
guard wrap else {
return expression
}
return "".wrap(expression)
}
func prefix(_ expressions: Expressible) -> Expressible {
return "\(self) ".wrap(expressions) as Expression<Void>
}
func prefix(_ expressions: [Expressible]) -> Expressible {
return "\(self) ".wrap(expressions) as Expression<Void>
}
func wrap<T>(_ expression: Expressible) -> Expression<T> {
return Expression("\(self)(\(expression.expression.template))", expression.expression.bindings)
}
func wrap<T>(_ expressions: [Expressible]) -> Expression<T> {
return wrap(", ".join(expressions))
}
}
func transcode(_ literal: Binding?) -> String {
guard let literal = literal else { return "NULL" }
switch literal {
case let blob as Blob:
return blob.description
case let string as String:
return string.quote("'")
case let binding:
return "\(binding)"
}
}
func value<A: Value>(_ v: Binding) -> A {
return A.fromDatatypeValue(v as! A.Datatype) as! A
}
func value<A: Value>(_ v: Binding?) -> A {
return value(v!)
}
+6
View File
@@ -0,0 +1,6 @@
@import Foundation;
FOUNDATION_EXPORT double SQLiteVersionNumber;
FOUNDATION_EXPORT const unsigned char SQLiteVersionString[];
#import "SQLiteObjc.h"
@@ -0,0 +1,264 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
private enum Function: String {
case count
case max
case min
case avg
case sum
case total
func wrap<T>(_ expression: Expressible) -> Expression<T> {
return self.rawValue.wrap(expression)
}
}
extension ExpressionType where UnderlyingType : Value {
/// Builds a copy of the expression prefixed with the `DISTINCT` keyword.
///
/// let name = Expression<String>("name")
/// name.distinct
/// // DISTINCT "name"
///
/// - Returns: A copy of the expression prefixed with the `DISTINCT`
/// keyword.
public var distinct: Expression<UnderlyingType> {
return Expression("DISTINCT \(template)", bindings)
}
/// Builds a copy of the expression wrapped with the `count` aggregate
/// function.
///
/// let name = Expression<String?>("name")
/// name.count
/// // count("name")
/// name.distinct.count
/// // count(DISTINCT "name")
///
/// - Returns: A copy of the expression wrapped with the `count` aggregate
/// function.
public var count: Expression<Int> {
return Function.count.wrap(self)
}
}
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value {
/// Builds a copy of the expression prefixed with the `DISTINCT` keyword.
///
/// let name = Expression<String?>("name")
/// name.distinct
/// // DISTINCT "name"
///
/// - Returns: A copy of the expression prefixed with the `DISTINCT`
/// keyword.
public var distinct: Expression<UnderlyingType> {
return Expression("DISTINCT \(template)", bindings)
}
/// Builds a copy of the expression wrapped with the `count` aggregate
/// function.
///
/// let name = Expression<String?>("name")
/// name.count
/// // count("name")
/// name.distinct.count
/// // count(DISTINCT "name")
///
/// - Returns: A copy of the expression wrapped with the `count` aggregate
/// function.
public var count: Expression<Int> {
return Function.count.wrap(self)
}
}
extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Comparable {
/// Builds a copy of the expression wrapped with the `max` aggregate
/// function.
///
/// let age = Expression<Int>("age")
/// age.max
/// // max("age")
///
/// - Returns: A copy of the expression wrapped with the `max` aggregate
/// function.
public var max: Expression<UnderlyingType?> {
return Function.max.wrap(self)
}
/// Builds a copy of the expression wrapped with the `min` aggregate
/// function.
///
/// let age = Expression<Int>("age")
/// age.min
/// // min("age")
///
/// - Returns: A copy of the expression wrapped with the `min` aggregate
/// function.
public var min: Expression<UnderlyingType?> {
return Function.min.wrap(self)
}
}
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Comparable {
/// Builds a copy of the expression wrapped with the `max` aggregate
/// function.
///
/// let age = Expression<Int?>("age")
/// age.max
/// // max("age")
///
/// - Returns: A copy of the expression wrapped with the `max` aggregate
/// function.
public var max: Expression<UnderlyingType> {
return Function.max.wrap(self)
}
/// Builds a copy of the expression wrapped with the `min` aggregate
/// function.
///
/// let age = Expression<Int?>("age")
/// age.min
/// // min("age")
///
/// - Returns: A copy of the expression wrapped with the `min` aggregate
/// function.
public var min: Expression<UnderlyingType> {
return Function.min.wrap(self)
}
}
extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Number {
/// Builds a copy of the expression wrapped with the `avg` aggregate
/// function.
///
/// let salary = Expression<Double>("salary")
/// salary.average
/// // avg("salary")
///
/// - Returns: A copy of the expression wrapped with the `min` aggregate
/// function.
public var average: Expression<Double?> {
return Function.avg.wrap(self)
}
/// Builds a copy of the expression wrapped with the `sum` aggregate
/// function.
///
/// let salary = Expression<Double>("salary")
/// salary.sum
/// // sum("salary")
///
/// - Returns: A copy of the expression wrapped with the `min` aggregate
/// function.
public var sum: Expression<UnderlyingType?> {
return Function.sum.wrap(self)
}
/// Builds a copy of the expression wrapped with the `total` aggregate
/// function.
///
/// let salary = Expression<Double>("salary")
/// salary.total
/// // total("salary")
///
/// - Returns: A copy of the expression wrapped with the `min` aggregate
/// function.
public var total: Expression<Double> {
return Function.total.wrap(self)
}
}
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Number {
/// Builds a copy of the expression wrapped with the `avg` aggregate
/// function.
///
/// let salary = Expression<Double?>("salary")
/// salary.average
/// // avg("salary")
///
/// - Returns: A copy of the expression wrapped with the `min` aggregate
/// function.
public var average: Expression<Double?> {
return Function.avg.wrap(self)
}
/// Builds a copy of the expression wrapped with the `sum` aggregate
/// function.
///
/// let salary = Expression<Double?>("salary")
/// salary.sum
/// // sum("salary")
///
/// - Returns: A copy of the expression wrapped with the `min` aggregate
/// function.
public var sum: Expression<UnderlyingType> {
return Function.sum.wrap(self)
}
/// Builds a copy of the expression wrapped with the `total` aggregate
/// function.
///
/// let salary = Expression<Double?>("salary")
/// salary.total
/// // total("salary")
///
/// - Returns: A copy of the expression wrapped with the `min` aggregate
/// function.
public var total: Expression<Double> {
return Function.total.wrap(self)
}
}
extension ExpressionType where UnderlyingType == Int {
static func count(_ star: Star) -> Expression<UnderlyingType> {
return Function.count.wrap(star(nil, nil))
}
}
/// Builds an expression representing `count(*)` (when called with the `*`
/// function literal).
///
/// count(*)
/// // count(*)
///
/// - Returns: An expression returning `count(*)` (when called with the `*`
/// function literal).
public func count(_ star: Star) -> Expression<Int> {
return Expression.count(star)
}
+340
View File
@@ -0,0 +1,340 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
extension QueryType {
/// Creates an `INSERT` statement by encoding the given object
/// This method converts any custom nested types to JSON data and does not handle any sort
/// of object relationships. If you want to support relationships between objects you will
/// have to provide your own Encodable implementations that encode the correct ids.
///
/// - Parameters:
///
/// - encodable: An encodable object to insert
///
/// - userInfo: User info to be passed to encoder
///
/// - otherSetters: Any other setters to include in the insert
///
/// - Returns: An `INSERT` statement fort the encodable object
public func insert(_ encodable: Encodable, userInfo: [CodingUserInfoKey:Any] = [:], otherSetters: [Setter] = []) throws -> Insert {
let encoder = SQLiteEncoder(userInfo: userInfo)
try encodable.encode(to: encoder)
return self.insert(encoder.setters + otherSetters)
}
/// Creates an `UPDATE` statement by encoding the given object
/// This method converts any custom nested types to JSON data and does not handle any sort
/// of object relationships. If you want to support relationships between objects you will
/// have to provide your own Encodable implementations that encode the correct ids.
///
/// - Parameters:
///
/// - encodable: An encodable object to insert
///
/// - userInfo: User info to be passed to encoder
///
/// - otherSetters: Any other setters to include in the insert
///
/// - Returns: An `UPDATE` statement fort the encodable object
public func update(_ encodable: Encodable, userInfo: [CodingUserInfoKey:Any] = [:], otherSetters: [Setter] = []) throws -> Update {
let encoder = SQLiteEncoder(userInfo: userInfo)
try encodable.encode(to: encoder)
return self.update(encoder.setters + otherSetters)
}
}
extension Row {
/// Decode an object from this row
/// This method expects any custom nested types to be in the form of JSON data and does not handle
/// any sort of object relationships. If you want to support relationships between objects you will
/// have to provide your own Decodable implementations that decodes the correct columns.
///
/// - Parameter: userInfo
///
/// - Returns: a decoded object from this row
public func decode<V: Decodable>(userInfo: [CodingUserInfoKey: Any] = [:]) throws -> V {
return try V(from: self.decoder(userInfo: userInfo))
}
public func decoder(userInfo: [CodingUserInfoKey: Any] = [:]) -> Decoder {
return SQLiteDecoder(row: self, userInfo: userInfo)
}
}
/// Generates a list of settings for an Encodable object
fileprivate class SQLiteEncoder: Encoder {
class SQLiteKeyedEncodingContainer<MyKey: CodingKey>: KeyedEncodingContainerProtocol {
typealias Key = MyKey
let encoder: SQLiteEncoder
let codingPath: [CodingKey] = []
init(encoder: SQLiteEncoder) {
self.encoder = encoder
}
func superEncoder() -> Swift.Encoder {
fatalError("SQLiteEncoding does not support super encoders")
}
func superEncoder(forKey key: Key) -> Swift.Encoder {
fatalError("SQLiteEncoding does not support super encoders")
}
func encodeNil(forKey key: SQLiteEncoder.SQLiteKeyedEncodingContainer<Key>.Key) throws {
self.encoder.setters.append(Expression<String?>(key.stringValue) <- nil)
}
func encode(_ value: Int, forKey key: SQLiteEncoder.SQLiteKeyedEncodingContainer<Key>.Key) throws {
self.encoder.setters.append(Expression(key.stringValue) <- value)
}
func encode(_ value: Bool, forKey key: Key) throws {
self.encoder.setters.append(Expression(key.stringValue) <- value)
}
func encode(_ value: Float, forKey key: Key) throws {
self.encoder.setters.append(Expression(key.stringValue) <- Double(value))
}
func encode(_ value: Double, forKey key: Key) throws {
self.encoder.setters.append(Expression(key.stringValue) <- value)
}
func encode(_ value: String, forKey key: Key) throws {
self.encoder.setters.append(Expression(key.stringValue) <- value)
}
func encode<T>(_ value: T, forKey key: Key) throws where T : Swift.Encodable {
if let data = value as? Data {
self.encoder.setters.append(Expression(key.stringValue) <- data)
}
else {
let encoded = try JSONEncoder().encode(value)
let string = String(data: encoded, encoding: .utf8)
self.encoder.setters.append(Expression(key.stringValue) <- string)
}
}
func encode(_ value: Int8, forKey key: Key) throws {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an Int8 is not supported"))
}
func encode(_ value: Int16, forKey key: Key) throws {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an Int16 is not supported"))
}
func encode(_ value: Int32, forKey key: Key) throws {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an Int32 is not supported"))
}
func encode(_ value: Int64, forKey key: Key) throws {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an Int64 is not supported"))
}
func encode(_ value: UInt, forKey key: Key) throws {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt is not supported"))
}
func encode(_ value: UInt8, forKey key: Key) throws {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt8 is not supported"))
}
func encode(_ value: UInt16, forKey key: Key) throws {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt16 is not supported"))
}
func encode(_ value: UInt32, forKey key: Key) throws {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt32 is not supported"))
}
func encode(_ value: UInt64, forKey key: Key) throws {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt64 is not supported"))
}
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey {
fatalError("encoding a nested container is not supported")
}
func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
fatalError("encoding nested values is not supported")
}
}
fileprivate var setters: [Setter] = []
let codingPath: [CodingKey] = []
let userInfo: [CodingUserInfoKey: Any]
init(userInfo: [CodingUserInfoKey: Any]) {
self.userInfo = userInfo
}
func singleValueContainer() -> SingleValueEncodingContainer {
fatalError("not supported")
}
func unkeyedContainer() -> UnkeyedEncodingContainer {
fatalError("not supported")
}
func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key : CodingKey {
return KeyedEncodingContainer(SQLiteKeyedEncodingContainer(encoder: self))
}
}
fileprivate class SQLiteDecoder : Decoder {
class SQLiteKeyedDecodingContainer<MyKey: CodingKey> : KeyedDecodingContainerProtocol {
typealias Key = MyKey
let codingPath: [CodingKey] = []
let row: Row
init(row: Row) {
self.row = row
}
var allKeys: [Key] {
return self.row.columnNames.keys.compactMap({Key(stringValue: $0)})
}
func contains(_ key: Key) -> Bool {
return self.row.hasValue(for: key.stringValue)
}
func decodeNil(forKey key: Key) throws -> Bool {
return !self.contains(key)
}
func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
return try self.row.get(Expression(key.stringValue))
}
func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
return try self.row.get(Expression(key.stringValue))
}
func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an Int8 is not supported"))
}
func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an Int16 is not supported"))
}
func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an Int32 is not supported"))
}
func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt64 is not supported"))
}
func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt is not supported"))
}
func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt8 is not supported"))
}
func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt16 is not supported"))
}
func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt32 is not supported"))
}
func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt64 is not supported"))
}
func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
return Float(try self.row.get(Expression<Double>(key.stringValue)))
}
func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
return try self.row.get(Expression(key.stringValue))
}
func decode(_ type: String.Type, forKey key: Key) throws -> String {
return try self.row.get(Expression(key.stringValue))
}
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Swift.Decodable {
if type == Data.self {
let data = try self.row.get(Expression<Data>(key.stringValue))
return data as! T
}
guard let JSONString = try self.row.get(Expression<String?>(key.stringValue)) else {
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "an unsupported type was found"))
}
guard let data = JSONString.data(using: .utf8) else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "invalid utf8 data found"))
}
return try JSONDecoder().decode(type, from: data)
}
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding nested containers is not supported"))
}
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding unkeyed containers is not supported"))
}
func superDecoder() throws -> Swift.Decoder {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding super encoders containers is not supported"))
}
func superDecoder(forKey key: Key) throws -> Swift.Decoder {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding super decoders is not supported"))
}
}
let row: Row
let codingPath: [CodingKey] = []
let userInfo: [CodingUserInfoKey: Any]
init(row: Row, userInfo: [CodingUserInfoKey: Any]) {
self.row = row
self.userInfo = userInfo
}
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
return KeyedDecodingContainer(SQLiteKeyedDecodingContainer(row: self.row))
}
func unkeyedContainer() throws -> UnkeyedDecodingContainer {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an unkeyed container is not supported"))
}
func singleValueContainer() throws -> SingleValueDecodingContainer {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding a single value container is not supported"))
}
}
+69
View File
@@ -0,0 +1,69 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
/// A collating function used to compare to strings.
///
/// - SeeAlso: <https://www.sqlite.org/datatype3.html#collation>
public enum Collation {
/// Compares string by raw data.
case binary
/// Like binary, but folds uppercase ASCII letters into their lowercase
/// equivalents.
case nocase
/// Like binary, but strips trailing space.
case rtrim
/// A custom collating sequence identified by the given string, registered
/// using `Database.create(collation:)`
case custom(String)
}
extension Collation : Expressible {
public var expression: Expression<Void> {
return Expression(literal: description)
}
}
extension Collation : CustomStringConvertible {
public var description : String {
switch self {
case .binary:
return "BINARY"
case .nocase:
return "NOCASE"
case .rtrim:
return "RTRIM"
case .custom(let collation):
return collation.quote()
}
}
}
+796
View File
@@ -0,0 +1,796 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
private enum Function: String {
case abs
case round
case random
case randomblob
case zeroblob
case length
case lower
case upper
case ltrim
case rtrim
case trim
case replace
case substr
case like = "LIKE"
case `in` = "IN"
case glob = "GLOB"
case match = "MATCH"
case regexp = "REGEXP"
case collate = "COLLATE"
case ifnull
func infix<T>(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression<T> {
return self.rawValue.infix(lhs, rhs, wrap: wrap)
}
func wrap<T>(_ expression: Expressible) -> Expression<T> {
return self.rawValue.wrap(expression)
}
func wrap<T>(_ expressions: [Expressible]) -> Expression<T> {
return self.rawValue.wrap(", ".join(expressions))
}
}
extension ExpressionType where UnderlyingType : Number {
/// Builds a copy of the expression wrapped with the `abs` function.
///
/// let x = Expression<Int>("x")
/// x.absoluteValue
/// // abs("x")
///
/// - Returns: A copy of the expression wrapped with the `abs` function.
public var absoluteValue : Expression<UnderlyingType> {
return Function.abs.wrap(self)
}
}
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Number {
/// Builds a copy of the expression wrapped with the `abs` function.
///
/// let x = Expression<Int?>("x")
/// x.absoluteValue
/// // abs("x")
///
/// - Returns: A copy of the expression wrapped with the `abs` function.
public var absoluteValue : Expression<UnderlyingType> {
return Function.abs.wrap(self)
}
}
extension ExpressionType where UnderlyingType == Double {
/// Builds a copy of the expression wrapped with the `round` function.
///
/// let salary = Expression<Double>("salary")
/// salary.round()
/// // round("salary")
/// salary.round(2)
/// // round("salary", 2)
///
/// - Returns: A copy of the expression wrapped with the `round` function.
public func round(_ precision: Int? = nil) -> Expression<UnderlyingType> {
guard let precision = precision else {
return Function.round.wrap([self])
}
return Function.round.wrap([self, Int(precision)])
}
}
extension ExpressionType where UnderlyingType == Double? {
/// Builds a copy of the expression wrapped with the `round` function.
///
/// let salary = Expression<Double>("salary")
/// salary.round()
/// // round("salary")
/// salary.round(2)
/// // round("salary", 2)
///
/// - Returns: A copy of the expression wrapped with the `round` function.
public func round(_ precision: Int? = nil) -> Expression<UnderlyingType> {
guard let precision = precision else {
return Function.round.wrap(self)
}
return Function.round.wrap([self, Int(precision)])
}
}
extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype == Int64 {
/// Builds an expression representing the `random` function.
///
/// Expression<Int>.random()
/// // random()
///
/// - Returns: An expression calling the `random` function.
public static func random() -> Expression<UnderlyingType> {
return Function.random.wrap([])
}
}
extension ExpressionType where UnderlyingType == Data {
/// Builds an expression representing the `randomblob` function.
///
/// Expression<Int>.random(16)
/// // randomblob(16)
///
/// - Parameter length: Length in bytes.
///
/// - Returns: An expression calling the `randomblob` function.
public static func random(_ length: Int) -> Expression<UnderlyingType> {
return Function.randomblob.wrap([])
}
/// Builds an expression representing the `zeroblob` function.
///
/// Expression<Int>.allZeros(16)
/// // zeroblob(16)
///
/// - Parameter length: Length in bytes.
///
/// - Returns: An expression calling the `zeroblob` function.
public static func allZeros(_ length: Int) -> Expression<UnderlyingType> {
return Function.zeroblob.wrap([])
}
/// Builds a copy of the expression wrapped with the `length` function.
///
/// let data = Expression<NSData>("data")
/// data.length
/// // length("data")
///
/// - Returns: A copy of the expression wrapped with the `length` function.
public var length: Expression<Int> {
return Function.length.wrap(self)
}
}
extension ExpressionType where UnderlyingType == Data? {
/// Builds a copy of the expression wrapped with the `length` function.
///
/// let data = Expression<NSData?>("data")
/// data.length
/// // length("data")
///
/// - Returns: A copy of the expression wrapped with the `length` function.
public var length: Expression<Int?> {
return Function.length.wrap(self)
}
}
extension ExpressionType where UnderlyingType == String {
/// Builds a copy of the expression wrapped with the `length` function.
///
/// let name = Expression<String>("name")
/// name.length
/// // length("name")
///
/// - Returns: A copy of the expression wrapped with the `length` function.
public var length: Expression<Int> {
return Function.length.wrap(self)
}
/// Builds a copy of the expression wrapped with the `lower` function.
///
/// let name = Expression<String>("name")
/// name.lowercaseString
/// // lower("name")
///
/// - Returns: A copy of the expression wrapped with the `lower` function.
public var lowercaseString: Expression<UnderlyingType> {
return Function.lower.wrap(self)
}
/// Builds a copy of the expression wrapped with the `upper` function.
///
/// let name = Expression<String>("name")
/// name.uppercaseString
/// // lower("name")
///
/// - Returns: A copy of the expression wrapped with the `upper` function.
public var uppercaseString: Expression<UnderlyingType> {
return Function.upper.wrap(self)
}
/// Builds a copy of the expression appended with a `LIKE` query against the
/// given pattern.
///
/// let email = Expression<String>("email")
/// email.like("%@example.com")
/// // "email" LIKE '%@example.com'
/// email.like("99\\%@%", escape: "\\")
/// // "email" LIKE '99\%@%' ESCAPE '\'
///
/// - Parameters:
///
/// - pattern: A pattern to match.
///
/// - escape: An (optional) character designated for escaping
/// pattern-matching characters (*i.e.*, the `%` and `_` characters).
///
/// - Returns: A copy of the expression appended with a `LIKE` query against
/// the given pattern.
public func like(_ pattern: String, escape character: Character? = nil) -> Expression<Bool> {
guard let character = character else {
return "LIKE".infix(self, pattern)
}
return Expression("(\(template) LIKE ? ESCAPE ?)", bindings + [pattern, String(character)])
}
/// Builds a copy of the expression appended with a `LIKE` query against the
/// given pattern.
///
/// let email = Expression<String>("email")
/// let pattern = Expression<String>("pattern")
/// email.like(pattern)
/// // "email" LIKE "pattern"
///
/// - Parameters:
///
/// - pattern: A pattern to match.
///
/// - escape: An (optional) character designated for escaping
/// pattern-matching characters (*i.e.*, the `%` and `_` characters).
///
/// - Returns: A copy of the expression appended with a `LIKE` query against
/// the given pattern.
public func like(_ pattern: Expression<String>, escape character: Character? = nil) -> Expression<Bool> {
guard let character = character else {
return Function.like.infix(self, pattern)
}
let like: Expression<Bool> = Function.like.infix(self, pattern, wrap: false)
return Expression("(\(like.template) ESCAPE ?)", like.bindings + [String(character)])
}
/// Builds a copy of the expression appended with a `GLOB` query against the
/// given pattern.
///
/// let path = Expression<String>("path")
/// path.glob("*.png")
/// // "path" GLOB '*.png'
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A copy of the expression appended with a `GLOB` query against
/// the given pattern.
public func glob(_ pattern: String) -> Expression<Bool> {
return Function.glob.infix(self, pattern)
}
/// Builds a copy of the expression appended with a `MATCH` query against
/// the given pattern.
///
/// let title = Expression<String>("title")
/// title.match("swift AND programming")
/// // "title" MATCH 'swift AND programming'
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A copy of the expression appended with a `MATCH` query
/// against the given pattern.
public func match(_ pattern: String) -> Expression<Bool> {
return Function.match.infix(self, pattern)
}
/// Builds a copy of the expression appended with a `REGEXP` query against
/// the given pattern.
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A copy of the expression appended with a `REGEXP` query
/// against the given pattern.
public func regexp(_ pattern: String) -> Expression<Bool> {
return Function.regexp.infix(self, pattern)
}
/// Builds a copy of the expression appended with a `COLLATE` clause with
/// the given sequence.
///
/// let name = Expression<String>("name")
/// name.collate(.Nocase)
/// // "name" COLLATE NOCASE
///
/// - Parameter collation: A collating sequence.
///
/// - Returns: A copy of the expression appended with a `COLLATE` clause
/// with the given sequence.
public func collate(_ collation: Collation) -> Expression<UnderlyingType> {
return Function.collate.infix(self, collation)
}
/// Builds a copy of the expression wrapped with the `ltrim` function.
///
/// let name = Expression<String>("name")
/// name.ltrim()
/// // ltrim("name")
/// name.ltrim([" ", "\t"])
/// // ltrim("name", ' \t')
///
/// - Parameter characters: A set of characters to trim.
///
/// - Returns: A copy of the expression wrapped with the `ltrim` function.
public func ltrim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
guard let characters = characters else {
return Function.ltrim.wrap(self)
}
return Function.ltrim.wrap([self, String(characters)])
}
/// Builds a copy of the expression wrapped with the `rtrim` function.
///
/// let name = Expression<String>("name")
/// name.rtrim()
/// // rtrim("name")
/// name.rtrim([" ", "\t"])
/// // rtrim("name", ' \t')
///
/// - Parameter characters: A set of characters to trim.
///
/// - Returns: A copy of the expression wrapped with the `rtrim` function.
public func rtrim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
guard let characters = characters else {
return Function.rtrim.wrap(self)
}
return Function.rtrim.wrap([self, String(characters)])
}
/// Builds a copy of the expression wrapped with the `trim` function.
///
/// let name = Expression<String>("name")
/// name.trim()
/// // trim("name")
/// name.trim([" ", "\t"])
/// // trim("name", ' \t')
///
/// - Parameter characters: A set of characters to trim.
///
/// - Returns: A copy of the expression wrapped with the `trim` function.
public func trim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
guard let characters = characters else {
return Function.trim.wrap([self])
}
return Function.trim.wrap([self, String(characters)])
}
/// Builds a copy of the expression wrapped with the `replace` function.
///
/// let email = Expression<String>("email")
/// email.replace("@mac.com", with: "@icloud.com")
/// // replace("email", '@mac.com', '@icloud.com')
///
/// - Parameters:
///
/// - pattern: A pattern to match.
///
/// - replacement: The replacement string.
///
/// - Returns: A copy of the expression wrapped with the `replace` function.
public func replace(_ pattern: String, with replacement: String) -> Expression<UnderlyingType> {
return Function.replace.wrap([self, pattern, replacement])
}
public func substring(_ location: Int, length: Int? = nil) -> Expression<UnderlyingType> {
guard let length = length else {
return Function.substr.wrap([self, location])
}
return Function.substr.wrap([self, location, length])
}
public subscript(range: Range<Int>) -> Expression<UnderlyingType> {
return substring(range.lowerBound, length: range.upperBound - range.lowerBound)
}
}
extension ExpressionType where UnderlyingType == String? {
/// Builds a copy of the expression wrapped with the `length` function.
///
/// let name = Expression<String?>("name")
/// name.length
/// // length("name")
///
/// - Returns: A copy of the expression wrapped with the `length` function.
public var length: Expression<Int?> {
return Function.length.wrap(self)
}
/// Builds a copy of the expression wrapped with the `lower` function.
///
/// let name = Expression<String?>("name")
/// name.lowercaseString
/// // lower("name")
///
/// - Returns: A copy of the expression wrapped with the `lower` function.
public var lowercaseString: Expression<UnderlyingType> {
return Function.lower.wrap(self)
}
/// Builds a copy of the expression wrapped with the `upper` function.
///
/// let name = Expression<String?>("name")
/// name.uppercaseString
/// // lower("name")
///
/// - Returns: A copy of the expression wrapped with the `upper` function.
public var uppercaseString: Expression<UnderlyingType> {
return Function.upper.wrap(self)
}
/// Builds a copy of the expression appended with a `LIKE` query against the
/// given pattern.
///
/// let email = Expression<String?>("email")
/// email.like("%@example.com")
/// // "email" LIKE '%@example.com'
/// email.like("99\\%@%", escape: "\\")
/// // "email" LIKE '99\%@%' ESCAPE '\'
///
/// - Parameters:
///
/// - pattern: A pattern to match.
///
/// - escape: An (optional) character designated for escaping
/// pattern-matching characters (*i.e.*, the `%` and `_` characters).
///
/// - Returns: A copy of the expression appended with a `LIKE` query against
/// the given pattern.
public func like(_ pattern: String, escape character: Character? = nil) -> Expression<Bool?> {
guard let character = character else {
return Function.like.infix(self, pattern)
}
return Expression("(\(template) LIKE ? ESCAPE ?)", bindings + [pattern, String(character)])
}
/// Builds a copy of the expression appended with a `LIKE` query against the
/// given pattern.
///
/// let email = Expression<String>("email")
/// let pattern = Expression<String>("pattern")
/// email.like(pattern)
/// // "email" LIKE "pattern"
///
/// - Parameters:
///
/// - pattern: A pattern to match.
///
/// - escape: An (optional) character designated for escaping
/// pattern-matching characters (*i.e.*, the `%` and `_` characters).
///
/// - Returns: A copy of the expression appended with a `LIKE` query against
/// the given pattern.
public func like(_ pattern: Expression<String>, escape character: Character? = nil) -> Expression<Bool?> {
guard let character = character else {
return Function.like.infix(self, pattern)
}
let like: Expression<Bool> = Function.like.infix(self, pattern, wrap: false)
return Expression("(\(like.template) ESCAPE ?)", like.bindings + [String(character)])
}
/// Builds a copy of the expression appended with a `GLOB` query against the
/// given pattern.
///
/// let path = Expression<String?>("path")
/// path.glob("*.png")
/// // "path" GLOB '*.png'
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A copy of the expression appended with a `GLOB` query against
/// the given pattern.
public func glob(_ pattern: String) -> Expression<Bool?> {
return Function.glob.infix(self, pattern)
}
/// Builds a copy of the expression appended with a `MATCH` query against
/// the given pattern.
///
/// let title = Expression<String?>("title")
/// title.match("swift AND programming")
/// // "title" MATCH 'swift AND programming'
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A copy of the expression appended with a `MATCH` query
/// against the given pattern.
public func match(_ pattern: String) -> Expression<Bool> {
return Function.match.infix(self, pattern)
}
/// Builds a copy of the expression appended with a `REGEXP` query against
/// the given pattern.
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A copy of the expression appended with a `REGEXP` query
/// against the given pattern.
public func regexp(_ pattern: String) -> Expression<Bool?> {
return Function.regexp.infix(self, pattern)
}
/// Builds a copy of the expression appended with a `COLLATE` clause with
/// the given sequence.
///
/// let name = Expression<String?>("name")
/// name.collate(.Nocase)
/// // "name" COLLATE NOCASE
///
/// - Parameter collation: A collating sequence.
///
/// - Returns: A copy of the expression appended with a `COLLATE` clause
/// with the given sequence.
public func collate(_ collation: Collation) -> Expression<UnderlyingType> {
return Function.collate.infix(self, collation)
}
/// Builds a copy of the expression wrapped with the `ltrim` function.
///
/// let name = Expression<String?>("name")
/// name.ltrim()
/// // ltrim("name")
/// name.ltrim([" ", "\t"])
/// // ltrim("name", ' \t')
///
/// - Parameter characters: A set of characters to trim.
///
/// - Returns: A copy of the expression wrapped with the `ltrim` function.
public func ltrim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
guard let characters = characters else {
return Function.ltrim.wrap(self)
}
return Function.ltrim.wrap([self, String(characters)])
}
/// Builds a copy of the expression wrapped with the `rtrim` function.
///
/// let name = Expression<String?>("name")
/// name.rtrim()
/// // rtrim("name")
/// name.rtrim([" ", "\t"])
/// // rtrim("name", ' \t')
///
/// - Parameter characters: A set of characters to trim.
///
/// - Returns: A copy of the expression wrapped with the `rtrim` function.
public func rtrim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
guard let characters = characters else {
return Function.rtrim.wrap(self)
}
return Function.rtrim.wrap([self, String(characters)])
}
/// Builds a copy of the expression wrapped with the `trim` function.
///
/// let name = Expression<String?>("name")
/// name.trim()
/// // trim("name")
/// name.trim([" ", "\t"])
/// // trim("name", ' \t')
///
/// - Parameter characters: A set of characters to trim.
///
/// - Returns: A copy of the expression wrapped with the `trim` function.
public func trim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
guard let characters = characters else {
return Function.trim.wrap(self)
}
return Function.trim.wrap([self, String(characters)])
}
/// Builds a copy of the expression wrapped with the `replace` function.
///
/// let email = Expression<String?>("email")
/// email.replace("@mac.com", with: "@icloud.com")
/// // replace("email", '@mac.com', '@icloud.com')
///
/// - Parameters:
///
/// - pattern: A pattern to match.
///
/// - replacement: The replacement string.
///
/// - Returns: A copy of the expression wrapped with the `replace` function.
public func replace(_ pattern: String, with replacement: String) -> Expression<UnderlyingType> {
return Function.replace.wrap([self, pattern, replacement])
}
/// Builds a copy of the expression wrapped with the `substr` function.
///
/// let title = Expression<String?>("title")
/// title.substr(-100)
/// // substr("title", -100)
/// title.substr(0, length: 100)
/// // substr("title", 0, 100)
///
/// - Parameters:
///
/// - location: The substrings start index.
///
/// - length: An optional substring length.
///
/// - Returns: A copy of the expression wrapped with the `substr` function.
public func substring(_ location: Int, length: Int? = nil) -> Expression<UnderlyingType> {
guard let length = length else {
return Function.substr.wrap([self, location])
}
return Function.substr.wrap([self, location, length])
}
/// Builds a copy of the expression wrapped with the `substr` function.
///
/// let title = Expression<String?>("title")
/// title[0..<100]
/// // substr("title", 0, 100)
///
/// - Parameter range: The character index range of the substring.
///
/// - Returns: A copy of the expression wrapped with the `substr` function.
public subscript(range: Range<Int>) -> Expression<UnderlyingType> {
return substring(range.lowerBound, length: range.upperBound - range.lowerBound)
}
}
extension Collection where Iterator.Element : Value {
/// Builds a copy of the expression prepended with an `IN` check against the
/// collection.
///
/// let name = Expression<String>("name")
/// ["alice", "betty"].contains(name)
/// // "name" IN ('alice', 'betty')
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A copy of the expression prepended with an `IN` check against
/// the collection.
public func contains(_ expression: Expression<Iterator.Element>) -> Expression<Bool> {
let templates = [String](repeating: "?", count: count).joined(separator: ", ")
return Function.in.infix(expression, Expression<Void>("(\(templates))", map { $0.datatypeValue }))
}
/// Builds a copy of the expression prepended with an `IN` check against the
/// collection.
///
/// let name = Expression<String?>("name")
/// ["alice", "betty"].contains(name)
/// // "name" IN ('alice', 'betty')
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A copy of the expression prepended with an `IN` check against
/// the collection.
public func contains(_ expression: Expression<Iterator.Element?>) -> Expression<Bool?> {
let templates = [String](repeating: "?", count: count).joined(separator: ", ")
return Function.in.infix(expression, Expression<Void>("(\(templates))", map { $0.datatypeValue }))
}
}
extension String {
/// Builds a copy of the expression appended with a `LIKE` query against the
/// given pattern.
///
/// let email = "some@thing.com"
/// let pattern = Expression<String>("pattern")
/// email.like(pattern)
/// // 'some@thing.com' LIKE "pattern"
///
/// - Parameters:
///
/// - pattern: A pattern to match.
///
/// - escape: An (optional) character designated for escaping
/// pattern-matching characters (*i.e.*, the `%` and `_` characters).
///
/// - Returns: A copy of the expression appended with a `LIKE` query against
/// the given pattern.
public func like(_ pattern: Expression<String>, escape character: Character? = nil) -> Expression<Bool> {
guard let character = character else {
return Function.like.infix(self, pattern)
}
let like: Expression<Bool> = Function.like.infix(self, pattern, wrap: false)
return Expression("(\(like.template) ESCAPE ?)", like.bindings + [String(character)])
}
}
/// Builds a copy of the given expressions wrapped with the `ifnull` function.
///
/// let name = Expression<String?>("name")
/// name ?? "An Anonymous Coward"
/// // ifnull("name", 'An Anonymous Coward')
///
/// - Parameters:
///
/// - optional: An optional expression.
///
/// - defaultValue: A fallback value for when the optional expression is
/// `nil`.
///
/// - Returns: A copy of the given expressions wrapped with the `ifnull`
/// function.
public func ??<V : Value>(optional: Expression<V?>, defaultValue: V) -> Expression<V> {
return Function.ifnull.wrap([optional, defaultValue])
}
/// Builds a copy of the given expressions wrapped with the `ifnull` function.
///
/// let nick = Expression<String?>("nick")
/// let name = Expression<String>("name")
/// nick ?? name
/// // ifnull("nick", "name")
///
/// - Parameters:
///
/// - optional: An optional expression.
///
/// - defaultValue: A fallback expression for when the optional expression is
/// `nil`.
///
/// - Returns: A copy of the given expressions wrapped with the `ifnull`
/// function.
public func ??<V : Value>(optional: Expression<V?>, defaultValue: Expression<V>) -> Expression<V> {
return Function.ifnull.wrap([optional, defaultValue])
}
/// Builds a copy of the given expressions wrapped with the `ifnull` function.
///
/// let nick = Expression<String?>("nick")
/// let name = Expression<String?>("name")
/// nick ?? name
/// // ifnull("nick", "name")
///
/// - Parameters:
///
/// - optional: An optional expression.
///
/// - defaultValue: A fallback expression for when the optional expression is
/// `nil`.
///
/// - Returns: A copy of the given expressions wrapped with the `ifnull`
/// function.
public func ??<V : Value>(optional: Expression<V?>, defaultValue: Expression<V?>) -> Expression<V> {
return Function.ifnull.wrap([optional, defaultValue])
}
@@ -0,0 +1,136 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
public extension Connection {
/// Creates or redefines a custom SQL function.
///
/// - Parameters:
///
/// - function: The name of the function to create or redefine.
///
/// - deterministic: Whether or not the function is deterministic (_i.e._
/// the function always returns the same result for a given input).
///
/// Default: `false`
///
/// - block: A block of code to run when the function is called.
/// The assigned types must be explicit.
///
/// - Returns: A closure returning an SQL expression to call the function.
func createFunction<Z : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z) throws -> (() -> Expression<Z>) {
let fn = try createFunction(function, 0, deterministic) { _ in block() }
return { fn([]) }
}
func createFunction<Z : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z?) throws -> (() -> Expression<Z?>) {
let fn = try createFunction(function, 0, deterministic) { _ in block() }
return { fn([]) }
}
// MARK: -
func createFunction<Z : Value, A : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z) throws -> ((Expression<A>) -> Expression<Z>) {
let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) }
return { arg in fn([arg]) }
}
func createFunction<Z : Value, A : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z) throws -> ((Expression<A?>) -> Expression<Z>) {
let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) }
return { arg in fn([arg]) }
}
func createFunction<Z : Value, A : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z?) throws -> ((Expression<A>) -> Expression<Z?>) {
let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) }
return { arg in fn([arg]) }
}
func createFunction<Z : Value, A : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z?) throws -> ((Expression<A?>) -> Expression<Z?>) {
let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) }
return { arg in fn([arg]) }
}
// MARK: -
func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z) throws -> (Expression<A>, Expression<B>) -> Expression<Z> {
let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), value(args[1])) }
return { a, b in fn([a, b]) }
}
func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z) throws -> (Expression<A?>, Expression<B>) -> Expression<Z> {
let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), value(args[1])) }
return { a, b in fn([a, b]) }
}
func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z) throws -> (Expression<A>, Expression<B?>) -> Expression<Z> {
let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), args[1].map(value)) }
return { a, b in fn([a, b]) }
}
func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z?) throws -> (Expression<A>, Expression<B>) -> Expression<Z?> {
let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), value(args[1])) }
return { a, b in fn([a, b]) }
}
func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z) throws -> (Expression<A?>, Expression<B?>) -> Expression<Z> {
let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), args[1].map(value)) }
return { a, b in fn([a, b]) }
}
func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z?) throws -> (Expression<A?>, Expression<B>) -> Expression<Z?> {
let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), value(args[1])) }
return { a, b in fn([a, b]) }
}
func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z?) throws -> (Expression<A>, Expression<B?>) -> Expression<Z?> {
let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), args[1].map(value)) }
return { a, b in fn([a, b]) }
}
func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z?) throws -> (Expression<A?>, Expression<B?>) -> Expression<Z?> {
let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), args[1].map(value)) }
return { a, b in fn([a, b]) }
}
// MARK: -
fileprivate func createFunction<Z : Value>(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z) throws -> (([Expressible]) -> Expression<Z>) {
createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in
block(arguments).datatypeValue
}
return { arguments in
function.quote().wrap(", ".join(arguments))
}
}
fileprivate func createFunction<Z : Value>(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z?) throws -> (([Expressible]) -> Expression<Z?>) {
createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in
block(arguments)?.datatypeValue
}
return { arguments in
function.quote().wrap(", ".join(arguments))
}
}
}
@@ -0,0 +1,106 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
/// All five date and time functions take a time string as an argument.
/// The time string is followed by zero or more modifiers.
/// The strftime() function also takes a format string as its first argument.
///
/// https://www.sqlite.org/lang_datefunc.html
public class DateFunctions {
/// The date() function returns the date in this format: YYYY-MM-DD.
public static func date(_ timestring: String, _ modifiers: String...) -> Expression<Date?> {
return timefunction("date", timestring: timestring, modifiers: modifiers)
}
/// The time() function returns the time as HH:MM:SS.
public static func time(_ timestring: String, _ modifiers: String...) -> Expression<Date?> {
return timefunction("time", timestring: timestring, modifiers: modifiers)
}
/// The datetime() function returns "YYYY-MM-DD HH:MM:SS".
public static func datetime(_ timestring: String, _ modifiers: String...) -> Expression<Date?> {
return timefunction("datetime", timestring: timestring, modifiers: modifiers)
}
/// The julianday() function returns the Julian day -
/// the number of days since noon in Greenwich on November 24, 4714 B.C.
public static func julianday(_ timestring: String, _ modifiers: String...) -> Expression<Date?> {
return timefunction("julianday", timestring: timestring, modifiers: modifiers)
}
/// The strftime() routine returns the date formatted according to the format string specified as the first argument.
public static func strftime(_ format: String, _ timestring: String, _ modifiers: String...) -> Expression<Date?> {
if !modifiers.isEmpty {
let templates = [String](repeating: "?", count: modifiers.count).joined(separator: ", ")
return Expression("strftime(?, ?, \(templates))", [format, timestring] + modifiers)
}
return Expression("strftime(?, ?)", [format, timestring])
}
private static func timefunction(_ name: String, timestring: String, modifiers: [String]) -> Expression<Date?> {
if !modifiers.isEmpty {
let templates = [String](repeating: "?", count: modifiers.count).joined(separator: ", ")
return Expression("\(name)(?, \(templates))", [timestring] + modifiers)
}
return Expression("\(name)(?)", [timestring])
}
}
extension Date {
public var date: Expression<Date?> {
return DateFunctions.date(dateFormatter.string(from: self))
}
public var time: Expression<Date?> {
return DateFunctions.time(dateFormatter.string(from: self))
}
public var datetime: Expression<Date?> {
return DateFunctions.datetime(dateFormatter.string(from: self))
}
public var julianday: Expression<Date?> {
return DateFunctions.julianday(dateFormatter.string(from: self))
}
}
extension Expression where UnderlyingType == Date {
public var date: Expression<Date> {
return Expression<Date>("date(\(template))", bindings)
}
public var time: Expression<Date> {
return Expression<Date>("time(\(template))", bindings)
}
public var datetime: Expression<Date> {
return Expression<Date>("datetime(\(template))", bindings)
}
public var julianday: Expression<Date> {
return Expression<Date>("julianday(\(template))", bindings)
}
}
+147
View File
@@ -0,0 +1,147 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
public protocol ExpressionType : Expressible { // extensions cannot have inheritance clauses
associatedtype UnderlyingType = Void
var template: String { get }
var bindings: [Binding?] { get }
init(_ template: String, _ bindings: [Binding?])
}
extension ExpressionType {
public init(literal: String) {
self.init(literal, [])
}
public init(_ identifier: String) {
self.init(literal: identifier.quote())
}
public init<U : ExpressionType>(_ expression: U) {
self.init(expression.template, expression.bindings)
}
}
/// An `Expression` represents a raw SQL fragment and any associated bindings.
public struct Expression<Datatype> : ExpressionType {
public typealias UnderlyingType = Datatype
public var template: String
public var bindings: [Binding?]
public init(_ template: String, _ bindings: [Binding?]) {
self.template = template
self.bindings = bindings
}
}
public protocol Expressible {
var expression: Expression<Void> { get }
}
extension Expressible {
// naïve compiler for statements that cant be bound, e.g., CREATE TABLE
// FIXME: make internal (0.13.0)
public func asSQL() -> String {
let expressed = expression
var idx = 0
return expressed.template.reduce("") { template, character in
let transcoded: String
if character == "?" {
transcoded = transcode(expressed.bindings[idx])
idx += 1
} else {
transcoded = String(character)
}
return template + transcoded
}
}
}
extension ExpressionType {
public var expression: Expression<Void> {
return Expression(template, bindings)
}
public var asc: Expressible {
return " ".join([self, Expression<Void>(literal: "ASC")])
}
public var desc: Expressible {
return " ".join([self, Expression<Void>(literal: "DESC")])
}
}
extension ExpressionType where UnderlyingType : Value {
public init(value: UnderlyingType) {
self.init("?", [value.datatypeValue])
}
}
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value {
public static var null: Self {
return self.init(value: nil)
}
public init(value: UnderlyingType.WrappedType?) {
self.init("?", [value?.datatypeValue])
}
}
extension Value {
public var expression: Expression<Void> {
return Expression(value: self).expression
}
}
public let rowid = Expression<Int64>("ROWID")
public func cast<T: Value, U: Value>(_ expression: Expression<T>) -> Expression<U> {
return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings)
}
public func cast<T: Value, U: Value>(_ expression: Expression<T?>) -> Expression<U?> {
return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings)
}
+605
View File
@@ -0,0 +1,605 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// TODO: use `@warn_unused_result` by the time operator functions support it
private enum Operator: String {
case plus = "+"
case minus = "-"
case or = "OR"
case and = "AND"
case not = "NOT "
case mul = "*"
case div = "/"
case mod = "%"
case bitwiseLeft = "<<"
case bitwiseRight = ">>"
case bitwiseAnd = "&"
case bitwiseOr = "|"
case bitwiseXor = "~"
case eq = "="
case neq = "!="
case gt = ">"
case lt = "<"
case gte = ">="
case lte = "<="
case concatenate = "||"
func infix<T>(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression<T> {
return self.rawValue.infix(lhs, rhs, wrap: wrap)
}
func wrap<T>(_ expression: Expressible) -> Expression<T> {
return self.rawValue.wrap(expression)
}
}
public func +(lhs: Expression<String>, rhs: Expression<String>) -> Expression<String> {
return Operator.concatenate.infix(lhs, rhs)
}
public func +(lhs: Expression<String>, rhs: Expression<String?>) -> Expression<String?> {
return Operator.concatenate.infix(lhs, rhs)
}
public func +(lhs: Expression<String?>, rhs: Expression<String>) -> Expression<String?> {
return Operator.concatenate.infix(lhs, rhs)
}
public func +(lhs: Expression<String?>, rhs: Expression<String?>) -> Expression<String?> {
return Operator.concatenate.infix(lhs, rhs)
}
public func +(lhs: Expression<String>, rhs: String) -> Expression<String> {
return Operator.concatenate.infix(lhs, rhs)
}
public func +(lhs: Expression<String?>, rhs: String) -> Expression<String?> {
return Operator.concatenate.infix(lhs, rhs)
}
public func +(lhs: String, rhs: Expression<String>) -> Expression<String> {
return Operator.concatenate.infix(lhs, rhs)
}
public func +(lhs: String, rhs: Expression<String?>) -> Expression<String?> {
return Operator.concatenate.infix(lhs, rhs)
}
// MARK: -
public func +<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
return Operator.plus.infix(lhs, rhs)
}
public func +<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.plus.infix(lhs, rhs)
}
public func +<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype : Number {
return Operator.plus.infix(lhs, rhs)
}
public func +<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.plus.infix(lhs, rhs)
}
public func +<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype : Number {
return Operator.plus.infix(lhs, rhs)
}
public func +<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype : Number {
return Operator.plus.infix(lhs, rhs)
}
public func +<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
return Operator.plus.infix(lhs, rhs)
}
public func +<V: Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.plus.infix(lhs, rhs)
}
public func -<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
return Operator.minus.infix(lhs, rhs)
}
public func -<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.minus.infix(lhs, rhs)
}
public func -<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype : Number {
return Operator.minus.infix(lhs, rhs)
}
public func -<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.minus.infix(lhs, rhs)
}
public func -<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype : Number {
return Operator.minus.infix(lhs, rhs)
}
public func -<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype : Number {
return Operator.minus.infix(lhs, rhs)
}
public func -<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
return Operator.minus.infix(lhs, rhs)
}
public func -<V: Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.minus.infix(lhs, rhs)
}
public func *<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
return Operator.mul.infix(lhs, rhs)
}
public func *<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.mul.infix(lhs, rhs)
}
public func *<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype : Number {
return Operator.mul.infix(lhs, rhs)
}
public func *<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.mul.infix(lhs, rhs)
}
public func *<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype : Number {
return Operator.mul.infix(lhs, rhs)
}
public func *<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype : Number {
return Operator.mul.infix(lhs, rhs)
}
public func *<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
return Operator.mul.infix(lhs, rhs)
}
public func *<V: Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.mul.infix(lhs, rhs)
}
public func /<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
return Operator.div.infix(lhs, rhs)
}
public func /<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.div.infix(lhs, rhs)
}
public func /<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype : Number {
return Operator.div.infix(lhs, rhs)
}
public func /<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.div.infix(lhs, rhs)
}
public func /<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype : Number {
return Operator.div.infix(lhs, rhs)
}
public func /<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype : Number {
return Operator.div.infix(lhs, rhs)
}
public func /<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
return Operator.div.infix(lhs, rhs)
}
public func /<V: Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.div.infix(lhs, rhs)
}
public prefix func -<V : Value>(rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
return Operator.minus.wrap(rhs)
}
public prefix func -<V : Value>(rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
return Operator.minus.wrap(rhs)
}
// MARK: -
public func %<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.mod.infix(lhs, rhs)
}
public func %<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.mod.infix(lhs, rhs)
}
public func %<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.mod.infix(lhs, rhs)
}
public func %<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.mod.infix(lhs, rhs)
}
public func %<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
return Operator.mod.infix(lhs, rhs)
}
public func %<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
return Operator.mod.infix(lhs, rhs)
}
public func %<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.mod.infix(lhs, rhs)
}
public func %<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.mod.infix(lhs, rhs)
}
public func <<<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseLeft.infix(lhs, rhs)
}
public func <<<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseLeft.infix(lhs, rhs)
}
public func <<<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseLeft.infix(lhs, rhs)
}
public func <<<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseLeft.infix(lhs, rhs)
}
public func <<<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseLeft.infix(lhs, rhs)
}
public func <<<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseLeft.infix(lhs, rhs)
}
public func <<<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseLeft.infix(lhs, rhs)
}
public func <<<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseLeft.infix(lhs, rhs)
}
public func >><V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseRight.infix(lhs, rhs)
}
public func >><V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseRight.infix(lhs, rhs)
}
public func >><V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseRight.infix(lhs, rhs)
}
public func >><V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseRight.infix(lhs, rhs)
}
public func >><V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseRight.infix(lhs, rhs)
}
public func >><V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseRight.infix(lhs, rhs)
}
public func >><V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseRight.infix(lhs, rhs)
}
public func >><V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseRight.infix(lhs, rhs)
}
public func &<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseAnd.infix(lhs, rhs)
}
public func &<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseAnd.infix(lhs, rhs)
}
public func &<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseAnd.infix(lhs, rhs)
}
public func &<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseAnd.infix(lhs, rhs)
}
public func &<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseAnd.infix(lhs, rhs)
}
public func &<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseAnd.infix(lhs, rhs)
}
public func &<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseAnd.infix(lhs, rhs)
}
public func &<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseAnd.infix(lhs, rhs)
}
public func |<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseOr.infix(lhs, rhs)
}
public func |<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseOr.infix(lhs, rhs)
}
public func |<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseOr.infix(lhs, rhs)
}
public func |<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseOr.infix(lhs, rhs)
}
public func |<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseOr.infix(lhs, rhs)
}
public func |<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseOr.infix(lhs, rhs)
}
public func |<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseOr.infix(lhs, rhs)
}
public func |<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseOr.infix(lhs, rhs)
}
public func ^<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return (~(lhs & rhs)) & (lhs | rhs)
}
public func ^<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return (~(lhs & rhs)) & (lhs | rhs)
}
public func ^<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
return (~(lhs & rhs)) & (lhs | rhs)
}
public func ^<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return (~(lhs & rhs)) & (lhs | rhs)
}
public func ^<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
return (~(lhs & rhs)) & (lhs | rhs)
}
public func ^<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
return (~(lhs & rhs)) & (lhs | rhs)
}
public func ^<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return (~(lhs & rhs)) & (lhs | rhs)
}
public func ^<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return (~(lhs & rhs)) & (lhs | rhs)
}
public prefix func ~<V : Value>(rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
return Operator.bitwiseXor.wrap(rhs)
}
public prefix func ~<V : Value>(rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
return Operator.bitwiseXor.wrap(rhs)
}
// MARK: -
public func ==<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Equatable {
return Operator.eq.infix(lhs, rhs)
}
public func ==<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
return Operator.eq.infix(lhs, rhs)
}
public func ==<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Equatable {
return Operator.eq.infix(lhs, rhs)
}
public func ==<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
return Operator.eq.infix(lhs, rhs)
}
public func ==<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Equatable {
return Operator.eq.infix(lhs, rhs)
}
public func ==<V : Value>(lhs: Expression<V?>, rhs: V?) -> Expression<Bool?> where V.Datatype : Equatable {
guard let rhs = rhs else { return "IS".infix(lhs, Expression<V?>(value: nil)) }
return Operator.eq.infix(lhs, rhs)
}
public func ==<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Equatable {
return Operator.eq.infix(lhs, rhs)
}
public func ==<V : Value>(lhs: V?, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
guard let lhs = lhs else { return "IS".infix(Expression<V?>(value: nil), rhs) }
return Operator.eq.infix(lhs, rhs)
}
public func !=<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Equatable {
return Operator.neq.infix(lhs, rhs)
}
public func !=<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
return Operator.neq.infix(lhs, rhs)
}
public func !=<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Equatable {
return Operator.neq.infix(lhs, rhs)
}
public func !=<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
return Operator.neq.infix(lhs, rhs)
}
public func !=<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Equatable {
return Operator.neq.infix(lhs, rhs)
}
public func !=<V : Value>(lhs: Expression<V?>, rhs: V?) -> Expression<Bool?> where V.Datatype : Equatable {
guard let rhs = rhs else { return "IS NOT".infix(lhs, Expression<V?>(value: nil)) }
return Operator.neq.infix(lhs, rhs)
}
public func !=<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Equatable {
return Operator.neq.infix(lhs, rhs)
}
public func !=<V : Value>(lhs: V?, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
guard let lhs = lhs else { return "IS NOT".infix(Expression<V?>(value: nil), rhs) }
return Operator.neq.infix(lhs, rhs)
}
public func ><V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.gt.infix(lhs, rhs)
}
public func ><V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gt.infix(lhs, rhs)
}
public func ><V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gt.infix(lhs, rhs)
}
public func ><V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gt.infix(lhs, rhs)
}
public func ><V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.gt.infix(lhs, rhs)
}
public func ><V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gt.infix(lhs, rhs)
}
public func ><V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.gt.infix(lhs, rhs)
}
public func ><V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gt.infix(lhs, rhs)
}
public func >=<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.gte.infix(lhs, rhs)
}
public func >=<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gte.infix(lhs, rhs)
}
public func >=<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gte.infix(lhs, rhs)
}
public func >=<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gte.infix(lhs, rhs)
}
public func >=<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.gte.infix(lhs, rhs)
}
public func >=<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gte.infix(lhs, rhs)
}
public func >=<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.gte.infix(lhs, rhs)
}
public func >=<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.gte.infix(lhs, rhs)
}
public func <<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.lt.infix(lhs, rhs)
}
public func <<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lt.infix(lhs, rhs)
}
public func <<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lt.infix(lhs, rhs)
}
public func <<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lt.infix(lhs, rhs)
}
public func <<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.lt.infix(lhs, rhs)
}
public func <<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lt.infix(lhs, rhs)
}
public func <<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.lt.infix(lhs, rhs)
}
public func <<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lt.infix(lhs, rhs)
}
public func <=<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.lte.infix(lhs, rhs)
}
public func <=<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lte.infix(lhs, rhs)
}
public func <=<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lte.infix(lhs, rhs)
}
public func <=<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lte.infix(lhs, rhs)
}
public func <=<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.lte.infix(lhs, rhs)
}
public func <=<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lte.infix(lhs, rhs)
}
public func <=<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
return Operator.lte.infix(lhs, rhs)
}
public func <=<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
return Operator.lte.infix(lhs, rhs)
}
public func ~=<V : Value>(lhs: ClosedRange<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) BETWEEN ? AND ?", rhs.bindings + [lhs.lowerBound.datatypeValue, lhs.upperBound.datatypeValue])
}
public func ~=<V : Value>(lhs: ClosedRange<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) BETWEEN ? AND ?", rhs.bindings + [lhs.lowerBound.datatypeValue, lhs.upperBound.datatypeValue])
}
public func ~=<V : Value>(lhs: Range<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) >= ? AND \(rhs.template) < ?", rhs.bindings + [lhs.lowerBound.datatypeValue] + rhs.bindings + [lhs.upperBound.datatypeValue])
}
public func ~=<V : Value>(lhs: Range<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) >= ? AND \(rhs.template) < ?", rhs.bindings + [lhs.lowerBound.datatypeValue] + rhs.bindings + [lhs.upperBound.datatypeValue])
}
public func ~=<V : Value>(lhs: PartialRangeThrough<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) <= ?", rhs.bindings + [lhs.upperBound.datatypeValue])
}
public func ~=<V : Value>(lhs: PartialRangeThrough<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) <= ?", rhs.bindings + [lhs.upperBound.datatypeValue])
}
public func ~=<V : Value>(lhs: PartialRangeUpTo<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) < ?", rhs.bindings + [lhs.upperBound.datatypeValue])
}
public func ~=<V : Value>(lhs: PartialRangeUpTo<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) < ?", rhs.bindings + [lhs.upperBound.datatypeValue])
}
public func ~=<V : Value>(lhs: PartialRangeFrom<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) >= ?", rhs.bindings + [lhs.lowerBound.datatypeValue])
}
public func ~=<V : Value>(lhs: PartialRangeFrom<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable & Value {
return Expression("\(rhs.template) >= ?", rhs.bindings + [lhs.lowerBound.datatypeValue])
}
// MARK: -
public func &&(lhs: Expression<Bool>, rhs: Expression<Bool>) -> Expression<Bool> {
return Operator.and.infix(lhs, rhs)
}
public func &&(lhs: Expression<Bool>, rhs: Expression<Bool?>) -> Expression<Bool?> {
return Operator.and.infix(lhs, rhs)
}
public func &&(lhs: Expression<Bool?>, rhs: Expression<Bool>) -> Expression<Bool?> {
return Operator.and.infix(lhs, rhs)
}
public func &&(lhs: Expression<Bool?>, rhs: Expression<Bool?>) -> Expression<Bool?> {
return Operator.and.infix(lhs, rhs)
}
public func &&(lhs: Expression<Bool>, rhs: Bool) -> Expression<Bool> {
return Operator.and.infix(lhs, rhs)
}
public func &&(lhs: Expression<Bool?>, rhs: Bool) -> Expression<Bool?> {
return Operator.and.infix(lhs, rhs)
}
public func &&(lhs: Bool, rhs: Expression<Bool>) -> Expression<Bool> {
return Operator.and.infix(lhs, rhs)
}
public func &&(lhs: Bool, rhs: Expression<Bool?>) -> Expression<Bool?> {
return Operator.and.infix(lhs, rhs)
}
public func ||(lhs: Expression<Bool>, rhs: Expression<Bool>) -> Expression<Bool> {
return Operator.or.infix(lhs, rhs)
}
public func ||(lhs: Expression<Bool>, rhs: Expression<Bool?>) -> Expression<Bool?> {
return Operator.or.infix(lhs, rhs)
}
public func ||(lhs: Expression<Bool?>, rhs: Expression<Bool>) -> Expression<Bool?> {
return Operator.or.infix(lhs, rhs)
}
public func ||(lhs: Expression<Bool?>, rhs: Expression<Bool?>) -> Expression<Bool?> {
return Operator.or.infix(lhs, rhs)
}
public func ||(lhs: Expression<Bool>, rhs: Bool) -> Expression<Bool> {
return Operator.or.infix(lhs, rhs)
}
public func ||(lhs: Expression<Bool?>, rhs: Bool) -> Expression<Bool?> {
return Operator.or.infix(lhs, rhs)
}
public func ||(lhs: Bool, rhs: Expression<Bool>) -> Expression<Bool> {
return Operator.or.infix(lhs, rhs)
}
public func ||(lhs: Bool, rhs: Expression<Bool?>) -> Expression<Bool?> {
return Operator.or.infix(lhs, rhs)
}
public prefix func !(rhs: Expression<Bool>) -> Expression<Bool> {
return Operator.not.wrap(rhs)
}
public prefix func !(rhs: Expression<Bool?>) -> Expression<Bool?> {
return Operator.not.wrap(rhs)
}
File diff suppressed because it is too large Load Diff
+517
View File
@@ -0,0 +1,517 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
extension SchemaType {
// MARK: - DROP TABLE / VIEW / VIRTUAL TABLE
public func drop(ifExists: Bool = false) -> String {
return drop("TABLE", tableName(), ifExists)
}
}
extension Table {
// MARK: - CREATE TABLE
public func create(temporary: Bool = false, ifNotExists: Bool = false, withoutRowid: Bool = false, block: (TableBuilder) -> Void) -> String {
let builder = TableBuilder()
block(builder)
let clauses: [Expressible?] = [
create(Table.identifier, tableName(), temporary ? .temporary : nil, ifNotExists),
"".wrap(builder.definitions) as Expression<Void>,
withoutRowid ? Expression<Void>(literal: "WITHOUT ROWID") : nil
]
return " ".join(clauses.compactMap { $0 }).asSQL()
}
public func create(_ query: QueryType, temporary: Bool = false, ifNotExists: Bool = false) -> String {
let clauses: [Expressible?] = [
create(Table.identifier, tableName(), temporary ? .temporary : nil, ifNotExists),
Expression<Void>(literal: "AS"),
query
]
return " ".join(clauses.compactMap { $0 }).asSQL()
}
// MARK: - ALTER TABLE ADD COLUMN
public func addColumn<V : Value>(_ name: Expression<V>, check: Expression<Bool>? = nil, defaultValue: V) -> String {
return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, nil))
}
public func addColumn<V : Value>(_ name: Expression<V>, check: Expression<Bool?>, defaultValue: V) -> String {
return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, nil))
}
public func addColumn<V : Value>(_ name: Expression<V?>, check: Expression<Bool>? = nil, defaultValue: V? = nil) -> String {
return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, nil))
}
public func addColumn<V : Value>(_ name: Expression<V?>, check: Expression<Bool?>, defaultValue: V? = nil) -> String {
return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, nil))
}
public func addColumn<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, references table: QueryType, _ other: Expression<V>) -> String where V.Datatype == Int64 {
return addColumn(definition(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil))
}
public func addColumn<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, references table: QueryType, _ other: Expression<V>) -> String where V.Datatype == Int64 {
return addColumn(definition(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil))
}
public func addColumn<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, references table: QueryType, _ other: Expression<V>) -> String where V.Datatype == Int64 {
return addColumn(definition(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil))
}
public func addColumn<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, references table: QueryType, _ other: Expression<V>) -> String where V.Datatype == Int64 {
return addColumn(definition(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil))
}
public func addColumn<V : Value>(_ name: Expression<V>, check: Expression<Bool>? = nil, defaultValue: V, collate: Collation) -> String where V.Datatype == String {
return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, collate))
}
public func addColumn<V : Value>(_ name: Expression<V>, check: Expression<Bool?>, defaultValue: V, collate: Collation) -> String where V.Datatype == String {
return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, collate))
}
public func addColumn<V : Value>(_ name: Expression<V?>, check: Expression<Bool>? = nil, defaultValue: V? = nil, collate: Collation) -> String where V.Datatype == String {
return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, collate))
}
public func addColumn<V : Value>(_ name: Expression<V?>, check: Expression<Bool?>, defaultValue: V? = nil, collate: Collation) -> String where V.Datatype == String {
return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, collate))
}
fileprivate func addColumn(_ expression: Expressible) -> String {
return " ".join([
Expression<Void>(literal: "ALTER TABLE"),
tableName(),
Expression<Void>(literal: "ADD COLUMN"),
expression
]).asSQL()
}
// MARK: - ALTER TABLE RENAME TO
public func rename(_ to: Table) -> String {
return rename(to: to)
}
// MARK: - CREATE INDEX
public func createIndex(_ columns: Expressible..., unique: Bool = false, ifNotExists: Bool = false) -> String {
let clauses: [Expressible?] = [
create("INDEX", indexName(columns), unique ? .unique : nil, ifNotExists),
Expression<Void>(literal: "ON"),
tableName(qualified: false),
"".wrap(columns) as Expression<Void>
]
return " ".join(clauses.compactMap { $0 }).asSQL()
}
// MARK: - DROP INDEX
public func dropIndex(_ columns: Expressible..., ifExists: Bool = false) -> String {
return drop("INDEX", indexName(columns), ifExists)
}
fileprivate func indexName(_ columns: [Expressible]) -> Expressible {
let string = (["index", clauses.from.name, "on"] + columns.map { $0.expression.template }).joined(separator: " ").lowercased()
let index = string.reduce("") { underscored, character in
guard character != "\"" else {
return underscored
}
guard "a"..."z" ~= character || "0"..."9" ~= character else {
return underscored + "_"
}
return underscored + String(character)
}
return database(namespace: index)
}
}
extension View {
// MARK: - CREATE VIEW
public func create(_ query: QueryType, temporary: Bool = false, ifNotExists: Bool = false) -> String {
let clauses: [Expressible?] = [
create(View.identifier, tableName(), temporary ? .temporary : nil, ifNotExists),
Expression<Void>(literal: "AS"),
query
]
return " ".join(clauses.compactMap { $0 }).asSQL()
}
// MARK: - DROP VIEW
public func drop(ifExists: Bool = false) -> String {
return drop("VIEW", tableName(), ifExists)
}
}
extension VirtualTable {
// MARK: - CREATE VIRTUAL TABLE
public func create(_ using: Module, ifNotExists: Bool = false) -> String {
let clauses: [Expressible?] = [
create(VirtualTable.identifier, tableName(), nil, ifNotExists),
Expression<Void>(literal: "USING"),
using
]
return " ".join(clauses.compactMap { $0 }).asSQL()
}
// MARK: - ALTER TABLE RENAME TO
public func rename(_ to: VirtualTable) -> String {
return rename(to: to)
}
}
public final class TableBuilder {
fileprivate var definitions = [Expressible]()
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil) {
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: V) {
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V>? = nil) {
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, defaultValue: V) {
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil) {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V?>) {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: V) {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V>? = nil) {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V?>) {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: V) {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V>, primaryKey: Bool, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil) {
column(name, V.declaredDatatype, primaryKey ? .default : nil, false, false, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V>, primaryKey: Bool, check: Expression<Bool?>, defaultValue: Expression<V>? = nil) {
column(name, V.declaredDatatype, primaryKey ? .default : nil, false, false, check, defaultValue, nil, nil)
}
public func column<V : Value>(_ name: Expression<V>, primaryKey: PrimaryKey, check: Expression<Bool>? = nil) where V.Datatype == Int64 {
column(name, V.declaredDatatype, primaryKey, false, false, check, nil, nil, nil)
}
public func column<V : Value>(_ name: Expression<V>, primaryKey: PrimaryKey, check: Expression<Bool?>) where V.Datatype == Int64 {
column(name, V.declaredDatatype, primaryKey, false, false, check, nil, nil, nil)
}
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, references table: QueryType, _ other: Expression<V>) where V.Datatype == Int64 {
column(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil)
}
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, references table: QueryType, _ other: Expression<V>) where V.Datatype == Int64 {
column(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, references table: QueryType, _ other: Expression<V>) where V.Datatype == Int64 {
column(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, references table: QueryType, _ other: Expression<V>) where V.Datatype == Int64 {
column(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil)
}
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
}
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: V, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
}
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V>? = nil, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
}
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, defaultValue: V, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V?>, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: V, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V>? = nil, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V?>, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate)
}
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: V, collate: Collation) where V.Datatype == String {
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate)
}
fileprivate func column(_ name: Expressible, _ datatype: String, _ primaryKey: PrimaryKey?, _ null: Bool, _ unique: Bool, _ check: Expressible?, _ defaultValue: Expressible?, _ references: (QueryType, Expressible)?, _ collate: Collation?) {
definitions.append(definition(name, datatype, primaryKey, null, unique, check, defaultValue, references, collate))
}
// MARK: -
public func primaryKey<T : Value>(_ column: Expression<T>) {
primaryKey([column])
}
public func primaryKey<T : Value, U : Value>(_ compositeA: Expression<T>, _ b: Expression<U>) {
primaryKey([compositeA, b])
}
public func primaryKey<T : Value, U : Value, V : Value>(_ compositeA: Expression<T>, _ b: Expression<U>, _ c: Expression<V>) {
primaryKey([compositeA, b, c])
}
public func primaryKey<T : Value, U : Value, V : Value, W : Value>(_ compositeA: Expression<T>, _ b: Expression<U>, _ c: Expression<V>, _ d: Expression<W>) {
primaryKey([compositeA, b, c, d])
}
fileprivate func primaryKey(_ composite: [Expressible]) {
definitions.append("PRIMARY KEY".prefix(composite))
}
public func unique(_ columns: Expressible...) {
unique(columns)
}
public func unique(_ columns: [Expressible]) {
definitions.append("UNIQUE".prefix(columns))
}
public func check(_ condition: Expression<Bool>) {
check(Expression<Bool?>(condition))
}
public func check(_ condition: Expression<Bool?>) {
definitions.append("CHECK".prefix(condition))
}
public enum Dependency: String {
case noAction = "NO ACTION"
case restrict = "RESTRICT"
case setNull = "SET NULL"
case setDefault = "SET DEFAULT"
case cascade = "CASCADE"
}
public func foreignKey<T : Value>(_ column: Expression<T>, references table: QueryType, _ other: Expression<T>, update: Dependency? = nil, delete: Dependency? = nil) {
foreignKey(column, (table, other), update, delete)
}
public func foreignKey<T : Value>(_ column: Expression<T?>, references table: QueryType, _ other: Expression<T>, update: Dependency? = nil, delete: Dependency? = nil) {
foreignKey(column, (table, other), update, delete)
}
public func foreignKey<T : Value, U : Value>(_ composite: (Expression<T>, Expression<U>), references table: QueryType, _ other: (Expression<T>, Expression<U>), update: Dependency? = nil, delete: Dependency? = nil) {
let composite = ", ".join([composite.0, composite.1])
let references = (table, ", ".join([other.0, other.1]))
foreignKey(composite, references, update, delete)
}
public func foreignKey<T : Value, U : Value, V : Value>(_ composite: (Expression<T>, Expression<U>, Expression<V>), references table: QueryType, _ other: (Expression<T>, Expression<U>, Expression<V>), update: Dependency? = nil, delete: Dependency? = nil) {
let composite = ", ".join([composite.0, composite.1, composite.2])
let references = (table, ", ".join([other.0, other.1, other.2]))
foreignKey(composite, references, update, delete)
}
fileprivate func foreignKey(_ column: Expressible, _ references: (QueryType, Expressible), _ update: Dependency?, _ delete: Dependency?) {
let clauses: [Expressible?] = [
"FOREIGN KEY".prefix(column),
reference(references),
update.map { Expression<Void>(literal: "ON UPDATE \($0.rawValue)") },
delete.map { Expression<Void>(literal: "ON DELETE \($0.rawValue)") }
]
definitions.append(" ".join(clauses.compactMap { $0 }))
}
}
public enum PrimaryKey {
case `default`
case autoincrement
}
public struct Module {
fileprivate let name: String
fileprivate let arguments: [Expressible]
public init(_ name: String, _ arguments: [Expressible]) {
self.init(name: name.quote(), arguments: arguments)
}
init(name: String, arguments: [Expressible]) {
self.name = name
self.arguments = arguments
}
}
extension Module : Expressible {
public var expression: Expression<Void> {
return name.wrap(arguments)
}
}
// MARK: - Private
private extension QueryType {
func create(_ identifier: String, _ name: Expressible, _ modifier: Modifier?, _ ifNotExists: Bool) -> Expressible {
let clauses: [Expressible?] = [
Expression<Void>(literal: "CREATE"),
modifier.map { Expression<Void>(literal: $0.rawValue) },
Expression<Void>(literal: identifier),
ifNotExists ? Expression<Void>(literal: "IF NOT EXISTS") : nil,
name
]
return " ".join(clauses.compactMap { $0 })
}
func rename(to: Self) -> String {
return " ".join([
Expression<Void>(literal: "ALTER TABLE"),
tableName(),
Expression<Void>(literal: "RENAME TO"),
Expression<Void>(to.clauses.from.name)
]).asSQL()
}
func drop(_ identifier: String, _ name: Expressible, _ ifExists: Bool) -> String {
let clauses: [Expressible?] = [
Expression<Void>(literal: "DROP \(identifier)"),
ifExists ? Expression<Void>(literal: "IF EXISTS") : nil,
name
]
return " ".join(clauses.compactMap { $0 }).asSQL()
}
}
private func definition(_ column: Expressible, _ datatype: String, _ primaryKey: PrimaryKey?, _ null: Bool, _ unique: Bool, _ check: Expressible?, _ defaultValue: Expressible?, _ references: (QueryType, Expressible)?, _ collate: Collation?) -> Expressible {
let clauses: [Expressible?] = [
column,
Expression<Void>(literal: datatype),
primaryKey.map { Expression<Void>(literal: $0 == .autoincrement ? "PRIMARY KEY AUTOINCREMENT" : "PRIMARY KEY") },
null ? nil : Expression<Void>(literal: "NOT NULL"),
unique ? Expression<Void>(literal: "UNIQUE") : nil,
check.map { " ".join([Expression<Void>(literal: "CHECK"), $0]) },
defaultValue.map { "DEFAULT".prefix($0) },
references.map(reference),
collate.map { " ".join([Expression<Void>(literal: "COLLATE"), $0]) }
]
return " ".join(clauses.compactMap { $0 })
}
private func reference(_ primary: (QueryType, Expressible)) -> Expressible {
return " ".join([
Expression<Void>(literal: "REFERENCES"),
primary.0.tableName(qualified: false),
"".wrap(primary.1) as Expression<Void>
])
}
private enum Modifier : String {
case unique = "UNIQUE"
case temporary = "TEMPORARY"
}
+277
View File
@@ -0,0 +1,277 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
precedencegroup ColumnAssignment {
associativity: left
assignment: true
lowerThan: AssignmentPrecedence
}
infix operator <- : ColumnAssignment
public struct Setter {
let column: Expressible
let value: Expressible
fileprivate init<V : Value>(column: Expression<V>, value: Expression<V>) {
self.column = column
self.value = value
}
fileprivate init<V : Value>(column: Expression<V>, value: V) {
self.column = column
self.value = value
}
fileprivate init<V : Value>(column: Expression<V?>, value: Expression<V>) {
self.column = column
self.value = value
}
fileprivate init<V : Value>(column: Expression<V?>, value: Expression<V?>) {
self.column = column
self.value = value
}
fileprivate init<V : Value>(column: Expression<V?>, value: V?) {
self.column = column
self.value = Expression<V?>(value: value)
}
}
extension Setter : Expressible {
public var expression: Expression<Void> {
return "=".infix(column, value, wrap: false)
}
}
public func <-<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter {
return Setter(column: column, value: value)
}
public func <-<V : Value>(column: Expression<V>, value: V) -> Setter {
return Setter(column: column, value: value)
}
public func <-<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter {
return Setter(column: column, value: value)
}
public func <-<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter {
return Setter(column: column, value: value)
}
public func <-<V : Value>(column: Expression<V?>, value: V?) -> Setter {
return Setter(column: column, value: value)
}
public func +=(column: Expression<String>, value: Expression<String>) -> Setter {
return column <- column + value
}
public func +=(column: Expression<String>, value: String) -> Setter {
return column <- column + value
}
public func +=(column: Expression<String?>, value: Expression<String>) -> Setter {
return column <- column + value
}
public func +=(column: Expression<String?>, value: Expression<String?>) -> Setter {
return column <- column + value
}
public func +=(column: Expression<String?>, value: String) -> Setter {
return column <- column + value
}
public func +=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype : Number {
return column <- column + value
}
public func +=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype : Number {
return column <- column + value
}
public func +=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype : Number {
return column <- column + value
}
public func +=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype : Number {
return column <- column + value
}
public func +=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype : Number {
return column <- column + value
}
public func -=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype : Number {
return column <- column - value
}
public func -=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype : Number {
return column <- column - value
}
public func -=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype : Number {
return column <- column - value
}
public func -=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype : Number {
return column <- column - value
}
public func -=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype : Number {
return column <- column - value
}
public func *=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype : Number {
return column <- column * value
}
public func *=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype : Number {
return column <- column * value
}
public func *=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype : Number {
return column <- column * value
}
public func *=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype : Number {
return column <- column * value
}
public func *=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype : Number {
return column <- column * value
}
public func /=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype : Number {
return column <- column / value
}
public func /=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype : Number {
return column <- column / value
}
public func /=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype : Number {
return column <- column / value
}
public func /=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype : Number {
return column <- column / value
}
public func /=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype : Number {
return column <- column / value
}
public func %=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column % value
}
public func %=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column % value
}
public func %=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column % value
}
public func %=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
return column <- column % value
}
public func %=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column % value
}
public func <<=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column << value
}
public func <<=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column << value
}
public func <<=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column << value
}
public func <<=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
return column <- column << value
}
public func <<=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column << value
}
public func >>=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column >> value
}
public func >>=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column >> value
}
public func >>=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column >> value
}
public func >>=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
return column <- column >> value
}
public func >>=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column >> value
}
public func &=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column & value
}
public func &=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column & value
}
public func &=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column & value
}
public func &=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
return column <- column & value
}
public func &=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column & value
}
public func |=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column | value
}
public func |=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column | value
}
public func |=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column | value
}
public func |=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
return column <- column | value
}
public func |=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column | value
}
public func ^=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column ^ value
}
public func ^=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column ^ value
}
public func ^=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
return column <- column ^ value
}
public func ^=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
return column <- column ^ value
}
public func ^=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
return column <- column ^ value
}
public postfix func ++<V : Value>(column: Expression<V>) -> Setter where V.Datatype == Int64 {
return Expression<Int>(column) += 1
}
public postfix func ++<V : Value>(column: Expression<V?>) -> Setter where V.Datatype == Int64 {
return Expression<Int>(column) += 1
}
public postfix func --<V : Value>(column: Expression<V>) -> Setter where V.Datatype == Int64 {
return Expression<Int>(column) -= 1
}
public postfix func --<V : Value>(column: Expression<V?>) -> Setter where V.Datatype == Int64 {
return Expression<Int>(column) -= 1
}
+138
View File
@@ -0,0 +1,138 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "SQLiteObjc.h"
#import "fts3_tokenizer.h"
#pragma mark - FTS
typedef struct __SQLiteTokenizer {
sqlite3_tokenizer base;
__unsafe_unretained _SQLiteTokenizerNextCallback callback;
} __SQLiteTokenizer;
typedef struct __SQLiteTokenizerCursor {
void * base;
const char * input;
int inputOffset;
int inputLength;
int idx;
} __SQLiteTokenizerCursor;
static NSMutableDictionary * __SQLiteTokenizerMap;
static int __SQLiteTokenizerCreate(int argc, const char * const * argv, sqlite3_tokenizer ** ppTokenizer) {
__SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)sqlite3_malloc(sizeof(__SQLiteTokenizer));
if (!tokenizer) {
return SQLITE_NOMEM;
}
memset(tokenizer, 0, sizeof(* tokenizer));
NSString * key = [NSString stringWithUTF8String:argv[0]];
tokenizer->callback = [__SQLiteTokenizerMap objectForKey:key];
if (!tokenizer->callback) {
return SQLITE_ERROR;
}
*ppTokenizer = &tokenizer->base;
return SQLITE_OK;
}
static int __SQLiteTokenizerDestroy(sqlite3_tokenizer * pTokenizer) {
sqlite3_free(pTokenizer);
return SQLITE_OK;
}
static int __SQLiteTokenizerOpen(sqlite3_tokenizer * pTokenizer, const char * pInput, int nBytes, sqlite3_tokenizer_cursor ** ppCursor) {
__SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)sqlite3_malloc(sizeof(__SQLiteTokenizerCursor));
if (!cursor) {
return SQLITE_NOMEM;
}
cursor->input = pInput;
cursor->inputOffset = 0;
cursor->inputLength = 0;
cursor->idx = 0;
*ppCursor = (sqlite3_tokenizer_cursor *)cursor;
return SQLITE_OK;
}
static int __SQLiteTokenizerClose(sqlite3_tokenizer_cursor * pCursor) {
sqlite3_free(pCursor);
return SQLITE_OK;
}
static int __SQLiteTokenizerNext(sqlite3_tokenizer_cursor * pCursor, const char ** ppToken, int * pnBytes, int * piStartOffset, int * piEndOffset, int * piPosition) {
__SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)pCursor;
__SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)cursor->base;
cursor->inputOffset += cursor->inputLength;
const char * input = cursor->input + cursor->inputOffset;
const char * token = [tokenizer->callback(input, &cursor->inputOffset, &cursor->inputLength) cStringUsingEncoding:NSUTF8StringEncoding];
if (!token) {
return SQLITE_DONE;
}
*ppToken = token;
*pnBytes = (int)strlen(token);
*piStartOffset = cursor->inputOffset;
*piEndOffset = cursor->inputOffset + cursor->inputLength;
*piPosition = cursor->idx++;
return SQLITE_OK;
}
static const sqlite3_tokenizer_module __SQLiteTokenizerModule = {
0,
__SQLiteTokenizerCreate,
__SQLiteTokenizerDestroy,
__SQLiteTokenizerOpen,
__SQLiteTokenizerClose,
__SQLiteTokenizerNext
};
int _SQLiteRegisterTokenizer(sqlite3 *db, const char * moduleName, const char * submoduleName, _SQLiteTokenizerNextCallback callback) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__SQLiteTokenizerMap = [NSMutableDictionary new];
});
sqlite3_stmt * stmt;
int status = sqlite3_prepare_v2(db, "SELECT fts3_tokenizer(?, ?)", -1, &stmt, 0);
if (status != SQLITE_OK ){
return status;
}
const sqlite3_tokenizer_module * pModule = &__SQLiteTokenizerModule;
sqlite3_bind_text(stmt, 1, moduleName, -1, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 2, &pModule, sizeof(pModule), SQLITE_STATIC);
sqlite3_step(stmt);
status = sqlite3_finalize(stmt);
if (status != SQLITE_OK ){
return status;
}
[__SQLiteTokenizerMap setObject:[callback copy] forKey:[NSString stringWithUTF8String:submoduleName]];
return SQLITE_OK;
}
+161
View File
@@ -0,0 +1,161 @@
/*
** 2006 July 10
**
** The author disclaims copyright to this source code.
**
*************************************************************************
** Defines the interface to tokenizers used by fulltext-search. There
** are three basic components:
**
** sqlite3_tokenizer_module is a singleton defining the tokenizer
** interface functions. This is essentially the class structure for
** tokenizers.
**
** sqlite3_tokenizer is used to define a particular tokenizer, perhaps
** including customization information defined at creation time.
**
** sqlite3_tokenizer_cursor is generated by a tokenizer to generate
** tokens from a particular input.
*/
#ifndef _FTS3_TOKENIZER_H_
#define _FTS3_TOKENIZER_H_
/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time.
** If tokenizers are to be allowed to call sqlite3_*() functions, then
** we will need a way to register the API consistently.
*/
#import "sqlite3.h"
/*
** Structures used by the tokenizer interface. When a new tokenizer
** implementation is registered, the caller provides a pointer to
** an sqlite3_tokenizer_module containing pointers to the callback
** functions that make up an implementation.
**
** When an fts3 table is created, it passes any arguments passed to
** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the
** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer
** implementation. The xCreate() function in turn returns an
** sqlite3_tokenizer structure representing the specific tokenizer to
** be used for the fts3 table (customized by the tokenizer clause arguments).
**
** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen()
** method is called. It returns an sqlite3_tokenizer_cursor object
** that may be used to tokenize a specific input buffer based on
** the tokenization rules supplied by a specific sqlite3_tokenizer
** object.
*/
typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;
typedef struct sqlite3_tokenizer sqlite3_tokenizer;
typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;
struct sqlite3_tokenizer_module {
/*
** Structure version. Should always be set to 0 or 1.
*/
int iVersion;
/*
** Create a new tokenizer. The values in the argv[] array are the
** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL
** TABLE statement that created the fts3 table. For example, if
** the following SQL is executed:
**
** CREATE .. USING fts3( ... , tokenizer <tokenizer-name> arg1 arg2)
**
** then argc is set to 2, and the argv[] array contains pointers
** to the strings "arg1" and "arg2".
**
** This method should return either SQLITE_OK (0), or an SQLite error
** code. If SQLITE_OK is returned, then *ppTokenizer should be set
** to point at the newly created tokenizer structure. The generic
** sqlite3_tokenizer.pModule variable should not be initialized by
** this callback. The caller will do so.
*/
int (*xCreate)(
int argc, /* Size of argv array */
const char *const*argv, /* Tokenizer argument strings */
sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */
);
/*
** Destroy an existing tokenizer. The fts3 module calls this method
** exactly once for each successful call to xCreate().
*/
int (*xDestroy)(sqlite3_tokenizer *pTokenizer);
/*
** Create a tokenizer cursor to tokenize an input buffer. The caller
** is responsible for ensuring that the input buffer remains valid
** until the cursor is closed (using the xClose() method).
*/
int (*xOpen)(
sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
const char *pInput, int nBytes, /* Input buffer */
sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */
);
/*
** Destroy an existing tokenizer cursor. The fts3 module calls this
** method exactly once for each successful call to xOpen().
*/
int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
/*
** Retrieve the next token from the tokenizer cursor pCursor. This
** method should either return SQLITE_OK and set the values of the
** "OUT" variables identified below, or SQLITE_DONE to indicate that
** the end of the buffer has been reached, or an SQLite error code.
**
** *ppToken should be set to point at a buffer containing the
** normalized version of the token (i.e. after any case-folding and/or
** stemming has been performed). *pnBytes should be set to the length
** of this buffer in bytes. The input text that generated the token is
** identified by the byte offsets returned in *piStartOffset and
** *piEndOffset. *piStartOffset should be set to the index of the first
** byte of the token in the input buffer. *piEndOffset should be set
** to the index of the first byte just past the end of the token in
** the input buffer.
**
** The buffer *ppToken is set to point at is managed by the tokenizer
** implementation. It is only required to be valid until the next call
** to xNext() or xClose().
*/
/* TODO(shess) current implementation requires pInput to be
** nul-terminated. This should either be fixed, or pInput/nBytes
** should be converted to zInput.
*/
int (*xNext)(
sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */
const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */
int *piStartOffset, /* OUT: Byte offset of token in input buffer */
int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
int *piPosition /* OUT: Number of tokens returned before this one */
);
/***********************************************************************
** Methods below this point are only available if iVersion>=1.
*/
/*
** Configure the language id of a tokenizer cursor.
*/
int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);
};
struct sqlite3_tokenizer {
const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */
/* Tokenizer implementations will typically add additional fields */
};
struct sqlite3_tokenizer_cursor {
sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */
/* Tokenizer implementations will typically add additional fields */
};
int fts3_global_term_cnt(int iTerm, int iCol);
int fts3_term_cnt(int iTerm, int iCol);
#endif /* _FTS3_TOKENIZER_H_ */
@@ -0,0 +1,32 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import Foundation;
@import SQLite3;
NS_ASSUME_NONNULL_BEGIN
typedef NSString * _Nullable (^_SQLiteTokenizerNextCallback)(const char *input, int *inputOffset, int *inputLength);
int _SQLiteRegisterTokenizer(sqlite3 *db, const char *module, const char *tokenizer, _Nullable _SQLiteTokenizerNextCallback callback);
NS_ASSUME_NONNULL_END