Ver Fonte

Added Sequence & Generator types for the results of SQL statements execution.

Damian Kołakowski há 10 anos atrás
pai
commit
00e8a4b279
2 ficheiros alterados com 64 adições e 13 exclusões
  1. 49 9
      Sources/SQLite.swift
  2. 15 4
      SwifterTestsCommon/SwifterTestsSQLite.swift

+ 49 - 9
Sources/SQLite.swift

@@ -14,19 +14,19 @@ enum SQLiteError: ErrorType {
 
 public class SQLite {
     
-    private let internalPointer: COpaquePointer
+    private let databaseConnection: COpaquePointer
     
     public static func open(path: String) throws -> SQLite {
-        var sqlite3DatabasePointer = COpaquePointer()
-        let openResult = path.withCString { sqlite3_open($0, &sqlite3DatabasePointer) }
+        var databaseConnection = COpaquePointer()
+        let openResult = path.withCString { sqlite3_open($0, &databaseConnection) }
         guard openResult == SQLITE_OK else {
-            throw SQLiteError.OpenFailed(String.fromCString(sqlite3_errmsg(sqlite3DatabasePointer)))
+            throw SQLiteError.OpenFailed(String.fromCString(sqlite3_errmsg(databaseConnection)))
         }
-        return SQLite(sqlite3DatabasePointer)
+        return SQLite(databaseConnection)
     }
     
-    private init(_ pointer: COpaquePointer) {
-        self.internalPointer = pointer
+    private init(_ databaseConnection: COpaquePointer) {
+        self.databaseConnection = databaseConnection
     }
     
     private struct ExecCContext { var callback: ([String: String] -> Void)? }
@@ -39,7 +39,7 @@ public class SQLite {
         var errorMessagePointer = UnsafeMutablePointer<Int8>()
         var execCContext = ExecCContext(callback: callback)
         let execResult = sql.withCString {
-            sqlite3_exec(internalPointer, $0, { (context, count, values, names) -> Int32 in
+            sqlite3_exec(databaseConnection, $0, { (context, count, values, names) -> Int32 in
                 var content = [String: String]()
                 for i in 0..<count {
                     if let name = String.fromCString(names.advancedBy(Int(i)).memory),
@@ -60,7 +60,47 @@ public class SQLite {
         }
     }
     
+    public func enumerate(sql: String) throws -> StatmentSequence {
+        var statement = COpaquePointer()
+        let prepeareResult = sql.withCString { sqlite3_prepare_v2(databaseConnection, $0, Int32(sql.utf8.count), &statement, nil) }
+        guard prepeareResult == SQLITE_OK else {
+            throw SQLiteError.ExecFailed(String.fromCString(sqlite3_errmsg(databaseConnection)))
+        }
+        return StatmentSequence(statement: statement)
+    }
+    
+    public struct StatmentGenerator: GeneratorType {
+        
+        public let statement: COpaquePointer
+        
+        public func next() -> [String: String]? {
+            switch sqlite3_step(statement) {
+            case SQLITE_ROW:
+                var content = [String: String]()
+                for i in 0..<sqlite3_column_count(statement) {
+                    if let name = String.fromCString(UnsafePointer<CChar>(sqlite3_column_name(statement, i))),
+                        let value = String.fromCString(UnsafePointer<CChar>(sqlite3_column_text(statement, i))) {
+                            content[name] = value
+                    }
+                }
+                return content
+            default:
+                sqlite3_finalize(statement)
+                return nil
+            }
+        }
+    }
+    
+    public struct StatmentSequence: SequenceType {
+        
+        public let statement: COpaquePointer
+        
+        public func generate() -> StatmentGenerator {
+            return StatmentGenerator(statement: statement)
+        }
+    }
+    
     public func close() throws {
-        sqlite3_close(internalPointer)
+        sqlite3_close(databaseConnection)
     }
 }

+ 15 - 4
SwifterTestsCommon/SwifterTestsSQLite.swift

@@ -15,10 +15,13 @@ class SwifterTestsSQLite: XCTestCase {
         
         print(try? File.currentWorkingDirectory())
         
-        let databseFileName = "test_\(Int64(NSDate().timeIntervalSince1970*1000)).db"
+        guard let databsePath = try? File.currentWorkingDirectory() + "/" + "test_\(Int64(NSDate().timeIntervalSince1970*1000)).db" else {
+            XCTAssert(false, "Could not find a path for a database file.")
+            return
+        }
     
         do {
-            let database = try SQLite.open(try File.currentWorkingDirectory() + "/" + databseFileName)
+            let database = try SQLite.open(databsePath)
             XCTAssert(true, "Opening the database should not throw any exceptions.")
             try database.close()
         } catch {
@@ -26,7 +29,7 @@ class SwifterTestsSQLite: XCTestCase {
         }
         
         do {
-            let database = try SQLite.open(try File.currentWorkingDirectory() + "/" + databseFileName)
+            let database = try SQLite.open(databsePath)
             try database.exec("CREATE TABLE swifter_tests (title TEXT, description TEXT);")
             try database.exec("INSERT INTO swifter_tests VALUES (\"Test1\", \"Test1 Description\");")
             try database.exec("INSERT INTO swifter_tests VALUES (\"Test2\", \"Test2 Description\");")
@@ -36,12 +39,20 @@ class SwifterTestsSQLite: XCTestCase {
         }
         
         do {
-            let database = try SQLite.open(try File.currentWorkingDirectory() + "/" + databseFileName)
+            let database = try SQLite.open(databsePath)
+            
             var counter = 0
+            for row in try database.enumerate("SELECT * FROM swifter_tests;") {
+                counter = counter + 1
+            }
+            XCTAssert(counter == 2, "Database should have two rows.")
+            
+            counter = 0
             try database.exec("SELECT * FROM swifter_tests;") { content in
                 counter = counter + 1
             }
             XCTAssert(counter == 2, "Database should have two rows.")
+            
             try database.close()
         } catch {
             XCTAssert(false, "Database manipulation should not throw any exceptions.")