Lets say we are working with Micronaut Reactive (Project Reactor) and we would like to create a user account. SignUp DTO is represented by the following Kotlin class:
@Introspected
data class SignUpDto(
@field:Schema(example = "admin")
@field:NotBlank @field:Max(value = 255) var username: String? = null,
// rest is omitted for brevity
)
In order to create and persist an account entity in the database, first, we have to convert the SignUpDTO to the account entity represented by the kotlin class below:
@Entity(name = "Accounts")
@Where("@.active = true")
open class AccountEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accounts_sequence_generator")
@SequenceGenerator(name = "accounts_sequence_generator", sequenceName = "sequence_accounts")
@Column(name = "id", nullable = false, unique = true)
open var id: Long? = null
@Column(name = "username", nullable = false, unique = true, updatable = false, length = 255)
open var username: String? = null
@Column(name = "active", nullable = false)
open var active: Boolean? = true
@ManyToMany(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST, CascadeType.MERGE])
@JoinTable(name = "accounts_roles",
joinColumns = [JoinColumn(name = "accounts", referencedColumnName = "id")],
inverseJoinColumns = [JoinColumn(name = "roles", referencedColumnName = "id")])
open var roles: MutableSet<RoleEntity> = mutableSetOf()
// rest is omitted for brevity
}
As you can see, AccountEntity has a many-to-many relationship on a RoleEntity. For completeness, RoleEntity is shown below:
@Entity(name = "Roles")
open class RoleEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "id", nullable = false, unique = true)
open var id: Long? = null
@Column(name = "role", nullable = false, unique = true)
@Enumerated(EnumType.STRING)
open var role: Role? = null
@Column(name = "description", nullable = false, length = 500)
open var description: String? = null
// rest is omitted for brevity
}
Application defines a RoleRepository as follows:
@Repository
interface RoleRepository : ReactorCrudRepository<RoleEntity, Long> {
fun findByRole(role: Role): Mono<RoleEntity>
}
We are interested in mapping a SignUpDTO request to an account entity and persisting that entity in a reactive way. Function that does the converting is given below:
fun convertSignUpToAccountEntity(@Valid signUpDto: SignUpDto): AccountEntity {
return AccountEntity().apply {
this.username = signUpDto.username
this.active = true
this.roles.add(**add a user role here**)
}
}
Given that the RoleRepository is available to this function, how would one fetch the Role.User entity and add it to the list of account roles in a reactive way, since calling block just indefinitely blocks the calling thread? Is there a way to handle this in a reactive way?
You can have something like this:
return Flux.fromIterable(Arrays.asList("role1", "role2"))
.flatMap(role -> roleRepository.findByRole(role))
.collectList()
.map(roles -> convertSignUpToAccountEntity(signUpDto, roles))
.flatMap(accountEntityRepository::save);