Skip to content

Commit 6cf7d60

Browse files
committed
better formating + basic querying
1 parent 6ed2d43 commit 6cf7d60

File tree

5 files changed

+335
-58
lines changed

5 files changed

+335
-58
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ DerivedData/
66
.swiftpm/configuration/registries.json
77
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
88
.netrc
9+
test.db

.swift-format

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"fileScopedDeclarationPrivacy" : {
3+
"accessLevel" : "private"
4+
},
5+
"indentation" : {
6+
"spaces" : 4
7+
},
8+
"indentConditionalCompilationBlocks" : true,
9+
"indentSwitchCaseLabels" : false,
10+
"lineBreakAroundMultilineExpressionChainComponents" : false,
11+
"lineBreakBeforeControlFlowKeywords" : false,
12+
"lineBreakBeforeEachArgument" : false,
13+
"lineBreakBeforeEachGenericRequirement" : false,
14+
"lineLength" : 100,
15+
"maximumBlankLines" : 1,
16+
"prioritizeKeepingFunctionOutputTogether" : false,
17+
"respectsExistingLineBreaks" : true,
18+
"rules" : {
19+
"AllPublicDeclarationsHaveDocumentation" : false,
20+
"AlwaysUseLowerCamelCase" : true,
21+
"AmbiguousTrailingClosureOverload" : true,
22+
"BeginDocumentationCommentWithOneLineSummary" : false,
23+
"DoNotUseSemicolons" : true,
24+
"DontRepeatTypeInStaticProperties" : true,
25+
"FileScopedDeclarationPrivacy" : true,
26+
"FullyIndirectEnum" : true,
27+
"GroupNumericLiterals" : true,
28+
"IdentifiersMustBeASCII" : true,
29+
"NeverForceUnwrap" : false,
30+
"NeverUseForceTry" : false,
31+
"NeverUseImplicitlyUnwrappedOptionals" : false,
32+
"NoAccessLevelOnExtensionDeclaration" : true,
33+
"NoAssignmentInExpressions" : true,
34+
"NoBlockComments" : true,
35+
"NoCasesWithOnlyFallthrough" : true,
36+
"NoEmptyTrailingClosureParentheses" : true,
37+
"NoLabelsInCasePatterns" : true,
38+
"NoLeadingUnderscores" : false,
39+
"NoParensAroundConditions" : true,
40+
"NoVoidReturnOnFunctionSignature" : true,
41+
"OneCasePerLine" : true,
42+
"OneVariableDeclarationPerLine" : true,
43+
"OnlyOneTrailingClosureArgument" : true,
44+
"OrderedImports" : true,
45+
"ReturnVoidInsteadOfEmptyTuple" : true,
46+
"UseEarlyExits" : false,
47+
"UseLetInEveryBoundCaseVariable" : true,
48+
"UseShorthandTypeNames" : true,
49+
"UseSingleLinePropertyGetter" : true,
50+
"UseSynthesizedInitializer" : true,
51+
"UseTripleSlashForDocumentationComments" : true,
52+
"UseWhereClausesInForLoops" : false,
53+
"ValidateDocumentationComments" : false
54+
},
55+
"spacesAroundRangeFormationOperators" : false,
56+
"tabWidth" : 4,
57+
"version" : 1
58+
}

Package.swift

+14-14
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@
44
import PackageDescription
55

66
let package = Package(
7-
name: "Libsql",
8-
products: [
9-
.library(name: "Libsql", targets: ["Libsql"])
10-
],
11-
targets: [
12-
.target(
13-
name: "Libsql",
14-
dependencies: ["CLibsql"],
15-
linkerSettings: [
16-
.unsafeFlags(["-L", "Sources/CLibsql/target/release"])
17-
]),
18-
.systemLibrary(name: "CLibsql"),
19-
.testTarget(name: "LibsqlTests", dependencies: ["Libsql"]),
20-
]
7+
name: "Libsql",
8+
products: [
9+
.library(name: "Libsql", targets: ["Libsql"])
10+
],
11+
targets: [
12+
.target(
13+
name: "Libsql",
14+
dependencies: ["CLibsql"],
15+
linkerSettings: [
16+
.unsafeFlags(["-L", "Sources/CLibsql/target/release"])
17+
]),
18+
.systemLibrary(name: "CLibsql"),
19+
.testTarget(name: "LibsqlTests", dependencies: ["Libsql"]),
20+
]
2121
)

Sources/Libsql/Libsql.swift

