Skip to content

Commit dcd8dd7

Browse files
committed
Reuse CursorWithBindingArray to fix step issue
1 parent e17fc4d commit dcd8dd7

File tree

5 files changed

+105
-54
lines changed

5 files changed

+105
-54
lines changed

Sources/SQLite/Core/Statement.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,41 @@ extension CursorProtocol {
291291
}
292292
}
293293

294+
struct CursorWithBindingArray: CursorProtocol {
295+
let elements: [Binding?]
296+
init(elements: [Binding?]) {
297+
self.elements = elements
298+
}
299+
300+
func getValue(_ idx: Int) throws -> Binding? {
301+
elements[idx]
302+
}
303+
func getValue(_ idx: Int) throws -> Double {
304+
guard let value = elements[idx] as? Double else {
305+
throw QueryError.unexpectedNullValue(name: "column at index \(idx)")
306+
}
307+
return value
308+
}
309+
func getValue(_ idx: Int) throws -> Int64 {
310+
guard let value = elements[idx] as? Int64 else {
311+
throw QueryError.unexpectedNullValue(name: "column at index \(idx)")
312+
}
313+
return value
314+
}
315+
func getValue(_ idx: Int) throws -> String {
316+
guard let value = elements[idx] as? String else {
317+
throw QueryError.unexpectedNullValue(name: "column at index \(idx)")
318+
}
319+
return value
320+
}
321+
func getValue(_ idx: Int) throws -> Blob {
322+
guard let value = elements[idx] as? Blob else {
323+
throw QueryError.unexpectedNullValue(name: "column at index \(idx)")
324+
}
325+
return value
326+
}
327+
}
328+
294329
public struct Cursor: CursorProtocol {
295330
fileprivate let statement: Statement
296331
fileprivate var handle: OpaquePointer {

Sources/SQLite/Typed/Query+Lazy.swift

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// SQLite.swift
3+
// https://github.com/stephencelis/SQLite.swift
4+
// Copyright © 2014-2015 Stephen Celis.
5+
//
6+
// Permission is hereby granted, free of charge, to any person obtaining a copy
7+
// of this software and associated documentation files (the "Software"), to deal
8+
// in the Software without restriction, including without limitation the rights
9+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
// copies of the Software, and to permit persons to whom the Software is
11+
// furnished to do so, subject to the following conditions:
12+
//
13+
// The above copyright notice and this permission notice shall be included in
14+
// all copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
// THE SOFTWARE.
23+
//
24+
25+
extension Array where Element == LazySequence<AnyIterator<Row>> {
26+
@available(swift, deprecated: 1, message: "Please use return value of prepare as Array directly")
27+
public init(_ values: Element) {
28+
preconditionFailure("Please use return value of prepare as Array directly")
29+
}
30+
}
31+
32+
extension Connection {
33+
@_disfavoredOverload
34+
public func prepare(_ query: QueryType) throws -> [Row] {
35+
let expression = query.expression
36+
let statement = try prepare(expression.template, expression.bindings)
37+
38+
let columnNames = try columnNamesForQuery(query)
39+
40+
return Array(AnyIterator {
41+
statement.next().map { cursor in
42+
Row(columnNames, (0..<columnNames.count).map({
43+
try? cursor.getValue($0) as Binding?
44+
}))
45+
}
46+
})
47+
}
48+
49+
public func prepare(_ query: QueryType) throws -> LazySequence<AnyIterator<Row>> {
50+
let expression = query.expression
51+
let statement = try prepare(expression.template, expression.bindings)
52+
53+
let columnNames = try columnNamesForQuery(query)
54+
55+
return AnyIterator { statement.next().map { Row(columnNames, $0) } }.lazy
56+
}
57+
}

Sources/SQLite/Typed/Query.swift

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,16 +1003,6 @@ public struct RowIterator: FailableIterator {
10031003
}
10041004

10051005
extension Connection {
1006-
1007-
public func prepare(_ query: QueryType) throws -> LazySequence<AnyIterator<Row>> {
1008-
let expression = query.expression
1009-
let statement = try prepare(expression.template, expression.bindings)
1010-
1011-
let columnNames = try columnNamesForQuery(query)
1012-
1013-
return AnyIterator { statement.next().map { Row(columnNames, $0) } }.lazy
1014-
}
1015-
10161006
public func prepareRowIterator(_ query: QueryType) throws -> RowIterator {
10171007
let expression = query.expression
10181008
let statement = try prepare(expression.template, expression.bindings)
@@ -1027,7 +1017,7 @@ extension Connection {
10271017
try prepare(statement, bindings).prepareRowIterator()
10281018
}
10291019

1030-
private func columnNamesForQuery(_ query: QueryType) throws -> [String: Int] {
1020+
func columnNamesForQuery(_ query: QueryType) throws -> [String: Int] {
10311021
var (columnNames, idx) = ([String: Int](), 0)
10321022
column: for each in query.clauses.select.columns {
10331023
var names = each.expression.template.split { $0 == "." }.map(String.init)
@@ -1177,6 +1167,10 @@ public struct Row {
11771167
self.values = values
11781168
}
11791169

1170+
init(_ columnNames: [String: Int], _ values: [Binding?]) {
1171+
self.init(columnNames, CursorWithBindingArray(elements: values))
1172+
}
1173+
11801174
func hasValue(for column: String) -> Bool {
11811175
guard let idx = columnNames[column.quote()] else {
11821176
return false

Tests/SQLiteTests/Extensions/FTSIntegrationTests.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ class FTSIntegrationTests: SQLiteTestCase {
5454
XCTAssertEqual(matches.map { $0[email ]}, ["[email protected]"])
5555
}
5656

57+
func testAny() throws {
58+
try createIndex()
59+
let match = try db.prepare(index.match("Paul")).last
60+
XCTAssertEqual(match?[email], "[email protected]")
61+
}
62+
5763
func testMatchPartial() throws {
5864
try insertUsers("Paula")
5965
try createIndex()
@@ -63,8 +69,8 @@ class FTSIntegrationTests: SQLiteTestCase {
6369

6470
func testTrigramIndex() throws {
6571
try createTrigramIndex()
66-
let matches = Array(try db.prepare(index.match("Paul")))
67-
XCTAssertEqual(1, matches.count)
72+
let matcheCount = try db.prepare(index.match("Paul")).count
73+
XCTAssertEqual(1, matcheCount)
6874
}
6975

7076
private func createOrSkip(_ createIndex: (Connection) throws -> Void) throws {

Tests/SQLiteTests/Typed/RowTests.swift

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,6 @@
11
import XCTest
22
@testable import SQLite
33

4-
struct CursorWithStringArray: CursorProtocol {
5-
let elements: [Binding?]
6-
init(elements: [Binding?]) {
7-
self.elements = elements
8-
}
9-
10-
func getValue(_ idx: Int) throws -> Binding? {
11-
elements[idx]
12-
}
13-
func getValue(_ idx: Int) throws -> Double {
14-
guard let value = elements[idx] as? Double else {
15-
throw QueryError.unexpectedNullValue(name: "column at index \(idx)")
16-
}
17-
return value
18-
}
19-
func getValue(_ idx: Int) throws -> Int64 {
20-
guard let value = elements[idx] as? Int64 else {
21-
throw QueryError.unexpectedNullValue(name: "column at index \(idx)")
22-
}
23-
return value
24-
}
25-
func getValue(_ idx: Int) throws -> String {
26-
guard let value = elements[idx] as? String else {
27-
throw QueryError.unexpectedNullValue(name: "column at index \(idx)")
28-
}
29-
return value
30-
}
31-
func getValue(_ idx: Int) throws -> Blob {
32-
guard let value = elements[idx] as? Blob else {
33-
throw QueryError.unexpectedNullValue(name: "column at index \(idx)")
34-
}
35-
return value
36-
}
37-
}
38-
39-
extension Row {
40-
init(_ columnNames: [String: Int], _ values: [Binding?]) {
41-
self.init(columnNames, CursorWithStringArray(elements: values))
42-
}
43-
}
44-
454
class RowTests: XCTestCase {
465
public func test_get_value() throws {
476
let row = Row(["\"foo\"": 0], ["value"])

0 commit comments

Comments
 (0)