How to add validation to limit number of rows being created - validation

I have a Grails domain class. I would like to add a validation such that when the application is running in TEST environment, the domain class can't have more than 100 records.
I can't figure out the best way to add this type of validation. I am on Grails 2.5.3.
This is what I have so far.
class MyDomain {
String test
static constraints = {
test blank: false, nullable: false
id blank: false, validator: {value, command ->
if (Environment.current == Environment.TEST) {
//do validation for not allowing more than 100 records
}
}
}
How can I add this validation?

Solution for a single domain
What #Joshua answered is perfectly fine but there are few other ways. One of them is:
class MyDomain {
String test
void beforeInsert() {
if (Environment.current == Environment.TEST) {
MyDomain.withNewSession {
if (MyDomain.count() == 100) {
throw new Exception("Not allowing more than 100 records")
}
}
}
}
static constraints = {
test blank: false
}
}
Also, please note two things:
The blank: false on the id field of no use since it is not a string because blank constraint is applicable on a String
The nullable: false is of no use since the default value of nullable constraint is false
Generic solution for across domain TL;DR
If you want this behavior across multiple domains, copying the same code is not recommended as your code won't be DRY. For that, you can register a custom event listener:
First define a Java annotation in src/groovy:
import java.lang.annotation.Documented
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
#Documented
#Target([ElementType.TYPE, ElementType.FIELD])
#Retention(RetentionPolicy.RUNTIME)
public #interface LimitRowsFoo {
int value() default 100
}
Now define another Groovy class:
import grails.util.Environment
import org.grails.datastore.mapping.engine.event.PreInsertEvent
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
class PreInsertEventListener extends AbstractPersistenceEventListener {
PreUpdateEventListener(final Datastore datastore) {
super(datastore)
}
#Override
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
// Instance of domain which is being created
Object domainInstance = event.entityObject
if (Environment.current == Environment.TEST) {
if (domainInstance.class.isAnnotationPresent(LimitRowsFoo.class)) {
// Just using any domain reference here
MyDomain.withNewTransaction {
int maxRows = domainInstance.class.getAnnotation(LimitRowsFoo.class).value()
if (domainInstance.class.count() == maxRows) {
event.cancel()
}
}
}
}
}
#Override
boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
// Only allow PreInsert event to be listened
eventType.name == PreInsertEvent.class.name
}
}
Now register this in Bootstrap.groovy:
application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
applicationContext.addApplicationListener new PreInsertEventListener(datastore)
}
Now, in your domain, all you have to do is like these:
#LimitRowsFoo
class MyDomain {
String test
static constraints = {
test blank: false
}
}
#LimitRowsFoo(value = 200) // to limit records to 200
class MyAnotherDomain {
String name
}

