Create dynamically closures in Groovy from a String object

后端 未结 2 679
Happy的楠姐
Happy的楠姐 2021-01-07 03:46

i would like to create a query with the Criteria API in Grails (GORM). The query will have to be something like this:

MyEntity.createCriteria().list{
   asso         


        
相关标签:
2条回答
  • 2021-01-07 03:53

    What about createAlias?. You could try something like this:

    def path = "assoc.parent.code"
    
    def split = path.split(/\./)
    
    MyEntity.createCriteria().list {
      // this will get you 'createAlias( assoc.parent, alias1 )'
      createAlias split.take( split.size() - 1 ), "alias1"
    
      // this will get you 'eq(alias1.code, userInput)'
      eq "alias1.${split[-1]}", userInput
    }
    

    This snippet is not generic, but you get the idea.


    Update

    Not conventional, but you can build a string containing the code with the closures and evaluate it using GroovyShell:

    assoc = 'assoc.parent.child.name'
    split = assoc.split( /\./ )
    path  = split[-2..0] // will get us 'child.parent.assoc';
                         // we will build it from inside-out
    
    def firstClosure = "{ eq '${split[-1]}', 'john doe' }"
    def lastClosure = firstClosure
    
    for (entity in path) {
      def criteriaClosure =  "{ ${entity} ${lastClosure} }"
      lastClosure = criteriaClosure
    }
    
    assert lastClosure == "{ assoc { parent { child { eq 'name', 'john doe' } } } }"
    def builtClosure = new GroovyShell().evaluate("return " + lastClosure)
    assert builtClosure instanceof Closure
    
    0 讨论(0)
  • 2021-01-07 04:10

    A more generic approach would be to metaClass String as below, and use it for any kind of separator
    . | , - ~ and more.

    String.metaClass.convertToClosureWithValue = {op, val ->
        split = delegate.split(op) as List
        if(split.size() == 1) {return "Cannot split string '$delegate' on '$op'"} 
    
        items = []
        split.each{
            if(it == split.last()){
                items << "{ eq '$it', $val }"
                split.indexOf(it).times{items.push("}")}
            } else {
                items << "{$it"
            }
        }
    
        println items.join()
        new GroovyShell().evaluate("return " + items.join())
    }
    
    assert "assoc.parent.child.name".convertToClosureWithValue(/\./, "John Doe") instanceof Closure
    assert "assoc-parent-child-name".convertToClosureWithValue(/\-/, "Billy Bob") instanceof Closure
    assert "assoc|parent|child|grandChild|name".convertToClosureWithValue(/\|/, "Max Payne") instanceof Closure
    assert "assoc~parent~child~grandChild~name".convertToClosureWithValue('\\~', "Private Ryan") instanceof Closure
    assert "assocparentchildname".convertToClosureWithValue(/\|/, "Captain Miller") == "Cannot split string 'assocparentchildname' on '\\|'"
    
    //Print lines from items.join()
    {assoc{parent{child{ eq 'name', John Doe }}}}
    {assoc{parent{child{ eq 'name', Billy Bob }}}}
    {assoc{parent{child{grandChild{ eq 'name', Max Payne }}}}}
    {assoc{parent{child{grandChild{ eq 'name', Private Ryan }}}}}
    
    0 讨论(0)
提交回复
热议问题