grails / grails-core

The Grails Web Application Framework
http://grails.org
Apache License 2.0
2.78k stars 950 forks source link

Clausule between on createCriteria().list not working with ID attribute #12381

Open lbiazotto opened 2 years ago

lbiazotto commented 2 years ago

Expected Behavior

Domain classes:

abstract class Contract implements Signable, Fileable, IdempotentResponse {
    Long loanId
    Integer installmentsNumber
}
class Ccb extends Contract {
    Long number
}

Service:

@Transactional
class RegenerateCcbJobService {
       execute(String idFrom, String idTo) {
                ConcurrentLinkedQueue<Long> ccbIds = new ConcurrentLinkedQueue(
                        Ccb.createCriteria().list {
                            between("id", Long.valueOf(idFrom), Long.valueOf(idTo))
                            projections {
                                id()
                            }
                        }
                )
                for(long i in ccbIds) { 
                   generateCcb(i);
                } 
        }

        private generateCcb(long ccbId) {
                try {
                    Ccb ccb = (Ccb) Ccb.createCriteria().get {
                        eq("id", ccbId)
                    }

                    ccbFilerService.generateBaseDocument(ccb)
            }
        }
}

I expect this unit test to pass:

@TestFor(RegenerateCcbJobService)
@Mock([Ccb, Signature])
class RegenerateCcbJobServiceSpec extends Specification {

    def setup() {
        service.ccbFilerService = Mock(CcbFilerService)
        service.executionUtils = new ExecutionUtils(new SyncExecutor())
        service.ccbFilerService.fileExporter = Mock(PdfExporter)
    }

    void "test regenerate CCB PDF"() {
        given: "a completed CCB but without document generated"
        Ccb ccb = TestHelper.createGrantedCcbContract(1) //The parameter is the ID
        ccb.number = 10
        ccb.save(flush: true, failOnError: true)

        Ccb ccb1 = TestHelper.createGrantedCcbContract(2)
        ccb1.number = 20
        ccb1.save(flush: true, failOnError: true)

        Ccb ccb2 = TestHelper.createGrantedCcbContract(4)
        ccb2.number = 40
        ccb2.save(flush: true, failOnError: true)

        when: "the process is called"
        JobResponse response = service.execute("1", "5")

        then: "the generate method run one time per ccb"
        1 * service.ccbFilerService.generateBaseDocument(ccb)
        1 * service.ccbFilerService.generateBaseDocument(ccb1)
        1 * service.ccbFilerService.generateBaseDocument(ccb2)
    }
}

Environment Test config in DataSource.groovy:

dataSource {
    dbCreate = "create-drop"
    driverClassName = "org.h2.Driver"
    dialect = "org.hibernate.dialect.H2Dialect"
    url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE"
    username = "******"
    password = "******"
}

Actual Behaviour

The unit test fails because the method Ccb.createCriteria().list returns a empty list.

Instead, if I filter by number attribute, something like this:

Ccb.createCriteria().list {
    between("number", 5L, 50L)
    projections {
        id()
    }
}

The method returns a list of 3 elements correctly.

And if I filter like this:

Ccb.createCriteria().list {
    eq("id", 1L)
    projections {
        id()
    }
}

The method returns the element correctly!

The problem seems to be when filtering by ID and with the beetwen clause.

Steps To Reproduce

No response

Environment Information

Example Application

No response

Version

2.5.6

osscontributor commented 2 years ago

I have worked to create a sample application to put your code in and there are a number of pieces missing that it would be helpful if you could provide. For example, your test includes this:

    def setup() {
        service.ccbFilerService = Mock(CcbFilerService)
        service.executionUtils = new ExecutionUtils(new SyncExecutor())
        service.ccbFilerService.fileExporter = Mock(PdfExporter)
    }

The service doesn't have all of those properties and it isn't clear if some of them are relevant. Also the generateCcb method in your RegenerateCcbJobService class will compile.

Can you share a minimal project that demonstrates the problem? If yes, that would be helpful.

Thank you for your feedback!