From 36b453293932688f5ddddec75554fd6273c780b0 Mon Sep 17 00:00:00 2001 From: shawn Date: Wed, 17 Jul 2024 23:55:16 +0800 Subject: [PATCH 1/7] add rocksdb.swift #5 --- Database/Package.resolved | 15 ++ Database/Package.swift | 8 +- Database/Sources/Database/Database.swift | 82 +++++++++++ .../Tests/DatabaseTests/DatabaseTests.swift | 131 +++++++++++++++++- 4 files changed, 228 insertions(+), 8 deletions(-) create mode 100644 Database/Package.resolved diff --git a/Database/Package.resolved b/Database/Package.resolved new file mode 100644 index 00000000..d03e5483 --- /dev/null +++ b/Database/Package.resolved @@ -0,0 +1,15 @@ +{ + "originHash" : "3d98e183a568a5accbc0c0c5599a833ac3f72dcbc6225970d7263ed1570547d8", + "pins" : [ + { + "identity" : "rocksdb.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/TapeIt/rocksdb.swift.git", + "state" : { + "revision" : "7eae85eb67d8225efd7e313d3900820032ae51fe", + "version" : "6.29.5" + } + } + ], + "version" : 3 +} diff --git a/Database/Package.swift b/Database/Package.swift index d495d31b..dd4c442b 100644 --- a/Database/Package.swift +++ b/Database/Package.swift @@ -12,11 +12,17 @@ let package = Package( targets: ["Database"] ), ], + dependencies: [ + .package(url: "https://github.com/TapeIt/rocksdb.swift.git", from: "6.29.5"), + ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products from dependencies. .target( - name: "Database" + name: "Database", + dependencies: [ + .product(name: "RocksDB", package: "rocksdb.swift"), + ] ), .testTarget( name: "DatabaseTests", diff --git a/Database/Sources/Database/Database.swift b/Database/Sources/Database/Database.swift index 08b22b80..8f4178fd 100644 --- a/Database/Sources/Database/Database.swift +++ b/Database/Sources/Database/Database.swift @@ -1,2 +1,84 @@ // The Swift Programming Language // https://docs.swift.org/swift-book +import Foundation +import RocksDB + +public class Database { + public let path: URL + public let prefix: String? + private var db: RocksDB? + + public init(path: URL, prefix: String? = nil) { + self.path = path + self.prefix = prefix + + db = try! RocksDB(path: path, prefix: prefix) + } + + public func put(key: String, value: some RocksDBValueRepresentable) throws { + guard let db else { + throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + } + do { + try db.put(key: key, value: value) + } catch { + throw error + } + } + + public func get(type: T.Type, key: String) throws -> T? { + guard let db else { + throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + } + do { + return try type.init(data: db.get(key: key)) + } catch { + throw error + } + } + + public func delete(key: String) throws { + guard let db else { + throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + } + do { + try db.delete(key: key) + } catch { + throw error + } + } + + public func iterate( + keyType _: Key.Type, + valueType _: Value.Type, + gte: String? = nil + ) throws -> RocksDBSequence { + guard let db else { + throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + } + + return db.sequence(gte: gte) + } + + public func iterate(keyType _: Key.Type, valueType _: Value.Type, + lte: String) throws -> RocksDBSequence + { + guard let db else { + throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + } + + return db.sequence(lte: lte) + } + + public func batch(operations: [RocksDBBatchOperation]) throws { + guard let db else { + throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + } + + do { + try db.batch(operations: operations) + } catch { + throw error + } + } +} diff --git a/Database/Tests/DatabaseTests/DatabaseTests.swift b/Database/Tests/DatabaseTests/DatabaseTests.swift index 0272d175..c97497c2 100644 --- a/Database/Tests/DatabaseTests/DatabaseTests.swift +++ b/Database/Tests/DatabaseTests/DatabaseTests.swift @@ -1,13 +1,130 @@ -import XCTest - @testable import Database +import XCTest final class DatabaseTests: XCTestCase { - func testExample() throws { - // XCTest Documentation - // https://developer.apple.com/documentation/xctest + var database: Database! + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testSimplePut() { + let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") + database = Database(path: path) + + try! database.put(key: "testText", value: "lolamkhaha") + try! database.put(key: "testEmoji", value: "😂") + try! database.put(key: "testTextEmoji", value: "emojitext 😂") + try! database.put(key: "testMultipleEmoji", value: "😂😂😂") + + XCTAssertEqual(try! database.get(type: String.self, key: "testText"), "lolamkhaha") + XCTAssertEqual(try! database.get(type: String.self, key: "testEmoji"), "😂") + XCTAssertEqual(try! database.get(type: String.self, key: "testTextEmoji"), "emojitext 😂") + XCTAssertEqual(try! database.get(type: String.self, key: "testMultipleEmoji"), "😂😂😂") + + try! FileManager.default.removeItem(at: database.path) + database = nil + } + + func testSimpleDelete() { + let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") + database = Database(path: path) + + try! database.put(key: "testDeleteKey", value: "this is a simple value 😘") + try! database.delete(key: "testDeleteKey") + + XCTAssertEqual(try! database.get(type: String.self, key: "testDeleteKey"), "") + + try! FileManager.default.removeItem(at: database.path) + database = nil + } + + func testSimpleIterator() { + let path = "/tmp/\(UUID().uuidString)" + database = Database(path: URL(fileURLWithPath: path)) + + let orderedKeysAndValues = [ + (key: "testEmoji", value: "😂"), + (key: "testMultipleEmoji", value: "😂😂😂"), + (key: "testText", value: "lolamkhaha"), + (key: "testTextEmoji", value: "emojitext 😂"), + ] + + for (k, v) in orderedKeysAndValues { + try! database.put(key: k, value: v) + } + + var i = 0 + for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self) { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i += 1 + } + XCTAssertEqual(i, 4) + + i = 1 + for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self, gte: "testMultipleEmoji") { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i += 1 + } + XCTAssertEqual(i, 4) + + i = 2 + for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self, gte: "testText") { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i += 1 + } + XCTAssertEqual(i, 4) + + i = 3 + for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self, lte: "testTextEmoji") { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i -= 1 + } + XCTAssertEqual(i, -1) + + i = 2 + for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self, lte: "testText") { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i -= 1 + } + XCTAssertEqual(i, -1) + + try! FileManager.default.removeItem(at: database.path) + database = nil + } + + func testBatchOperations() { + let prefixedPath = "/tmp/\(UUID().uuidString)" + + let prefixedDB = Database(path: URL(fileURLWithPath: prefixedPath), prefix: "correctprefix") + + try! prefixedDB.put(key: "testText", value: "lolamkhaha") + try! prefixedDB.put(key: "testEmoji", value: "😂") + try! prefixedDB.put(key: "testTextEmoji", value: "emojitext 😂") + try! prefixedDB.put(key: "testMultipleEmoji", value: "😂😂😂") + + try! prefixedDB.batch(operations: [ + .delete(key: "testText"), + .put(key: "someThing", value: "someValue"), + .delete(key: "someThing"), + .put(key: "secondKey", value: "anotherValue"), + .put(key: "testText", value: "textTextValue"), + ]) + + XCTAssertEqual(try! prefixedDB.get(type: String.self, key: "testEmoji"), "😂") + XCTAssertEqual(try! prefixedDB.get(type: String.self, key: "someThing"), "") + XCTAssertEqual(try! prefixedDB.get(type: String.self, key: "secondKey"), "anotherValue") + XCTAssertEqual(try! prefixedDB.get(type: String.self, key: "testText"), "textTextValue") - // Defining Test Cases and Test Methods - // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods + try! FileManager.default.removeItem(at: prefixedDB.path) } } From e63b9b7767337e466e78450317ddac8f3013a1fd Mon Sep 17 00:00:00 2001 From: shawn Date: Sun, 21 Jul 2024 22:04:25 +0800 Subject: [PATCH 2/7] lint fix --- Database/Sources/Database/Database.swift | 22 ++-- .../Tests/DatabaseTests/DatabaseTests.swift | 106 +++++++++++------- 2 files changed, 81 insertions(+), 47 deletions(-) diff --git a/Database/Sources/Database/Database.swift b/Database/Sources/Database/Database.swift index 8f4178fd..e6d6142b 100644 --- a/Database/Sources/Database/Database.swift +++ b/Database/Sources/Database/Database.swift @@ -8,16 +8,22 @@ public class Database { public let prefix: String? private var db: RocksDB? - public init(path: URL, prefix: String? = nil) { + private static let errorDomain = "DatabaseErrorDomain" + + public init(path: URL, prefix: String? = nil) throws { self.path = path self.prefix = prefix - db = try! RocksDB(path: path, prefix: prefix) + do { + db = try RocksDB(path: path, prefix: prefix) + } catch { + throw NSError(domain: Database.errorDomain, code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to initialize RocksDB: \(error)"]) + } } public func put(key: String, value: some RocksDBValueRepresentable) throws { guard let db else { - throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) } do { try db.put(key: key, value: value) @@ -28,7 +34,7 @@ public class Database { public func get(type: T.Type, key: String) throws -> T? { guard let db else { - throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) } do { return try type.init(data: db.get(key: key)) @@ -39,7 +45,7 @@ public class Database { public func delete(key: String) throws { guard let db else { - throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) } do { try db.delete(key: key) @@ -54,7 +60,7 @@ public class Database { gte: String? = nil ) throws -> RocksDBSequence { guard let db else { - throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) } return db.sequence(gte: gte) @@ -64,7 +70,7 @@ public class Database { lte: String) throws -> RocksDBSequence { guard let db else { - throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) } return db.sequence(lte: lte) @@ -72,7 +78,7 @@ public class Database { public func batch(operations: [RocksDBBatchOperation]) throws { guard let db else { - throw NSError(domain: "DatabaseErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) + throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) } do { diff --git a/Database/Tests/DatabaseTests/DatabaseTests.swift b/Database/Tests/DatabaseTests/DatabaseTests.swift index c97497c2..3f78340a 100644 --- a/Database/Tests/DatabaseTests/DatabaseTests.swift +++ b/Database/Tests/DatabaseTests/DatabaseTests.swift @@ -16,31 +16,47 @@ final class DatabaseTests: XCTestCase { let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") database = Database(path: path) - try! database.put(key: "testText", value: "lolamkhaha") - try! database.put(key: "testEmoji", value: "😂") - try! database.put(key: "testTextEmoji", value: "emojitext 😂") - try! database.put(key: "testMultipleEmoji", value: "😂😂😂") - - XCTAssertEqual(try! database.get(type: String.self, key: "testText"), "lolamkhaha") - XCTAssertEqual(try! database.get(type: String.self, key: "testEmoji"), "😂") - XCTAssertEqual(try! database.get(type: String.self, key: "testTextEmoji"), "emojitext 😂") - XCTAssertEqual(try! database.get(type: String.self, key: "testMultipleEmoji"), "😂😂😂") - - try! FileManager.default.removeItem(at: database.path) - database = nil + do { + try database.put(key: "testText", value: "lolamkhaha") + try database.put(key: "testEmoji", value: "😂") + try database.put(key: "testTextEmoji", value: "emojitext 😂") + try database.put(key: "testMultipleEmoji", value: "😂😂😂") + + XCTAssertEqual(try database.get(type: String.self, key: "testText"), "lolamkhaha") + XCTAssertEqual(try database.get(type: String.self, key: "testEmoji"), "😂") + XCTAssertEqual(try database.get(type: String.self, key: "testTextEmoji"), "emojitext 😂") + XCTAssertEqual(try database.get(type: String.self, key: "testMultipleEmoji"), "😂😂😂") + } catch { + XCTFail("An error occurred during simple put test: \(error)") + } + + do { + try FileManager.default.removeItem(at: database.path) + database = nil + } catch { + XCTFail("Failed to remove RocksDB path: \(error)") + } } func testSimpleDelete() { let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") database = Database(path: path) - try! database.put(key: "testDeleteKey", value: "this is a simple value 😘") - try! database.delete(key: "testDeleteKey") + do { + try database.put(key: "testDeleteKey", value: "this is a simple value 😘") + try database.delete(key: "testDeleteKey") - XCTAssertEqual(try! database.get(type: String.self, key: "testDeleteKey"), "") + XCTAssertEqual(try database.get(type: String.self, key: "testDeleteKey"), "") - try! FileManager.default.removeItem(at: database.path) - database = nil + } catch { + XCTFail("An error occurred during simple delete test: \(error)") + } + do { + try FileManager.default.removeItem(at: database.path) + database = nil + } catch { + XCTFail("Failed to remove RocksDB path: \(error)") + } } func testSimpleIterator() { @@ -54,8 +70,12 @@ final class DatabaseTests: XCTestCase { (key: "testTextEmoji", value: "emojitext 😂"), ] - for (k, v) in orderedKeysAndValues { - try! database.put(key: k, value: v) + do { + for (k, v) in orderedKeysAndValues { + try database.put(key: k, value: v) + } + } catch { + XCTFail("An error occurred during simple iterator test: \(error)") } var i = 0 @@ -98,8 +118,12 @@ final class DatabaseTests: XCTestCase { } XCTAssertEqual(i, -1) - try! FileManager.default.removeItem(at: database.path) - database = nil + do { + try FileManager.default.removeItem(at: database.path) + database = nil + } catch { + XCTFail("Failed to remove RocksDB path: \(error)") + } } func testBatchOperations() { @@ -107,24 +131,28 @@ final class DatabaseTests: XCTestCase { let prefixedDB = Database(path: URL(fileURLWithPath: prefixedPath), prefix: "correctprefix") - try! prefixedDB.put(key: "testText", value: "lolamkhaha") - try! prefixedDB.put(key: "testEmoji", value: "😂") - try! prefixedDB.put(key: "testTextEmoji", value: "emojitext 😂") - try! prefixedDB.put(key: "testMultipleEmoji", value: "😂😂😂") - - try! prefixedDB.batch(operations: [ - .delete(key: "testText"), - .put(key: "someThing", value: "someValue"), - .delete(key: "someThing"), - .put(key: "secondKey", value: "anotherValue"), - .put(key: "testText", value: "textTextValue"), - ]) - - XCTAssertEqual(try! prefixedDB.get(type: String.self, key: "testEmoji"), "😂") - XCTAssertEqual(try! prefixedDB.get(type: String.self, key: "someThing"), "") - XCTAssertEqual(try! prefixedDB.get(type: String.self, key: "secondKey"), "anotherValue") - XCTAssertEqual(try! prefixedDB.get(type: String.self, key: "testText"), "textTextValue") - + do { + try prefixedDB.put(key: "testText", value: "lolamkhaha") + try prefixedDB.put(key: "testEmoji", value: "😂") + try prefixedDB.put(key: "testTextEmoji", value: "emojitext 😂") + try prefixedDB.put(key: "testMultipleEmoji", value: "😂😂😂") + + try prefixedDB.batch(operations: [ + .delete(key: "testText"), + .put(key: "someThing", value: "someValue"), + .delete(key: "someThing"), + .put(key: "secondKey", value: "anotherValue"), + .put(key: "testText", value: "textTextValue"), + ]) + + XCTAssertEqual(try prefixedDB.get(type: String.self, key: "testEmoji"), "😂") + XCTAssertEqual(try prefixedDB.get(type: String.self, key: "someThing"), "") + XCTAssertEqual(try prefixedDB.get(type: String.self, key: "secondKey"), "anotherValue") + XCTAssertEqual(try prefixedDB.get(type: String.self, key: "testText"), "textTextValue") + + } catch { + XCTFail("An error occurred during batch test: \(error)") + } try! FileManager.default.removeItem(at: prefixedDB.path) } } From 6b7b9fdca2f7494ce75c51281025c2125b96539f Mon Sep 17 00:00:00 2001 From: shawn Date: Sun, 21 Jul 2024 22:06:44 +0800 Subject: [PATCH 3/7] lint fix --- .../Tests/DatabaseTests/DatabaseTests.swift | 81 ++++++++++--------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/Database/Tests/DatabaseTests/DatabaseTests.swift b/Database/Tests/DatabaseTests/DatabaseTests.swift index 3f78340a..12c11de1 100644 --- a/Database/Tests/DatabaseTests/DatabaseTests.swift +++ b/Database/Tests/DatabaseTests/DatabaseTests.swift @@ -74,49 +74,49 @@ final class DatabaseTests: XCTestCase { for (k, v) in orderedKeysAndValues { try database.put(key: k, value: v) } - } catch { - XCTFail("An error occurred during simple iterator test: \(error)") - } - var i = 0 - for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self) { - XCTAssertEqual(key, orderedKeysAndValues[i].key) - XCTAssertEqual(val, orderedKeysAndValues[i].value) - i += 1 - } - XCTAssertEqual(i, 4) + var i = 0 + for (key, val) in try database.iterate(keyType: String.self, valueType: String.self) { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i += 1 + } + XCTAssertEqual(i, 4) - i = 1 - for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self, gte: "testMultipleEmoji") { - XCTAssertEqual(key, orderedKeysAndValues[i].key) - XCTAssertEqual(val, orderedKeysAndValues[i].value) - i += 1 - } - XCTAssertEqual(i, 4) + i = 1 + for (key, val) in try database.iterate(keyType: String.self, valueType: String.self, gte: "testMultipleEmoji") { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i += 1 + } + XCTAssertEqual(i, 4) - i = 2 - for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self, gte: "testText") { - XCTAssertEqual(key, orderedKeysAndValues[i].key) - XCTAssertEqual(val, orderedKeysAndValues[i].value) - i += 1 - } - XCTAssertEqual(i, 4) + i = 2 + for (key, val) in try database.iterate(keyType: String.self, valueType: String.self, gte: "testText") { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i += 1 + } + XCTAssertEqual(i, 4) - i = 3 - for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self, lte: "testTextEmoji") { - XCTAssertEqual(key, orderedKeysAndValues[i].key) - XCTAssertEqual(val, orderedKeysAndValues[i].value) - i -= 1 - } - XCTAssertEqual(i, -1) + i = 3 + for (key, val) in try database.iterate(keyType: String.self, valueType: String.self, lte: "testTextEmoji") { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i -= 1 + } + XCTAssertEqual(i, -1) - i = 2 - for (key, val) in try! database.iterate(keyType: String.self, valueType: String.self, lte: "testText") { - XCTAssertEqual(key, orderedKeysAndValues[i].key) - XCTAssertEqual(val, orderedKeysAndValues[i].value) - i -= 1 + i = 2 + for (key, val) in try database.iterate(keyType: String.self, valueType: String.self, lte: "testText") { + XCTAssertEqual(key, orderedKeysAndValues[i].key) + XCTAssertEqual(val, orderedKeysAndValues[i].value) + i -= 1 + } + XCTAssertEqual(i, -1) + } catch { + XCTFail("An error occurred during simple iterator test: \(error)") } - XCTAssertEqual(i, -1) do { try FileManager.default.removeItem(at: database.path) @@ -153,6 +153,11 @@ final class DatabaseTests: XCTestCase { } catch { XCTFail("An error occurred during batch test: \(error)") } - try! FileManager.default.removeItem(at: prefixedDB.path) + + do { + try FileManager.default.removeItem(at: prefixedDB.path) + } catch { + XCTFail("Failed to remove RocksDB path: \(error)") + } } } From 394a3c5adbd3d82a4a2256600f64251d90ebf855 Mon Sep 17 00:00:00 2001 From: shawn Date: Sun, 21 Jul 2024 22:25:02 +0800 Subject: [PATCH 4/7] add DatabaseTests/LinuxMain.swift --- Database/Tests/LinuxMain.swift | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Database/Tests/LinuxMain.swift diff --git a/Database/Tests/LinuxMain.swift b/Database/Tests/LinuxMain.swift new file mode 100644 index 00000000..80ca1c70 --- /dev/null +++ b/Database/Tests/LinuxMain.swift @@ -0,0 +1,7 @@ +import XCTest + +import DatabaseTests + +var tests = [XCTestCaseEntry]() +tests += DatabaseTests.allTests() +XCTMain(tests) From 75190ef2559a132ac2d1f5ae47c9310ff72af969 Mon Sep 17 00:00:00 2001 From: shawn Date: Mon, 22 Jul 2024 14:07:18 +0800 Subject: [PATCH 5/7] database testcase fix --- Database/Sources/Database/Database.swift | 10 +++--- .../Tests/DatabaseTests/DatabaseTests.swift | 34 ++++++------------- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/Database/Sources/Database/Database.swift b/Database/Sources/Database/Database.swift index e6d6142b..6f4147b2 100644 --- a/Database/Sources/Database/Database.swift +++ b/Database/Sources/Database/Database.swift @@ -17,7 +17,7 @@ public class Database { do { db = try RocksDB(path: path, prefix: prefix) } catch { - throw NSError(domain: Database.errorDomain, code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to initialize RocksDB: \(error)"]) + throw NSError(domain: Database.errorDomain, code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to init RocksDB: \(error)"]) } } @@ -66,9 +66,11 @@ public class Database { return db.sequence(gte: gte) } - public func iterate(keyType _: Key.Type, valueType _: Value.Type, - lte: String) throws -> RocksDBSequence - { + public func iterate( + keyType _: Key.Type, + valueType _: Value.Type, + lte: String + ) throws -> RocksDBSequence { guard let db else { throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) } diff --git a/Database/Tests/DatabaseTests/DatabaseTests.swift b/Database/Tests/DatabaseTests/DatabaseTests.swift index 12c11de1..24ede548 100644 --- a/Database/Tests/DatabaseTests/DatabaseTests.swift +++ b/Database/Tests/DatabaseTests/DatabaseTests.swift @@ -4,19 +4,12 @@ import XCTest final class DatabaseTests: XCTestCase { var database: Database! - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - func testSimplePut() { let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") - database = Database(path: path) do { + database = try Database(path: path) + try database.put(key: "testText", value: "lolamkhaha") try database.put(key: "testEmoji", value: "😂") try database.put(key: "testTextEmoji", value: "emojitext 😂") @@ -40,9 +33,10 @@ final class DatabaseTests: XCTestCase { func testSimpleDelete() { let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") - database = Database(path: path) do { + database = try Database(path: path) + try database.put(key: "testDeleteKey", value: "this is a simple value 😘") try database.delete(key: "testDeleteKey") @@ -60,9 +54,6 @@ final class DatabaseTests: XCTestCase { } func testSimpleIterator() { - let path = "/tmp/\(UUID().uuidString)" - database = Database(path: URL(fileURLWithPath: path)) - let orderedKeysAndValues = [ (key: "testEmoji", value: "😂"), (key: "testMultipleEmoji", value: "😂😂😂"), @@ -71,6 +62,9 @@ final class DatabaseTests: XCTestCase { ] do { + let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") + database = try Database(path: path) + for (k, v) in orderedKeysAndValues { try database.put(key: k, value: v) } @@ -127,11 +121,9 @@ final class DatabaseTests: XCTestCase { } func testBatchOperations() { - let prefixedPath = "/tmp/\(UUID().uuidString)" - - let prefixedDB = Database(path: URL(fileURLWithPath: prefixedPath), prefix: "correctprefix") - do { + let prefixedPath = "/tmp/\(UUID().uuidString)" + let prefixedDB = try Database(path: URL(fileURLWithPath: prefixedPath), prefix: "correctprefix") try prefixedDB.put(key: "testText", value: "lolamkhaha") try prefixedDB.put(key: "testEmoji", value: "😂") try prefixedDB.put(key: "testTextEmoji", value: "emojitext 😂") @@ -150,14 +142,10 @@ final class DatabaseTests: XCTestCase { XCTAssertEqual(try prefixedDB.get(type: String.self, key: "secondKey"), "anotherValue") XCTAssertEqual(try prefixedDB.get(type: String.self, key: "testText"), "textTextValue") - } catch { - XCTFail("An error occurred during batch test: \(error)") - } - - do { try FileManager.default.removeItem(at: prefixedDB.path) + } catch { - XCTFail("Failed to remove RocksDB path: \(error)") + XCTFail("An error occurred during batch test: \(error)") } } } From e527ae5ecbe81fc4dd3e1189cbd6169ffa862634 Mon Sep 17 00:00:00 2001 From: shawn Date: Mon, 22 Jul 2024 17:07:24 +0800 Subject: [PATCH 6/7] database tests fix --- Database/Tests/DatabaseTests/DatabaseTests.swift | 9 ++++++++- Database/Tests/DatabaseTests/XCTestManifests.swift | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 Database/Tests/DatabaseTests/XCTestManifests.swift diff --git a/Database/Tests/DatabaseTests/DatabaseTests.swift b/Database/Tests/DatabaseTests/DatabaseTests.swift index 24ede548..48015087 100644 --- a/Database/Tests/DatabaseTests/DatabaseTests.swift +++ b/Database/Tests/DatabaseTests/DatabaseTests.swift @@ -1,7 +1,7 @@ @testable import Database import XCTest -final class DatabaseTests: XCTestCase { +final class DatabaseTests: XCTestCase, @unchecked Sendable { var database: Database! func testSimplePut() { @@ -148,4 +148,11 @@ final class DatabaseTests: XCTestCase { XCTFail("An error occurred during batch test: \(error)") } } + + static let allTests = [ + ("testSimplePut", testSimplePut), + ("testSimpleDelete", testSimpleDelete), + ("testSimpleIterator", testSimpleIterator), + ("testBatchOperations", testBatchOperations), + ] } diff --git a/Database/Tests/DatabaseTests/XCTestManifests.swift b/Database/Tests/DatabaseTests/XCTestManifests.swift new file mode 100644 index 00000000..54655d89 --- /dev/null +++ b/Database/Tests/DatabaseTests/XCTestManifests.swift @@ -0,0 +1,9 @@ +import XCTest + +#if !canImport(ObjectiveC) + public func allTests() -> [XCTestCaseEntry] { + [ + testCase(DatabaseTests.allTests), + ] + } +#endif From d823636c8f5e40dafee05ba228ce878519f6888b Mon Sep 17 00:00:00 2001 From: shawn Date: Mon, 22 Jul 2024 23:28:44 +0800 Subject: [PATCH 7/7] use @_exported import RocksDB --- Database/Sources/Database/Database.swift | 93 +------------------ .../Tests/DatabaseTests/DatabaseTests.swift | 31 +++---- .../Tests/DatabaseTests/XCTestManifests.swift | 9 -- Database/Tests/LinuxMain.swift | 7 -- 4 files changed, 13 insertions(+), 127 deletions(-) delete mode 100644 Database/Tests/DatabaseTests/XCTestManifests.swift delete mode 100644 Database/Tests/LinuxMain.swift diff --git a/Database/Sources/Database/Database.swift b/Database/Sources/Database/Database.swift index 6f4147b2..07b11d65 100644 --- a/Database/Sources/Database/Database.swift +++ b/Database/Sources/Database/Database.swift @@ -1,92 +1 @@ -// The Swift Programming Language -// https://docs.swift.org/swift-book -import Foundation -import RocksDB - -public class Database { - public let path: URL - public let prefix: String? - private var db: RocksDB? - - private static let errorDomain = "DatabaseErrorDomain" - - public init(path: URL, prefix: String? = nil) throws { - self.path = path - self.prefix = prefix - - do { - db = try RocksDB(path: path, prefix: prefix) - } catch { - throw NSError(domain: Database.errorDomain, code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to init RocksDB: \(error)"]) - } - } - - public func put(key: String, value: some RocksDBValueRepresentable) throws { - guard let db else { - throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) - } - do { - try db.put(key: key, value: value) - } catch { - throw error - } - } - - public func get(type: T.Type, key: String) throws -> T? { - guard let db else { - throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) - } - do { - return try type.init(data: db.get(key: key)) - } catch { - throw error - } - } - - public func delete(key: String) throws { - guard let db else { - throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) - } - do { - try db.delete(key: key) - } catch { - throw error - } - } - - public func iterate( - keyType _: Key.Type, - valueType _: Value.Type, - gte: String? = nil - ) throws -> RocksDBSequence { - guard let db else { - throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) - } - - return db.sequence(gte: gte) - } - - public func iterate( - keyType _: Key.Type, - valueType _: Value.Type, - lte: String - ) throws -> RocksDBSequence { - guard let db else { - throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) - } - - return db.sequence(lte: lte) - } - - public func batch(operations: [RocksDBBatchOperation]) throws { - guard let db else { - throw NSError(domain: Database.errorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Database is not opened"]) - } - - do { - try db.batch(operations: operations) - } catch { - throw error - } - } -} +@_exported import RocksDB diff --git a/Database/Tests/DatabaseTests/DatabaseTests.swift b/Database/Tests/DatabaseTests/DatabaseTests.swift index 48015087..63516da6 100644 --- a/Database/Tests/DatabaseTests/DatabaseTests.swift +++ b/Database/Tests/DatabaseTests/DatabaseTests.swift @@ -1,14 +1,14 @@ -@testable import Database +@testable import RocksDB import XCTest -final class DatabaseTests: XCTestCase, @unchecked Sendable { - var database: Database! +final class DatabaseTests: XCTestCase { + var database: RocksDB! func testSimplePut() { let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") do { - database = try Database(path: path) + database = try RocksDB(path: path) try database.put(key: "testText", value: "lolamkhaha") try database.put(key: "testEmoji", value: "😂") @@ -35,7 +35,7 @@ final class DatabaseTests: XCTestCase, @unchecked Sendable { let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") do { - database = try Database(path: path) + database = try RocksDB(path: path) try database.put(key: "testDeleteKey", value: "this is a simple value 😘") try database.delete(key: "testDeleteKey") @@ -63,14 +63,14 @@ final class DatabaseTests: XCTestCase, @unchecked Sendable { do { let path = URL(fileURLWithPath: "/tmp/\(UUID().uuidString)") - database = try Database(path: path) + database = try RocksDB(path: path) for (k, v) in orderedKeysAndValues { try database.put(key: k, value: v) } var i = 0 - for (key, val) in try database.iterate(keyType: String.self, valueType: String.self) { + for (key, val) in database.sequence(keyType: String.self, valueType: String.self) { XCTAssertEqual(key, orderedKeysAndValues[i].key) XCTAssertEqual(val, orderedKeysAndValues[i].value) i += 1 @@ -78,7 +78,7 @@ final class DatabaseTests: XCTestCase, @unchecked Sendable { XCTAssertEqual(i, 4) i = 1 - for (key, val) in try database.iterate(keyType: String.self, valueType: String.self, gte: "testMultipleEmoji") { + for (key, val) in database.sequence(keyType: String.self, valueType: String.self, gte: "testMultipleEmoji") { XCTAssertEqual(key, orderedKeysAndValues[i].key) XCTAssertEqual(val, orderedKeysAndValues[i].value) i += 1 @@ -86,7 +86,7 @@ final class DatabaseTests: XCTestCase, @unchecked Sendable { XCTAssertEqual(i, 4) i = 2 - for (key, val) in try database.iterate(keyType: String.self, valueType: String.self, gte: "testText") { + for (key, val) in database.sequence(keyType: String.self, valueType: String.self, gte: "testText") { XCTAssertEqual(key, orderedKeysAndValues[i].key) XCTAssertEqual(val, orderedKeysAndValues[i].value) i += 1 @@ -94,7 +94,7 @@ final class DatabaseTests: XCTestCase, @unchecked Sendable { XCTAssertEqual(i, 4) i = 3 - for (key, val) in try database.iterate(keyType: String.self, valueType: String.self, lte: "testTextEmoji") { + for (key, val) in database.sequence(keyType: String.self, valueType: String.self, lte: "testTextEmoji") { XCTAssertEqual(key, orderedKeysAndValues[i].key) XCTAssertEqual(val, orderedKeysAndValues[i].value) i -= 1 @@ -102,7 +102,7 @@ final class DatabaseTests: XCTestCase, @unchecked Sendable { XCTAssertEqual(i, -1) i = 2 - for (key, val) in try database.iterate(keyType: String.self, valueType: String.self, lte: "testText") { + for (key, val) in database.sequence(keyType: String.self, valueType: String.self, lte: "testText") { XCTAssertEqual(key, orderedKeysAndValues[i].key) XCTAssertEqual(val, orderedKeysAndValues[i].value) i -= 1 @@ -123,7 +123,7 @@ final class DatabaseTests: XCTestCase, @unchecked Sendable { func testBatchOperations() { do { let prefixedPath = "/tmp/\(UUID().uuidString)" - let prefixedDB = try Database(path: URL(fileURLWithPath: prefixedPath), prefix: "correctprefix") + let prefixedDB = try RocksDB(path: URL(fileURLWithPath: prefixedPath), prefix: "correctprefix") try prefixedDB.put(key: "testText", value: "lolamkhaha") try prefixedDB.put(key: "testEmoji", value: "😂") try prefixedDB.put(key: "testTextEmoji", value: "emojitext 😂") @@ -148,11 +148,4 @@ final class DatabaseTests: XCTestCase, @unchecked Sendable { XCTFail("An error occurred during batch test: \(error)") } } - - static let allTests = [ - ("testSimplePut", testSimplePut), - ("testSimpleDelete", testSimpleDelete), - ("testSimpleIterator", testSimpleIterator), - ("testBatchOperations", testBatchOperations), - ] } diff --git a/Database/Tests/DatabaseTests/XCTestManifests.swift b/Database/Tests/DatabaseTests/XCTestManifests.swift deleted file mode 100644 index 54655d89..00000000 --- a/Database/Tests/DatabaseTests/XCTestManifests.swift +++ /dev/null @@ -1,9 +0,0 @@ -import XCTest - -#if !canImport(ObjectiveC) - public func allTests() -> [XCTestCaseEntry] { - [ - testCase(DatabaseTests.allTests), - ] - } -#endif diff --git a/Database/Tests/LinuxMain.swift b/Database/Tests/LinuxMain.swift deleted file mode 100644 index 80ca1c70..00000000 --- a/Database/Tests/LinuxMain.swift +++ /dev/null @@ -1,7 +0,0 @@ -import XCTest - -import DatabaseTests - -var tests = [XCTestCaseEntry]() -tests += DatabaseTests.allTests() -XCTMain(tests)