Inconsistency in grails command object validation - grails

I have following command object with constraints :
#Validateable
class RefundCommand{
private static final Logger log = Logger.getLogger(RefundCommand.class)
Double amount
String order_id
MerchantAccount merchant
OrderReference order
String unique_request_id
public void getDerivedValues() {
this.order = OrderReference.findByOrderIdAndMerchantId(order_id, merchant.merchantId)
}
static constraints = {
amount nullable: false, validator: {amount, cmd->
if(cmd.amount <= 0) {
log.info("Amount must be greater than 0. Given value: ${cmd.amount}")
return ['invalid.amount']
}
}
}
}
Initiating an object in following way inside a controller:
def refund = {RefundCommand cmd->
def String orderId = params.orderId
def String merchantId = params.merchant.merchantId
def Double amount = params.amount.toDouble()
OrderReference orderReference = OrderReference.findByOrderIdAndMerchantId(orderId, merchantId)
MerchantAccount merchantAccount = MerchantAccount.findByMerchantId(merchantId)
cmd.order_id = orderId
cmd.merchant = merchantAccount
cmd.order = orderReference
cmd.amount = amount
cmd.unique_request_id = "rf_" + util.generateUniqueReference()
cmd.clearErrors()
cmd.validate()
log.info(cmd.dump())
if(cmd.hasErrors()) {
.....
return
}
proceedForRefund()
}
When I deploy initially validations are not working, validate() always return true and hasError() return null.
As we are using nginx, if I make any change in RefundCommand file then after auto-compile validation start working.
What could be the reason for that?
we are using grails-2.2.2 with nginx server.

Related

How to correctly handle DTO conversion in Micronaut Reactive

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);

Derived field in GORM utilizing mapped owner's fields

I'm trying to figure out how to make a derived boolean field in my domain class. The boolean field is derived from comparison to the mapped owner's values. Is this possible in GORM? I've tried it quite a few different ways and I keep getting various SQL errors. My domain classes are below:
class Reading {
float readingValue
Date dateCreated
boolean alarmedState
static constraints = {
readingValue(nullable: false)
}
static belongsTo = [sensor : Sensor]
static mapping = {
autoTimestamp true
sort "dateCreated"
alarmedState formula: "(READING_VALUE < SENSOR.ALARM_IF_LESS) || (READING_VALUE > SENSOR.ALARM_IF_GREATER)"
}
}
class Sensor {
String description
String location
SensorType typeEnum
double alarmIfGreater
double alarmIfLess
static hasMany = [readings : Reading]
static constraints = {
alarmIfGreater(nullable: true)
alarmIfLess(nullable: true)
description(blank: false)
location(blank: false)
typeEnum(blank: false)
}
}
The transients property might do what you want. E.g.
class Reading {
float readingValue
Date dateCreated
static constraints = {
readingValue(nullable: false)
}
static belongsTo = [sensor : Sensor]
static transients = ['alarmedState']
static mapping = {
autoTimestamp true
sort "dateCreated"
//alarmedState formula: "(READING_VALUE < SENSOR.ALARM_IF_LESS) || (READING_VALUE > SENSOR.ALARM_IF_GREATER)"
}
Boolean getAlarmedState() {
( readingValue < sensor.alarmIfLess || readingValue > sensor.alarmIfGreater )
}
}
I've not tested this code but it might get you on the right track...

Null ID on persisted objects - GORM marks object loaded from database as unsaved

