-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Schema-abiding smart constructors / setters #87
Comments
Hello! No, theres been no explorartion of any sort like that. What would the API look like? If you're just talking about a conversion |
Thanks for the quick response. I'm not really sure what a builder for a schema-abiding Given this schema: type PersonSchema = [schema|
{
person: {
name: Name,
age: Age
}
}
|] We could define some paths we want to set w/ values. type PathSchema = '[ '("person.name", Name), '("person.age", Age) ]
schemaBuilderPerson :: Proxy PathSchema
schemaBuilderPerson = Proxy In order to ensure we could validate
:: (ValidSchema pathSchema schema)
=> Proxy pathSchema
-> Proxy schema
-> ValidSchemaBuilder pathSchema schema
validate = ValidSchemaBuilder mempty Once the setPersonSchema
:: Name
-> Age
-> ValidSchemaBuilder PersonSchema PathSchema
-> ValidSchemaBuilder PersonSchema '[]
-- ^ the act of calling `set` removes a path in the type-level path list of `ValidSchemaBuilder`.
setPersonSchema name age (ValidSchemaBuilder schema)
= ValidSchemaBuilder $ schema
& set (Proxy @ "person.name") name
& set (Proxy @ "person.age") age And then finally we can encode constructed validSchemaBuilderToJSON :: ValidSchemaBuilder schema '[] -> Value
-- ^ builder ~ '[] in order to make `Value` I haven't really fully fleshed out this idea, but I think the above is possible. |
✨ This is an old work account. Please reference @brandonchinn178 for all future communication ✨ Interesting! Yes, that certainly looks possible, but I'm not sure we need that many new concepts. It should be possible to do something like type PersonSchema = [schema| { person: { name: Name, age: Age } } |]
-- buildObject :: [SomeField] -> Maybe (Object PersonSchema)
buildObject
[ field @'["person", "name"] "Alice"
, field @'["person", "age"] 20
]
data SomeField = forall path a. SomeField (Field path a)
data Field path a = Field
{ path :: [String] -- value-representation of type level 'path'
, value :: a
}
field :: forall path a. All KnownSymbol path => a -> Field path a I'd certainly be open to a PR of that sort Note: somewhat related to #2. |
@brandonchinn178 In your example, is the "person" type save? If I made a typo buildObject
[ field @'["person2", "name"] "Alice"
, field @'["person", "age"] 20
] Would it error? |
No, it wouldn't error in my example, it would return Nothing at runtime, as the object it builds up would have a person key and a person2 key, which doesnt match the PersonSchema schema. Rereading the thread, I guess my example didn't really answer the original question. In general, this problem could be solved in two ways:
Solution (2) / OP's example could be implemented, but I don't see how the example would prevent someone from specifying a PathsSchema that doesnt match PersonSchema. So I think (1) would be better. It could be done with something like data PartialObject paths = UnsafePartialObject [([String], Dynamic)]
set ::
forall path a paths.
(ToJSON a, AllKnownSymbol path) =>
a
-> PartialObject paths
-> PartialObject (path ': paths)
set a (UnsafePartialObject paths) =
UnsafePartialObject $ (getPath @path, toDyn a) : paths
class AllKnownSymbol path where
getPath :: [String]
instance AllKnownSymbol [] where
getPath = []
instance
( KnownSymbol s
, AllKnownSymbol ss
) => AllKnownSymbol (s ': ss) where
getPath = knownSym s : getPath @ss
validate ::
forall schema paths.
Matches schema paths =>
PartialObject paths
-> Object schema
validate (UnsafePartialObject paths) = UnsafeObject (foldr insertPath Map.empty paths)
where
insertPath :: ([String], Dynamic) -> Map Text Dynamic -> Map Text Dynamic
insertPath = _ The hard part here is defining the type family |
Hello 👋🏼
Great work on this library.
I was curious / had a potential feature request. Has there been any exploration into generating smart constructors / setters that would allow a schema-abiding
Value
to be constructed? Would be nice if it could also guarantee all fields / leaves had been populated.Thanks again for this library.
The text was updated successfully, but these errors were encountered: