BehaviorSubject with transformation - rx-swift

Is there a way to return a transformed BehaviorSubject?
class ViewModel {
let username: BehaviorSubject<String>
init() {
// I want username to emit trimmed values...
username = BehaviorSubject<String>(value: "")
// ... but map returns an Observable<>, not BehaviorSubject
.map { $0.trimmingCharacters(in: CharacterSet.whitespaces)
}
}

The short answer is no, there is no way to return a transformed BehaviorSubject.
You have to first define the output that you want to affect, then figure out what inputs affect it. The map will go between those. So for example:
myTextField.rx.text.orEmpty
.map { $0.trimmingCharacters(in: CharacterSet.whitespaces)
.bind(to: username)
.disposed(by: disposeBag)
If you want username to be the output, or
username.asObservable() // I'm not sure if the asObservable() is actually necessary at the moment. Check that.
.map { $0.trimmingCharacters(in: CharacterSet.whitespaces)
.bind(to: myLabel.rx.text)
.disposed(by: disposeBag)
if you want username to be the input.
To create a username just use let username = BehaviorSubject<String>()

Related

I don't know why edge generate doesn't work in entgo

i'm trying build app by golang and entgo and falling problem about entgo generate,
https://entgo.io/
below is user table code
type user table
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("nickname").NotEmpty().Unique(),
field.String("user_type").Default("guest"),
field.Time("created_at").Default(time.Now()),
field.Time("updated_at").Default(time.Now()).UpdateDefault(time.Now()),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("token", Token.Type),
}
}
and below is about token
// Token holds the schema definition for the Token entity.
type Token struct {
ent.Schema
}
// Fields of the Token.
func (Token) Fields() []ent.Field {
return []ent.Field{
field.String("token"),
field.Int("user_id"),
field.Time("created_at").Default(time.Now()),
field.Time("updated_at").Default(time.Now()).UpdateDefault(time.Now()),
}
}
// Edges of the Token.
func (Token) Edges() []ent.Edge {
return []ent.Edge{
edge.From("user", User.Type).Ref("users").Field("user_id"),
}
}
and im try generate entgo like this
go generate ./ent
but it is not working and i give error like below,
entc/gen: resolve "Token" relations: edge "users" is missing for inverse edge: Token.user(User)
exit status 1
i dont know what
I don't know what's wrong, please help
You've reversed the order of edge.To / edge.From.
See the ent docs:
A schema that defines an edge using the edge.To builder owns the relation, unlike using the edge.From builder that gives only a back-reference for the relation (with a different name).
From your example it looks like you're trying to achieve a O2M relation where a User can have many Tokens associated.
Change the Edges methods on both structs to be:
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.From("token", Token.Type).
Ref("users"),
}
}
and
// Edges of the Token.
func (Token) Edges() []ent.Edge {
return []ent.Edge{
edge.To("users", User.Type).
Unique().
Field("user_id").
Required(),
}
}

Unable to iterate over stream inside use{} block

