Skip to content

Commit 34bbcf4

Browse files
committed
chore: init project
0 parents  commit 34bbcf4

File tree

8 files changed

+172
-0
lines changed

8 files changed

+172
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.DS_Store
2+
Packages
3+
.build/
4+
xcuserdata
5+
DerivedData/
6+
*.xcodeproj

.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// swift-tools-version:5.3
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "Sqlite",
8+
platforms: [
9+
.iOS(.v9),
10+
.macOS(.v10_10)
11+
],
12+
products: [
13+
.library(
14+
name: "Sqlite",
15+
targets: ["Sqlite"]
16+
),
17+
],
18+
dependencies: [],
19+
targets: [
20+
.target(
21+
name: "Sqlite",
22+
dependencies: [
23+
.target(name: "Csqlite3")
24+
]
25+
),
26+
.testTarget(
27+
name: "SqliteTests",
28+
dependencies: ["Sqlite"]
29+
),
30+
.systemLibrary(
31+
name: "Csqlite3",
32+
providers: [
33+
.apt(["libsqlite3-dev"]),
34+
.brew(["sqlite3"]),
35+
]
36+
)
37+
]
38+
)

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Sqlite
2+
3+
A description of this package.

Sources/Csqlite3/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module Csqlite3 [system] {
2+
header "shim.h"
3+
link "sqlite3"
4+
export *
5+
}

Sources/Csqlite3/shim.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#include <sqlite3.h>

Sources/Sqlite/Sqlite.swift

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#if os(Linux)
2+
import Csqlite3
3+
#else
4+
import SQLite3
5+
#endif
6+
7+
private let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
8+
9+
public final class Sqlite {
10+
public private(set) var handle: OpaquePointer?
11+
12+
public init(path: String) throws {
13+
try self.validate(
14+
sqlite3_open_v2(
15+
path,
16+
&self.handle,
17+
SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE,
18+
nil
19+
)
20+
)
21+
}
22+
23+
deinit {
24+
sqlite3_close_v2(self.handle)
25+
}
26+
27+
public func execute(_ sql: String) throws {
28+
try self.validate(
29+
sqlite3_exec(self.handle, sql, nil, nil, nil)
30+
)
31+
}
32+
33+
@discardableResult
34+
public func run(_ sql: String, _ bindings: Datatype...) throws -> [[Datatype]] {
35+
var stmt: OpaquePointer?
36+
try self.validate(sqlite3_prepare_v2(self.handle, sql, -1, &stmt, nil))
37+
defer { sqlite3_finalize(stmt) }
38+
for (idx, binding) in zip(Int32(1)..., bindings) {
39+
switch binding {
40+
case .null:
41+
try self.validate(sqlite3_bind_null(stmt, idx))
42+
case let .integer(value):
43+
try self.validate(sqlite3_bind_int64(stmt, idx, value))
44+
case let .real(value):
45+
try self.validate(sqlite3_bind_double(stmt, idx, value))
46+
case let .text(value):
47+
try self.validate(sqlite3_bind_text(stmt, idx, value, -1, SQLITE_TRANSIENT))
48+
case let .blob(value):
49+
try self.validate(sqlite3_bind_blob(stmt, idx, value, -1, SQLITE_TRANSIENT))
50+
}
51+
}
52+
let cols = sqlite3_column_count(stmt)
53+
var rows: [[Datatype]] = []
54+
while try self.validate(sqlite3_step(stmt)) == SQLITE_ROW {
55+
rows.append(
56+
try (0..<cols).map { idx -> Datatype in
57+
switch sqlite3_column_type(stmt, idx) {
58+
case SQLITE_BLOB:
59+
return .blob(sqlite3_column_blob(stmt, idx).load(as: [UInt8].self))
60+
case SQLITE_FLOAT:
61+
return .real(sqlite3_column_double(stmt, idx))
62+
case SQLITE_INTEGER:
63+
return .integer(sqlite3_column_int64(stmt, idx))
64+
case SQLITE_NULL:
65+
return .null
66+
case SQLITE_TEXT:
67+
return .text(String(cString: sqlite3_column_text(stmt, idx)))
68+
default:
69+
throw Error(description: "fatal")
70+
}
71+
}
72+
)
73+
}
74+
return rows
75+
}
76+
77+
public var lastInsertRowid: Int64 {
78+
sqlite3_last_insert_rowid(self.handle)
79+
}
80+
81+
@discardableResult
82+
private func validate(_ code: Int32) throws -> Int32 {
83+
guard code == SQLITE_OK || code == SQLITE_ROW || code == SQLITE_DONE
84+
else { throw Error(code: code, db: self.handle) }
85+
return code
86+
}
87+
88+
public enum Datatype: Equatable {
89+
case blob([UInt8])
90+
case integer(Int64)
91+
case null
92+
case real(Double)
93+
case text(String)
94+
}
95+
96+
public struct Error: Swift.Error, Equatable {
97+
public var code: Int32?
98+
public var description: String
99+
}
100+
}
101+
102+
extension Sqlite.Error {
103+
init(code: Int32, db: OpaquePointer?) {
104+
self.code = code
105+
self.description = String(cString: sqlite3_errstr(code))
106+
}
107+
}

Tests/SqliteTests/SqliteTests.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import XCTest
2+
@testable import Sqlite
3+
4+
final class SqliteTests: XCTestCase {
5+
}

0 commit comments

Comments
 (0)