Domain.where {
1 == 0
}.count()
This returned all the elements of the domain class. The more general case:
Domain.where {
false
}.count()
Will return all elements; if I use one of the fields and make a false condition, the result is as expected.
My question is why does this happen (the first case) ? If it is a too naive question, please just suggest some reading material. Thanks!
The version of grails that I use is 2.3.6 (it may be different in newer versions?)
I'm not sure what you are trying to achieve, but here is an explanation (maybe a bit general because of that :).
What you pass to the where method is actually a DSL for specifying SQL criterias, it just uses normal Groovy syntax to pretend to be more natural. But when you do someProperty != 5 && someOtherProperty == 6 that is not evaluated directly, but transformed to end up in an SQL query as select * from Domain where some_property != 5 and some_other_property = 6.
Since you are not passing any reference to a property in your criteria (1 == 0), it gets ignored by the detached criteria DSL evaluator, thus returning the result of select * from domain. You can try to do for example id != id to see how you get an empty list as the result. If you again examine the resulting query, you'll see that a where id<>id is included.
You can learn more about the where method: https://grails.github.io/grails-doc/latest/guide/GORM.html#whereQueries
Bear in mind that what you pass to the where method is a Closure, so the code inside is not executed upfront, and is not necessarily evaluated in the context where it was declared. You can learn more about Groovy Closures. Also about creating DSLs with Groovy, though is a bit of an advanced topic.
(I simplified the SQL queries to make them more undestandable, if you activate the query log of Hibernate or MySQL/other DB you are using, you'll see they are bigger).
To illustrate Deigote's explanation, here's a very crude implementation of a WHERE query builder (actually just the WHERE clause) using the criteria criteria format:
class WhereBuilder {
def conditions = []
def eq(column, value) {
conditions << [
column: column,
operator: '=',
value: value]
}
def ne(column, value) {
conditions << [
column: column,
operator: '!=',
value: value]
}
String toString() {
'WHERE ' <<
conditions.collect {
"${it.column} ${it.operator} '${it.value}'"
}.join(' AND ')
}
}
def builder = new WhereBuilder()
builder.with {
1 == 0
false
eq 'firstName', 'John'
ne 'lastName', 'Smith'
}
assert builder.toString() == "WHERE firstName = 'John' AND lastName != 'Smith'"
As you can see, the expressions 1 == 0 and false have no effect.
Related
what is wrong with below code, comparing 2 strings in groovy
I am trying do the comparison between the 2 parameters in a single line to make it look tidier
if (params.dirname == ((params.path =~ ~/${params.dirname}/).with { matches() ? it[0] : null })) {
print success
}
Throwing Exception -
java.lang.NoSuchMethodError: No such DSL method 'matches' found among steps
There is no need to over-complicate your use case. According to:
params.dirname = hde, params.path = /usr/tmp/jenkins/hde/filename.txt or /usr/hde/jenkins/ing/filename.txt or any random path which has hde in it
you are trying to find if given string a contains substring b. It can be done using Java's method String.contains(String substring). Alternatively you can use regular expression for that, but String.contains() just looks a few times simpler to understand what is your intention. Consider following Groovy script:
def params = [
dirname: 'hde',
path: '/usr/tmp/jenkins/hde/filename.txt'
]
// Using String.contains()
if (params.path.contains(params.dirname)) {
println "Path '${params.path}' contains '${params.dirname}'"
}
// Using regular expression
if (params.path ==~ /(.*)${params.dirname}(.*)/) {
println "Path '${params.path}' contains '${params.dirname}'"
}
When you run it both if statements evaluates to true:
Path '/usr/tmp/jenkins/hde/filename.txt' contains 'hde'
Path '/usr/tmp/jenkins/hde/filename.txt' contains 'hde'
I have a question about validating arguments in a mock call with a closure. Sometimes I do this:
customerRepository.save({ Customer customer ->
assert ...
assert ...
}) >> { ... some return value ... }
etc. i.e. multiple (but not too many) asserts in the closure, and also want to stub the call to return something. What I found out is that the code above doesn't work, I need to return a truthy value from the closure, otherwise the object I want to return is not returned and the test will fail somewhere else.
I don't think this is documented, could anybody say what the rules here are exactly?
Edit: actually, I've just checked and I need to return a truthy value even if I don't stub the return value.
So far i know two options for validating arguments. Either match the arguments in-place which does not require asserts:
then:
1 * customerRepository.save({ it.id == 1 && it.name == "joe" }) >> returnValue
However, this will give you "too few invocations" if the validation fails which I find misleading in some cases and usually harder to debug.
Alternatively, match all arguments and assert in the implementation:
then:
1 * customerRepository.save(_) >> { Customer customer ->
assert customer.id == 1
assert customer.name == "joe"
return returnValue
}
This will give you very descriptive assertion errors.
I am getting weird error in my geb functional tests.
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Spec expression: 1: expecting '}', found 'assert' # line 1, column 71.
} ) { at(JobOfferDetailPage) assert des
My test looks like this. I click on a link which opens a new window with details of the job offer. Than I want to assert some text on the new page using Page Pattern.
Test:
withNewWindow( { quickShowOption.click() } ) { //TODO fix me
at(JobOfferDetailPage)
assert description.text() == 'some text'
assert requirements.text() == 'some text'
assert advatages.text() == 'some text.'
assert categories.text() == 'some text'
assert locality.text() == 'some text'
}
Page:
class JobOfferDetailPage extends Page {
static at = {$('#contactLabel').text() == 'Contact'}
static content = {
description {$('#jobOfferDescription')}
requirements {$('#jobOfferRequirements')}
advatages {$('#jobOfferAdvantages')}
jobOfferType {$('#jobOfferType')}
categories {$('#categories')}
locality {$('#locality')}
startDate {$('#startDate')}
requiredLanguages {$('#requiredLanguages')}
}
}
I get compilation error after my conditions are asserted. If I make a typo in asserted text than the test will fail normally, but if it passes, than it fails with this weird error.
Thank you #Erdi.
I use spock,geb versions "0.13.1" and selenium version "2.51.0".
If one was to believe this comment in one of Geb's own tests, which was nota bene written by me some time ago, this indeed seems like some sort of bug in Spock. What is interesting is that I just now moved that statement to an expect block and it works as long as the last statement in the second closure passed to newWindow() evaluates to true. This makes me think that it is an issue with old version of Spock and/or Groovy. Which versions of the aforementioned tools are you using?
One possible workaround would be to move your statement from expect/then to one that is not asserting (given or when) as shown in the test I linked to.
I have this piece of code on my accounts model.
scope :unverified, lambda { |limit|
select('accounts.id, accounts.email').joins('LEFT OUTER JOIN verifications v ON v.account_id = accounts.id')
.where('v.account_id IS NULL').limit(limit)
}
Because my team has rubocop with strict settings, I cannot write it the normal way rails recommends which would look like this:
scope :unverified, -> (limit = nil) {
select('accounts.id, accounts.email').joins('LEFT OUTER JOIN verifications v ON v.account_id = accounts.id')
.where('v.account_id IS NULL').limit(limit)
}
Writing it the normal way will trigger a rubocop error. I have the code close to the way I want but I can't figure out how exactly to pass in a default argument for a lambda. Can someone provide just a little push?
You can simply provide the defaults to the block parameters:
scope :unverified, lambda { |limit = nil|
select('accounts.id, accounts.email').joins('LEFT OUTER JOIN verifications v ON v.account_id = accounts.id')
.where('v.account_id IS NULL').limit(limit)
}
But not sure if it makes sense to pass nil to .limit(). You may want to default it to an integer.
In a controller how can i validate a password so it contains at least 1 letter, 1 number, 1 special character and is at least 8 digits long. The code i am trying to use is as follows:
boolean validatePassword(String password) {
System.out.println("In validate")
def pattern = /^.*(?=.{7,})(?=.*\d)(?=.*[a-zA-Z])(?=.*[!##$%*&+()]).*$/
def matcher = password =~ pattern
System.out.println("HERERERE")
return matcher.getCount() ? true : false
}
This does not work if says everything is invalid.
I have spring security ui plug in installed. Is there a way I can use its validation features?
I know i can use it to encode the password.
Rather than trying to do everything in one regex I'd split up the tests. Since in Groovy a Matcher coerces to boolean by calling find(), the following should work, and makes the intent clearer.
boolean validatePassword(String pass) {
return (pass) && (pass.length() > 7) && (pass =~ /\p{Alpha}/) &&
(pass =~ /\p{Digit}/) && (pass =~ /[!##$%*&+()]/)
}
There is also a nice java library called vtpassword for this purpose if you need something more sophisticated
http://code.google.com/p/vt-middleware/wiki/vtpassword