-
Notifications
You must be signed in to change notification settings - Fork 2
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
Adds support for extensible validation #41
Conversation
The new `Validator` associated type and `FleeceValidator` superclass constraint on the `Fleece` class allow extensions to validation beyond lifting Haskell functions via constraints on the `Validator schema` type. See the `CustomValidator` class and `SchemaValidatorInfo` instance in `json-fleece-examples` for an example.
1df2eaa
to
d5d98fe
Compare
Also added an example of how to use the validator to create a conversion function.
Just FYI - I plan to review this but it will take me a little while to get to at the moment. I think this is not blocking something else at the moment, right? |
Right, it isn't blocking anything. |
|
||
class Fleece schema where | ||
class FleeceValidator (Validator schema) => Fleece schema where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the biggest drawback of the PR, I think. It means coming into the library the base thing to learn isn't a schema, but is now a Validator. That said, I don't have at the moment a great idea on how to change this, but the introduction/beginner friendliness is something we should consider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of type family features means the internals of fleece have never been beginner friendly. So I don't think any potential user base is lost. But it would be good to add more comments to explain the context. Something like "FleeceValidator means you can run arbitrary validation, but still have that validation serialize to e.g. OpenAPI." Not sure if that documentation should be here though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ysangkok Notably this isn't about the internals. This is about what you'd be exposed to as a user of the library. One might say "Oh I need an implementation of the Fleece
class. Let me see what that is.." after which they would immediately be hit by another class to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I call it internals because you can achieve so much with Fleece by just working with examples using #+
, FC.object
, FC.required
and FC.constructor
and the base schemas. Without ever looking inside Class.hs
. It wasn't the first thing I when starting to work with Fleece. So I think it's still fair to call these internals. If what's in Class.hs
isn't internals, I don't know what would be. class Fleece
is the very heart of it to me.
Maybe it's not important anyway, whether the heart is internal or not. Regardless of whether these are internals or not, maybe it's too complicated. It's my impression that it's worth the cost, when I heard about how even the stock schemas can be represented using these validation primitives.
If we can't get sufficient consensus that this is worthwhile, I'd prefer for this to be closed with a conclusion instead of having this linger for months.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is the right place to worry about being beginner friendly because implementing the Fleece
class isn't something that a beginner is expected to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but the introduction/beginner friendliness is something we should consider
Thinking about this more. You're right that we should consider those things, and I agree that the superclass constraint makes it more difficult to understand the Fleece
class. I think the superclass is an ergonomic way to model the relationship between the two classes.
Another option I considered was renaming Fleece
to FleeceSchema
and exporting a constraint:
type Fleece schema = (FleeceSchema schema, FleeceValidator (Validator schema))
That's probably fine too but is less pleasant to work with.
Or we could flatten the classes like this instead:
class Fleece schema where
-- ...
-- Use data instead of type
data Validator schema :: Type -> Type -> Type
-- ...
-- Add the methods from the FleeceValidator class directly to Fleece
mkValidator :: (b -> a) -> (a -> Either String b) -> Validator schema a b
compose :: Validator schema b c -> Validator schema a b -> Validator schema a c
With the flattened approach you lose the ability to treat a validator as something distinct from a schema. I don't think it simplifies things enough to justify losing the separate FleeceValidator
class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@telser do you have further concerns regarding your original comment that haven't been addressed?
Closed for now due to inactivity. |
The new
Validator
associated type andFleeceValidator
superclass constraint on theFleece
class allow extensions to validation beyond lifting Haskell functions, via constraints on theValidator schema
type.See the
CustomValidator
class andSchemaValidatorInfo
instance injson-fleece-examples
for an example.