Recently I have started refactoring my Grails application, everything looked good until I got 'object references an unsaved transient instance' errors. While debugging I have found that id for one of my domain object is always null for every instance. Even for instances loaded from database.
I have found that composite id (which I use in that class) is known to cause problems, but it worked fine few days ago, since then, I have done a lot changes to this class but none of them should cause this kind of problems... at least I couldn't find change that could cause it.
class QuestionPriority implements Serializable{
static int maxPriority = 6
static int minPriority = 1
int priority = maxPriority
Date lastTestDate
Date nextTestDate = new Date()
static belongsTo = [question:Question, subscription:Subscription]
static constraints = {
nextTestDate(nullable: true)
lastTestDate(nullable: true)
}
static mapping = {
id composite: ['subscription', 'question']
version false
}
static QuestionPriority create(Subscription sub, Question question, boolean flush = false) {
assert sub != null
assert question != null
assert sub.id != null
assert question.id != null
QuestionPriority qp = new QuestionPriority(subscription: sub, question: question)
sub.addToPriorities(qp)
question.addToPriorities(qp)
assert (qp.save(flush: flush, insert: true, failOnError: true))
return qp
}
boolean equals(other) {
if (!(other instanceof QuestionPriority)) {
return false
}
other.subscription?.id == subscription?.id &&
other.getQuestionToAsk?.id == question?.id
}
int hashCode() {
def builder = new HashCodeBuilder()
if (subscription) builder.append(subscription.id)
if (question) builder.append(question.id)
builder.toHashCode()
}
void markAsCorrect() {
priorityDown()
calculateNextTestDate()
}
void markAsWrong() {
priorityUp()
calculateNextTestDate()
}
String getQuestionToAsk() {
return question.question
}
String getExpectedAnswer() {
return question.answer
}
Date calculateNextTestDate() {
DailyTestMode mode = subscription.testMode
if (!lastTestDate) {
nextTestDate = new Date(0, 0, 0)
} else {
nextTestDate = mode.calculateNextAskDate(this)
}
return nextTestDate
}
static void delete(User user, Question q) {
QuestionPriority qp = get(user.id, q)
if (qp) {
qp.delete()
}
}
static QuestionPriority get(Subscription sub, Question question) {
assert sub != null
assert question != null
assert sub.id != null
assert question.id != null
QuestionPriority qp = find 'from QuestionPriority where subscription.id=:subId and question.id=:questionId',
[subId: sub.id, questionId: question.id]
if (!qp) {
qp = create(sub, question)
}
return qp
}
private void priorityUp() {
priority = Math.min(priority + 1, maxPriority)
lastTestDate = new Date()
calculateNextTestDate()
}
private void priorityDown() {
priority = Math.max(priority - 1, minPriority)
lastTestDate = new Date()
calculateNextTestDate()
}
}
I would really appreciate any help
-----EDIT-------
Question domain oject:
class Question {
String question
String answer
boolean deleted
static transients = [ 'deleted']
static belongsTo = [studyList: StudyList]
static hasMany = [priorities: QuestionPriority]
static constraints = {
question(blank:false)
answer(blank:false)
}
static mapping = {
priorities(cascade: 'all-delete-orphan')
}
void setAnswer(String a){
answer = a.trim()
}
String toString(){
return "${question} = ${answer}"
}
}
Subscription domain object
class Subscription implements Serializable {
boolean active = true
Integer rating = null
Date subscriptionStartDate = new Date()
String dailyTestModeLiteral
static belongsTo = [user:User, studyList:StudyList]
static hasMany = [priorities:QuestionPriority]
static constraints = {
priorities(nullable: true)
rating(nullable: true)
subscriptionStartDate(nullable: true)
}
static mapping = {
priorities(cascade: 'all-delete-orphan')
}
void setDailyTestMode(DailyTestMode mode){
dailyTestModeLiteral = mode.getModeLiteral()
for(QuestionPriority priority:priorities){
priority.calculateNextTestDate()
}
}
DailyTestMode getTestMode(){
return DailyTestMode.getMode(dailyTestModeLiteral)
}
public static Subscription create(User user, StudyList list, String testModeLiteral = NormalDailyTestStrategy.literal, boolean flush = false){
Subscription subscription = get(user.id, list.id)
if(!subscription){
withTransaction {
subscription = new Subscription(user: user, studyList: list, dailyTestModeLiteral: testModeLiteral)
user.addToSubscriptions(subscription)
list.addToSubscriptions(subscription)
subscription.save(failOnError: true, flush: true)
}
subscription.studyList.questions.each {
QuestionPriority.create(subscription, it)
}
}
return subscription
}
int getScore(){
float prioritySum = 0
float priorityMax = 0
float priorityMin = 0
priorities.each {
prioritySum += it.priority
priorityMin += 1
priorityMax += QuestionPriority.maxPriority
}
return Math.round(100 * (prioritySum-priorityMax)/(priorityMin - priorityMax))
}
public static void delete(User user, StudyList list){
Subscription subscription = get(user.id, list.id)
if(subscription){
subscription.delete()
}
}
static Subscription get(long userId, long studyListId) {
find 'from Subscription where user.id=:userId and studyList.id=:studyListId',
[userId: userId, studyListId: studyListId]
}
boolean equals(other) {
if (!(other instanceof Subscription)) {
return false
}
other.user?.id == user?.id &&
other.studyList?.id == studyList?.id
}
int hashCode() {
def builder = new HashCodeBuilder()
if (user) builder.append(user.id)
if (studyList) builder.append(studyList.id)
builder.toHashCode()
}
boolean checkIfMatches(QuestionPriority questionPriority, String questionAsked, String answerGiven) {
return(questionPriority.question.question==questionAsked &&
questionPriority.question.answer == answerGiven)
}
QuestionPriority checkIfMatchesAny(String questionAsked, String answerGiven) {
Question q = Question.withCriteria {
and {
eq('question', questionAsked)
eq('answer', answerGiven)
eq('studyList', studyList)
}
}
if(q){
List<QuestionPriority> qp = QuestionPriority.withCriteria {
and {
eq('question', q)
eq('subscription', this)
}
}
if(qp.size()>0){
return qp[0]
}else{
return null
}
}
}
}
A few hours of debuging later I still know only that executing save(flush: true, failOnError: true) on QuestionPriority object returns unsaved object (no validation errors, no exceptions... no helpful information).
Any idea where to look or how to search for cause of this problem would be helpful, because I'm 100% stuck on this...
After hours of searching, changing framework to newest version and fixing new problems resulting from version change, I fixed this problem. It looks like changing composite ID into normal ID + composite unique key solved the problem. I couldn't find other solution, even thou my code worked fine with composite id for first couple of months... (any part of code related to composite id was changed when it stopped working) and I'm almost sure that I tried removing composite ID earlier and it didn't help then...

