ModelMapper - condition AND provider - conditional-statements

All -
I'm trying to do an "addmapping" with a condition and a provider... bottom line is, one of my values are an Instant, and without the provider, it blows up telling me that Instant doesnt have a default constructor (which it doesnt)
I've gotten this far:
.addMappings(mapper -> {
mapper.when(ctx -> customerSource(ctx).getEnableDuplicatePOChangedTime().isDirty())
.<Instant>map(src -> src.getEnableDuplicatePOChangedTime().getValue(), (dest, v) -> dest.setEnableDuplicatePOChangedTime(v));
mapper.with(req -> req.getSource()).<Instant>map(src -> src.getEnableDuplicatePOChangedTime().getValue(), (dest, v) -> dest.setEnableDuplicatePOChangedTime(v));
})
However, what seems to happen now is, it skips the condition all together - it maps it no matter what!
In debug, this seems to overwrite the condition, setting it to null.
Any thoughts??

well, I seemed to figure it out by using a provider up front, and getting rid of the add mappings.... so it would be something like this
.setProvider(request -> {
CustomerPreferencesDirty source = CustomerPreferencesDirty.class.cast(request.getSource());
PreferencesByCustomer dest = new PreferencesByCustomer();
if (source.getEnableDuplicatePOChangedTime().isDirty()) {
dest.setEnableDuplicatePOChangedTime(source.getEnableDuplicatePOChangedTime().getValue());
return dest;
})
and then I continue on with addMappings for properties other than this one.... I'm good with that.

Related

Godot/GDScript Grid Movement Tweening

So I've been using KidsCanCode's Godot tutorials/documentation to help me create a Pokemon-like grid-based movement for a project I'm working on. For all intents and purposes, I would like to create a movement system as close to that in the earlier handheld Pokemon games as possible.
I would like to add two things before I start; one, I have grown fond of the way KidsCanCode attempted to teach grid-based movement, so while other ways of coding it may be simpler such as those that can be found on videos such as this one (https://www.youtube.com/watch?v=jSv5sGpnFso), I would like to hard-headidly stick to this method of coding it... you'll see what I mean when you read the code. Lastly, I would like to add that I had this code working before ! I actually haven't made any changes to the code since it was last working, however, for some reason it no longer seems to work, I'm not sure if that's due to Godot updating since, but hopefully someone can help me out with that.
So first of all, this is my player scene node tree. The most important parts of this being the RayCast2D and Tween nodes.
And this is my code for the main Area2D Player node:
extends Area2D
const tile_size = 16
export var speed = 5
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
func _ready():
position = position.snapped(Vector2.ONE * tile_size/2)
func _unhandled_input(event):
if $Tween.is_active():
return
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(inputs[dir])
func move(dir):
$RayCast2D.cast_to = inputs[dir] * tile_size
$RayCast2D.force_raycast_update()
if !$RayCast2D.is_colliding():
move_tween(dir)
func move_tween(dir):
$Tween.interpolate_property(self, "position", position,
position + inputs[dir] * tile_size, 1.0/speed, Tween.TRANS_SINE, Tween.EASE_IN_OUT)
$Tween.start()
To quickly explain, func _ready(): snaps the player to the grid. func _unhandled_input(event): then checks to see if a Tween is occurring, and if not, calls func move(dir). This function raycasts to the given direction input, forces a raycast update, and if no static body is in the given direction, calls func move_tween(dir). This last functions handles tween interpolation to the given direction and starts the tweening process. That's pretty much it. Once again, this used to work just fine.
However, now when I try to run this, I get an error "Invalid get index '(0, 1)' (on base: 'Dictionary')" where "(0, 1)" changes based on what direction I tried to move in when the game was running.
In the Debugger dock, underneath Stack Frames, it gives me errors on lines "22 - at function; move" $RayCast2D.cast_to = inputs[dir] * tile_size and "19 - at function: _unhandled_input" move(inputs[dir]).
The code on the website had these say (dir) only instead of (inputs[dir]). But doing so only gives me another error. If anyone smarter than me has any idea what's going on, I would very much appreciate any and all insight. Thank you !
Understanding the problem
Alright, let us see. The variable inputs has your dictionary:
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
The keys are String, and the values are Vector2.
Thus, here:
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(inputs[dir])
The variable dir is going to be a String. Which is what you need for is_action_pressed, so that is correct.
And inputs[dir] is going to be a Vector2. Which means that in move you are getting a Vector2 as argument.
Now, in move you say::
func move(dir):
$RayCast2D.cast_to = inputs[dir] * tile_size
But remember that the argument you are passing is a Vector2, and the keys of input are all String. So it fails here: inputs[dir].
Early warning for similar problems
Using types can help you identify this kind of problems early. Sadly in Godot 3.x there is no way to specify the the keys and values of a Dictionary.
Arguably you could use C# and use .NET Dictionary<TKey,TValue> from the System.Collections.Generic, which would let you specify the key and value types. Yet, we are not talking about those dictionaries here.
What you can tell with GDScript is that your parameters are either Vector2:
func move(displacement:Vector2):
# …
Or String
func move(dir:String):
# …
This way Godot can tell you when you are calling them with the wrong parameter.
Another thing that will help. Although it is more on the discipline side, is to keep consistent names. If the names you use have a concrete meaning in your system, they will help you.
For instance, you call move like this:
move(inputs[dir])
Meaning that what you are passing is not called dir※. But you have move defined like this:
func move(dir):
# …
So move expects something you call a dir. And you would see that when you are typing the call to move.
※: I'd say you are passing one of the values of inputs, so what you are passing is called an input. Or you could call them action, given that you use them in is_action_pressed. Which, again, would be using names in a way that helps you.
Solving the problem
The way I would solve this is by using the String and inputs in _unhandled_input only (after all, that function is meant to deal with inputs). And work with Vector2 from there on. This means that:
The other methods would also be useful if in the future you wanted a movement that does not come from one of the inputs.
You are not repeating the effort of looking up in the Dictionary.
Admittedly, these aren't a huge deal for your game right now. And ultimately what you do is up to you. Yet, consider this approach submitted to your consideration.
This is the code (I have added some type annotations):
extends Area2D
const tile_size:float = 16
export var speed:float = 5
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
func _ready():
position = position.snapped(Vector2.ONE * tile_size/2)
func _unhandled_input(event:InputEvent) -> void:
if $Tween.is_active():
return
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(inputs[dir])
func move(displacement:Vector2) -> void:
$RayCast2D.cast_to = displacement * tile_size
$RayCast2D.force_raycast_update()
if !$RayCast2D.is_colliding():
move_tween(displacement)
func move_tween(displacement:Vector2) -> void:
$Tween.interpolate_property(self, "position", position,
position + displacement * tile_size, 1.0/speed, Tween.TRANS_SINE, Tween.EASE_IN_OUT)
$Tween.start()
Or you can using String thought out, and querying the dictionary every time. Which, I believe, is what you intended. Like this:
extends Area2D
const tile_size:float = 16
export var speed:float = 5
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
func _ready():
position = position.snapped(Vector2.ONE * tile_size/2)
func _unhandled_input(event:InputEvent) -> void:
if $Tween.is_active():
return
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(dir)
func move(dir:String) -> void:
$RayCast2D.cast_to = input[dir] * tile_size
$RayCast2D.force_raycast_update()
if !$RayCast2D.is_colliding():
move_tween(dir)
func move_tween(dir:String) -> void:
$Tween.interpolate_property(self, "position", position,
position + input[dir] * tile_size, 1.0/speed, Tween.TRANS_SINE, Tween.EASE_IN_OUT)
$Tween.start()
Notice here that _unhandled_input is passing dir to move. The same way that move is passing dir to move_tween.

Kotlin Stateflow get one-but-last value

In my viewModel i have a StateFlow<Destination>, with those values:
enum class Destination {
FIRST_SCREEN,
SECOND_SCREEN,
THIRD_SCREEN,
FOURTH_SCREEN,
}
Somewhere in my activity i use this flow for navigation:
viewModel.destinations[...]
.collect { destination ->
fragmentManager.navigateTo(
when(destination){
FIRST_SCREEN -> FirstScreenFragment(),
SECOND_SCREEN -> SecondScreenFragment(),
THIRD_SCREEN -> ThirdScreenFragment(),
FOURTH_SCREEN -> FourthScreenFragment(),
}
)
}
...where navigateTo() is very simple in the moment
fun FragmentManager.navigateTo(fragment: Fragment) {
beginTransaction()
.replace(R.id.contentFragment, fragment)
.commit()
}
I would now like to add transitions ~ like in a viewPager.
The animations themselves are a piece of cake, but i need to know in which direction to animate:
Am i moving "forward" or "backward", which boils down to:
Is my current destination < or > my new destination?
i could use the fragment-backstack (but i and a few others hate it)
i could simply use a variable in my activity storing the last screen we navigated to, but that feels hacky
i could try to use flows for that, but i have no real idea how to do that. Any suggestions?
An optimal usage would look like:
viewModel.destinations[...]
.rememberHistory()
.collect { currentDestination, lastDestination ->
}
For those wondering how i solved this:
I used runningFold
data class DestinationHistory(val previous: Destination?, val current: Destination)
val destinationHistory: Flow<DestinationHistory> = destination.runningFold(
initial = DestinationHistory(previous = null, current = Destination.FIRST_SCREEN)
) { history, newDestination ->
DestinationHistory(
previous = history.current,
current = newDestination
)
}
Effectively this maps the destination-flow to a "pair" of previous & current destination.

Async Wait Efficient Execution

I need to iterate 100's of ids in parallel and collect the result in list. I am trying to do it in following way
val context = newFixedThreadPoolContext(5, "custom pool")
val list = mutableListOf<String>()
ids.map {
val result:Deferred<String> = async(context) {
getResult(it)
}
//list.add(result.await()
}.mapNotNull(result -> list.add(result.await())
I am getting error at
mapNotNull(result -> list.add(result.await())
as await method is not available. Why await is not applicable at this place? Instead commented line
//list.add(result.await()
is working fine.
What is the best way to run this block in parallel using coroutine with custom thread pool?
Generally, you go in the right direction: you need to create a list of Deferred and then await() on them.
If this is exactly the code you are using then you did not return anything from your first map { } block, so you don't get a List<Deferred> as you expect, but List<Unit> (list of nothing). Just remove val result:Deferred<String> = - this way you won't assign result to a variable, but return it from the lambda. Also, there are two syntactic errors in the last line: you used () instead of {} and there is a missing closing parenthesis.
After these changes I believe your code will work, but still, it is pretty weird. You seem to mix two distinct approaches to transform a collection into another. One is using higher-order functions like map() and another is using a loop and adding to a list. You use both of them at the same time. I think the following code should do exactly what you need (thanks #Joffrey for improving it):
val list = ids.map {
async(context) {
getResult(it)
}
}.awaitAll().filterNotNull()

Why .map on a mutableList doesn't actually change values inside of List in Kotlin?

This is what I have and what I want to achieve:
I have a class which has a mutableList as a field.
I want to find a specific element inside that list and change it.
This is what I've tried so far:
This is the functional statement I was hoping would have worked, after I've also put it in an Extension function:
fun Classroom.setNewParameters(id: String, modifiedName: String) {
this.students.filter { l -> l.id == id }
.map { l -> l.name = modifiedName }
.toList()
}
But the list students appears to be unchanged after this function is called.
I found an "ugly" solution with the code below:
fun Classroom.setNewParameters(id: String, modifiedName: String) {
for (l : Student in this.students) {
if (l.id == id) {
l.name = modifiedName
break
}
}
}
Still tho, I'd really like to know why the first block of code behaves like it does and doesn't actually have any effect on the list.
You can think of map as a way to transform input to get new output. Normally it should not mutate state inside, in other words it should be a function without side effects to pursue maintainability
In your case you clearly want to mutate elements, for that you might want to use that code snippet:
fun Classroom.setNewParameters(id: String, modifiedName: String) {
this.students.filter { l -> l.id == id }
.onEach { l -> l.name = modifiedName }
}
Also, even you used map incorrectly it should must modify field l.name (unless you have implemented you own delegates or getter/setter). Try to debug set breakpoint on this.students.filter { l -> l.id == id } and see if there are any items left after filtering
Noob here but I did just see something related to this the other day.
Is there a reason you wouldn't just check to see if your array contains the old value, return the element id and then assign your new value to that id?
I guess I'm just pointing out that this could be accomplished with a "value in array" type search... but I'm still too new to know the pros and cons of using it vs map.
Kind of like this below, which I got from Kotlin - Idiomatic way to check array contains value
"value" in array
Which translates into the Java API:
array.contains("value")
So I'd check for the old value in the array, return it's index and then reassign that index with the new value.

How to get Result<T, E1> aligned with Result<T,E2>?

I have this code
fn get_last_commit () -> String {
Command::new("git")
.arg("rev-parse")
.arg("HEAD")
.output()
.map(|output| {
String::from_utf8(output.stdout).ok().expect("error reading into string")
})
.ok().expect("error invoking git rev-parse")
}
I'd like to be able to cut the ok().expect(..) a bit down so that I ideally have something like that:
fn get_last_commit () -> String {
Command::new("git")
.arg("rev-parse")
.arg("HEAD")
.output()
.and_then(|output| {
String::from_utf8(output.stdout)
})
.ok().expect("error invoking git rev-parse")
}
However, that doesn't work because the errors don't line up leaving me with:
mismatched types:
expected `core::result::Result<_, std::io::error::Error>`,
found `core::result::Result<collections::string::String, collections::string::FromUtf8Error>`
(expected struct `std::io::error::Error`,
found struct `collections::string::FromUtf8Error`)
I know the error handling changed quite a bit within the last month and I have the feeling there should be away to get them aligned without too much hassle. I seem unable to figure it out though.
The problem is that the closure passed to the and_then needs to return a Result with the same error type as the Result that and_then was called on; otherwise, there's no single type that and_then could return; and_then maps one Ok type to another, but keeps the error type the same.
Since you are just throwing away the error value by converting it to an option with ok() that you unwrap anyhow, you can do that before calling and_then, and within the closure, as the Option type returned by and_then on an Option only depends on the value returned by the closure:
fn get_last_commit () -> String {
Command::new("git")
.arg("rev-parse")
.arg("HEAD")
.output()
.ok()
.and_then(|output| {
String::from_utf8(output.stdout).ok()
})
.expect("error invoking git rev-parse")
}
If you actually cared about the error value, you would need to define your own error type that could contain either of the two types of errors, and wrap either of the errors up. The FromError trait and try! macro offer a convenient way to is wrap up the value and return it from one of several places in your function, though in this case map_err would probably be a better way to do that as you are doing it all via chained method calls rather than separate statements.
enum MyError {
Io(IoError),
Utf8(FromUtf8Error)
}
fn get_last_commit () -> Result<String,MyError> {
Command::new("git")
.arg("rev-parse")
.arg("HEAD")
.output()
.map_err(MyError::Io)
.and_then(|output| {
String::from_utf8(output.stdout)
.map_err(MyError::Utf8)
})
}
If you notice, this parallels the earlier solution fairly closely, coercing both of the result types into a single common type; in the first solution, it just throws away the error value by using ok(), while in the second, it preserves the error value so you can return it, but you now need the extra machinery of a type that could wrap either.