jamesfredley commented on code in PR #16820:
URL: https://github.com/apache/grails-core/pull/16820#discussion_r4480529191
##########
grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/query/criteria/AbstractDetachedCriteria.groovy:
##########
@@ -1108,16 +1168,47 @@ abstract class AbstractDetachedCriteria<T> implements
Criteria, Cloneable {
protected abstract QueryableCriteria buildQueryableCriteria(Closure
queryClosure)
+ /**
+ * Applies a pending {@code buildLazy} closure to this criteria, if any,
and clears it. Used when this
+ * criteria is itself extended; a query reads a deferred criteria through
{@link #materializeLazyCriteria()}.
+ */
protected void applyLazyCriteria() {
if (lazyQuery == null) {
return
}
def criteria = lazyQuery
lazyQuery = null
+ materializedTemplate = null
Review Comment:
where { ne('name', 'Z') } after list() clears the template and runs the
deferred closure again. Build the criteria with eq('name', wanted.name), run it
while wanted.name is A, then set wanted.name to B and extend the criteria. The
derived query returns B. The original query still returns A. Keep the
restrictions from the first run and add the new one.
##########
grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/query/criteria/AbstractDetachedCriteria.groovy:
##########
@@ -1108,16 +1168,47 @@ abstract class AbstractDetachedCriteria<T> implements
Criteria, Cloneable {
protected abstract QueryableCriteria buildQueryableCriteria(Closure
queryClosure)
+ /**
+ * Applies a pending {@code buildLazy} closure to this criteria, if any,
and clears it. Used when this
+ * criteria is itself extended; a query reads a deferred criteria through
{@link #materializeLazyCriteria()}.
+ */
protected void applyLazyCriteria() {
if (lazyQuery == null) {
return
}
def criteria = lazyQuery
lazyQuery = null
+ materializedTemplate = null
this.with(criteria)
}
+ /**
+ * Returns this criteria with its deferred query applied, without mutating
it. The deferred closure runs
+ * once, on a private template that is never handed out; every call
returns a fresh copy of that template, so
+ * a criteria shared between threads is never changed by a query that
reads or extends the result.
+ * A criteria without a deferred query returns itself.
+ */
+ AbstractDetachedCriteria<T> materializeLazyCriteria() {
+ if (lazyQuery == null) {
+ return this
+ }
+ AbstractDetachedCriteria<T> template = materializedTemplate
Review Comment:
The first list() stores a template, and a later list() returns a clone of
that template. Add a restriction to an association that already exists, such as
createAlias('organisation', 'o') and then eq('name', 'A') after the first
execution. The second list() still returns the organisations that the first one
returned. A projection, order, or alias set after the first execution is
skipped the same way. Use the criteria as it is when the query runs. Do not run
the deferred closure again.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]