Skip to content
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

Support for "Async" validation #56

Open
mdedetrich opened this issue Dec 1, 2015 · 8 comments
Open

Support for "Async" validation #56

mdedetrich opened this issue Dec 1, 2015 · 8 comments

Comments

@mdedetrich
Copy link

Adding first class support for "Async" validation (i.e. through using scala.concurrent.Future) would enable you to do validation that involves looking up values from Databases or other services (i.e. you would be able to make a validation for UserId which checks if UserId exists), in a performant non blocking way.

scala.concurrent.Future also exists on Scala.js, so this wouldn't effect Scala.js support.

I suppose you would create an asyncValidator which requires something of type Future[T], and just like with normal validation, accord would handle transformations and chains of validations.

One could argue that this could be out of scope for accord, however scala.concurrent.Future is part of stdlib, so it wouldn't add any dependencies.

Would also be willing to make a pull request with the implementation assuming there are no major qualms with the idea

@holograph
Copy link
Contributor

I'm not sure this jives with Accord's fundamental design goals (see discussion on #53), but I'm not yet convinced one way or the other. A sensible baseline implementation would go a long way towards convincing me ;-)

@mdedetrich
Copy link
Author

I am trying an implementation now, its not completely trivial (as that other issue is describing), but I will see how it goes. I am basically making an AsyncValidator/AyncResult types, and probably conversions/lifting (maybe implicit) from the standard types to the AsyncVersions

@holograph holograph self-assigned this Feb 11, 2016
@dsounded
Copy link

+1

@holograph
Copy link
Contributor

@dsounded @mdedetrich Can either of you provide a usage example? A case where this would be useful, and what your ideal syntax would look like?

@dsounded
Copy link

dsounded commented Aug 4, 2016

@holograph Simple example, let's say I want to implement my is unique validation(this is real example) and I need to do a slick select query for getting the result -> Slick returns Future[Something], so basically I need to do sth like result.map(_ > 0) where result is Future[Int] in COUNT(id) from TABLE_NAME where needed_column = needed_value query.

But
new NullSafeValidator[ String ] (
test = { }

needs boolean result, it will be ok if can wrap it in async {} block or just something like new FutureNullSafeValidator[ String ] (

@mdedetrich
Copy link
Author

@holograph My use case is pretty much the same, its when you have validation that depends on a database (or HTTP service or something along these lines), basically anything that returns a Future[T]

I haven't had any time to get a working version, I made an attempt quite some time ago but didn't manage to get a working version (I had issues in making the various apply methods work throughout the validation).

I think if this is to go forward we should probably have a look at how its going to be designed, since once you use the Future monad you basically have to use it everywhere, and we might need stuff like Monad transformers to make the API clean

@holograph
Copy link
Contributor

... which is why I'm not entirely clear on how the the whole thing should work. Returning a Future[Result] fundamentally changes the way Accord is used, and I have two concerns:

  1. I don't see a way to make it backwards-compatible without significantly complicating the (already fairly complicated) API signature. The only idea off the top of my head would be to leverage something like @propensive's "modes" idea (implicits+path-dependent types+dependent method types) in Rapture.io. It ends up very easy to use but even harder to grok at the API level than the standard library's CanBuildFrom.
  2. From a philosophical standpoint, validations should be dead simple and very fast; you don't expect validating a domain object to have effects or be long-running. Introducing a Future-based API is fundamentally opposed to that assumption. That being said, it's my own bias and I certainly won't object to trying it out, providing the previous issue can be suitably resolved.

To actually be able to make progress, I'd like some idea on what the definition API would look like if Futures are supported:

trait FutureValidator[T] {
  def apply(value: T)(implicit ec: ExecutionContext): Future[Result]
}

val aValidDBEntity: FutureValidator[String] = ???

val futurePersonValidator = futureValidator[Person] { p =>
  p.name is notEmpty
  p.address is valid
  p.objectType is aValidDBEntity
}

My concerns here are backwards-compatibility (I don't see how to work around having a FutureValidator type) and reuse (since the DSL would have to be largely duplicated for handling Futures). Ideas would be appreciated...

@ryantheleach
Copy link

I'll be honest I havn't really played much with accord, but as a Scala newbie, I "understand" modes much easier then canBuildFrom

canBuildFrom seems like magic that I can ignore until I run into issues, propensives modes, as long as they are documented, make sense as it's I, the author, importing something which changes the behaviour.

Whilst I don't really understand how either work, at least I feel like i'm in control when I'm using modes.

@holograph holograph removed their assignment Nov 29, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants