R/RomTS.R

#' Time Series data object
#' @description Object for storing single time series value
#' @details Has standard methods for managing data and meta data
#' @importFrom R6 R6Class  
#' @param datasource optional RomDataSource for remote and local storage
#' @param config list of attributes to set
#' @return reference class of type openmi.om.base.
#' @seealso NA
#' @examples NA
#' @export RomTS
RomTS <- R6Class(
  "RomTS",
  inherit = RomEntity,
  public = list(
    #' @field base_entity_type kind of entity
    base_entity_type = 'dh_timeseries',
    #' @field pk_name the name of this entity's pk column
    pk_name = 'tid',
    #' @field has_vardef is pluggable?
    has_vardef = TRUE,
    #' @field tid unique ID in this RomDataSource
    tid = NA,
    #' @field featureid id of entity this is attached to
    featureid = NA,
    #' @field entity_type type of entity this is attached to
    entity_type = NA,
    #' @field tstime begin timestamp
    tstime = NA,
    #' @field tsendtime end time stamp
    tsendtime = NA,
    #' @field tsvalue numerical value
    tsvalue = NA,
    #' @field tscode alphanumeric value
    tscode = NA,
    #' @field tlid timeline ID (for future use)
    tlid = NA,
    #' @field varid variable ID from RomDataSource
    varid = NA,
    #' @field bundle (for future use)
    bundle = NA,
    #' @field uid user id of creator
    uid = NA,
    #' @field modified timestamp 
    modified = NA,
    #' @field datasource RomDataSource
    datasource = NA,
    #' @field sql_select_from syntax to use to select via an odbc or other SQL based datasource
    sql_select_from = "
      select * from (
        select a.*, c.filename as image_name, c.uri as image_uri
        from dh_timeseries as a 
        left outer join field_data_field_image as b
        on (
          b.entity_id = a.tid
          and b.entity_type = 'dh_timeseries'
        )
        left outer join file_managed as c
        on (
          c.fid = b.field_image_fid
        )
      ) as dh_timeseries
    ",
    #' @return get_id the id of this entity alias to remote pkid, subclassed as function
    get_id = function() {
      return(self$tid)
    },
    #' @param site URL of some RESTful repository
    #' @param config list of attributes to set, see also: to_list() for format
    #' @param load_remote automatically query REST data source for matches?
    #' @return object instance
    initialize = function(datasource = NULL, config = list(), load_remote = FALSE) {
      # a config template can be generated by using the to_list() method 
      # of a blank object
      # todo: some of this can be handled by the RomDataSource?
      stopifnot(class(datasource)[[1]] == "RomDataSource")
      self$datasource <- datasource 
      config_cols <- names(config)
      if (is.element("varkey", config_cols)) {
        if (!is.null(self$datasource)) {
          message(paste("getting varid for", config$varkey))
          vardef = self$datasource$get_vardef(config$varkey)
          config$varid = vardef$hydroid
          message(paste(" varid =", config$varid))
          # eliminate this since if passed raw to rest will cause problems
          config$varkey <- NULL
        }
      }
      # if requested, we try to load
      # only the last one returned will be sent back to user if multiple
      if (load_remote) {
        ts <- self$datasource$get_ts(config, 'list', TRUE, self)
        # merge config with ts
        #message("Found")
        if (!is.logical(ts)) {
          config <- ts
        }
      }
      self$from_list(config)
    },
    #' @param config list of attributes to set, see also: to_list() for format
    #' @return NULL
    from_list = function(config) {
      for (i in names(config)) {
        if (i == "tid") {
          self$tid = as.integer(as.character(config$tid))
        } else if (i == "varid") {
          self$varid = as.integer(as.character(config$varid))
        } else if (i == "entity_type") {
          self$entity_type = config$entity_type
        } else if (i == "featureid") {
          self$featureid = as.integer(as.character(config$featureid))
        } else if (i == "tstime") {
          self$tstime = as.integer(as.character(config$tstime))
        } else if (i == "tsendtime") {
          self$tsendtime = as.integer(as.character(config$tsendtime))
        } else if (i == "tsvalue") {
          self$tsvalue = config$tsvalue
        } else if (i == "tscode") {
          self$tscode = config$tscode
        } else if (i == "tlid") {
          self$tlid = as.integer(as.character(config$tlid))
        } else if (i == "bundle") {
          self$bundle = config$bundle
        }
      }
    },
    #' @return list of object attributes suitable for input to new() and from_list() methods
    to_list = function() {
      # returns as a list, which can be set and fed back to 
      # from_list() or new(config)
      t_list <- list(
        tid = as.integer(self$tid),
        entity_type = self$entity_type,
        varid = as.integer(self$varid),
        featureid = as.integer(self$featureid),
        tstime = as.integer(self$tstime),
        tsendtime = as.integer(self$tsendtime),
        tsvalue = self$tsvalue,
        tscode = self$tscode 
        # todo
        #modified = self$modified,
        # todo:
        #tlid = self$tlid,
        # todo:
        # uid = self$uid
        # todo:
        # bundle = self$bundle
      )
      return(t_list)
    },
    #' @param name attribute name
    #' @param value attribute value
    #' @param format type of data being sent (default, json, ...)
    #' @return object instance
    set_prop = function(name, value, format='default') {
      # this should be at the base class, should not have to subclass
      # @tbd: can this even be done on a local object field? 
      # it may not be necessary, we may only implement 
      # calls to set RomProperties linked to it?
      # self$hair <- val
    },
    #' @param push_remote whether to automatically propagate changes to remote data source
    #' @return boolean TRUE on success, FALSE on failure
    save = function(push_remote=FALSE) {
      # this should be at the base class, should not have to subclass
      # @tbd: can this even be done on a local object field? 
      # data source responsibilities:
      # - know how to format any entity for REST on this data source
      # - know the site, token, and supporting functions if need be
      # - support data retrieval functions, such as vardef
      # object class responsibilities
      # - know the required elements such as varid, featureid, entity_type
      #   fail if these required elements are not available 
      # it may not be necessary, we may only implement 
      # calls to set RomProperties linked to it?
      # self$hair <- val
      # do I have a varid? If not, get one, or fail.
      if (push_remote) {
        tid = self$datasource$post('dh_timeseries', 'tid', self$to_list())
        message(paste("Post returned:", tid))
        if (!is.logical(tid)) {
          self$tid = tid
        }
      }
      self$datasource$set_ts(self$to_list())
    }
  )
)
HARPgroup/hydro-tools documentation built on July 4, 2025, 11:05 a.m.