Построить createCriteria в Граалях динамически и сухим способом?

Я работаю над созданием createCriteria динамически. Пока все хорошо:

obj это объект(ы) домена, который я хочу вернуть

rulesList - это список карт, которые содержат поле для поиска, оператор для использования и значение для поиска по

def c = obj.createCriteria()
l = c.list (max: irows, offset: offset) {
    switch(obj){           //constrain results to those relevant to the user
        case Vehicle:
            eq("garage", usersGarage)
            break
        case Garage:
            users {
                idEq(user.id)
            }
            break
    }
    rulesList.each { rule ->
        switch(rule['op']){
            case 'eq':
                eq("${rule['field']}", rule['value'])
                break
            case 'ne':
                ne("${rule['field']}", rule['value'])
                break
            case 'gt':
                gt("${rule['field']}", rule['value'])
                break;
            case 'ge':
                ge("${rule['field']}", rule['value'])
                break
            case 'lt':
                lt("${rule['field']}", rule['value'])
                break
            case 'le':
                le("${rule['field']}", rule['value'])
                break
            case 'bw':
                ilike("${rule['field']}", "${rule['value']}%")
                break
            case 'bn':
                not{ilike("${rule['field']}", "${rule['value']}%")}
                break
            case 'ew':
                ilike("${rule['field']}", "%${rule['value']}")
                break
            case 'en':
                not{ilike("${rule['field']}", "%${rule['value']}")}
                break
            case 'cn':
                ilike("${rule['field']}", "%${rule['value']}%")
                break
            case 'nc':
                not{ilike("${rule['field']}", "%${rule['value']}%")}
                break
            }
        }
    }
}

приведенный выше код отлично работает и только немного многословен с операторами switch. Но что, если я хочу добавить функциональность, чтобы выбрать, чтобы соответствовать любому из правил или всем из них? Я бы нужно условно поставить правила в or{}. Я не могу сделать что-то вроде

if(groupOp == 'or'){
    or{
}

прежде чем я пройти через rulesList, а потом

if(groupOp == 'or'){
    }
}

позже. Все, что я могу придумать, это повторить код для каждого условия:

if(groupOp == 'or'){
    or{
        rulesList.each { rule ->
            switch(rule['op']){
                ...
            }
        }
    }
}
else{
    rulesList.each { rule ->
        switch(rule['op']){
            ...
        }
    }

теперь код выглядит довольно небрежным и повторяющимся. Предположим, я хочу выполнить поиск по свойству свойства объекта домена? (Пример: я хочу вернуть транспортные средства, шины которых являются определенной маркой; автомобиль.шины.бренд или транспортные средства, водители которых соответствуют названию; транспортное средство.водитель.имя). Должен ли я сделать что-то вроде:

switch(rule['op']){
    case 'eq':
        switch(thePropertiesProperty){
            case Garage:
                garage{
                    eq("${rule['field']}", rule['value'])
                }
                break
            case Driver:
                driver{
                     eq("${rule['field']}", rule['value'])
                }
                break
        }
        break
    case 'ne':
        ...
}

1 ответов


во-первых, вы можете упростить свой большой переключатель, используя GString для имени метода:

case ~/^(?:eq|ne|gt|ge|lt|le)$/:
  "${rule['op']}"("${rule['field']}", rule['value'])
  break

тот же трюк работает для and / or:

"${(groupOp == 'or') ? 'or' : 'and'}"() {
  rulesList.each { rule ->
    switch(rule['op']){
        ...
    }
  }
}

или вы можете сначала назначить закрытие переменной, а затем вызвать либо or(theClosure) или and(theClosure) по мере необходимости. Наконец, для поиска" свойства свойства", если вы добавляете

createAlias('driver', 'drv')
createAlias('garage', 'grg')

в верхней части критериев закрытия, то вы можете запросить на такие вещи, как eq('drv.name', 'Fred') без добавления вмешиваться!--6--> или garage {...} узел.