Compare commits
1 Commits
GRDB-4.0
...
feature/xc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1081515035 |
@ -611,7 +611,7 @@ struct SchemaInfo: Equatable {
|
||||
var sql: String?
|
||||
var isTemporary: Bool
|
||||
|
||||
#if !swift(>=4.2)
|
||||
#if !swift(>=4.1.50)
|
||||
var hashValue: Int {
|
||||
var hash = type.hashValue
|
||||
hash ^= name.hashValue
|
||||
|
||||
@ -290,13 +290,13 @@ struct StatementCache {
|
||||
}
|
||||
|
||||
mutating func remove(_ statement: SelectStatement) {
|
||||
if let index = selectStatements.index(where: { $0.1 === statement }) {
|
||||
if let index = selectStatements.firstIndex(where: { $0.1 === statement }) {
|
||||
selectStatements.remove(at: index)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func remove(_ statement: UpdateStatement) {
|
||||
if let index = updateStatements.index(where: { $0.1 === statement }) {
|
||||
if let index = updateStatements.firstIndex(where: { $0.1 === statement }) {
|
||||
updateStatements.remove(at: index)
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ extension DatabaseCollation: Hashable {
|
||||
// implies hash equality) is thus non trivial. But it's not that
|
||||
// important, since this hashValue is only used when one adds
|
||||
// or removes a collation from a database connection.
|
||||
#if swift(>=4.2)
|
||||
#if swift(>=4.1.50)
|
||||
/// :nodoc:
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(0)
|
||||
|
||||
@ -294,9 +294,15 @@ public final class DatabaseFunction: Hashable {
|
||||
case .string(let string):
|
||||
sqlite3_result_text(sqliteContext, string, -1, SQLITE_TRANSIENT)
|
||||
case .blob(let data):
|
||||
data.withUnsafeBytes { bytes in
|
||||
sqlite3_result_blob(sqliteContext, bytes, Int32(data.count), SQLITE_TRANSIENT)
|
||||
#if swift(>=5.0)
|
||||
data.withUnsafeBytes {
|
||||
sqlite3_result_blob(sqliteContext, $0.baseAddress, Int32($0.count), SQLITE_TRANSIENT)
|
||||
}
|
||||
#else
|
||||
data.withUnsafeBytes {
|
||||
sqlite3_result_blob(sqliteContext, $0, Int32(data.count), SQLITE_TRANSIENT)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,7 +319,7 @@ public final class DatabaseFunction: Hashable {
|
||||
}
|
||||
|
||||
extension DatabaseFunction {
|
||||
#if swift(>=4.2)
|
||||
#if swift(>=4.1.50)
|
||||
/// :nodoc:
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(identity)
|
||||
|
||||
@ -149,7 +149,7 @@ public struct DatabaseValue: Hashable, CustomStringConvertible, DatabaseValueCon
|
||||
// Hashable
|
||||
extension DatabaseValue {
|
||||
|
||||
#if swift(>=4.2)
|
||||
#if swift(>=4.1.50)
|
||||
/// :nodoc:
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
switch storage {
|
||||
|
||||
@ -994,7 +994,7 @@ extension Row {
|
||||
|
||||
// Hashable
|
||||
extension Row {
|
||||
#if swift(>=4.2)
|
||||
#if swift(>=4.1.50)
|
||||
/// :nodoc:
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(count)
|
||||
@ -1317,7 +1317,7 @@ private struct ArrayRowImpl : RowImpl {
|
||||
|
||||
func index(ofColumn name: String) -> Int? {
|
||||
let lowercaseName = name.lowercased()
|
||||
return columns.index { (column, _) in column.lowercased() == lowercaseName }
|
||||
return columns.firstIndex { (column, _) in column.lowercased() == lowercaseName }
|
||||
}
|
||||
|
||||
func copiedRow(_ row: Row) -> Row {
|
||||
@ -1356,7 +1356,7 @@ private struct StatementCopyRowImpl : RowImpl {
|
||||
|
||||
func index(ofColumn name: String) -> Int? {
|
||||
let lowercaseName = name.lowercased()
|
||||
return columnNames.index { $0.lowercased() == lowercaseName }
|
||||
return columnNames.firstIndex { $0.lowercased() == lowercaseName }
|
||||
}
|
||||
|
||||
func copiedRow(_ row: Row) -> Row {
|
||||
|
||||
@ -44,7 +44,7 @@ final class SchedulingWatchdog {
|
||||
}
|
||||
|
||||
static func preconditionValidQueue(_ db: Database, _ message: @autoclosure() -> String = "Database was not used on the correct thread.", file: StaticString = #file, line: UInt = #line) {
|
||||
GRDBPrecondition(current?.allows(db) ?? false, message, file: file, line: line)
|
||||
GRDBPrecondition(current?.allows(db) ?? false, message(), file: file, line: line)
|
||||
}
|
||||
|
||||
static var current: SchedulingWatchdog? {
|
||||
|
||||
@ -189,11 +189,11 @@ final class SerializedDatabase {
|
||||
|
||||
/// Fatal error if current dispatch queue is not valid.
|
||||
func preconditionValidQueue(_ message: @autoclosure() -> String = "Database was not used on the correct thread.", file: StaticString = #file, line: UInt = #line) {
|
||||
SchedulingWatchdog.preconditionValidQueue(db, message, file: file, line: line)
|
||||
SchedulingWatchdog.preconditionValidQueue(db, message(), file: file, line: line)
|
||||
}
|
||||
|
||||
/// Fatal error if a transaction has been left opened.
|
||||
private func preconditionNoUnsafeTransactionLeft(_ db: Database, _ message: @autoclosure() -> String = "A transaction has been left opened at the end of a database access", file: StaticString = #file, line: UInt = #line) {
|
||||
GRDBPrecondition(configuration.allowsUnsafeTransactions || !db.isInsideTransaction, message, file: file, line: line)
|
||||
GRDBPrecondition(configuration.allowsUnsafeTransactions || !db.isInsideTransaction, message(), file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,9 +176,15 @@ public class Statement {
|
||||
case .string(let string):
|
||||
code = sqlite3_bind_text(sqliteStatement, index, string, -1, SQLITE_TRANSIENT)
|
||||
case .blob(let data):
|
||||
code = data.withUnsafeBytes { bytes in
|
||||
sqlite3_bind_blob(sqliteStatement, index, bytes, Int32(data.count), SQLITE_TRANSIENT)
|
||||
#if swift(>=5.0)
|
||||
code = data.withUnsafeBytes {
|
||||
sqlite3_bind_blob(sqliteStatement, index, $0.baseAddress, Int32($0.count), SQLITE_TRANSIENT)
|
||||
}
|
||||
#else
|
||||
code = data.withUnsafeBytes {
|
||||
sqlite3_bind_blob(sqliteStatement, index, $0, Int32(data.count), SQLITE_TRANSIENT)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// It looks like sqlite3_bind_xxx() functions do not access the file system.
|
||||
|
||||
@ -26,14 +26,14 @@ extension DatabaseValueConvertible where Self: ReferenceConvertible, Self.Refere
|
||||
}
|
||||
}
|
||||
|
||||
public extension DatabaseValueConvertible where Self: Decodable & ReferenceConvertible, Self.ReferenceType: DatabaseValueConvertible {
|
||||
extension DatabaseValueConvertible where Self: Decodable & ReferenceConvertible, Self.ReferenceType: DatabaseValueConvertible {
|
||||
public static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Self? {
|
||||
// Preserve custom database decoding
|
||||
return ReferenceType.fromDatabaseValue(databaseValue).flatMap { cast($0) }
|
||||
}
|
||||
}
|
||||
|
||||
public extension DatabaseValueConvertible where Self: Encodable & ReferenceConvertible, Self.ReferenceType: DatabaseValueConvertible {
|
||||
extension DatabaseValueConvertible where Self: Encodable & ReferenceConvertible, Self.ReferenceType: DatabaseValueConvertible {
|
||||
public var databaseValue: DatabaseValue {
|
||||
// Preserve custom database encoding
|
||||
return (self as! ReferenceType).databaseValue
|
||||
|
||||
@ -53,9 +53,15 @@ extension UUID: DatabaseValueConvertible {
|
||||
public static func fromDatabaseValue(_ dbValue: DatabaseValue) -> UUID? {
|
||||
switch dbValue.storage {
|
||||
case .blob(let data) where data.count == 16:
|
||||
#if swift(>=5.0)
|
||||
return data.withUnsafeBytes {
|
||||
UUID(uuid: $0.bindMemory(to: uuid_t.self).first!)
|
||||
}
|
||||
#else
|
||||
return data.withUnsafeBytes {
|
||||
UUID(uuid: $0.pointee)
|
||||
}
|
||||
#endif
|
||||
case .string(let string):
|
||||
return UUID(uuidString: string)
|
||||
default:
|
||||
|
||||
@ -178,13 +178,13 @@ private struct DatabaseValueDecoder: Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
public extension DatabaseValueConvertible where Self: Decodable {
|
||||
extension DatabaseValueConvertible where Self: Decodable {
|
||||
public static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Self? {
|
||||
return try? self.init(from: DatabaseValueDecoder(dbValue: databaseValue, codingPath: []))
|
||||
}
|
||||
}
|
||||
|
||||
public extension DatabaseValueConvertible where Self: Decodable & RawRepresentable, Self.RawValue: DatabaseValueConvertible {
|
||||
extension DatabaseValueConvertible where Self: Decodable & RawRepresentable, Self.RawValue: DatabaseValueConvertible {
|
||||
public static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Self? {
|
||||
// Preserve custom database decoding
|
||||
return RawValue.fromDatabaseValue(databaseValue).flatMap { self.init(rawValue: $0) }
|
||||
|
||||
@ -89,7 +89,7 @@ private struct DatabaseValueEncoder : Encoder {
|
||||
}
|
||||
}
|
||||
|
||||
public extension DatabaseValueConvertible where Self: Encodable {
|
||||
extension DatabaseValueConvertible where Self: Encodable {
|
||||
public var databaseValue: DatabaseValue {
|
||||
var dbValue: DatabaseValue! = nil
|
||||
let encoder = DatabaseValueEncoder(encode: { dbValue = $0 })
|
||||
@ -98,7 +98,7 @@ public extension DatabaseValueConvertible where Self: Encodable {
|
||||
}
|
||||
}
|
||||
|
||||
public extension DatabaseValueConvertible where Self: Encodable & RawRepresentable, Self.RawValue: DatabaseValueConvertible {
|
||||
extension DatabaseValueConvertible where Self: Encodable & RawRepresentable, Self.RawValue: DatabaseValueConvertible {
|
||||
public var databaseValue: DatabaseValue {
|
||||
// Preserve custom database encoding
|
||||
return rawValue.databaseValue
|
||||
|
||||
@ -205,8 +205,8 @@ extension TableRequest where Self: FilteredRequest {
|
||||
return key
|
||||
// Preserve ordering of columns in the unique index
|
||||
.sorted { (kv1, kv2) in
|
||||
let index1 = lowercaseColumns.index(of: kv1.key.lowercased())!
|
||||
let index2 = lowercaseColumns.index(of: kv2.key.lowercased())!
|
||||
let index1 = lowercaseColumns.firstIndex(of: kv1.key.lowercased())!
|
||||
let index2 = lowercaseColumns.firstIndex(of: kv2.key.lowercased())!
|
||||
return index1 < index2
|
||||
}
|
||||
.map { (column, value) in Column(column) == value }
|
||||
|
||||
@ -213,7 +213,7 @@ public struct SQLBinaryOperator : Hashable {
|
||||
return SQLBinaryOperator(negatedSQL, negated: sql)
|
||||
}
|
||||
|
||||
#if !swift(>=4.2)
|
||||
#if !swift(>=4.1.50)
|
||||
/// :nodoc:
|
||||
public var hashValue: Int {
|
||||
return sql.hashValue ^ (negatedSQL?.hashValue ?? 0)
|
||||
|
||||
@ -271,7 +271,7 @@ public class TableAlias: Hashable {
|
||||
return expression.qualifiedExpression(with: self)
|
||||
}
|
||||
|
||||
#if swift(>=4.2)
|
||||
#if swift(>=4.1.50)
|
||||
/// :nodoc:
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(ObjectIdentifier(root))
|
||||
|
||||
@ -439,7 +439,7 @@ public final class TableDefinition {
|
||||
let primaryKeyColumns: [String]
|
||||
if let (columns, _) = primaryKeyConstraint {
|
||||
primaryKeyColumns = columns
|
||||
} else if let index = columns.index(where: { $0.primaryKey != nil }) {
|
||||
} else if let index = columns.firstIndex(where: { $0.primaryKey != nil }) {
|
||||
primaryKeyColumns = [columns[index].name]
|
||||
} else {
|
||||
// WITHOUT ROWID optimization requires a primary key. If the
|
||||
|
||||
@ -887,7 +887,7 @@ extension FetchedRecordsController where Record: MutablePersistableRecord {
|
||||
/// if record could not be found.
|
||||
public func indexPath(for record: Record) -> IndexPath? {
|
||||
let item = Item<Record>(row: Row(record))
|
||||
guard let fetchedItems = fetchedItems, let index = fetchedItems.index(where: { itemsAreIdentical($0, item) }) else {
|
||||
guard let fetchedItems = fetchedItems, let index = fetchedItems.firstIndex(where: { itemsAreIdentical($0, item) }) else {
|
||||
return nil
|
||||
}
|
||||
return IndexPath(indexes: [0, index])
|
||||
|
||||
@ -1263,7 +1263,7 @@ private struct InsertQuery: Hashable {
|
||||
let tableName: String
|
||||
let insertedColumns: [String]
|
||||
|
||||
#if !swift(>=4.2)
|
||||
#if !swift(>=4.1.50)
|
||||
var hashValue: Int { return tableName.hashValue }
|
||||
#endif
|
||||
}
|
||||
@ -1297,7 +1297,7 @@ private struct UpdateQuery: Hashable {
|
||||
let updatedColumns: [String]
|
||||
let conditionColumns: [String]
|
||||
|
||||
#if !swift(>=4.2)
|
||||
#if !swift(>=4.1.50)
|
||||
var hashValue: Int { return tableName.hashValue }
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ struct OrderedDictionary<Key: Hashable, Value> {
|
||||
guard let value = dictionary.removeValue(forKey: key) else {
|
||||
return nil
|
||||
}
|
||||
let index = keys.index { $0 == key }!
|
||||
let index = keys.firstIndex { $0 == key }!
|
||||
keys.remove(at: index)
|
||||
return value
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ func GRDBPrecondition(_ condition: @autoclosure() -> Bool, _ message: @autoclosu
|
||||
/// https://bugs.swift.org/browse/SR-905 and
|
||||
/// https://github.com/groue/GRDB.swift/issues/37
|
||||
if !condition() {
|
||||
fatalError(message, file: file, line: line)
|
||||
fatalError(message(), file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ func cast<T, U>(_ value: T) -> U? {
|
||||
extension Array {
|
||||
/// Removes the first object that matches *predicate*.
|
||||
mutating func removeFirst(_ predicate: (Element) throws -> Bool) rethrows {
|
||||
if let index = try index(where: predicate) {
|
||||
if let index = try firstIndex(where: predicate) {
|
||||
remove(at: index)
|
||||
}
|
||||
}
|
||||
@ -81,3 +81,17 @@ extension DispatchQueue {
|
||||
return DispatchQueue.getSpecific(key: mainKey) != nil
|
||||
}
|
||||
}
|
||||
|
||||
#if !swift(>=4.2)
|
||||
extension Collection {
|
||||
func firstIndex(where predicate:(Element) throws -> Bool) rethrows -> Index? {
|
||||
return try index(where: predicate)
|
||||
}
|
||||
}
|
||||
|
||||
extension Collection where Element: Equatable {
|
||||
func firstIndex(of element: Element) -> Index? {
|
||||
return index(of: element)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -17,56 +17,55 @@ class DataMemoryTests: GRDBTestCase {
|
||||
func testMemoryBehavior() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
try db.execute("CREATE TABLE datas (data BLOB)")
|
||||
// Make sure Data is on the heap (15 bytes is enough)
|
||||
// For more context, see:
|
||||
// https://forums.swift.org/t/swift-5-how-to-test-data-bytesnocopydeallocator/20299/2?u=gwendal.roue
|
||||
let data = Data(repeating: 0xaa, count: 15)
|
||||
|
||||
let data = "foo".data(using: .utf8)
|
||||
try db.execute("INSERT INTO datas (data) VALUES (?)", arguments: [data])
|
||||
|
||||
let rows = try Row.fetchCursor(db, "SELECT * FROM datas")
|
||||
let rows = try Row.fetchCursor(db, "SELECT ?", arguments: [data])
|
||||
while let row = try rows.next() {
|
||||
let sqliteStatement = row.sqliteStatement
|
||||
let sqliteBytes = sqlite3_column_blob(sqliteStatement, 0)
|
||||
let blobPointer = sqlite3_column_blob(row.sqliteStatement, 0)
|
||||
|
||||
do {
|
||||
// This data should be copied:
|
||||
let copiedData: Data = row[0]
|
||||
copiedData.withUnsafeBytes { copiedBytes in
|
||||
XCTAssertNotEqual(copiedBytes, sqliteBytes)
|
||||
}
|
||||
XCTAssertEqual(copiedData, data)
|
||||
copiedData.withBaseAddress { dataPointer in
|
||||
XCTAssertNotEqual(dataPointer, blobPointer)
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
// This data should not be copied
|
||||
let nonCopiedData = row.dataNoCopy(atIndex: 0)!
|
||||
nonCopiedData.withUnsafeBytes { nonCopiedBytes in
|
||||
XCTAssertEqual(nonCopiedBytes, sqliteBytes)
|
||||
}
|
||||
XCTAssertEqual(nonCopiedData, data)
|
||||
nonCopiedData.withBaseAddress { dataPointer in
|
||||
XCTAssertEqual(dataPointer, blobPointer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let row = try Row.fetchOne(db, "SELECT * FROM datas")!
|
||||
let dbValue = row.first!.1
|
||||
let row = try Row.fetchOne(db, "SELECT ?", arguments: [data])!
|
||||
let dbValue = row.first!.1 // TODO: think about exposing a (column:,databaseValue:) tuple
|
||||
switch dbValue.storage {
|
||||
case .blob(let data):
|
||||
data.withUnsafeBytes { (dataBytes: UnsafePointer<UInt8>) -> Void in
|
||||
data.withBaseAddress { dataPointer in
|
||||
do {
|
||||
// This data should not be copied:
|
||||
let nonCopiedData: Data = row[0]
|
||||
nonCopiedData.withUnsafeBytes { nonCopiedBytes in
|
||||
XCTAssertEqual(nonCopiedBytes, dataBytes)
|
||||
}
|
||||
XCTAssertEqual(nonCopiedData, data)
|
||||
nonCopiedData.withBaseAddress { nonCopiedBytes in
|
||||
XCTAssertEqual(nonCopiedBytes, dataPointer)
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
// This data should not be copied:
|
||||
let nonCopiedData = row.dataNoCopy(atIndex: 0)!
|
||||
nonCopiedData.withUnsafeBytes { nonCopiedBytes in
|
||||
XCTAssertEqual(nonCopiedBytes, dataBytes)
|
||||
}
|
||||
XCTAssertEqual(nonCopiedData, data)
|
||||
nonCopiedData.withBaseAddress { nonCopiedBytes in
|
||||
XCTAssertEqual(nonCopiedBytes, dataPointer)
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
@ -75,3 +74,18 @@ class DataMemoryTests: GRDBTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Data {
|
||||
// Helper for comparing data heap pointers, depending on the Swift version
|
||||
fileprivate func withBaseAddress(_ body: (UnsafeRawPointer?) -> Void) {
|
||||
#if swift(>=5.0)
|
||||
withUnsafeBytes {
|
||||
body($0.baseAddress)
|
||||
}
|
||||
#else
|
||||
withUnsafeBytes {
|
||||
body(UnsafeRawPointer($0))
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,11 @@ private extension DatabaseValue {
|
||||
|
||||
private let emojiString = "'fooéı👨👨🏿🇫🇷🇨🇮'"
|
||||
private let emojiData = emojiString.data(using: .utf8)
|
||||
#if swift(>=5.0)
|
||||
private let nonUTF8Data = Data([0x80])
|
||||
#else
|
||||
private let nonUTF8Data = Data(bytes: [0x80])
|
||||
#endif
|
||||
private let invalidString = "\u{FFFD}" // decoded from nonUTF8Data
|
||||
// Until SPM tests can load resources, disable this test for SPM.
|
||||
#if !SWIFT_PACKAGE
|
||||
|
||||
@ -167,10 +167,22 @@ class GRDBTestCase: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
#if !swift(>=4.2)
|
||||
#if !swift(>=4.1.5)
|
||||
extension Sequence {
|
||||
func allSatisfy(_ predicate: (Self.Element) throws -> Bool) rethrows -> Bool {
|
||||
return try !contains(where: { try !predicate($0) })
|
||||
}
|
||||
}
|
||||
|
||||
extension Collection {
|
||||
func firstIndex(where predicate:(Element) throws -> Bool) rethrows -> Index? {
|
||||
return try index(where: predicate)
|
||||
}
|
||||
}
|
||||
|
||||
extension Collection where Element: Equatable {
|
||||
func firstIndex(of element: Element) -> Index? {
|
||||
return index(of: element)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -36,14 +36,14 @@ class IndexInfoTests: GRDBTestCase {
|
||||
let indexes = try db.indexes(on: "citizenships")
|
||||
|
||||
XCTAssertEqual(indexes.count, 2)
|
||||
if let i = indexes.index(where: { $0.columns == ["year"] }) {
|
||||
if let i = indexes.firstIndex(where: { $0.columns == ["year"] }) {
|
||||
XCTAssertEqual(indexes[i].name, "citizenshipsOnYear")
|
||||
XCTAssertEqual(indexes[i].columns, ["year"])
|
||||
XCTAssertFalse(indexes[i].isUnique)
|
||||
} else {
|
||||
XCTFail()
|
||||
}
|
||||
if let i = indexes.index(where: { $0.columns == ["personId", "countryIsoCode"] }) {
|
||||
if let i = indexes.firstIndex(where: { $0.columns == ["personId", "countryIsoCode"] }) {
|
||||
XCTAssertEqual(indexes[i].name, "sqlite_autoindex_citizenships_1")
|
||||
XCTAssertEqual(indexes[i].columns, ["personId", "countryIsoCode"])
|
||||
XCTAssertTrue(indexes[i].isUnique)
|
||||
|
||||
@ -48,9 +48,9 @@ class RowFromDictionaryLiteralTests : RowTestCase {
|
||||
func testRowValueAtIndex() {
|
||||
let row: Row = ["a": 0, "b": 1, "c": 2]
|
||||
|
||||
let aIndex = row.distance(from: row.startIndex, to: row.index(where: { (column, value) in column == "a" })!)
|
||||
let bIndex = row.distance(from: row.startIndex, to: row.index(where: { (column, value) in column == "b" })!)
|
||||
let cIndex = row.distance(from: row.startIndex, to: row.index(where: { (column, value) in column == "c" })!)
|
||||
let aIndex = row.distance(from: row.startIndex, to: row.firstIndex(where: { (column, value) in column == "a" })!)
|
||||
let bIndex = row.distance(from: row.startIndex, to: row.firstIndex(where: { (column, value) in column == "b" })!)
|
||||
let cIndex = row.distance(from: row.startIndex, to: row.firstIndex(where: { (column, value) in column == "c" })!)
|
||||
|
||||
// Raw extraction
|
||||
assertRowRawValueEqual(row, index: aIndex, value: 0 as Int64)
|
||||
@ -140,11 +140,11 @@ class RowFromDictionaryLiteralTests : RowTestCase {
|
||||
func testRowDatabaseValueAtIndex() throws {
|
||||
let row: Row = ["null": nil, "int64": 1, "double": 1.1, "string": "foo", "blob": "SQLite".data(using: .utf8)]
|
||||
|
||||
let nullIndex = row.distance(from: row.startIndex, to: row.index(where: { (column, value) in column == "null" })!)
|
||||
let int64Index = row.distance(from: row.startIndex, to: row.index(where: { (column, value) in column == "int64" })!)
|
||||
let doubleIndex = row.distance(from: row.startIndex, to: row.index(where: { (column, value) in column == "double" })!)
|
||||
let stringIndex = row.distance(from: row.startIndex, to: row.index(where: { (column, value) in column == "string" })!)
|
||||
let blobIndex = row.distance(from: row.startIndex, to: row.index(where: { (column, value) in column == "blob" })!)
|
||||
let nullIndex = row.distance(from: row.startIndex, to: row.firstIndex(where: { (column, value) in column == "null" })!)
|
||||
let int64Index = row.distance(from: row.startIndex, to: row.firstIndex(where: { (column, value) in column == "int64" })!)
|
||||
let doubleIndex = row.distance(from: row.startIndex, to: row.firstIndex(where: { (column, value) in column == "double" })!)
|
||||
let stringIndex = row.distance(from: row.startIndex, to: row.firstIndex(where: { (column, value) in column == "string" })!)
|
||||
let blobIndex = row.distance(from: row.startIndex, to: row.firstIndex(where: { (column, value) in column == "blob" })!)
|
||||
|
||||
guard case .null = (row[nullIndex] as DatabaseValue).storage else { XCTFail(); return }
|
||||
guard case .int64(let int64) = (row[int64Index] as DatabaseValue).storage, int64 == 1 else { XCTFail(); return }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user