Skip to content

Commit

Permalink
Make DatabasePromise a proper monad
Browse files Browse the repository at this point in the history
  • Loading branch information
groue committed Feb 4, 2019
1 parent a1c9942 commit e99823d
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 15 deletions.
11 changes: 9 additions & 2 deletions GRDB/QueryInterface/DatabasePromise.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,16 @@ struct DatabasePromise<T> {
}

/// Returns a promise whose value is transformed by the given closure.
func map<U>(_ transform: @escaping (Database, T) throws -> U) -> DatabasePromise<U> {
func map<U>(_ transform: @escaping (T) throws -> U) -> DatabasePromise<U> {
return DatabasePromise<U> { db in
try transform(db, self.resolve(db))
try transform(self.resolve(db))
}
}

// TODO: write human-readable documentation for this classic monadic operation
func flatMap<U>(_ transform: @escaping (T) -> DatabasePromise<U>) -> DatabasePromise<U> {
return DatabasePromise<U> { db in
try transform(self.resolve(db)).resolve(db)
}
}
}
25 changes: 14 additions & 11 deletions GRDB/QueryInterface/SQLRelation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ extension SQLRelation {

func filter(_ predicate: @escaping (Database) throws -> SQLExpressible) -> SQLRelation {
var relation = self
relation.filterPromise = relation.filterPromise.map { (db, filter) in
relation.filterPromise = relation.filterPromise.flatMap { filter in
if let filter = filter {
return try filter && predicate(db)
return DatabasePromise { try filter && predicate($0) }
} else {
return try predicate(db).sqlExpression
return DatabasePromise { try predicate($0).sqlExpression }
}
}
return relation
Expand Down Expand Up @@ -138,7 +138,7 @@ extension SQLRelation {
var reversed: Element {
switch self {
case .terms(let terms):
return .terms(terms.map { (db, terms) in terms.map { $0.reversed } })
return .terms(terms.map { $0.map { $0.reversed } })
case .ordering(let ordering):
return .ordering(ordering.reversed)
}
Expand All @@ -147,7 +147,7 @@ extension SQLRelation {
func qualified(with alias: TableAlias) -> Element {
switch self {
case .terms(let terms):
return .terms(terms.map { (db, terms) in terms.map { $0.qualifiedOrdering(with: alias) } })
return .terms(terms.map { $0.map { $0.qualifiedOrdering(with: alias) } })
case .ordering(let ordering):
return .ordering(ordering.qualified(with: alias))
}
Expand Down Expand Up @@ -371,13 +371,16 @@ extension SQLRelation {
return nil
}

let mergedFilterPromise = filterPromise.map { (db, expression) -> SQLExpression? in
let otherExpression = try other.filterPromise.resolve(db)
let expressions = [expression, otherExpression].compactMap { $0 }
if expressions.isEmpty {
return nil
let mergedFilterPromise: DatabasePromise<SQLExpression?> = filterPromise.flatMap { expression in
return DatabasePromise { db in
let otherExpression = try other.filterPromise.resolve(db)
let expressions = [expression, otherExpression].compactMap { $0 }
if expressions.isEmpty {
return nil
} else {
return expressions.joined(operator: .and)
}
}
return expressions.joined(operator: .and)
}

var mergedJoins: OrderedDictionary<String, SQLJoin> = [:]
Expand Down
4 changes: 2 additions & 2 deletions GRDB/QueryInterface/SQLSelectQueryGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct SQLSelectQueryGenerator {
// This turns `GROUP BY id` INTO `GROUP BY book.id`, and
// `HAVING MAX(year) < 2000` INTO `HAVING MAX(book.year) < 2000`.
let alias = relation.alias
groupPromise = query.groupPromise?.map { [alias] (_, exprs) in exprs.map { $0.qualifiedExpression(with: alias) } }
groupPromise = query.groupPromise?.map { [alias] in $0.map { $0.qualifiedExpression(with: alias) } }
havingExpression = query.havingExpression?.qualifiedExpression(with: alias)

// Preserve other flags
Expand Down Expand Up @@ -287,7 +287,7 @@ private struct SQLQualifiedRelation {
// identifiers can be correctly disambiguated and qualified.
joins = relation.joins.mapValues(SQLQualifiedJoin.init)
ownSelection = relation.selection.map { $0.qualifiedSelectable(with: alias) }
filterPromise = relation.filterPromise.map { [alias] (_, expr) in expr?.qualifiedExpression(with: alias) }
filterPromise = relation.filterPromise.map { [alias] in $0?.qualifiedExpression(with: alias) }
ownOrdering = relation.ordering.qualified(with: alias)
}

Expand Down

0 comments on commit e99823d

Please sign in to comment.