Wouldn't something like this do the trick for you?
class MyDomain {
String test
static constraints = {
test blank: false, nullable: false
id blank: false, validator: {value, command ->
if (Environment.current == Environment.TEST) {
//do validation for not allowing more than 100 records
if (MyDomain.count() > 100) return ['too.many.records']
}
}
}

Related

DelegateEndpointDefinition IsTemporary

I have a simple ConsumerDefinition:
public class HealthCheckConsumerDefinition : ConsumerDefinition<LoopbackConsumer>
{
public HealthCheckConsumerDefinition(IOptions<HealthCheckOptions> options)
{
EndpointName = options.Value.HostName;
Endpoint(configurator => configurator.Temporary = true); // not work
}
protected override void ConfigureConsumer(IReceiveEndpointConfigurator endpointConfigurator, IConsumerConfigurator<LoopbackConsumer> consumerConfigurator)
{
endpointConfigurator.ConfigureConsumeTopology = false;
base.ConfigureConsumer(endpointConfigurator, consumerConfigurator);
}
}
I expect the Temporary=true property to configure an endpoint with the AutoDelete = true and Durable = false properties, because this code is in the ApplyEndpointDefinition method of the RabbitMqHostConfiguration class:
https://github.com/MassTransit/MassTransit/blob/5fb6b4e31582970b0571e9fe6ac77793a0b3242a/src/MassTransit.RabbitMqTransport/Configuration/Configuration/RabbitMqHostConfiguration.cs#L60
public void ApplyEndpointDefinition(IRabbitMqReceiveEndpointConfigurator configurator, IEndpointDefinition definition)
{
if (definition.IsTemporary)
{
configurator.AutoDelete = true;
configurator.Durable = false;
}
...
}
But in the ConfigureEndpoints method of the class, the ConsumerDefinition registry is converted to the DelegateEndpointDefinition, which does not override the IsTemporary property based on the ConsumerDefinition object passed to the constructor:
https://github.com/MassTransit/MassTransit/blob/89ba77036230a15be108e8ade3a0e6fe5309a94d/src/MassTransit/Configuration/Registration/Registration.cs#L178
How to get around this problem and declare Temporary endpoint within the ConsumerDefinition?
I have confirmed that this works as expected in the upcoming MassTransit v7 release. Using this syntax, the temporary flag is now passed through to the transport.
Note that this would be overridden by using .Endpoint() following the AddConsumer<T>() container configuration method.
class RequestConsumerDefinition :
ConsumerDefinition<RequestConsumer>
{
public RequestConsumerDefinition()
{
Endpoint(e => e.Temporary = true);
}
}

Can I override/delegate assignment operator?

I began learn Groovy, and faced the challenge.
I have this code, that stores meta-data to object:
class Meta {
final MetaItem name
final MetaItem description
// ...
// And more fields with type MetaItem
// ...
Meta() {
name = new MetaItem("name")
description = new MetaItem("description")
}
void setName(String name) {
this.name.value = name
}
String getName() {
return this.name.value
}
void setDescription(String description) {
this.description.value = description
}
String getDescription() {
return this.description.value
}
// ...
// And more methods. Two for each field
// ...
}
class MetaItem {
private final def id
def value
MetaItem(String id) {
this.id = id
}
}
// Validating
def meta = new Meta()
assert meta.name == null
assert meta.description == null
meta.with {
name = "Name"
description = "Desc"
}
assert meta.name == "Name"
assert meta.description == "Desc"
print "Success!"
As you can see from the code, it increases quicly in volumes when new fields are added, because for each field you need to add two methods. Can this somehow be optimized? Redirect the assignment operation from object to his member. I've looked on Delegate, but this is not what I need.
P.S. I can't use access by .value because this class is used in Gradle extension and I need to configure it like this:
myExtension {
meta {
name = "Name"
description = "Desc"
// And many others
}
}
P.P.S. Sorry for my bad english, it's not my first language

Test code for enum

If I am declaring 2 enums inside my class this way:
public class EnumerationExample {
public enum Season {WINTER,SPRING,SUMMER,FALL}
public enum Month {JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC}
public List<Month> listMonths;
public Month convert (String val) {
for (Month mtObj : Month.values()) {
if (mtObj.name() == val) {
system.debug('The value passed is ' +mtObj);
}
}
return null;
}
public List<Month> seasonMonths(Season s) {
Season seasonObj = Season.SPRING;
listMonths = new List<Month>();
if(s==season.WINTER) {
listMonths.add(Month.DEC);
listMonths.add(Month.JAN);
listMonths.add(Month.FEB);
}
else if(s==season.SPRING) {
listMonths.add(Month.MAR);
listMonths.add(Month.APR);
listMonths.add(Month.MAY);
}
else if(s==season.SUMMER) {
listMonths.add(Month.JUN);
listMonths.add(Month.JUL);
listMonths.add(Month.AUG);
}
else if(s==season.FALL) {
listMonths.add(Month.SEP);
listMonths.add(Month.OCT);
listMonths.add(Month.NOV);
}
return listMonths;
}
}
how do i write test code for this ??
i tried doing this way but it says season variable does not exist at line EnumerationExampleObj.seasonMonths(Season.WINTER);...
#isTest
public class TestEnumerationExample {
public static testMethod void myUnitTest() {
EnumerationExample EnumerationExampleObj = new EnumerationExample();
EnumerationExampleObj.convert('wintery');
EnumerationExampleObj.seasonMonths(Season.WINTER);
system.assertEquals(EnumerationExampleObj.listMonths.get(0) , Month.DEC );
}}
is there any problem with the access modifier or any specific annotations.?
Your problem is not related to testing at all, but to C# basics like scope and syntax (your sample code is full of syntax errors).
To answer your specific question: if you define a public enum inside a class, you have to prefix it with the class name when used outside that class. Example:
var enumerationExampleObj = new EnumerationExample();
enumerationExampleObj.seasonMonths(EnumerationExample.Season.WINTER);

Missing validate() method in a command class

I'm having some hard time figuring out what's wrong in this simple code:
This is a command I made for changing the password:
package myapp.commands
import org.springframework.web.context.request.RequestContextHolder as RCH
import myapp.User
class PasswordCommand {
String currentPassword
String password
String passwordConfirm
private u
User getUser() {
def id = RCH.requestAttributes.session?.user?.id
if (!u && id) {
u = User.get(id)
}
return u
}
static constraints = {
currentPassword blank: false, validator: { val, cmd ->
if (cmd.user && cmd.user.password != val)
return "user.password.invalid"
}
...
}
And in the appropriate controller I use this action:
def doPassword = { PasswordCommand cmd ->
if (!cmd.hasErrors()) {
User user = cmd.getUser()
...
Unfortunately, I get an Error 500 when I try to change the password:
URI: /Myapp/user/doPassword
Class: java.lang.NoSuchMethodError
Message: PasswordCommand.validate()Z
What is going on ?!
Add the #Validateable annotation:
import grails.validation.Validateable
...
#Validateable
class PasswordCommand {
...
}

How to write a date validator with grails command object?

I want to add a date expression validator in my command object, but I'm not sure what's the correct syntax...
class UserController {
…
}
class DateServiceCommand {
String date //valid format is DD-MMM-YYYY, 01-APR-2011
static constraints = {
date(blank:false, ??? )
}
}
You can use a custom validator:
import java.text.*
class DateServiceCommand {
String date
static constraints = {
date blank: false, validator: { v ->
def df = new SimpleDateFormat('dd-MMM-yyyy')
df.lenient = false
// parse will return null if date was unparseable
return df.parse(v, new ParsePosition(0)) ? true : false
}
}
}

Resources