-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRomFeature.R
More file actions
226 lines (224 loc) · 8.89 KB
/
RomFeature.R
File metadata and controls
226 lines (224 loc) · 8.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#' Feature entity data object
#' @description Object for storing a single feature with attribute and timeseries related
#' @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 feature class of type RomFeature
#' @seealso NA
#' @examples NA
#' @export RomFeature
RomFeature <- R6Class(
"RomFeature",
inherit = RomEntity,
public = list(
#' @field base_entity_type kind of entity
base_entity_type = 'dh_feature',
#' @field pk_name the name of this entity's pk column
pk_name = 'hydroid',
#' @field name of this entity
name = NA,
#' @field hydrocode alpha code for this entity from original dataset
hydrocode = NA,
#' @field ftype feature type
ftype = NA,
#' @field hydroid unique ID (integer)
hydroid = NA,
#' @field bundle main content type, i.e. facility, well, intake, ...
bundle = NA,
#' @field fstatus entity status
fstatus = NA,
# list of object references? or list format name, value, ...
#' @field description notes field
description = NA,
#' @field mps linked features
mps = NA,
#' @field geom feature geometry WKT
geom = NA,
#' @field nextdown_id feature geometry WKT
nextdown_id = NA,
#' @field parent_id feature geometry WKT
parent_id = NA,
#' @field sql_select_from syntax to use to select via an odbc or other SQL based datasource
sql_select_from = "
select * from dh_feature_fielded
",
#' @field base_only - how to export to list in case of complex multi table entity and ODBC
base_only = FALSE,
#' @param datasource RESTful repository object
#' @param config list of attributes to set, see also: to_list() for format
#' @param load_remote automatically query REST dataa source for matches?
#' @return object instance
initialize = function(datasource = NULL, config, load_remote = FALSE) {
#col.names(self$properties <-
super$initialize(datasource, config, load_remote)
# experimental support for automatic local caching
self$datasource$set_feature(self$to_list())
self$mps = list()
},
#' @return get_id the unique id of this entity alias to remote pkid, subclassed as function
get_id = function() {
return(self$hydroid)
},
#' @param config
#' @param load_remote automatically query remote data source for matches?
#' @return the data from the remote connection
load_data = function(config, load_remote) {
#message(paste("load_data() called "))
if (is.data.frame(config)) {
if (nrow(config) >= 1) {
config <- as.list(config[1,])
}
}
super$load_data(config, load_remote)
},
#' @param base_only include only base table columns (TRUE) or add fields (FALSE)
#' @return list of object attributes suitable for input to new() and from_list() methods
to_list = function(base_only=FALSE) {
# returns as a list, which can be set and fed back to
# from_list() or new(config)
t_list <- list(
hydroid = self$hydroid,
name = self$name,
hydrocode = self$hydrocode,
ftype = self$ftype,
fstatus = self$fstatus,
bundle = self$bundle,
nextdown_id = self$nextdown_id,
geom = self$geom
)
# accounts for ODBC
if (base_only == FALSE) {
t_list$geom = self$geom
}
return(t_list)
},
#' @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 == "hydroid") {
if (is.na(config$hydroid)) {
self$hydroid = NA
} else {
self$hydroid = as.integer(as.character(config$hydroid))
}
} else if (i == "name") {
self$name = as.character(config$name)
} else if (i == "hydrocode") {
self$hydrocode = as.character(config$hydrocode)
} else if (i == "ftype") {
self$ftype = as.character(config$ftype)
} else if (i == "bundle") {
self$bundle = as.character(config$bundle)
} else if (i == "fstatus") {
self$fstatus = as.character(config$fstatus)
} else if (i == "dh_geofield") {
self$geom = as.character(config$dh_geofield)
} else if (i == "nextdown_id") {
self$nextdown_id = as.integer(config$nextdown_id)
} else if (i == "parent_id") {
self$parent_id = as.integer(config$parent_id)
}
}
},
#' @return a dataframe of connected MPs
get_mps = function () {
if (self$datasource$connection_type == 'odbc') {
sql = paste("select * from dh_feature_fielded where parent_id =",self$get_id())
mps <- sqldf(sql,connection = self$datasource$connection)
return(mps)
} else {
message("get_mps() is not enabled for non-ODBC data sources")
return(FALSE)
}
},
#' @param thismp mp entity
#' @return add a connected MP. TBD
add_mp = function (thismp) {
j = length(self$mps) + 1
#self$mps[j] <- thismp
self$mps[j] <- list('obj' = thismp)
},
#' @param push_remote update locally only or push to remote database
#' @return NULL
save = function(push_remote=FALSE) {
# object class responsibilities
# - know the required elemenprop such as varid, featureid, entity_type
# fail if these required elemenprop are not available
if (push_remote) {
finfo <- self$to_list(self$base_only)
#Dont send geometry to dh_feature, won't exist as a field
finfo <- finfo[names(finfo) != 'geom']
finfo <- finfo[names(finfo) != 'nextdown_id']
hydroid = self$datasource$post('dh_feature', 'hydroid', finfo)
if (!is.logical(hydroid)) {
self$hydroid = hydroid
}
}
},
#' @param target_entity what type to relate to (default dh_feature)
#' @param inputs criteria to search for (list key = value format)
#' @param operator what type of spatial function,default = st_contains
#' Other options are 'overlaps' or 'st_within'
#' @param return_geoms FALSE will return a smaller dataframe
#' @param query_remote FALSE will search on in local datasource
#' @return dataframe of spatially related entities
find_spatial_relations = function(
target_entity = 'dh_feature',
inputs = list(
bundle = NA,
ftype = NA
),
operator = 'st_contains',
return_geoms = FALSE,
query_remote = TRUE
) {
# todo: should we move this to the ODBC functions? Needs more generic handling.
# currently only supports dh_feature, but could later support others
target_geomcol = 'dh_geofield_geom'
base_geomcol = 'dh_geofield_geom'
if (operator == 'overlaps') {
spatial_join = paste0(' (base.', base_geomcol, ' && target.', target_geomcol,') ')
} else if ( operator == 'st_overlaps' ) {
# same as overlaps
spatial_join = paste0(' (base.', base_geomcol, ' && target.', target_geomcol,') ')
} else if ( operator == 'st_contains' ) {
spatial_join = paste0(' (st_contains(base.', base_geomcol, ', target.', target_geomcol,')) ')
} else if ( operator == 'st_within' ) {
spatial_join = paste0(' (st_within(base.', target_geomcol, ', target.', base_geomcol,')) ')
} else if ( operator == 'st_contains_centroid' ) {
spatial_join = paste0(' (st_contains(base.', target_geomcol, ', st_centroid(target.', base_geomcol,'))) ')
}
# include this in inputs for odbc routines
input_where = paste0(
" base.hydroid = ", self$get_id()
)
if (length(inputs[!is.na(inputs)]) > 0) {
input_where = paste0(
input_where,
" AND ",
fn_guess_sql_where(self$base_entity_type, self$pk_name, inputs, "target")
)
}
sql = paste0("select target.*
from dh_feature_fielded as base
left outer join dh_feature_fielded as target
on ( ", spatial_join, ")",
" WHERE ", input_where
)
if (query_remote == FALSE) {
message("Warning: query_remote = FALSE is not yet supported for spatial relations")
}
message(sql)
related_entities <- dbGetQuery(conn = self$datasource$connection, sql)
if (return_geoms == FALSE) {
retcols = unlist(names(related_entities))
retcols <- retcols[-which(retcols == "dh_geofield")]
retcols <- retcols[-which(retcols == "dh_geofield_geom")]
related_entities <- related_entities[,retcols]
}
return(related_entities)
}
)
)