Language-ext: chain Either<L, R> with Option? - language-ext

I am just starting with language-ext, trying to use it in my Azure Function.
In this function, I first parse/validate the POSTed data from the HTTP request using some validator.
This validator returns an Either<ValidationErrors, RequestModel>.
Then I would like to chain onto the either result a service call that should use the request model to grab some data from an API an return an Option.
At the end of the chain I would then like to return an IActionResult BadRequest if there were ValidationErrors in the first step, or otherwise perform a Match on the result of the service call Option to either return a NotFoundResult or ObjectResult.
The issue I run into is that if I want to chain my service call (using Bind, or BiBind) after the Either<ValidationErrors, GetRequestModel>, then the signature of my service method must be some Either<ValidationErrors, ...>, which is incorrect, since my service method has nothing to do with ValidationErrors. It should just return an Option.
So I guess my question is how can preserve any ValidationErrors until the end of the chain, and be able to chain my service call with a Option signature onto an Either?

You have to decide what the result of your chained expression is.
Option:
var maybeResult = from validated in GetValidationResult(...).ToOption()
from apiResult in ApiCall(...)
select apiResult;
Either:
var resultOrError = from validated in GetValidationResult(...)
from apiResult in ApiCall(...).ToEither(*LEFT*)
select apiResult;
You have to replace *LEFT* by some error value or error generating function returning same type like left type of GetValidationResult.
Replace above pseudo code with your own code and look at the return types of the functions used above to see what's going on.
The reason why you need a common left type is that the bind operation can return some left (error) of first (GetValidationResult) or second (ApiCall) function call -- or right of your last (ApiCall) function if your reach successful end of your chain.
Recommendation: If you mix different left (error) return types you might want to use some thing like LanguageExt's built-in Error type or maybe just a plain string (or Exception).
Either with string as error type:
var resultOrError = from validated in GetValidationResult(...).MapLeft(Prelude.toString)
from apiResult in ApiCall(...).ToEither("api call failed")
select apiResult;
Additional note: I use LINQ style here, you can use method style:
var resultOrError = GetValidationResult(...)
.MapLeft(Prelude.toString)
.Bind(validated => ApiCall(...)
.ToEither("api call failed"));

Related

Matching a method signature with a unknown parameter in a mocked class

I have this method:
Future<Either<Failure, WorkEntity>> updateWorkEntity({int id, String title, TimeType timeType, int times, DateTime executed})
that is being called like this:
repository.updateWorkEntity(id: workEntity.id, executed: DateTime.now())
the id I can control in a test, but the "DateTime.now()" I ofcourse can not. What I tried was this in my test:
when(repository.updateWorkEntity(id: expected.id, executed: any)).thenAnswer((_) async => Right(expected));
to be able to make my mock return a object for my test, by using "any" in the place of the "DateTime.now()", but I get this error:
Invalid argument(s): The "any" argument matcher is used outside of
method stubbing (via when) or verification (via verify or
untilCalled). This is invalid, and results in bad behavior during
the next stubbing or verification.
So I guess I can not use any here, but then how do I get my mock to return an object when I do not control one of the input parameters?
Thank you
Søren
Use executed: anyNamed('executed') instead of executed: any

How to use Database by opening File to send and receive data from Server to Client?