How can I get a Grails UUID of n digests in a domain-class?

I am new in Grails and want to have a id column as uuid with n digests. Like:
class Book {
String id
}
How do I get that done?
You can use the following:
class Book {
String id
static constraints = {
id maxSize: 18
}
static mapping = {
id generator:'assigned'
}
def beforeValidate() {
if (!id) {
String uuid = UUID.randomUUID().toString()
MessageDigest sha1 = MessageDigest.getInstance("SHA1")
byte[] digest = sha1.digest(uuid.getBytes())
def tmpId = new BigInteger(1, digest).toString(16)
id = tmpId[0..n] // size of the id
}
}
}
where n is the number of digests.

Are Rails-style chained queries available in Grails?

I am writing a scheduling feature in a new Grails 2.1.0 application. I am transitioning from a Ruby on Rails project, so much of my query strategy derives from Rails style. I have the following domain classes:
Schedule.groovy
class Schedule {
// Number of minutes between available appointment slots
int defaultAppointmentInterval
Time officeOpenStart
Time officeOpenEnd
Time lunchStart
Time lunchEnd
static hasMany = [inventorySlots: InventorySlot]
static constraints = {
// long validation rules
}
def boolean isAvailableAt(Date dateTime) {
def isAvailable = true
if (inventorySlots.isEmpty()) {
isAvailable = false
} else if (inventorySlotsSurroundingTime(dateTime).isEmpty()) {
isAvailable = false
}
isAvailable
}
def inventorySlotsSurroundingTime(Date dateTime) {
InventorySlot.surroundingTime(dateTime) {
and {
inventorySlot.schedule = this
}
}
}
}
InventorySlot.groovy
class InventorySlot {
Date startTime
static belongsTo = [schedule: Schedule]
static constraints = {
startTime nullable: false, blank: false
}
static mapping = {
tablePerHierarchy true
schedule lazy: false
}
static namedQueries = {}
def static surroundingTime(Date time) {
[UnboundedInventorySlot.surroundingTime(time), BoundedInventorySlot.surroundingTime(time)].flatten()
}
def endTime() {
return ((BoundedInventorySlot) this).endTime?: (UnboundedInventorySlot (this)).endTime()
}
}
UnboundedInventorySlot.groovy
class UnboundedInventorySlot extends InventorySlot {
static namedQueries = {
// surroundingTime { time ->
// le 'startTime', time
// ge 'startTime', time - 1
// }
}
#Override
def static surroundingTime(Date time) {
findAllByStartTimeLessThanEqualsAndStartTimeGreaterThanEquals(time, time - 1)
}
def Date endTime() {
def endTime
// If the office closing is defined, use that, otherwise use tonight # 23:59:59
endTime = schedule?.officeOpenEnd?: new DateTime(startTime + 1).withTimeAtStartOfDay().plusSeconds(-1).toDate()
return endTime
}
}
BoundedInventorySlot.groovy
class BoundedInventorySlot extends InventorySlot {
Date endTime
static constraints = {
endTime nullable: false, blank: false, validator: {val, obj ->
if (val.date != obj.startTime.date) { return ["invalid.differentDate", val.date] }
}
}
static namedQueries = {
// surroundingTime { time ->
// le 'startTime', time
// ge 'endTime', time
// }
}
#Override
def static surroundingTime(Date time) {
findAllByStartTimeLessThanEqualsAndEndTimeGreaterThanEquals(time, time)
}
#Override
def Date endTime() {
endTime
}
}
What I would like to do is to implement the Schedule#isAvailableAt(Date) method as follows:
def boolean isAvailableAt(Date dateTime) {
def isAvailable = true
if (inventorySlots.isEmpty()) {
isAvailable = false
} else if (inventorySlots.surroundingTime(dateTime).isEmpty()) {
isAvailable = false
}
isAvailable
}
where the inventorySlots.surroundingTime() invocation is essentially InventorySlot.surroundingTime() but instead of querying the universe of InventorySlots, it pre-filters on just the instances associated with the schedule instance. This is very common in Rails, but any searches for "chained query" or "collection query" in Grails doesn't seem to provide good documentation. Thanks for any help.
I can think of two approaches off the top of my head which would work:
A more complex dynamic finder:
InventorySlots.findAllByScheduleAndStartTimeLessThanEqualsAndEndTimeGreaterThanEquals(this, time, time -1)
You can chain named queries together, then use any of the autowired finders to run the actual query, so if you uncomment your named query:
static namedQueries = {
surroundingTime { time ->
le 'startTime', time
ge 'startTime', time - 1
}
}
You could simply call:
InventorySlots.surroundingTime(time).findAllBySchedule(this)
You might also want to look into where queries in Grails 2 if you are not a fan of the criteria builder syntax. They are more type safe than criteria queries, and can be chained in the same fashion.
Update: Unfortunately, I'm not familiar with the inner workings of how named queries work with polymorphism, and I presume trouble with that is why you commented that out. I think worst case though, you could build a query on the parent like this one:
surroundingTime { time ->
or {
and {
eq('class', BoundedInventorySlot.name)
le 'startTime', time
ge 'startTime', time
}
and {
eq('class', UnboundedInventorySlot.name)
le 'startTime', time
ge 'startTime', time - 1
}
}
}
***Update: Could you leverage the spread operator to simplify your task? i.e. Keep this code, but remove the .flatten() and call surroundingTime as a named query or where query.
def static surroundingTime(Date time) {
[UnboundedInventorySlot.surroundingTime(time), BoundedInventorySlot.surroundingTime(time)]
}
Then you could call:
Schedule.surroundingTime(time)*.findAllBySchedule(this).flatten()
Not ideal that the caller needs to know to combine the results, but an interesting approach maybe.
As a reference:
Query chaining in Grails' docs: http://grails.org/doc/latest/guide/GORM.html#querying
See the "Query Composition" part.
Adding an answer as this was the first search result. According to the docs, a where clause is a 'Detached Criteria'.
Example:
def query = Person.where {
lastName == "Simpson"
}
def bartQuery = query.where {
firstName == "Bart"
}
Person p = bartQuery.find()
Where Query Composition

Resources