Skip to content

Instantly share code, notes, and snippets.

@EricRabil
Created July 21, 2021 19:26
Show Gist options
  • Save EricRabil/f9c2fb79dee8fa89596c00c3d0693b3c to your computer and use it in GitHub Desktop.
Save EricRabil/f9c2fb79dee8fa89596c00c3d0693b3c to your computer and use it in GitHub Desktop.
SQLite.swift expansion
import Foundation
import SQLite
protocol TableActionable {
associatedtype SelfType
@discardableResult
func insert(db: Connection) throws -> SelfType
@discardableResult
func update(db: Connection) throws -> SelfType
@discardableResult
func delete(db: Connection) throws -> SelfType
}
protocol TableBase: TableActionable, Codable where SelfType: Codable {
static var table: Table { get }
static func create(inDatabase database: Connection) throws
static func allRecords(db: Connection) throws -> [SelfType]
static func selectMany(db: Connection, _ filter: Table) throws -> [SelfType]
static func selectOne(db: Connection, _ filter: Table) throws -> SelfType?
static func deleteWhere(db: Connection, _ filter: Table) throws
/// updates the record after the closure completes
func updating(db: Connection, _ cb: () throws -> ()) throws
var table: Table { get }
var selector: Table { get }
}
protocol ConnectionProviding {
static var connection: Connection { get }
var connection: Connection { get }
}
protocol TableActionableImpliedConnection: TableActionable {
func insert() throws -> SelfType
func update() throws -> SelfType
func delete() throws -> SelfType
}
extension ConnectionProviding {
var connection: Connection {
Self.connection
}
}
extension TableBase {
var table: Table {
Self.table
}
static func allRecords(db: Connection) throws -> [SelfType] {
try db.prepare(table).map {
try $0.decode()
}
}
static func selectMany(db: Connection, _ filter: Table) throws -> [SelfType] {
try db.prepare(filter).map {
try $0.decode()
}
}
static func selectOne(db: Connection, _ filter: Table) throws -> SelfType? {
if let row = try db.pluck(filter) {
return try row.decode() as SelfType
} else {
return nil
}
}
static func deleteWhere(db: Connection, _ filter: Table) throws {
try db.run(filter.delete())
}
func updating(db: Connection, _ cb: () throws -> ()) throws {
try cb()
try self.update(db: db)
}
func insert(db: Connection) throws -> Self {
try db.run(Self.table.insert(self))
return self
}
func update(db: Connection) throws -> Self {
try db.run(selector.update(self))
return self
}
func delete(db: Connection) throws -> Self {
try db.run(selector.delete())
return self
}
}
// MARK: - Array APIs
extension Array where Element: TableActionable {
@inline(__always)
fileprivate func _transact(_ db: Connection, _ cb: (Element, Connection) throws -> ()) throws {
try db.transaction {
for record in self {
try cb(record, db)
}
}
}
}
extension Array: TableActionable where Element: TableActionable {
typealias SelfType = [Element]
func insert(db: Connection) throws -> [Element] {
try _transact(db) { element, db in
try element.insert(db: db)
}
return self
}
func update(db: Connection) throws -> [Element] {
try _transact(db) { element, db in
try element.update(db: db)
}
return self
}
func delete(db: Connection) throws -> [Element] {
try _transact(db) { element, db in
try element.delete(db: db)
}
return self
}
}
extension Array: ConnectionProviding where Element: ConnectionProviding {
@inline(__always)
static var connection: Connection {
Element.connection
}
}
// Make ConnectionProviding TableActionableImpliedConnection when it is TableActionable
extension TableActionable where Self: ConnectionProviding {
@inline(__always)
@discardableResult
func insert() throws -> SelfType {
try insert(db: connection)
}
@inline(__always)
@discardableResult
func update() throws -> SelfType {
try update(db: connection)
}
@inline(__always)
@discardableResult
func delete() throws -> SelfType {
try delete(db: connection)
}
}
extension TableBase where Self: ConnectionProviding {
@inline(__always)
static func allRecords() throws -> [SelfType] {
try allRecords(db: connection)
}
@inline(__always)
static func selectOne(_ filter: Table) throws -> SelfType? {
try selectOne(db: connection, filter)
}
@inline(__always)
static func selectMany(_ filter: Table) throws -> [SelfType] {
try selectMany(db: connection, filter)
}
@inline(__always)
static func deleteWhere(_ filter: Table) throws {
try deleteWhere(db: connection, filter)
}
@inline(__always)
func updating(_ cb: () throws -> ()) throws {
try updating(db: connection, cb)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment