coldbox-modules / quick

A ColdBox ORM Engine
https://quick.ortusbooks.com
MIT License
23 stars 19 forks source link

v5 regression in when trying to apply a where clause without chaining methods #198

Closed ryanalbrecht closed 1 year ago

ryanalbrecht commented 1 year ago

On quick v5 there seems to an issue when trying to apply a where clause without using method chaining.

    // this does work
    var entity = getInstance('Device').where('id',4);

    // this does NOT work
    var entity = getInstance('Device')
    local.entity.where('id',4);

    var result = entity.get();
    writeDump(var=result, top=2);
davidAtInleague commented 1 year ago

Looks like it returns a new copy instead of mutating itself. e.g. the following now seems required

entity = local.entity.where('id', 4);

It's tough because it alters the meaning of existing code, without triggering loud failures. Old v4 code continues to run, and perform queries against the db, and return result sets, but it might not select what it used to (that last entity.get() is really "just" getInstance("Device").get(), unconstrained).

Possible connection to https://github.com/coldbox-modules/quick/issues/195 (similar "unconstrained" queries issue)?

ryanalbrecht commented 1 year ago

@davidAtInleague

The problem is that calling .where() against a quick instance will return a new QuickBuilder instance. The QuickBuilder instance is created in the forwardToQB() method. This means you need to keep track of the initial QuickBuilder instance to apply more constraints. I proposed a solution to store the QuickBuilder instance on the entity itself and instead of creating a new instance every time you call where(), return the cached instance instead

BaseEntity.cfc

    /**
     * If the quickbuilder instance exists, then return it, else create it, cache it and return it
     *
     * @return  quick.models.QuickBuilder
     */
    public any function getQuickBuilder() {
        if(!isDefined('variables._quickBuilder')){
            variables._quickBuilder = newQuery();
        }

        return variables._quickBuilder;
    }

    /**
     * Forwards a missing method call on to qb.
     *
     * @missingMethodName       The potential scope name.
     * @missingMethodArguments  Any arguments to pass to the potential scope.
     *
     * @return                  any
     */
    private any function forwardToQB( required string missingMethodName, struct missingMethodArguments = {} ) {
        return invoke(
            getQuickBuilder(),
            arguments.missingMethodName,
            arguments.missingMethodArguments
        );
    }