From 3df3ed734bfbf23fce979dadd7611635b68448ab Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Tue, 3 Mar 2015 12:01:20 -0800 Subject: [PATCH] Avoid circular reference The REPL particularly hates this. This does mean, however, that `step()` needs to live on the statement itself, not the cursor. In fact, cursor may be better accessed as `row`, so let's do just that: while stmt.step() { let id = stmt.row[0] as Int // ... } Signed-off-by: Stephen Celis --- SQLite Tests/StatementTests.swift | 8 +++--- SQLite/Statement.swift | 41 +++++++++++++++++-------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/SQLite Tests/StatementTests.swift b/SQLite Tests/StatementTests.swift index 86a0ce3..cf297c6 100644 --- a/SQLite Tests/StatementTests.swift +++ b/SQLite Tests/StatementTests.swift @@ -172,13 +172,13 @@ class StatementTests: XCTestCase { XCTAssertEqual(6, count) } - func test_cursor_returnsValues() { + func test_row_returnsValues() { InsertUser(db, "alice") let stmt = db.prepare("SELECT id, email FROM users") - stmt.cursor.step() + stmt.step() - XCTAssertEqual(Int64(1), stmt.cursor[0] as Int64) - XCTAssertEqual("alice@example.com", stmt.cursor[1] as String) + XCTAssertEqual(Int64(1), stmt.row[0] as Int64) + XCTAssertEqual("alice@example.com", stmt.row[1] as String) } } diff --git a/SQLite/Statement.swift b/SQLite/Statement.swift index d50d5e6..4be14a8 100644 --- a/SQLite/Statement.swift +++ b/SQLite/Statement.swift @@ -32,7 +32,7 @@ public final class Statement { private let database: Database - public lazy var cursor: Cursor = { Cursor(self) }() + public lazy var row: Cursor = { Cursor(self) }() internal init(_ database: Database, _ SQL: String) { self.database = database @@ -115,7 +115,7 @@ public final class Statement { public func run(bindings: Binding?...) -> Statement { if !bindings.isEmpty { return run(bindings) } reset(clearBindings: false) - while cursor.step() {} + while step() {} return self } @@ -142,8 +142,8 @@ public final class Statement { public func scalar(bindings: Binding?...) -> Binding? { if !bindings.isEmpty { return scalar(bindings) } reset(clearBindings: false) - cursor.step() - return cursor[0] + step() + return row[0] } /// :param: bindings A list of parameters to bind to the statement. @@ -163,6 +163,11 @@ public final class Statement { // MARK: - + public func step() -> Bool { + try(sqlite3_step(handle)) + return status == SQLITE_ROW + } + private func reset(clearBindings: Bool = true) { (status, reason) = (SQLITE_OK, nil) sqlite3_reset(handle) @@ -209,7 +214,7 @@ extension Statement: GeneratorType { /// :returns: The next row from the result set (or nil). public func next() -> [Binding?]? { - return cursor.step() ? Array(cursor) : nil + return step() ? Array(row) : nil } } @@ -236,33 +241,31 @@ public func || (lhs: Statement, rhs: @autoclosure () -> Statement) -> Statement /// Cursors provide direct access to a statement's current row. public struct Cursor { - private unowned let statement: Statement + private let handle: COpaquePointer + + private let columnCount: Int private init(_ statement: Statement) { - self.statement = statement - } - - public func step() -> Bool { - statement.try(sqlite3_step(statement.handle)) - return statement.status == SQLITE_ROW + handle = statement.handle + columnCount = statement.columnCount } public subscript(idx: Int) -> Blob { - let bytes = sqlite3_column_blob(statement.handle, Int32(idx)) - let length = sqlite3_column_bytes(statement.handle, Int32(idx)) + let bytes = sqlite3_column_blob(handle, Int32(idx)) + let length = sqlite3_column_bytes(handle, Int32(idx)) return Blob(bytes: bytes, length: Int(length)) } public subscript(idx: Int) -> Double { - return sqlite3_column_double(statement.handle, Int32(idx)) + return sqlite3_column_double(handle, Int32(idx)) } public subscript(idx: Int) -> Int64 { - return sqlite3_column_int64(statement.handle, Int32(idx)) + return sqlite3_column_int64(handle, Int32(idx)) } public subscript(idx: Int) -> String { - return String.fromCString(UnsafePointer(sqlite3_column_text(statement.handle, Int32(idx)))) ?? "" + return String.fromCString(UnsafePointer(sqlite3_column_text(handle, Int32(idx)))) ?? "" } public subscript(idx: Int) -> Bool { @@ -279,7 +282,7 @@ public struct Cursor { extension Cursor: SequenceType { public subscript(idx: Int) -> Binding? { - switch sqlite3_column_type(statement.handle, Int32(idx)) { + switch sqlite3_column_type(handle, Int32(idx)) { case SQLITE_BLOB: return self[idx] as Blob case SQLITE_FLOAT: @@ -298,7 +301,7 @@ extension Cursor: SequenceType { public func generate() -> GeneratorOf { var idx = 0 return GeneratorOf { - idx >= self.statement.columnCount ? Optional.None : self[idx++] + idx >= self.columnCount ? Optional.None : self[idx++] } }