updates to support encoding configuration
- allows user to configure encoding delimiter with configuration parameter - does not yet support quote wrapping configuration option
This commit is contained in:
parent
b1aac4d7db
commit
77fb41f605
|
@ -33,12 +33,14 @@ public final class CSVEncoder {
|
|||
///
|
||||
/// Currently, this decideds how `nil` and `bool` values should be handled.
|
||||
public var encodingOptions: CSVCodingOptions
|
||||
public var configuration: Config
|
||||
|
||||
/// Creates a new `CSVEncoder` instance.
|
||||
///
|
||||
/// - Parameter encodingOptions: The encoding options the use when encoding an object.
|
||||
public init(encodingOptions: CSVCodingOptions = .default) {
|
||||
public init(encodingOptions: CSVCodingOptions = .default, configuration: Config = Config()) {
|
||||
self.encodingOptions = encodingOptions
|
||||
self.configuration = configuration
|
||||
}
|
||||
|
||||
/// Creates a `CSVSyncEncoder` using the registered encoding options.
|
||||
|
@ -46,7 +48,7 @@ public final class CSVEncoder {
|
|||
/// This encoder is for if you have several objects that you want to encode at
|
||||
/// a single time into a single document.
|
||||
public var sync: CSVSyncEncoder {
|
||||
return CSVSyncEncoder(encodingOptions: self.encodingOptions)
|
||||
return CSVSyncEncoder(encodingOptions: self.encodingOptions, configuration: self.configuration)
|
||||
}
|
||||
|
||||
/// Creates a new `CSVAsyncEncoder` using the registered encoding options.
|
||||
|
@ -59,7 +61,7 @@ public final class CSVEncoder {
|
|||
/// - Returns: A `CSVAsyncEncoder` instance with the current encoder's encoding
|
||||
/// options and the `onRow` closure as its callback.
|
||||
public func async(_ onRow: @escaping ([UInt8]) -> ()) -> CSVAsyncEncoder {
|
||||
return CSVAsyncEncoder(encodingOptions: self.encodingOptions, onRow: onRow)
|
||||
return CSVAsyncEncoder(encodingOptions: self.encodingOptions, configuration: self.configuration, onRow: onRow)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,9 +70,11 @@ public final class CSVEncoder {
|
|||
/// You can get an instance of the `CSVSyncEncoder` with the `CSVEncoder.sync` property.
|
||||
public final class CSVSyncEncoder {
|
||||
internal var encodingOptions: CSVCodingOptions
|
||||
internal var configuration: Config
|
||||
|
||||
internal init(encodingOptions: CSVCodingOptions) {
|
||||
internal init(encodingOptions: CSVCodingOptions, configuration: Config = Config()) {
|
||||
self.encodingOptions = encodingOptions
|
||||
self.configuration = configuration
|
||||
}
|
||||
|
||||
/// Encodes an array of encodable objects into a single CSV document.
|
||||
|
@ -83,7 +87,7 @@ public final class CSVSyncEncoder {
|
|||
var rows: [[UInt8]] = []
|
||||
rows.reserveCapacity(objects.count)
|
||||
|
||||
let encoder = AsyncEncoder(encodingOptions: self.encodingOptions) { row in
|
||||
let encoder = AsyncEncoder(encodingOptions: self.encodingOptions, configuration: self.configuration) { row in
|
||||
rows.append(row)
|
||||
}
|
||||
try objects.forEach(encoder.encode)
|
||||
|
@ -99,9 +103,9 @@ public final class CSVAsyncEncoder {
|
|||
internal var encodingOptions: CSVCodingOptions
|
||||
private var encoder: AsyncEncoder
|
||||
|
||||
internal init(encodingOptions: CSVCodingOptions, onRow: @escaping ([UInt8]) -> ()) {
|
||||
internal init(encodingOptions: CSVCodingOptions, configuration: Config = Config(), onRow: @escaping ([UInt8]) -> ()) {
|
||||
self.encodingOptions = encodingOptions
|
||||
self.encoder = AsyncEncoder(encodingOptions: encodingOptions, onRow: onRow)
|
||||
self.encoder = AsyncEncoder(encodingOptions: encodingOptions, configuration: configuration, onRow: onRow)
|
||||
}
|
||||
|
||||
/// Encodes an `Encodable` object into a row for a CSV document and passes it into
|
||||
|
|
|
@ -5,18 +5,21 @@ final class AsyncEncoder: Encoder {
|
|||
let userInfo: [CodingUserInfoKey : Any]
|
||||
let container: DataContainer
|
||||
let encodingOptions: CSVCodingOptions
|
||||
let configuration: Config
|
||||
let onRow: ([UInt8]) -> ()
|
||||
|
||||
init(
|
||||
path: [CodingKey] = [],
|
||||
info: [CodingUserInfoKey : Any] = [:],
|
||||
encodingOptions: CSVCodingOptions,
|
||||
configuration: Config = Config(),
|
||||
onRow: @escaping ([UInt8]) -> ()
|
||||
) {
|
||||
self.codingPath = path
|
||||
self.userInfo = info
|
||||
self.container = DataContainer(section: .header)
|
||||
self.encodingOptions = encodingOptions
|
||||
self.configuration = configuration
|
||||
self.onRow = onRow
|
||||
}
|
||||
|
||||
|
@ -39,14 +42,14 @@ final class AsyncEncoder: Encoder {
|
|||
switch self.container.section {
|
||||
case .header:
|
||||
try object.encode(to: self)
|
||||
self.onRow(Array(self.container.cells.joined(separator: [44])))
|
||||
self.onRow(Array(self.container.cells.joined(separator: [self.configuration.delimiter.asciiValue ?? 44])))
|
||||
self.container.section = .row
|
||||
self.container.rowCount += 1
|
||||
self.container.cells = []
|
||||
fallthrough
|
||||
case .row:
|
||||
try object.encode(to: self)
|
||||
self.onRow(Array(self.container.cells.joined(separator: [44])))
|
||||
self.onRow(Array(self.container.cells.joined(separator: [self.configuration.delimiter.asciiValue ?? 44])))
|
||||
self.container.rowCount += 1
|
||||
self.container.cells = []
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ final class AsyncKeyedEncoder<K>: KeyedEncodingContainerProtocol where K: Coding
|
|||
func encode(_ value: String, forKey key: K) throws { self._encode(value.bytes, for: key) }
|
||||
|
||||
func encode<T>(_ value: T, forKey key: K) throws where T : Encodable {
|
||||
let encoder = AsyncEncoder(encodingOptions: self.encoder.encodingOptions, onRow: self.encoder.onRow)
|
||||
let encoder = AsyncEncoder(encodingOptions: self.encoder.encodingOptions, configuration: self.encoder.configuration, onRow: self.encoder.onRow)
|
||||
try value.encode(to: encoder)
|
||||
self._encode(encoder.container.cells[0], for: key)
|
||||
}
|
||||
|
|
|
@ -88,16 +88,20 @@ public struct Serializer {
|
|||
/// - Returns: A `Result` instance with a `.failure` case with all the errors from the the `.onRow` callback calls.
|
||||
/// If there are no errors, the result will be a `.success` case.
|
||||
@discardableResult
|
||||
public mutating func serialize<Data>(_ data: Data) -> Result<Void, ErrorList> where
|
||||
public mutating func serialize<Data>(_ data: Data, configuration: Config = Config()) -> Result<Void, ErrorList> where
|
||||
Data: KeyedCollection, Data.Key: BytesRepresentable, Data.Value: Collection, Data.Value.Element: BytesRepresentable,
|
||||
Data.Value.Index: Strideable, Data.Value.Index.Stride: SignedInteger
|
||||
{
|
||||
var errors = ErrorList()
|
||||
guard data.count > 0 else { return errors.result }
|
||||
|
||||
guard let delimiterASCII = configuration.delimiter.asciiValue else { return errors.result }
|
||||
|
||||
if !self.serializedHeaders {
|
||||
let headers = data.keys.map { title in Array([[34], title.bytes, [34]].joined()) }
|
||||
do { try self.onRow(Array(headers.joined(separator: [10]))) }
|
||||
print(headers)
|
||||
print(Array(headers.joined(separator: [delimiterASCII])))
|
||||
do { try self.onRow(Array(headers.joined(separator: [delimiterASCII]))) }
|
||||
catch let error { errors.errors.append(error) }
|
||||
self.serializedHeaders = true
|
||||
}
|
||||
|
@ -107,7 +111,7 @@ public struct Serializer {
|
|||
let cells = data.values.map { column -> [UInt8] in
|
||||
return Array([[34], column[index].bytes, [34]].joined())
|
||||
}
|
||||
do { try onRow(Array(cells.joined(separator: [10]))) }
|
||||
do { try onRow(Array(cells.joined(separator: [delimiterASCII]))) }
|
||||
catch let error { errors.errors.append(error) }
|
||||
}
|
||||
|
||||
|
@ -129,7 +133,7 @@ public struct SyncSerializer {
|
|||
///
|
||||
/// - Parameter data: The dictionary (or other object) to parse.
|
||||
/// - Returns: The serialized CSV data.
|
||||
public func serialize<Data>(_ data: Data) -> [UInt8] where
|
||||
public func serialize<Data>(_ data: Data, configuration: Config = Config()) -> [UInt8] where
|
||||
Data: KeyedCollection, Data.Key: BytesRepresentable, Data.Value: Collection, Data.Value.Element: BytesRepresentable,
|
||||
Data.Value.Index: Strideable, Data.Value.Index.Stride: SignedInteger
|
||||
{
|
||||
|
@ -137,7 +141,7 @@ public struct SyncSerializer {
|
|||
rows.reserveCapacity(data.first?.value.count ?? 0)
|
||||
|
||||
var serializer = Serializer { row in rows.append(row) }
|
||||
serializer.serialize(data)
|
||||
serializer.serialize(data, configuration: configuration)
|
||||
|
||||
return Array(rows.joined(separator: [10]))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue