forked from vapor/postgres-kit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPostgresDataEncoder.swift
160 lines (131 loc) · 4.24 KB
/
PostgresDataEncoder.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import Foundation
import protocol PostgresNIO.PostgresJSONEncoder
import var PostgresNIO._defaultJSONEncoder
public final class PostgresDataEncoder {
public let json: PostgresJSONEncoder
public init(json: PostgresJSONEncoder = PostgresNIO._defaultJSONEncoder) {
self.json = json
}
public func encode(_ value: Encodable) throws -> PostgresData {
if let custom = value as? PostgresDataConvertible, let data = custom.postgresData {
return data
} else {
let context = _Context()
try value.encode(to: _Encoder(context: context))
if let value = context.value {
return value
} else if let array = context.array {
let elementType = array.first?.type ?? .jsonb
assert(array.filter { $0.type != elementType }.isEmpty, "Array does not contain all: \(elementType)")
return PostgresData(array: array, elementType: elementType)
} else {
return try PostgresData(jsonb: self.json.encode(_Wrapper(value)))
}
}
}
final class _Context {
var value: PostgresData?
var array: [PostgresData]?
init() { }
}
struct _Encoder: Encoder {
var userInfo: [CodingUserInfoKey : Any] {
[:]
}
var codingPath: [CodingKey] {
[]
}
let context: _Context
func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key>
where Key : CodingKey
{
.init(_KeyedEncoder<Key>())
}
func unkeyedContainer() -> UnkeyedEncodingContainer {
self.context.array = []
return _UnkeyedEncoder(context: self.context)
}
func singleValueContainer() -> SingleValueEncodingContainer {
_ValueEncoder(context: self.context)
}
}
struct _UnkeyedEncoder: UnkeyedEncodingContainer {
var codingPath: [CodingKey] {
[]
}
var count: Int {
0
}
var context: _Context
func encodeNil() throws {
self.context.array!.append(.null)
}
func encode<T>(_ value: T) throws where T : Encodable {
try self.context.array!.append(PostgresDataEncoder().encode(value))
}
func nestedContainer<NestedKey>(
keyedBy keyType: NestedKey.Type
) -> KeyedEncodingContainer<NestedKey>
where NestedKey : CodingKey
{
fatalError()
}
func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
fatalError()
}
func superEncoder() -> Encoder {
fatalError()
}
}
struct _KeyedEncoder<Key>: KeyedEncodingContainerProtocol
where Key: CodingKey
{
var codingPath: [CodingKey] {
[]
}
func encodeNil(forKey key: Key) throws {
// do nothing
}
func encode<T>(_ value: T, forKey key: Key) throws where T : Encodable {
// do nothing
}
func nestedContainer<NestedKey>(
keyedBy keyType: NestedKey.Type,
forKey key: Key
) -> KeyedEncodingContainer<NestedKey>
where NestedKey : CodingKey
{
fatalError()
}
func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
fatalError()
}
func superEncoder() -> Encoder {
fatalError()
}
func superEncoder(forKey key: Key) -> Encoder {
fatalError()
}
}
struct _ValueEncoder: SingleValueEncodingContainer {
var codingPath: [CodingKey] {
[]
}
let context: _Context
func encodeNil() throws {
self.context.value = .null
}
func encode<T>(_ value: T) throws where T : Encodable {
self.context.value = try PostgresDataEncoder().encode(value)
}
}
struct _Wrapper: Encodable {
let encodable: Encodable
init(_ encodable: Encodable) {
self.encodable = encodable
}
func encode(to encoder: Encoder) throws {
try self.encodable.encode(to: encoder)
}
}
}