Hi Gwendal,
There are no stupid questions — everything helps hammer out this API,
so I appreciate you taking the time to look at this so deeply.
I have to confess that I’m not familiar with this concept, but let’s
take a look:
```swift
if let valueType = T.self as? DatabaseValueConvertible.Type {
// if column is missing, trigger the "missing key" error or return
nil.
} else if let complexType = T.self as? RowConvertible.Type {
// if row scope is missing, trigger the "missing key" error or
return nil.
} else {
// don't know what to do
fatalError("unsupported")
}
```
Is it appropriate for a type which is neither `DatabaseValueConvertible`
nor `RowConvertible` to be decoded with your decoder? If not, then this
warrants a `preconditionFailure` or an error of some sort, right? In
this case, that would be valid.
You also mention that "it’s still impossible to support other Codable
types" — what do you mean by this? Perhaps there’s a way to
accomplish what you’re looking to do.
In any case, one option (which is not recommended unless if there are
other avenues to solve this by) is to perform a "dry run" decoding.
Attempt to decode the type with a dummy decoder to see what container it
will need, then prepare your approach and do it again for real.
Obviously, this isn’t a clean way to do it if we can find
alternatives, but it’s an option.
— Itai
On 29 May 2017, at 4:51, Gwendal Roué via swift-evolution wrote:
Hello,
I have already asked stupid questions about SE-0167 and SE-0166, but
this time I hope this is a real one.
According so SE-0166, codable types themselves instantiate a single
value decoder, or a keyed container:
public struct Farm : Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy:
CodingKeys.self
...
}
}
public enum Animal : Int, Codable {
public init(from decoder: Decoder) throws
let intValue = try
decoder.singleValueContainer().decode(Int.self)
...
}
}
According to SE-0167, decoder decode non-trivial types in their
decode(_:forKey:) and decodeIfPresent(_:forKey:) methods:
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T :
Decodable
func decodeIfPresent<T>(_ type: T.Type, forKey key: Key) throws -> T?
where T : Decodable
My trouble is that the decoder does not know whether the Decodable
type will ask for a keyed container, or for a single value container.
Why is it a problem?
In the context of decoding of SQL rows, keys may refer to different
things, depending on whether we are decoding a *value*, or a *complex
object*:
- for values, keys are column names, as everybody can expect
- for complex objects, keys are names of "row scopes". Row scopes are
a concept introduced by GRDB.swift and allows a type that knows how to
consume `SELECT * FROM table1` to consume as well the results of
`SELECT table1.*, table2.* FROM table1 JOIN table2` through a "scope"
that presents the row in the shape expected by the consumer (here,
only columns from table1).
This is supposed to allow support for types that contain both nested
types and values (one of the goals of SE-0166 and SE-0167):
struct Compound : Codable {
let someStruct: SomeStruct // object that feeds on the "someStruct"
scope
let name: String // value that feeds on the "name" column
}
The two decoding methods decode(_:forKey:) and
decodeIfPresent(_:forKey:) can't be implemented nicely, because they
don't know whether the decodable type will ask for a keyed container
or a single value container, and thus they don't know whether they
should look for the presence of a row scope, or of a column:
A workaround is to perform runtime checks on the GRDB protocols
adopted by T, as below. But it's still impossible to support other
codable types:
if let valueType = T.self as? DatabaseValueConvertible.Type {
// if column is missing, trigger the "missing key" error or return
nil.
} else if let complexType = T.self as? RowConvertible.Type {
// if row scope is missing, trigger the "missing key" error or
return nil.
} else {
// don't know what to do
fatalError("unsupported")
}
Do you have any advice?
Gwendal Roué
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution