Skip to content

Commit b831dcb

Browse files
committed
Merge branch '6.1.x'
2 parents 822c827 + d5df2f6 commit b831dcb

File tree

6 files changed

+92
-11
lines changed

6 files changed

+92
-11
lines changed

grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/dirty/checking/DirtyCheckable.groovy

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ trait DirtyCheckable {
7878
void markDirty(String propertyName, newValue) {
7979
if( $changedProperties != null && !$changedProperties.containsKey(propertyName)) {
8080
def oldValue = ((GroovyObject) this).getProperty(propertyName)
81-
if(newValue != oldValue) {
81+
if ((newValue == null && oldValue != null) ||
82+
(newValue != null && oldValue == null) ||
83+
(newValue && !newValue.equals(oldValue))) {
8284
$changedProperties.put propertyName, oldValue
8385
}
8486
}
@@ -91,7 +93,9 @@ trait DirtyCheckable {
9193
*/
9294
void markDirty(String propertyName, newValue, oldValue) {
9395
if( $changedProperties != null && !$changedProperties.containsKey(propertyName)) {
94-
if(newValue != oldValue) {
96+
if ((newValue == null && oldValue != null) ||
97+
(newValue != null && oldValue == null) ||
98+
(newValue && !newValue.equals(oldValue))) {
9599
$changedProperties.put propertyName, oldValue
96100
}
97101
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.grails.datastore.mapping.dirty.checking
2+
3+
4+
import groovy.transform.Sortable
5+
import spock.lang.Issue
6+
import spock.lang.Specification
7+
8+
class DirtyCheckableSpec extends Specification {
9+
10+
@Issue('https://github.com/grails/grails-data-mapping/issues/1231')
11+
def 'setting a field that implements Comparable dirty checks properly'() {
12+
given: 'a person'
13+
def person = new Person(name: 'John Doe')
14+
15+
and: 'a blog post'
16+
def blogPost = new BlogPost(title: 'Hello World', content: 'some content')
17+
person.lastViewedPost = blogPost
18+
19+
and: 'a second blog post is made'
20+
def anotherBlogPost = new BlogPost(title: blogPost.title, content: 'different content, same title')
21+
22+
and: 'change list is reset'
23+
person.trackChanges()
24+
25+
when: 'the lastViewedPost is set to something different'
26+
person.lastViewedPost = anotherBlogPost
27+
28+
and: 'markDirty is called (normally would be weaved in by a DirtyCheckingTransformer)'
29+
person.markDirty('lastViewedPost', anotherBlogPost, blogPost)
30+
31+
then:
32+
person.hasChanged()
33+
person.hasChanged('lastViewedPost')
34+
person.getOriginalValue('lastViewedPost').equals(blogPost)
35+
}
36+
}
37+
38+
class Person implements DirtyCheckable {
39+
String name
40+
BlogPost lastViewedPost
41+
}
42+
43+
@Sortable(includes = ['title'])
44+
class BlogPost {
45+
String title
46+
String content
47+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package grails.gorm.tests
2+
3+
class NullValueEqualSpec extends GormDatastoreSpec {
4+
5+
void "test null value in equal and not equal"() {
6+
when:
7+
new TestEntity(name:"Fred", age: null).save(failOnError: true)
8+
new TestEntity(name:"Bob", age: 11).save(failOnError: true)
9+
new TestEntity(name:"Jack", age: null).save(flush:true, failOnError: true)
10+
11+
then:
12+
TestEntity.countByAge(11) == 1
13+
TestEntity.findAllByAge(null).size() == 2
14+
TestEntity.countByAge(null) == 2
15+
16+
TestEntity.countByAgeNotEqual(11) == 2
17+
TestEntity.countByAgeNotEqual(null) == 1
18+
}
19+
}

grails-datastore-gorm-tck/src/main/groovy/grails/gorm/tests/TestEntity.groovy

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ class TestEntity implements Serializable {
1616

1717
static mapping = {
1818
name index:true
19-
age index:true, nullable:true
20-
child index:true, nullable:true
19+
age index:true
20+
child index:true
2121
}
2222

2323
static constraints = {
2424
name blank:false
2525
child nullable:true
26+
age nullable:true
2627
}
2728
}

grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/DynamicFinder.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -765,11 +765,11 @@ private static String calcPropertyName(String queryParameter, String clause) {
765765
* @return the initialized expression
766766
*/
767767
private MethodExpression getInitializedExpression(MethodExpression expression, Object[] arguments) {
768-
if (expression instanceof Equal && arguments.length == 1 && arguments[0] == null) {
769-
expression = new IsNull(expression.propertyName);
770-
} else {
771-
expression.setArguments(arguments);
772-
}
768+
// if (expression instanceof Equal && arguments.length == 1 && arguments[0] == null) { // logic moved directly to Equal.createCriterion
769+
// expression = new IsNull(expression.propertyName);
770+
// } else {
771+
expression.setArguments(arguments);
772+
// }
773773
return expression;
774774
}
775775

grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/MethodExpression.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,12 @@ public Equal(String propertyName) {
422422

423423
@Override
424424
public Query.Criterion createCriterion() {
425-
return Restrictions.eq(propertyName, arguments[0]);
425+
Object argument = arguments[0];
426+
if (argument != null) {
427+
return Restrictions.eq(propertyName, argument);
428+
} else {
429+
return Restrictions.isNull(propertyName);
430+
}
426431
}
427432

428433
}
@@ -437,7 +442,12 @@ public NotEqual(String propertyName) {
437442

438443
@Override
439444
public Query.Criterion createCriterion() {
440-
return Restrictions.ne(propertyName, arguments[0]);
445+
Object argument = arguments[0];
446+
if (argument != null) {
447+
return Restrictions.ne(propertyName, arguments[0]);
448+
} else {
449+
return Restrictions.isNotNull(propertyName);
450+
}
441451
}
442452

443453
}

0 commit comments

Comments
 (0)