I just want to print name of every user stored in database.
I am using this repository:
#Repository
interface User: JpaSpecificationExecutor<User>, PagingAndSortingRepository<User, Long> {
#Query("from User")
fun findAllUsers(): Stream<User>
}
inside this Service:
#Service
class MyService(val user: User) {
private val log = LoggerFactory.getLogger(javaClass)
#Transactional(readOnly = true)
fun printNames() {
log.info("here")
user.findAllUsers().use { users ->
users.map { it.firstName }
}
}
}
and it prints only here in console, but no name.
It seems like map() automatically closed the stream but I don`t know why and how to workaround it. When I put inside of use{} block only log.info(users.count()) it prints number of users stored in database. So there is a user I can print.
My question is, how can I print all names from the given stream?
Kotlin's use function is just a short-hand way of executing some code (your closure function) and then call close on the receiver (in this case the Stream) once done.
What you called users is actually the Stream<User>returned by your repository, so basically your code is just calling users.map {...}. Now, the map operator is an intermediate operator, and since Java streams are lazy, they won't actually do anything until you call a terminal operator (such as .collect or .forEach).
Assuming you want to print the user, try with:
user.findAllUsers().use {
it.forEach { println(it.firstName) }
}
Full working example (without Spring data):
import java.util.stream.Stream
// simulate a repository
fun findAllUsers() = Stream.of("First", "Second", "Third")
fun printNames() {
findAllUsers().use {
it.forEach(::println)
}
}
fun main() {
printNames()
}
Prints:
First
Second
Third

Use Value of Result Mono from DB Request in Another Request

I want to get a user by his username, assign this user as the author of a note and then save that note to the database. The problem is that I get a Mono with a user in it and I can't assign that to the author field of type user.
What I'm trying to do:
noteRepository
.save(noteMapper
.fromDTO(noteDTO)
.apply { owner = userReository
.findByUsername(userPrincipalService.getCurrentUserPrincipal()
.map { it.username })
})
userRepository
// Find the User
.findByUsername(userPrincipalService.getCurrentUserPrincipal()
.map { it.username })
// Map the User to a Note, while setting the note's owner
.map { user ->
noteMapper.fromDTO(noteDTO).apply {
owner = user
}
}
// Save the Note
.flatMap { note -> noteRepository.save(note) }

How to check if Mono is empty?

I'm developing a app with Spring Boot 2.0 and Kotlin using the WebFlux framework.
I want to check if a user id exits before save a transaction. I'm stucked in a simple thing like validate if a Mono is empty.
fun createTransaction(serverRequest: ServerRequest) : Mono<ServerResponse> {
val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java))
transaction.flatMap {
val user = userRepository.findById(it.userId)
// If it's empty, return badRequest()
}
return transaction.flatMap { transactionRepository.save(it).then(created(URI.create("/transaction/" + it.id)).build()) }
}
It is possible to do what I want?
The techniques that allow checking whether Flux/Mono is empty
Using operators .switchIfEmpty/.defaultIfEmpty/Mono.repeatWhenEmpty
Using mentioned operators you will be able to react to the case when Stream has been completed without emitting any elements.
First of all, remember that operators such .map, .flatMap, .filter and many others will not be invoked at all if there no onNext has been invoked.
That means that in your case next code
transaction.flatMap {
val user = userRepository.findById(it.userId)
// If it's empty, return badRequest()
}
return transaction.flatMap { transactionRepository.save(it).then(created(URI.create("/transaction/" + it.id)).build()) }
will not be invoked at all, if transaction will be empty.
In case if there is a requirement for handling cases when your flow is empty, you should consider operators like next in the following manner:
transaction
.flatMap(it -> {
val user = userRepository.findById(it.userId)
})
.swithIfEmpty(Flux.defer(() -> Flux.just(badRequest())));
Actual solution
Also, I have noted that you created two sub-flows from the main transaction. Actually, following code will not be executed at all:
transaction.flatMap {
val user = userRepository.findById(it.userId)
// If it's empty, return badRequest()
}
and will be only executed the last one, which is returned from the method. That happens because you ain't subscribed using operator .subscribe(...).
The second point, you can't subscribe to the same request body more the one time (kind of limitation for WebClient's reponse). Thus you are required to share your request body in the next way, so completed example will be:
fun createTransaction(serverRequest: ServerRequest): Mono<ServerResponse> {
val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java)).cache()
transaction
.flatMap { userRepository.findById(it.userId) }
.flatMap { transaction.flatMap { transactionRepository.save(it) } }
.flatMap { ServerResponse.created(URI.create("/transaction/" + it.id)).build() }
.switchIfEmpty(transaction.flatMap { ServerResponse.badRequest().syncBody("missed User for transaction " + it.id) })
}
Or more simple case without sharing transaction flow but using Tuple:
fun createTransaction(serverRequest: ServerRequest): Mono<ServerResponse> {
val emptyUser = !User()
val transaction = serverRequest.body<Mono<Transaction>>(BodyExtractors.toMono(Transaction::class.java))
transaction
.flatMap { t ->
userRepository.findById(t.userId)
.map { Tuples.of(t, it) }
.defaultIfEmpty(Tuples.of(t, emptyUser))
}
.flatMap {
if (it.t2 != emptyUser) {
transactionRepository.save(it.t1)
.flatMap { ServerResponse.created(URI.create("/transaction/" + it.id)).build() }
} else {
ServerResponse.badRequest().syncBody("missed User for transaction " + it.t1.id)
}
}
}
You can check it using the Mono's provided method hasElement() which is analogous to Optional's isPresent(). The method definition is :
Mono<Boolean> hasElement()
for more details checkout : project reactor documentation
In case you have to perform some action based on this value you can further use switchIfEmpty() to provide with alternate publisher.
Let me start by saying I am a newbie on reactive (java) and on this forum.
I think you cannot really check in this code if a mono is empty because a mono represents code that will be executed later on, so in this code body you won't know yet if its is empty. Does that make sense?
I just wrote something similar in Java which seems to work (but not 100% this is the best approach either):
public Mono<ServerResponse> queryStore(ServerRequest request) {
Optional<String> postalCode = request.queryParam("postalCode");
Mono<ServerResponse> badQuery = ServerResponse.badRequest().build();
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
if (!postalCode.isPresent()) { return badQuery; }
Flux<Store> stores = this.repository
.getNearByStores(postalCode.get(), 5);
return ServerResponse.ok().contentType(APPLICATION_JSON)
.body(stores, Store.class)
.switchIfEmpty(notFound);
}
We can use switchIfEmpty method for this
Below example, I'm checking if the user exists with email if not then add it
userRepository.findByEmail(user.getEmail())
.switchIfEmpty(s -> {
user.setStatus("InActive");
String encodedPassword = DigestUtils.sha256Hex(user.getPassword());
user.setPassword(encodedPassword);
userRepository.save(user).subscribe();
s.onComplete();
}).then(Mono.just(user));
Use Mono with Optional:
return findExistingUserMono
.map(Optional::of)
.defaultIfEmpty(Optional.empty())
.flatMap(optionalUser -> {
if(optionalUser.isPresent()) {
return Mono.error('xxxx');
}
return this.userService.create(optionalUser.get());
});
This way it will always emit Optional value so that the stream will never break.

Initializing structures dynamically

I have a couple of structures, like:
type SomeObject struct {
sample int
}
I want to fill the sample variable based on what I get in the request body. To do this, I want to create a function, pass request body as a string to it, create an empty structure inside, fill the structure with data, return it, and replace chosen structure with this.
How do I do this? What do I return from the function? Is there a way to do this?
If you're dealing with multiple types then you should make your method return an interface{}. For all of the applicable types, create a convenience method like;
func NewSomeObject(reqBody string) *SomeObject {
return &SomeObject{sample:reqBody}
}
Which takes a string and returns a new instance of the type with that field set to whatever was passed in. Your question is missing information about how you determine which type should be instantiated but assuming you have a few, you'll likely need an if/else or a switch in the method which receives the request body so to give a very vague example it would be something like;
func ProcessRequest(reqBody string) interface{} {
if someCondition {
return NewSomeObject(reqBody)
} else if otherCondition {
return NewSomeOtherObject(reqBody)
} // potentially several other statements like this
return nil // catch all, if no conditions match
}
How about
func foo (s *SomeObject) {
s.sample = 123
}
or
func (s *SomeObject) foo() {
s.sample = 123
}

Resources