1
0

SQLite.swift 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. //
  2. // SQLite.swift
  3. // Swifter
  4. //
  5. // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved.
  6. //
  7. import Foundation
  8. enum SQLiteError: ErrorType {
  9. case OpenFailed(String?)
  10. case ExecFailed(String?)
  11. }
  12. public class SQLite {
  13. private let databaseConnection: COpaquePointer
  14. public static func open(path: String) throws -> SQLite {
  15. var databaseConnection = COpaquePointer()
  16. let openResult = path.withCString { sqlite3_open($0, &databaseConnection) }
  17. guard openResult == SQLITE_OK else {
  18. throw SQLiteError.OpenFailed(String.fromCString(sqlite3_errmsg(databaseConnection)))
  19. }
  20. return SQLite(databaseConnection)
  21. }
  22. private init(_ databaseConnection: COpaquePointer) {
  23. self.databaseConnection = databaseConnection
  24. }
  25. private struct ExecCContext { var callback: ([String: String] -> Void)? }
  26. public func exec(sql: String) throws {
  27. try exec(sql, callback: nil)
  28. }
  29. public func exec(sql: String, callback: ([String: String] -> Void)?) throws {
  30. var errorMessagePointer = UnsafeMutablePointer<Int8>()
  31. var execCContext = ExecCContext(callback: callback)
  32. let execResult = sql.withCString {
  33. sqlite3_exec(databaseConnection, $0, { (context, count, values, names) -> Int32 in
  34. var content = [String: String]()
  35. for i in 0..<count {
  36. if let name = String.fromCString(names.advancedBy(Int(i)).memory),
  37. let value = String.fromCString(values.advancedBy(Int(i)).memory) {
  38. content[name] = value
  39. }
  40. }
  41. if let callback = UnsafeMutablePointer<ExecCContext>(context).memory.callback {
  42. callback(content)
  43. }
  44. return SQLITE_OK
  45. }, &execCContext, &errorMessagePointer)
  46. }
  47. guard execResult == SQLITE_OK else {
  48. let errorDetails = String.fromCString(errorMessagePointer)
  49. sqlite3_free(errorMessagePointer)
  50. throw SQLiteError.ExecFailed(errorDetails)
  51. }
  52. }
  53. public func enumerate(sql: String) throws -> StatmentSequence {
  54. var statement = COpaquePointer()
  55. let prepeareResult = sql.withCString { sqlite3_prepare_v2(databaseConnection, $0, Int32(sql.utf8.count), &statement, nil) }
  56. guard prepeareResult == SQLITE_OK else {
  57. throw SQLiteError.ExecFailed(String.fromCString(sqlite3_errmsg(databaseConnection)))
  58. }
  59. return StatmentSequence(statement: statement)
  60. }
  61. public struct StatmentGenerator: GeneratorType {
  62. public let statement: COpaquePointer
  63. public func next() -> [String: String]? {
  64. switch sqlite3_step(statement) {
  65. case SQLITE_ROW:
  66. var content = [String: String]()
  67. for i in 0..<sqlite3_column_count(statement) {
  68. if let name = String.fromCString(UnsafePointer<CChar>(sqlite3_column_name(statement, i))),
  69. let value = String.fromCString(UnsafePointer<CChar>(sqlite3_column_text(statement, i))) {
  70. content[name] = value
  71. }
  72. }
  73. return content
  74. default:
  75. sqlite3_finalize(statement)
  76. return nil
  77. }
  78. }
  79. }
  80. public struct StatmentSequence: SequenceType {
  81. public let statement: COpaquePointer
  82. public func generate() -> StatmentGenerator {
  83. return StatmentGenerator(statement: statement)
  84. }
  85. }
  86. public func close() throws {
  87. sqlite3_close(databaseConnection)
  88. }
  89. }