首页 > 解决方案 > 用于数据库连接的 R 函数装饰器

问题描述

我想在 R 中编写函数装饰器来建立数据库连接。我红色了在 R 中编写装饰器的基本步骤 R 中的弱学习器装饰器。这篇文章中的示例工作正常。

要连接到数据库,我必须data_base_name在装饰器本身内部传递一个参数,这会给我一条错误消息:Error in eval(parse(text = text, keep.source = FALSE), envir) : object 'data_base_name' not found

我的装饰器功能:

    db_connect_decorator<-function(f) {
    function(...) {
        loginfo(str_glue("connecting to {data_base_name}"))
        for(i in 1:5){
        bSuccess=F
        tryCatch({
            con = dbConnect(RMySQL::MySQL(), 
                            user=Sys.getenv("DB_USER"), 
                            password=Sys.getenv("DB_PASSWORD"), 
                            dbname=data_base_name, 
                            host=Sys.getenv("DB_HOST"),
                            port=Sys.getenv("DB_PORT") %>% as.integer())
            bSuccess=T
        }, error = function(e) {
            logerror(str_c("Error connecting data base: ", e, "trying to reconnect", sep = " "))
            Sys.sleep(1)
        })
        if(bSuccess) {
            assert(dbIsValid(con))
            Sys.sleep(1)
            result = f(con, ...)  
            assert(dbDisconnect(con))
            return(result)
        }else{
            logerror("Failed to connect to database")
            return(NULL)
        }
        }
    }
    }

教程中描述的装饰器包装器(无需额外参数即可正常工作):

    `%@%` = function(`@`, f) {
    `@`(f)
    }

使用数据库的函数,包含数据库名称:

    db_download<-db_connect_decorator %@% function(data_base_name, con=NULL){
    db_rs = dbSendQuery(con, "select * from my_table")
    res<<-fetch(db_rs, n=-1)
    dbClearResult(db_rs)
    res    
    }

这段代码给了我错误:

    db_download("mydb")

如何将附加变量传递给 R 中的装饰器函数,或一些解决方法?

标签: rdecorator

解决方案


我自己找到了答案。这是通用方法,但我将其用于数据库查询示例。

有必要将省略号参数转换为R list函数调用中的所有参数都必须命名。这是我的解决方案:

    fdecorator<-function(f, ...) {
        function(...) {
        kargs<-list(...)
        print(kargs$data_base_name)
        tryCatch({
            con= dbConnect(RMySQL::MySQL(),
                        user=Sys.getenv("DB_USER"),
                        password=Sys.getenv("DB_PASSWORD"),
                        dbname=kargs$data_base_name,
                        host=Sys.getenv("DB_HOST"),
                        port=Sys.getenv("DB_PORT") %>% as.integer())
            f(con, ...)
            dbDisconnect(con)
        }, error = function(e) {
            logerror(str_glue("Error connecting data base: {e}"))
        })
        }
    }
    f<-function(con, ...){
        kargs<-list(...)
        print(str_glue("Querying data base {kargs$data_base_name}"))
        # query database
    }
    fdecorated<-fdecorator(f)
    fdecorated(data_base_name="my_db")

推荐阅读