Skip to content

Commit bbb4c8a

Browse files
committed
wip
1 parent 7305560 commit bbb4c8a

File tree

3 files changed

+47
-15
lines changed

3 files changed

+47
-15
lines changed

Sources/StructuredQueriesSQLiteCore/DatabaseFunction.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// A type representing a database function.
22
///
3-
/// Don't conform to this protocol directly. Instead, use the `@DatabaseFunction` macros to
4-
/// generate a conformance.
3+
/// Don't conform to this protocol directly. Instead, use the `@DatabaseFunction` macro to generate
4+
/// a conformance.
55
public protocol DatabaseFunction {
66
/// The name of the function.
77
var name: String { get }
@@ -15,7 +15,7 @@ public protocol DatabaseFunction {
1515
}
1616

1717
public protocol ScalarDatabaseFunction: DatabaseFunction {
18-
/// The function body. Transforms a collection of bindings handed to the function into a binding
18+
/// The function body. Transforms an array of bindings handed to the function into a binding
1919
/// returned to the query.
2020
///
2121
/// - Parameter arguments: Arguments passed to the database function.

Sources/_StructuredQueriesSQLite/DatabaseFunction.swift

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ import Foundation
22

33
extension ScalarDatabaseFunction {
44
public func install(_ db: OpaquePointer) {
5-
let body = Unmanaged.passRetained(ScalarDatabaseFunctionContext(self)).toOpaque()
5+
let box = Unmanaged.passRetained(ScalarDatabaseFunctionBox(self)).toOpaque()
66
sqlite3_create_function_v2(
77
db,
88
name,
99
Int32(argumentCount ?? -1),
1010
SQLITE_UTF8 | (isDeterministic ? SQLITE_DETERMINISTIC : 0),
11-
body,
11+
box,
1212
{ context, argumentCount, arguments in
1313
do {
14-
let body = Unmanaged<ScalarDatabaseFunctionContext>
14+
let box = Unmanaged<ScalarDatabaseFunctionBox>
1515
.fromOpaque(sqlite3_user_data(context))
1616
.takeUnretainedValue()
1717
let arguments = try [QueryBinding](argumentCount: argumentCount, arguments: arguments)
18-
let output = body(arguments)
18+
let output = box.function.invoke(arguments)
1919
try output.result(db: context)
2020
} catch {
2121
sqlite3_result_error(context, error.localizedDescription, -1)
@@ -25,19 +25,16 @@ extension ScalarDatabaseFunction {
2525
nil,
2626
{ context in
2727
guard let context else { return }
28-
Unmanaged<ScalarDatabaseFunctionContext>.fromOpaque(context).release()
28+
Unmanaged<ScalarDatabaseFunctionBox>.fromOpaque(context).release()
2929
}
3030
)
3131
}
3232
}
3333

34-
private final class ScalarDatabaseFunctionContext {
35-
let body: ([QueryBinding]) -> QueryBinding
34+
private final class ScalarDatabaseFunctionBox {
35+
let function: any ScalarDatabaseFunction
3636
init(_ function: some ScalarDatabaseFunction) {
37-
body = function.invoke
38-
}
39-
func callAsFunction(_ arguments: [QueryBinding]) -> QueryBinding {
40-
body(arguments)
37+
self.function = function
4138
}
4239
}
4340

@@ -93,3 +90,38 @@ extension QueryBinding {
9390
}
9491
}
9592
}
93+
94+
private final class Stream<Element>: Sequence {
95+
private let condition = NSCondition()
96+
private var buffer: [Element] = []
97+
private var isFinished = false
98+
99+
func send(_ element: Element) {
100+
condition.withLock {
101+
buffer.append(element)
102+
condition.signal()
103+
}
104+
}
105+
106+
func finish() {
107+
condition.withLock {
108+
isFinished = true
109+
condition.broadcast()
110+
}
111+
}
112+
113+
func makeIterator() -> Iterator { Iterator(base: self) }
114+
115+
struct Iterator: IteratorProtocol {
116+
fileprivate let base: Stream
117+
mutating func next() -> Element? {
118+
base.condition.withLock {
119+
while base.buffer.isEmpty && !base.isFinished {
120+
base.condition.wait()
121+
}
122+
guard !base.buffer.isEmpty else { return nil }
123+
return base.buffer.removeFirst()
124+
}
125+
}
126+
}
127+
}

Tests/StructuredQueriesTests/DatabaseFunctionTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ extension SnapshotTests {
7575
"""
7676
}
7777
}
78-
78+
7979
@DatabaseFunction
8080
func throwing() throws -> String {
8181
struct Failure: LocalizedError {

0 commit comments

Comments
 (0)