From 7dbf64655803ac038b37e2bcfb6a4172dd99b77d Mon Sep 17 00:00:00 2001 From: Alexander Ignition Date: Sun, 2 Feb 2025 12:01:36 +0300 Subject: [PATCH] reset after execute --- Playgrounds/README.playground/Contents.swift | 7 ++-- README.md | 7 ++-- Sources/SQLyra/DataFrame.swift | 1 + Sources/SQLyra/PreparedStatement.swift | 9 +++++- .../SQLyraTests/PreparedStatementTests.swift | 32 +++++++++++++++++-- 5 files changed, 46 insertions(+), 10 deletions(-) diff --git a/Playgrounds/README.playground/Contents.swift b/Playgrounds/README.playground/Contents.swift index 41f8708..eea508b 100644 --- a/Playgrounds/README.playground/Contents.swift +++ b/Playgrounds/README.playground/Contents.swift @@ -39,7 +39,7 @@ try database.execute(sql) Insert new contacts Paul and John. */ let insert = try database.prepare("INSERT INTO contacts (id, name) VALUES (?, ?);") -try insert.bind(parameters: 1, "Paul").execute().reset() +try insert.bind(parameters: 1, "Paul").execute() try insert.bind(parameters: 2, "John").execute() /*: ## Select @@ -48,11 +48,12 @@ try insert.bind(parameters: 2, "John").execute() */ struct Contact: Codable { let id: Int - let name: String + let name: String? } let select = try database.prepare("SELECT * FROM contacts;") let contacts = try select.array(Contact.self) +print(contacts) /*: ## DataFrame @@ -60,7 +61,7 @@ let contacts = try select.array(Contact.self) It can help to print the table. */ -let df = try database.prepare("SELECT * FROM contacts;").dataFrame() +let df = try select.dataFrame() print(df) /*: ``` diff --git a/README.md b/README.md index e148f4c..13a5e80 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ try database.execute(sql) Insert new contacts Paul and John. ```swift let insert = try database.prepare("INSERT INTO contacts (id, name) VALUES (?, ?);") -try insert.bind(parameters: 1, "Paul").execute().reset() +try insert.bind(parameters: 1, "Paul").execute() try insert.bind(parameters: 2, "John").execute() ``` ## Select @@ -47,11 +47,12 @@ Select all contacts from database. ```swift struct Contact: Codable { let id: Int - let name: String + let name: String? } let select = try database.prepare("SELECT * FROM contacts;") let contacts = try select.array(Contact.self) +print(contacts) ``` ## DataFrame @@ -59,7 +60,7 @@ The [DataFrame](https://developer.apple.com/documentation/tabulardata/dataframe) It can help to print the table. ```swift -let df = try database.prepare("SELECT * FROM contacts;").dataFrame() +let df = try select.dataFrame() print(df) ``` ``` diff --git a/Sources/SQLyra/DataFrame.swift b/Sources/SQLyra/DataFrame.swift index dc7dd54..4c81e57 100644 --- a/Sources/SQLyra/DataFrame.swift +++ b/Sources/SQLyra/DataFrame.swift @@ -41,6 +41,7 @@ extension PreparedStatement { } var df = DataFrame(columns: columns) var count = 0 + defer { _reset() } while let row = try row() { df.appendEmptyRow() for index in (0.. PreparedStatement { - try check(sqlite3_step(stmt), SQLITE_DONE) + defer { _reset() } + return try check(sqlite3_step(stmt), SQLITE_DONE) } /// Reset the prepared statement. @@ -47,6 +48,11 @@ public final class PreparedStatement: DatabaseHandle { public func reset() throws -> PreparedStatement { try check(sqlite3_reset(stmt)) } + + /// clear error state and prepare for reuse + func _reset() { + sqlite3_reset(stmt) + } } // MARK: - Retrieving Statement SQL @@ -176,6 +182,7 @@ extension PreparedStatement { } public func array(_ type: T.Type, using decoder: RowDecoder) throws -> [T] where T: Decodable { + defer { _reset() } var array: [T] = [] while let row = try row() { let value = try row.decode(type, using: decoder) diff --git a/Tests/SQLyraTests/PreparedStatementTests.swift b/Tests/SQLyraTests/PreparedStatementTests.swift index a154699..c152055 100644 --- a/Tests/SQLyraTests/PreparedStatementTests.swift +++ b/Tests/SQLyraTests/PreparedStatementTests.swift @@ -8,7 +8,7 @@ struct Contact: Codable, Equatable, Sendable { let rating: Double? let image: Data? - static let table = "CREATE TABLE contacts (id INT, name TEXT, rating FLOAT, image BLOB);" + static let table = "CREATE TABLE contacts (id INT, name TEXT, rating REAL, image BLOB) STRICT;" static let insert = "INSERT INTO contacts (id, name, rating, image) VALUES (:id, :name, :rating, :image)" } @@ -71,7 +71,7 @@ struct PreparedStatementTests { @Test func columns() throws { let insert = try db.prepare(Contact.insert) - try insert.bind(parameters: 5, "A", 2.0, .null).execute().reset() + try insert.bind(parameters: 5, "A", 2.0, .null).execute() try insert.bind(parameters: 6, "B", .null, .blob(Data("123".utf8))).execute() let select = try db.prepare("SELECT * FROM contacts;") @@ -94,11 +94,37 @@ struct PreparedStatementTests { #expect(contracts == expected) } + @Test func decode() throws { + let insert = try db.prepare(Contact.insert) + + try insert.bind(parameters: 5, "A", 2.0, .null).execute() + try insert.bind(parameters: 6, "B", .null, .blob(Data("123".utf8))).execute() + + let select = try db.prepare("SELECT * FROM contacts;") + let contracts = try select.array(Contact.self) + + let expected = [ + Contact(id: 5, name: "A", rating: 2.0, image: nil), + Contact(id: 6, name: "B", rating: nil, image: Data("123".utf8)), + ] + #expect(contracts == expected) + } + + @Test func execute() throws { + let insert = try db.prepare(Contact.insert) + + try insert.bind(name: ":id", parameter: "invalid") + #expect(throws: DatabaseError.self) { try insert.execute() } + + try insert.bind(name: ":id", parameter: 4) + #expect(throws: Never.self) { try insert.execute() } + } + @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) @Test func dataFrame() throws { let insert = try db.prepare(Contact.insert) - try insert.bind(parameters: 5, "A").execute().reset() + try insert.bind(parameters: 5, "A").execute() try insert.bind(parameters: 6, "B").execute() let df = try db.prepare("SELECT * FROM contacts;").dataFrame()