+238-33
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,256 @@
11
import CLibsql
2+
import Foundation
3+
4+
enum Value {
5+
case integer(Int64)
6+
case text(String)
7+
case blob(Data)
8+
case real(Double)
9+
}
10+
11+
protocol ValueRepresentable {
12+
func toValue() -> Value
13+
}
14+
15+
extension Int: ValueRepresentable {
16+
func toValue() -> Value { .integer(Int64(self)) }
17+
}
18+
19+
extension Int64: ValueRepresentable {
20+
func toValue() -> Value { .integer(self) }
21+
}
22+
23+
extension String: ValueRepresentable {
24+
func toValue() -> Value { .text(self) }
25+
}
26+
27+
extension Data: ValueRepresentable {
28+
func toValue() -> Value { .blob(self) }
29+
}
30+
31+
extension Double: ValueRepresentable {
32+
func toValue() -> Value { .real(self) }
33+
}
234

335
enum LibsqlError: Error {
4-
case runtimeError(String)
36+
case runtimeError(String)
37+
case unexpectedType
538
}
639

7-
class Database {
8-
var inner: libsql_database_t
40+
class Row {
41+
var inner: libsql_row_t
42+
43+
fileprivate init?(fromPtr inner: libsql_row_t?) {
44+
guard let inner = inner else {
45+
return nil
46+
}
47+
48+
self.inner = inner
49+
}
50+
51+
func getData(_ index: Int32) throws -> Data {
52+
var slice: blob = blob()
953

10-
deinit {
11-
print("closing")
12-
libsql_close(self.inner)
13-
}
54+
var err: UnsafePointer<CChar>?
55+
if libsql_get_blob(self.inner, index, &slice, &err) != 0 {
56+
defer { libsql_free_string(err) }
57+
throw LibsqlError.runtimeError(String(cString: err!))
58+
}
59+
60+
return Data(bytes: slice.ptr, count: Int(slice.len))
61+
}
62+
63+
func getDouble(_ index: Int32) throws -> Double {
64+
var double: Double = 0
65+
66+
var err: UnsafePointer<CChar>?
67+
if libsql_get_float(self.inner, index, &double, &err) != 0 {
68+
defer { libsql_free_string(err) }
69+
throw LibsqlError.runtimeError(String(cString: err!))
70+
}
71+
72+
return double
73+
}
74+
75+
func getString(_ index: Int32) throws -> String {
76+
var string: UnsafePointer<CChar>? = nil
77+
78+
var err: UnsafePointer<CChar>?
79+
if libsql_get_string(self.inner, index, &string, &err) != 0 {
80+
defer { libsql_free_string(err) }
81+
throw LibsqlError.runtimeError(String(cString: err!))
82+
}
83+
84+
return String(cString: string!)
85+
}
86+
87+
func getInt(_ index: Int32) throws -> Int {
88+
var integer: Int64 = 0
89+
90+
var err: UnsafePointer<CChar>?
91+
if libsql_get_int(self.inner, index, &integer, &err) != 0 {
92+
defer { libsql_free_string(err) }
93+
throw LibsqlError.runtimeError(String(cString: err!))
94+
}
95+
return Int(integer)
96+
}
97+
}
1498

15-
init?(path: String) throws {
16-
var db: libsql_database_t? = nil
17-
var err: UnsafePointer<CChar>? = nil
99+
class Rows {
100+
var inner: libsql_rows_t
18101

19-
try path.withCString { path in
20-
if libsql_open_file(path, &db, &err) != 0 {
21-
throw LibsqlError.runtimeError(String(cString: err!))
22-
}
102+
fileprivate init(fromPtr inner: libsql_rows_t) {
103+
self.inner = inner
23104
}
24105

25-
if let db = db {
26-
self.inner = db
27-
} else {
28-
return nil
106+
deinit {
107+
libsql_free_rows(self.inner)
29108
}
30-
}
31109

32-
init?(url: String, authToken: String) throws {
33-
var db: libsql_database_t? = nil
34-
var err: UnsafePointer<CChar>? = nil
110+
func next() throws -> Row? {
111+
var row: libsql_row_t?
35112

36-
try url.withCString { url in
37-
try authToken.withCString { authToken in
38-
if libsql_open_remote(url, authToken, &db, &err) == 0 {
39-
defer { libsql_free_string(err) }
40-
throw LibsqlError.runtimeError(String(cString: err!))
113+
var err: UnsafePointer<CChar>?
114+
if libsql_next_row(self.inner, &row, &err) != 0 {
115+
defer { libsql_free_string(err) }
116+
throw LibsqlError.runtimeError(String(cString: err!))
41117
}
42-
}
118+
119+
return Row(fromPtr: row)
120+
43121
}
122+
}
123+
124+
class Connection {
125+
var inner: libsql_connection_t
126+
127+
deinit {
128+
libsql_disconnect(self.inner)
129+
}
130+
131+
fileprivate init(fromPtr inner: libsql_connection_t) {
132+
self.inner = inner
133+
}
134+
135+
func query(_ sql: String) throws -> Rows {
136+
var rows: libsql_rows_t? = nil
137+
try sql.withCString { sql in
138+
var err: UnsafePointer<CChar>? = nil
139+
if libsql_query(self.inner, sql, &rows, &err) != 0 {
140+
defer { libsql_free_string(err) }
141+
throw LibsqlError.runtimeError(String(cString: err!))
142+
}
143+
}
144+
145+
return Rows(fromPtr: rows!)
146+
}
147+
148+
func execute(_ sql: String) throws {
149+
try sql.withCString { sql in
150+
var err: UnsafePointer<CChar>? = nil
151+
if libsql_execute(self.inner, sql, &err) != 0 {
152+
defer { libsql_free_string(err) }
153+
throw LibsqlError.runtimeError(String(cString: err!))
154+
}
155+
}
156+
}
157+
158+
func execute(_ sql: String, _ params: ValueRepresentable...) throws {
159+
var stmt: libsql_stmt_t? = nil
160+
161+
try sql.withCString { sql in
162+
var err: UnsafePointer<CChar>? = nil
163+
if libsql_prepare(self.inner, sql, &stmt, &err) != 0 {
164+
defer { libsql_free_string(err) }
165+
throw LibsqlError.runtimeError(String(cString: err!))
166+
}
167+
}
168+
169+
for (i, v) in params.enumerated() {
170+
let i = Int32(i + 1)
171+
172+
switch v.toValue() {
173+
case .integer(let integer):
174+
var err: UnsafePointer<CChar>? = nil
175+
if libsql_bind_int(stmt, i, integer, &err) != 0 {
176+
defer { libsql_free_string(err) }
177+
throw LibsqlError.runtimeError(String(cString: err!))
178+
}
179+
case .text(let text):
180+
try text.withCString { text in
181+
var err: UnsafePointer<CChar>? = nil
182+
if libsql_bind_string(stmt, i, text, &err) != 0 {
183+
defer { libsql_free_string(err) }
184+
throw LibsqlError.runtimeError(String(cString: err!))
185+
}
186+
}
187+
case .blob(let blob):
188+
try blob.withUnsafeBytes { blob in
189+
let blob = blob.baseAddress?.assumingMemoryBound(to: UInt8.self)
190+
var err: UnsafePointer<CChar>? = nil
191+
if libsql_bind_string(stmt, i, blob, &err) != 0 {
192+
defer { libsql_free_string(err) }
193+
throw LibsqlError.runtimeError(String(cString: err!))
194+
}
195+
}
196+
case .real(let real):
197+
var err: UnsafePointer<CChar>? = nil
198+
if libsql_bind_float(stmt, i, real, &err) != 0 {
199+
defer { libsql_free_string(err) }
200+
throw LibsqlError.runtimeError(String(cString: err!))
201+
}
202+
}
203+
}
204+
205+
}
206+
}
207+
208+
class Database {
209+
var inner: libsql_database_t
210+
211+
deinit {
212+
libsql_close(self.inner)
213+
}
214+
215+
func connect() throws -> Connection {
216+
var conn: libsql_connection_t? = nil
217+
var err: UnsafePointer<CChar>? = nil
218+
219+
if libsql_connect(self.inner, &conn, &err) != 0 {
220+
defer { libsql_free_string(err) }
221+
throw LibsqlError.runtimeError(String(cString: err!))
222+
}
223+
224+
return Connection(fromPtr: conn!)
225+
}
226+
227+
init(_ path: String) throws {
228+
var db: libsql_database_t? = nil
229+
var err: UnsafePointer<CChar>? = nil
230+
231+
try path.withCString { path in
232+
if libsql_open_ext(path, &db, &err) != 0 {
233+
defer { libsql_free_string(err) }
234+
throw LibsqlError.runtimeError(String(cString: err!))
235+
}
236+
}
237+
238+
self.inner = db!
239+
}
240+
241+
init(url: String, authToken: String) throws {
242+
var db: libsql_database_t? = nil
243+
var err: UnsafePointer<CChar>? = nil
244+
245+
try url.withCString { url in
246+
try authToken.withCString { authToken in
247+
if libsql_open_remote(url, authToken, &db, &err) != 0 {
248+
defer { libsql_free_string(err) }
249+
throw LibsqlError.runtimeError(String(cString: err!))
250+
}
251+
}
252+
}
44253

45-
if let db = db {
46-
self.inner = db
47-
} else {
48-
return nil
254+
self.inner = db!
49255
}
50-
}
51256
}

0 commit comments

Comments
 (0)