PostgresRaw.swift 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Copyright IBM Corporation 2018
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Foundation
  17. import LoggerAPI
  18. import SwiftKuery
  19. import KueryPostgres
  20. import TechEmpowerCommon
  21. let dbRows = 10000
  22. let maxValue = 10000
  23. // Kuery table definition for World
  24. class World: Table {
  25. let tableName = "world"
  26. let id = Column("id")
  27. let randomNumber = Column("randomnumber")
  28. }
  29. // Kuery table definition for Fortune
  30. class Fortunes: Table {
  31. let tableName = "fortune"
  32. let id = Column("id")
  33. let message = Column("message")
  34. }
  35. let world = World()
  36. let fortunes = Fortunes()
  37. // Kuery update statement for Updates
  38. var update = Update(world, set: [(world.randomNumber, RandomRow.randomValue)])
  39. .where(world.id == RandomRow.randomId)
  40. /// Get a list of Fortunes from the database.
  41. ///
  42. /// - Parameter callback: The callback that will be invoked once the DB query
  43. /// has completed and results are available, passing an
  44. /// optional [Fortune] (on success) or AppError on
  45. /// failure.
  46. ///
  47. public func getFortunes(callback: @escaping ([Fortune]?, AppError?) -> Void) -> Void {
  48. // Get a dedicated connection object for this transaction from the pool
  49. guard let dbConn = dbConnPool.getConnection() else {
  50. return callback(nil, AppError.OtherError("Timed out waiting for a DB connection from the pool"))
  51. }
  52. // Initiate database query
  53. let query = Select(from: fortunes)
  54. dbConn.execute(query: query) { result in
  55. var resultFortunes: [Fortune]? = nil
  56. guard let rows = result.asRows, result.success else {
  57. return callback(nil, AppError.DBKueryError("Query failed: \(String(describing: result.asError))"))
  58. }
  59. do {
  60. resultFortunes = try rows.map { try Fortune.init(row: $0) }
  61. } catch {
  62. return callback(nil, AppError.DataFormatError("\(error)"))
  63. }
  64. // Invoke callback with results
  65. callback(resultFortunes, nil)
  66. }
  67. }
  68. /// Get a random row (range 1 to 10,000) from the database.
  69. ///
  70. /// - Parameter callback: The callback that will be invoked once the DB query
  71. /// has completed and results are available, passing an
  72. /// optional RandomRow (on success) or AppError on
  73. /// failure.
  74. ///
  75. public func getRandomRow_Raw(callback: @escaping (RandomRow?, AppError?) -> Void) -> Void {
  76. // Get a dedicated connection object for this transaction from the pool
  77. guard let dbConn = dbConnPool.getConnection() else {
  78. return callback(nil, AppError.OtherError("Timed out waiting for a DB connection from the pool"))
  79. }
  80. // Select random row from database range
  81. let rnd = RandomRow.randomId
  82. let query = Select(world.randomNumber, from: world)
  83. .where(world.id == rnd)
  84. // Initiate database query
  85. dbConn.execute(query: query) { result in
  86. var resultRow: RandomRow? = nil
  87. guard let resultSet = result.asResultSet, result.success else {
  88. return callback(nil, AppError.DBKueryError("Query failed: \(String(describing: result.asError))"))
  89. }
  90. for row in resultSet.rows {
  91. for value in row {
  92. guard let value = value else {
  93. return callback(nil, AppError.DBKueryError("Error: randomNumber value is nil"))
  94. }
  95. guard let randomNumber = value as? Int32 else {
  96. return callback(nil, AppError.DBKueryError("Error: could not convert \(value) to Int32"))
  97. }
  98. resultRow = RandomRow(id: rnd, randomNumber: Int(randomNumber))
  99. }
  100. }
  101. // Invoke callback with results
  102. callback(resultRow, nil)
  103. }
  104. }
  105. /// Updates a row of World to a new value.
  106. ///
  107. /// - Parameter callback: The callback that will be invoked once the DB update
  108. /// has completed, passing an optional AppError if the
  109. /// update failed.
  110. ///
  111. public func updateRow_Raw(id: Int, callback: @escaping (AppError?) -> Void) -> Void {
  112. // Get a dedicated connection object for this transaction from the pool
  113. guard let dbConn = dbConnPool.getConnection() else {
  114. return callback(AppError.OtherError("Timed out waiting for a DB connection from the pool"))
  115. }
  116. // Generate a random number for this row
  117. let rndValue = RandomRow.randomValue
  118. let query = Update(world, set: [(world.randomNumber, rndValue)])
  119. .where(world.id == id)
  120. // Initiate database query
  121. dbConn.execute(query: query) { result in
  122. guard result.success else {
  123. return callback(AppError.DBKueryError("Update failed: \(String(describing: result.asError))"))
  124. }
  125. // Invoke callback once done
  126. callback(nil)
  127. }
  128. }
  129. /// Get `count` random rows from the database, and pass the resulting array
  130. /// to a completion handler (or an AppError, in the event that a row could
  131. /// not be retrieved).
  132. ///
  133. /// - Parameter count: The number of rows to retrieve
  134. /// - Parameter result: The intermediate result array being built
  135. /// - Parameter completion: The closure to invoke with the result array, or error
  136. ///
  137. public func getRandomRows_Raw(count: Int, result: [RandomRow] = [], completion: @escaping ([RandomRow]?, AppError?) -> Void) {
  138. if count > 0 {
  139. // Select random row from database range
  140. getRandomRow_Raw { (resultRow, err) in
  141. if let resultRow = resultRow {
  142. var result = result
  143. result.append(resultRow)
  144. // Call recursively to get remaining rows
  145. getRandomRows_Raw(count: count-1, result: result, completion: completion)
  146. } else {
  147. if let err = err {
  148. completion(nil, err)
  149. } else {
  150. fatalError("Unexpected: result and error both nil")
  151. }
  152. }
  153. }
  154. } else {
  155. completion(result, nil)
  156. }
  157. }
  158. /// Update and retrieve `count` random rows from the database, and pass the
  159. /// resulting array to a completion handler (or an AppError, in the event
  160. /// that a row could not be retrieved or updated).
  161. ///
  162. /// - Parameter count: The number of rows to retrieve
  163. /// - Parameter result: The intermediate result array being built
  164. /// - Parameter completion: The closure to invoke with the result array, or error
  165. ///
  166. public func updateRandomRows_Raw(count: Int, result: [RandomRow] = [], completion: @escaping ([RandomRow]?, AppError?) -> Void) {
  167. if count > 0 {
  168. // Select random row from database range
  169. getRandomRow_Raw { (resultRow, err) in
  170. if let resultRow = resultRow {
  171. var result = result
  172. // Execute inner callback for updating the row
  173. updateRow_Raw(id: resultRow.id) { (err) in
  174. if let err = err {
  175. return completion(nil, err)
  176. }
  177. result.append(resultRow)
  178. // Call recursively to update remaining rows
  179. updateRandomRows_Raw(count: count-1, result: result, completion: completion)
  180. }
  181. } else {
  182. if let err = err {
  183. completion(nil, err)
  184. } else {
  185. fatalError("Unexpected: result and error both nil")
  186. }
  187. }
  188. }
  189. } else {
  190. completion(result, nil)
  191. }
  192. }