123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- /*
- * Copyright IBM Corporation 2018
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- import Foundation
- import Dispatch
- import LoggerAPI
- import SwiftKuery
- import SwiftKueryORM
- import KueryPostgres
- import TechEmpowerCommon
- // ORM conformance
- extension RandomRow: Model {
- public static var tableName: String { return "world" }
- }
- // ORM conformance
- extension Fortune: Model {
- public static var tableName: String { return "fortune" }
- }
- // Configure our ORM Database connection pool as dbConnPool created by KueryPostgres
- public func setupORM() {
- Database.default = Database(dbConnPool)
- }
- /// Get a list of Fortunes from the database.
- ///
- /// - Parameter callback: The callback that will be invoked once the DB query
- /// has completed and results are available, passing an
- /// optional [Fortune] (on success) or RequestError on
- /// failure.
- ///
- public func getFortunes(callback: @escaping ([Fortune]?, RequestError?) -> Void) -> Void {
- Fortune.findAll { (fortunes, err) in
- if let err = err {
- return callback(nil, err)
- } else {
- callback(fortunes, nil)
- }
- }
- }
- /// Get a random row (range 1 to 10,000) from the database.
- ///
- /// - Parameter callback: The callback that will be invoked once the DB query
- /// has completed and results are available, passing an
- /// optional RandomRow (on success) or RequestError on
- /// failure.
- ///
- public func getRandomRow(callback: @escaping (RandomRow?, RequestError?) -> Void) -> Void {
- // Select random row from database range
- let rnd = RandomRow.randomId
- RandomRow.find(id: rnd, callback)
- }
- /// Updates a row of World to a new value.
- ///
- /// - Parameter callback: The callback that will be invoked once the DB update
- /// has completed, passing an optional RequestError if the
- /// update failed.
- ///
- public func updateRow(id: Int, callback: @escaping (RequestError?) -> Void) -> Void {
- // Generate a random number for this row
- let row = RandomRow(id: id, randomNumber: RandomRow.randomValue)
- row.update(id: id) { (resultRow, err) in
- if let err = err {
- return callback(err)
- } else {
- callback(nil)
- }
- }
- }
- /// Get `count` random rows from the database, and pass the resulting array
- /// to a completion handler (or a RequestError, in the event that a row could
- /// not be retrieved).
- ///
- /// - Parameter count: The number of rows to retrieve
- /// - Parameter result: The intermediate result array being built
- /// - Parameter completion: The closure to invoke with the result array, or error
- ///
- public func getRandomRows(count: Int, result: [RandomRow] = [], completion: @escaping ([RandomRow]?, RequestError?) -> Void) {
- if count > 0 {
- // Select random row from database range
- RandomRow.find(id: RandomRow.randomId) { (resultRow, err) in
- if let resultRow = resultRow {
- var result = result
- result.append(resultRow)
- getRandomRows(count: count-1, result: result, completion: completion)
- } else {
- if let err = err {
- completion(nil, err)
- } else {
- fatalError("Unexpected: result and error both nil")
- }
- }
- }
- } else {
- completion(result, nil)
- }
- }
- /// A parallel version of `getRandomRows` that invokes each get in parallel, builds an
- /// array of results and waits for each get to complete before returning.
- ///
- /// - Parameter count: The number of rows to retrieve
- /// - Parameter completion: The closure to invoke with the result array, or error
- ///
- public func getRandomRowsParallel(count: Int, completion: @escaping ([RandomRow]?, RequestError?) -> Void) {
- var results: [RandomRow] = []
- guard count > 0 else {
- return completion(results, nil)
- }
- // Used to protect result array from concurrent modification
- let updateLock = DispatchSemaphore(value: 1)
- // Execute each query. Each callback will append its result to `results`
- for _ in 1...count {
- RandomRow.find(id: RandomRow.randomId) { (resultRow, err) in
- guard let resultRow = resultRow else {
- Log.error("\(err ?? .internalServerError)")
- completion(nil, err ?? .internalServerError)
- return
- }
- updateLock.wait()
- results.append(resultRow)
- if results.count == count {
- completion(results, nil)
- }
- updateLock.signal()
- }
- }
- }
- /// Update and retrieve `count` random rows from the database, and pass the
- /// resulting array to a completion handler (or a RequestError, in the event
- /// that a row could not be retrieved or updated).
- ///
- /// - Parameter count: The number of rows to retrieve
- /// - Parameter result: The intermediate result array being built
- /// - Parameter completion: The closure to invoke with the result array, or error
- ///
- public func updateRandomRows(count: Int, result: [RandomRow] = [], completion: @escaping ([RandomRow]?, RequestError?) -> Void) {
- if count > 0 {
- // Select random row from database range
- RandomRow.find(id: RandomRow.randomId) { (resultRow, err) in
- if let resultRow = resultRow {
- var result = result
- let row = RandomRow(id: resultRow.id, randomNumber: RandomRow.randomValue)
- row.update(id: row.id) { (resultRow, err) in
- if let resultRow = resultRow {
- result.append(resultRow)
- updateRandomRows(count: count-1, result: result, completion: completion)
- } else {
- completion(nil, err)
- }
- }
- } else {
- if let err = err {
- completion(nil, err)
- } else {
- fatalError("Unexpected: result and error both nil")
- }
- }
- }
- } else {
- completion(result, nil)
- }
- }
- /// A parallel version of `updateRandomRows` that invokes each get/update operation
- /// in parallel, builds an array of results and waits for each get to complete before
- /// returning.
- ///
- /// - Parameter count: The number of rows to retrieve
- /// - Parameter completion: The closure to invoke with the result array, or error
- ///
- public func updateRandomRowsParallel(count: Int, completion: @escaping ([RandomRow]?, RequestError?) -> Void) {
- var results: [RandomRow] = []
- guard count > 0 else {
- return completion(results, nil)
- }
- // Used to protect result array from concurrent modification
- let updateLock = DispatchSemaphore(value: 1)
- // Execute each query. Each callback will append its result to `results`
- for _ in 1...count {
- RandomRow.find(id: RandomRow.randomId) { (resultRow, err) in
- guard let resultRow = resultRow else {
- Log.error("\(err ?? .internalServerError)")
- completion(nil, err ?? .internalServerError)
- return
- }
- let row = RandomRow(id: resultRow.id, randomNumber: RandomRow.randomValue)
- row.update(id: row.id) { (resultRow, err) in
- if let resultRow = resultRow {
- updateLock.wait()
- results.append(resultRow)
- if results.count == count {
- completion(results, nil)
- }
- updateLock.signal()
- } else {
- Log.error("\(err ?? .internalServerError)")
- completion(nil, err ?? .internalServerError)
- return
- }
- }
- }
- }
- }
|