将动态查询结果写入文件

时间:2014-10-24 22:27:14

标签: groovy

我正在尝试在Groovy中编写一个通用程序,它将从配置文件中获取SQL以及其他参数并将它们放入文件中。

这是程序:

def config = new ConfigSlurper().parse(new File("config.properties").toURL())
Sql sql = Sql.newInstance(config.db.url, config.db.login, config.db.password, config.db.driver);

def fileToWrite = new File(config.copy.location)
def writer = fileToWrite.newWriter()
writer.write(config.file.headers)

sql.eachRow(config.sql){ res->
    writer.write(config.file.rows)
}

在配置中,sql是这样的:

sql ="从mydb"

中选择*

file.rows =" $ {res.column1} | $ {res.column2} | $ {res.column3} \ n"

当我跑它时,我得到了

  

[:] | [:] | [:]

     

[:] | [:] | [:]

     

[:] | [:] | [:]

在文件中。如果我替换

 writer.write(config.file.rows)

writer.write("${res.column1}|${res.column2}|${res.column3}\n")

它输出实际结果。为获得结果,我需要做些什么?

2 个答案:

答案 0 :(得分:4)

您可以通过使用Gstring的惰性求值以及更改委托来实现此目的。 首先通过使值成为调用Closures的结果来使Gstring变得懒惰:

file.rows="${->res.column1}|${->res.column2}|${-> res.column3}"

然后在评估更改闭包的委托之前:

config.file.rows.values.each {
    if (Closure.class.isAssignableFrom(it.getClass())) {
       it.resolveStrategy = Closure.DELEGATE_FIRST
       it.delegate = this
    }
}

委托必须在范围内具有变量res。这是一个完整的工作示例:

class Test {
Map res

void run() {
    String configText = '''file.rows="${->res.column1}|${->res.column2}|${-> res.column3}"
    sql="select * from mydb"'''
    def slurper = new ConfigSlurper()
    def config = slurper.parse(configText)

    config.file.rows.values.each {
        if (Closure.class.isAssignableFrom(it.getClass())) {
           it.resolveStrategy = Closure.DELEGATE_FIRST
           it.delegate = this
        }
    }

    def results = [
            [column1: 1, column2: 2, column3: 3],
            [column1: 4, column2: 5, column3: 6],
        ]

    results.each {
        res = it
        println config.file.rows.toString()
    }
}
}
new Test().run()

答案 1 :(得分:0)

好消息是ConfigSlurper能够按预期为您执行GString变量替换。坏消息是它在调用parse()方法之前进行了这种替换,早在您有一个res变量替换到解析器之前。另一个坏消息是,如果被替换的变量没有在配置文件本身中定义,那么你必须通过binding属性提前将它们提供给slurper。

因此,要获得您想要的效果,您必须通过eachRow的每次传递来解析属性。这是否意味着你必须为每一行创建一个新的ConfigSlurper重新读取一次文件?不。您 必须为每次传递创建新的ConfigObject,但您可以重复使用ConfigSlurper和文件文本,如下所示:

def slurper = new ConfigSlurper();
def configText = new File("scripts/config.properties").text
def config = slurper.parse(configText)
Sql sql = Sql.newInstance(config.db.url, config.db.login, config.db.password, config.db.driver);

def fileToWrite = new File(config.copy.location)
def writer = fileToWrite.newWriter()
writer.write(config.file.headers)

sql.eachRow(config.sql){ result ->
    slurper.binding = [res:result]
    def reconfig = slurper.parse(configText)
    print(reconfig.file.rows)
}

请注意,我将Closure参数的名称从res更改为result。我这样做是为了强调slurper从绑定映射键中绘制名称res,而不是从闭包参数名称。

如果你想减少浪费" reparsing"时间和精力,你可以将file.rows属性分成它自己的单独文件。我仍然会在该文件中读取一次并重复使用"每行"解析。