Skip to content

Commit 164a8a6

Browse files
committed
Add lazy sequence decoder
1 parent ff4cd63 commit 164a8a6

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

sources/declarative/decodable/Decoder.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,22 @@ extension CSVDecoder {
6060
let source = ShadowDecoder.Source(reader: reader, configuration: self.configuration, userInfo: self.userInfo)
6161
return try T(from: ShadowDecoder(source: source, codingPath: []))
6262
}
63+
64+
/// Returns a sequence for decoding each row from a CSV file (given as a `Data` blob).
65+
/// - parameter data: The data blob representing a CSV file.
66+
/// - throws: `CSVError<CSVReader>` exclusively.
67+
open func lazy(from data: Data) throws -> CSVDecoderSequence {
68+
let reader = try CSVReader(input: data, configuration: self.configuration.readerConfiguration)
69+
let source = ShadowDecoder.Source(reader: reader, configuration: self.configuration, userInfo: self.userInfo)
70+
return CSVDecoderSequence(source: source)
71+
}
72+
73+
/// Returns a sequence for decoding each row from a CSV file (being pointed by `url`).
74+
/// - parameter url: The URL pointing to the file to decode.
75+
/// - throws: `CSVError<CSVReader>` exclusively.
76+
open func lazy(from url: URL) throws -> CSVDecoderSequence {
77+
let reader = try CSVReader(input: url, configuration: self.configuration.readerConfiguration)
78+
let source = ShadowDecoder.Source(reader: reader, configuration: self.configuration, userInfo: self.userInfo)
79+
return CSVDecoderSequence(source: source)
80+
}
6381
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
open class CSVDecoderSequence: IteratorProtocol, Sequence {
2+
private let source: ShadowDecoder.Source
3+
private var currentIndex: Int = 0
4+
5+
init(source: ShadowDecoder.Source) {
6+
self.source = source
7+
}
8+
9+
/// Advances to the next row and returns a `CSVRowDecoder`, or `nil` if no next row exists.
10+
public func next() -> CSVRowDecoder? {
11+
guard !self.source.isRowAtEnd(index: self.currentIndex) else {
12+
return nil
13+
}
14+
15+
defer { self.currentIndex += 1 }
16+
let decoder = ShadowDecoder(source: source, codingPath: [IndexKey(self.currentIndex)])
17+
return CSVRowDecoder(decoder: decoder)
18+
}
19+
}
20+
21+
public struct CSVRowDecoder {
22+
/// The representation of the decoding process point-in-time.
23+
let decoder: ShadowDecoder
24+
25+
/// Returns a value of the type you specify, decoded from CSV row.
26+
/// - parameter type: The type of the value to decode from the supplied file.
27+
/// - throws: `DecodingError`, or `CSVError<CSVReader>`, or the error raised by your custom types.
28+
public func decode<T:Decodable>(_ type: T.Type) throws -> T {
29+
return try T(from: decoder)
30+
}
31+
}

tests/CodableTests/DecodingRegularUsageTests.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ extension DecodingRegularUsageTests {
9191
XCTAssertEqual(pet.gender?.rawValue ?? "", testPet[3])
9292
XCTAssertEqual(pet.animal, testPet[4])
9393
}
94+
95+
for (index, row) in try decoder.lazy(from: input).enumerated() {
96+
let pet = try row.decode(Pet.self)
97+
let testPet = TestData.content[index]
98+
XCTAssertEqual(pet.sequence, Int(testPet[0])!)
99+
XCTAssertEqual(pet.name, testPet[1])
100+
XCTAssertEqual(pet.age, Double(testPet[2])!)
101+
XCTAssertEqual(pet.gender?.rawValue ?? "", testPet[3])
102+
XCTAssertEqual(pet.animal, testPet[4])
103+
}
94104
}
95105
}
96106

0 commit comments

Comments
 (0)