Skip to content

Commit

Permalink
refactor coders to better support json (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanner0101 authored Feb 21, 2020
1 parent f098081 commit 6d1f957
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 130 deletions.
37 changes: 16 additions & 21 deletions Sources/SQLiteKit/SQLiteDataDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ public struct SQLiteDataDecoder {
public func decode<T>(_ type: T.Type, from data: SQLiteData) throws -> T
where T: Decodable
{
return try _decode(T.self, decoder: _Decoder(data: data), data: data, codingPath: [])
if
let type = type as? SQLiteDataConvertible.Type,
let value = type.init(sqliteData: data)
{
return value as! T
} else {
return try T.init(from: _Decoder(data: data))
}
}

private final class _Decoder: Decoder {
Expand All @@ -32,19 +39,19 @@ public struct SQLiteDataDecoder {
}

func jsonDecoder() throws -> Decoder {
guard case .blob(let buffer) = self.data else {
throw DecodingError.valueNotFound(Any.self, .init(
codingPath: self.codingPath,
debugDescription: "Cannot decode JSON from nil data"
))
let data: Data
if case .blob(let buffer) = self.data {
data = Data(buffer.readableBytesView)
} else {
data = .init()
}
return try JSONDecoder()
.decode(DecoderUnwrapper.self, from: Data(buffer.readableBytesView))
.decode(DecoderUnwrapper.self, from: data)
.decoder
}

func singleValueContainer() throws -> SingleValueDecodingContainer {
return _SingleValueDecoder(self)
_SingleValueDecoder(self)
}
}

Expand All @@ -62,20 +69,8 @@ public struct SQLiteDataDecoder {
}

func decode<T>(_ type: T.Type) throws -> T where T: Decodable {
return try _decode(T.self, decoder: self.decoder, data: self.decoder.data, codingPath: self.codingPath)
}
}
}


private func _decode<T>(_ type: T.Type, decoder: Decoder, data: SQLiteData, codingPath: [CodingKey]) throws -> T where T: Decodable {
if let type = type as? SQLiteDataConvertible.Type {
guard let decoded = type.init(sqliteData: data) else {
throw DecodingError.typeMismatch(T.self, DecodingError.Context.init(codingPath: codingPath, debugDescription: "Could not convert \(data) to \(T.self)"))
try SQLiteDataDecoder().decode(T.self, from: self.decoder.data)
}
return decoded as! T
} else {
return try T.init(from: decoder)
}
}

Expand Down
187 changes: 78 additions & 109 deletions Sources/SQLiteKit/SQLiteDataEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,33 @@ import Foundation
public struct SQLiteDataEncoder {
public init() { }

public func encode(_ type: Encodable) throws -> SQLiteData {
if let custom = try _encode(type, codingPath: []) {
return custom
public func encode(_ value: Encodable) throws -> SQLiteData {
if
let custom = value as? SQLiteDataConvertible,
let data = custom.sqliteData
{
return data
} else {
do {
let encoder = _Encoder()
try type.encode(to: encoder)
return encoder.data
} catch is DoJSON {
let json = JSONEncoder()
let data = try json.encode(Wrapper(type))
var buffer = ByteBufferAllocator().buffer(capacity: data.count)
buffer.writeBytes(data)
let encoder = _Encoder()
try value.encode(to: encoder)
switch encoder.result {
case .data(let data):
return data
case .unkeyed, .keyed:
let json = try JSONEncoder().encode(AnyEncodable(value))
var buffer = ByteBufferAllocator().buffer(capacity: json.count)
buffer.writeBytes(json)
return SQLiteData.blob(buffer)
}
}
}

private enum Result {
case keyed
case unkeyed
case data(SQLiteData)
}

private final class _Encoder: Encoder {
var codingPath: [CodingKey] {
return []
Expand All @@ -30,152 +39,112 @@ public struct SQLiteDataEncoder {
var userInfo: [CodingUserInfoKey : Any] {
return [:]
}
var data: SQLiteData

var result: Result
init() {
self.data = .null
self.result = .data(.null)
}

func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key : CodingKey {
return .init(_KeyedValueEncoder(self))
func container<Key>(
keyedBy type: Key.Type
) -> KeyedEncodingContainer<Key>
where Key: CodingKey
{
self.result = .keyed
return .init(_KeyedEncoder())
}

func unkeyedContainer() -> UnkeyedEncodingContainer {
_UnkeyedEncodingContainer(self)
self.result = .unkeyed
return _UnkeyedEncoder()
}

func singleValueContainer() -> SingleValueEncodingContainer {
_SingleValueEncoder(self)
_SingleValueEncoder(encoder: self)
}
}

struct DoJSON: Error {}
private struct _KeyedEncoder<Key>: KeyedEncodingContainerProtocol
where Key: CodingKey
{
var codingPath: [CodingKey] { [] }

struct Wrapper: Encodable {
let encodable: Encodable
init(_ encodable: Encodable) {
self.encodable = encodable
}
func encode(to encoder: Encoder) throws {
try self.encodable.encode(to: encoder)
}
}

private struct _UnkeyedEncodingContainer: UnkeyedEncodingContainer {
var codingPath: [CodingKey] {
self.encoder.codingPath
}
var count: Int {
0
}

let encoder: _Encoder
init(_ encoder: _Encoder) {
self.encoder = encoder
}

mutating func encodeNil() throws {
throw DoJSON()
}

mutating func encode<T>(_ value: T) throws
mutating func encodeNil(forKey key: Key) throws { }
mutating func encode<T>(_ value: T, forKey key: Key) throws
where T: Encodable
{
throw DoJSON()
}

{ }

mutating func nestedContainer<NestedKey>(
keyedBy keyType: NestedKey.Type
keyedBy keyType: NestedKey.Type,
forKey key: Key
) -> KeyedEncodingContainer<NestedKey>
where NestedKey : CodingKey
where NestedKey: CodingKey
{
self.encoder.container(keyedBy: NestedKey.self)
.init(_KeyedEncoder<NestedKey>())
}

mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
self.encoder.unkeyedContainer()
mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
_UnkeyedEncoder()
}

mutating func superEncoder() -> Encoder {
self.encoder
_Encoder()
}
}

private struct _KeyedValueEncoder<Key>: KeyedEncodingContainerProtocol where Key: CodingKey {
var codingPath: [CodingKey] {
return self.encoder.codingPath
}

let encoder: _Encoder
init(_ encoder: _Encoder) {
self.encoder = encoder
mutating func superEncoder(forKey key: Key) -> Encoder {
_Encoder()
}
}

mutating func encodeNil(forKey key: Key) throws {
throw DoJSON()
}
private struct _UnkeyedEncoder: UnkeyedEncodingContainer {
var codingPath: [CodingKey] { [] }
var count: Int = 0

mutating func encode<T>(_ value: T, forKey key: Key) throws where T : Encodable {
throw DoJSON()
}
mutating func encodeNil() throws { }
mutating func encode<T>(_ value: T) throws
where T: Encodable
{ }

mutating func nestedContainer<NestedKey>(
keyedBy keyType: NestedKey.Type,
forKey key: Key
keyedBy keyType: NestedKey.Type
) -> KeyedEncodingContainer<NestedKey>
where NestedKey : CodingKey
where NestedKey: CodingKey
{
self.encoder.container(keyedBy: NestedKey.self)
.init(_KeyedEncoder<NestedKey>())
}

mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
self.encoder.unkeyedContainer()
mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
_UnkeyedEncoder()
}

mutating func superEncoder() -> Encoder {
self.encoder
}

mutating func superEncoder(forKey key: Key) -> Encoder {
self.encoder
_Encoder()
}
}


private struct _SingleValueEncoder: SingleValueEncodingContainer {
var codingPath: [CodingKey] {
return self.encoder.codingPath
}

var codingPath: [CodingKey] { [] }
let encoder: _Encoder
init(_ encoder: _Encoder) {
self.encoder = encoder
}

mutating func encodeNil() throws {
self.encoder.data = .null
self.encoder.result = .data(.null)
}

mutating func encode<T>(_ value: T) throws where T : Encodable {
if let data = try _encode(value, codingPath: self.codingPath) {
self.encoder.data = data
} else {
try value.encode(to: self.encoder)
}
mutating func encode<T>(_ value: T) throws
where T: Encodable
{
let data = try SQLiteDataEncoder().encode(value)
self.encoder.result = .data(data)
}
}
}

private func _encode(_ value: Encodable, codingPath: [CodingKey]) throws -> SQLiteData? {
if let value = value as? SQLiteDataConvertible {
guard let data = value.sqliteData else {
throw EncodingError.invalidValue(value, .init(
codingPath: codingPath,
debugDescription: "Could not encode \(value) to SQLite data"
))
}
return data
} else {
return nil
private struct AnyEncodable: Encodable {
let encodable: Encodable
init(_ encodable: Encodable) {
self.encodable = encodable
}
func encode(to encoder: Encoder) throws {
try self.encodable.encode(to: encoder)
}
}

0 comments on commit 6d1f957

Please sign in to comment.