I want to receive data (simply as a string) from the client-web side to update the database, but it's a bit lock for me now, so first write the data to a file in the drive with using System.IO.File.WriteAllText(#"my-file.txt")
I got that error
error FS9001: Method name not found in JavaScript compilation: (receive : System.Object -> unit)
Can you tell me where I did wrong and fix it?
Remoting.fs
Client.fs
Main.fs
WebSharper's client side can call methods that are themselves in [<JavaScript>] scope or marked [<Remote>] for remote calls. The error message is not mentioning the second option, but that is what you need here (same as the sample function DoSomething has it too).
You will also need to make the remote function to not send over an obj but a string. Remote function arguments are deserialized based on type information and cannot be obj. For example in client code, use Server.receive rvInput.Value. (rvInput is a reactive variable for which .Value contains current value)
Note that if you want to return a value to the server, the remote function must be an async. Here, just for logging, returning unit works too, but then you have no way on the server to determine if the logging was successful. By returning an async<unit>, you can catch errors in the client code if you want to guard against connection or server errors. Again, the sample code in the template gives some guidance.
(Cross posting from http://forums.websharper.com/topic/84579)
Here is what your server-side function should look like:
[<Remote>]
let Receive (input: string) =
async {
System.IO.File.WriteAllText(#"D:/myDatabase.txt", "Server received data: " + input)
}
and to call it from Client.fs, you need:
...
button [
on.click (fun _ _ ->
async {
do! Server.Receive rvInput.Value
} |> Async.Start
)
] [text "Receive"]
...

closure verification override default mocking

I have a method looks like this:
public void save(DbSession session,Wrappe wrapper,Wrappe wrappe){
//...other logic
//save wrapper
wrapper=(Wrapper)session.save(wrapper)
//set wrapper's id into wrappee
wrappee.setWrapperId(wrapper.getId());
//save wrappee
session.save(wrappee);
}
and test code looks like this:
given:
session.save(_) >> wrapperWithGeneratedId
when:
obj.save(session,wrapper,wrappee)
then:"wrapper got saved"
1*session.save(_) >> {Wrapper save ->
diffs(wrapper,saved)==null
}
and:"wrappee"
1*session.save(_) >> {Wrappe saved ->
diffs(wrappee,saved)==null
}
These test code will give an exception:
java.lang.ClassCastException: java.lang.Boolean cannot be cast to com.company.model.Wrapper
If commented verification closure in "then" section,test will pass,so I guess this section
1*session.save(_) >> {Wrapper save ->
diffs(wrapper,saved)==null
}
overrode this mocking:
session.save(_) >> wrapperWithGeneratedId
Is any way do both correctly?
1st. 'and' is syntactic sugar. It's just a way to visually separate code within the same block. Your last two mocks are effectively the same (although since you're testing behaviorally it will still verify that save is called twice.)
2nd. Assuming you want to verify thatdiffs(wrapper,saved)==null, that won't currently happen because it's not a 'base level' evaluation. Anything within then/where/closures/etc needs to be prepended with 'assert ' if you want to evaluate it.
3rd. A then block is scoped to its when block and can override existing mocks; your assumption that your mock was being overwritten is correct.
4th. Is there any reason you don't just include your return value alongside your evaluation?
2 * session.save(_) >> {Wrapper save ->
diffs(wrapper,saved)==null
return wrapperWithGeneratedId
}
5th. Your error is due to your mock returning a boolean (your assertion logic) which Groovy then tries (and fails) to parse into a Wrapper. My assumption for why this is happening is that .save() has a return type of Wrapper. To fix that you will either need to create a boolean constructor for Wrapper, or change your mock to return something Groovy can turn into a Wrapper (how-to in point 4)
Official Stub/Mock/Spy documentation (quite good, worth a read)

How the return type of intercept() is used by struts?

I am not able to understand the concept behind the return type of intercept().Is it any time related to the return type of actionInvocationInstance.invoke().Need guidance.Thanks in advance.
It's a String, and should be the name of a result.
It may be the result from invoke, or an interceptor's result that "intercepts" the action invocation, e.g., the workflow interceptor returns "input" on a validation error.
It isn't related, but the ActionInvocation::invoke() can return a result code which is suitable to return by the interceptor's intercept method. It's up to you to decide which result code to return by the interceptor, but the result code type is a String defined as a return type by the method Interceptor::intercept(). Note, that a result code corresponds to the result name in the action config, and a result with such name should be available to the configuration at runtime.

Strange behavior of gorm finder

In a controller I have this finder
User.findByEmail('test#test.com')
And works.
Works even if I write
User.findByEmail(null)
But if i write
User.findByEmail(session.email)
and session.email is not defined (ergo is null) it throw exception
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
Is this behavior right?
If i evaluate "session.email" it give me null so I think it must work as it do when I write
User.findByEmail(null)
Even more strange....
If I run this code in groovy console:
import myapp.User
User.findByEmail(null)
It return a user that has null email but if I run the same code a second time it return
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
You can't use standard findBySomething dynamic finders to search for null values, you need to use the findBySomethingIsNull version instead. Try
def user = (session.email ? User.findByEmail(session.email)
: User.findByEmailIsNull())
Note that even if User.findByEmail(null) worked correctly every time, it would not necessarily give you the correct results on all databases as a findBySomething(null) would translate to
WHERE something = null
in the underlying SQL query, and according to the SQL spec null is not equal to anything else (not even to null). You have to use something is null in SQL to match null values, which is what findBySomethingIsNull() translates to.
You could write a static utility method in the User class to gather this check into one place
public static User byOptEmail(val) {
if(val == null) {
return User.findByEmailIsNull()
}
User.findByEmail(val)
}
and then use User.byOptEmail(session.email) in your controllers.
Jeff Brown from grails nabble forum has identified my problem. It's a GORM bug. see jira
More info on this thread
This jira too
I tried with debugger and it looks it should be working, as you write. Maybe the groovy itself is a little bit confused here, try to help it this way:
User.findByEmail( session['email'] )

Resources