Skip to content

Commit 268c644

Browse files
authored
Merge pull request #414 from ropensci/filter_user
Add filter_osm_user() to generate overpass queries filtering by user
2 parents 4682978 + 4b4b0e9 commit 268c644

17 files changed

+289
-31
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: osmdata
22
Title: Import 'OpenStreetMap' Data as Simple Features or Spatial Objects
3-
Version: 0.3.0.9024
3+
Version: 0.3.0.9025
44
Authors@R: c(
55
person("Joan", "Maspons", , "joanmaspons@gmail.com", role = c("aut", "cre"),
66
comment = c(ORCID = "0000-0003-2286-8727")),

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export(add_osm_features)
1818
export(available_features)
1919
export(available_tags)
2020
export(bbox_to_string)
21+
export(filter_osm_user)
2122
export(get_overpass_url)
2223
export(getbb)
2324
export(opq)

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
## Major changes
99

1010
- `getbb()` can query wikidata ids for OSM relations properties (P402) (idea from @mhpob in #401, implemented in #403).
11+
- Add `filter_osm_user()` to add user filter to `overpass_queries` objects (#414).
1112

1213
## Minor changes
1314

R/opq.R

Lines changed: 102 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,85 @@ check_features <- function (features) {
618618
}
619619
}
620620

621+
622+
#' Add an user filter to an Overpass query
623+
#'
624+
#' Select objects last edited or ever touched by a specific user.
625+
#'
626+
#' @param opq An `overpass_query` object.
627+
#' @param user A vector of user names or user ids. If `is.numeric(user)` or
628+
#' `all(grepl(^[0-9]+$, user`)), assumes that `user` is a user id.
629+
#' @param touched If `TRUE`, selects objects of which at least one version has been edited
630+
#' by `user`. If `FALSE` (default), selects objects with `user` as the last editor
631+
#' only.
632+
#' @param is_uid If `FALSE`, assume that `user` are user names. Useful to filter for a
633+
#' user name which contains numbers only and otherwise would be considered an user id.
634+
#'
635+
#' @details
636+
#' The order of `filter_osm_user()` in a query construction is not relevant and is applied
637+
#' to the whole query (i.e. it affects all the statements of the query).
638+
#'
639+
#' See
640+
#' \url{https://dev.overpass-api.de/overpass-doc/en/criteria/misc_criteria.html#by_user}
641+
#' for details.
642+
#'
643+
#'
644+
#' @returns An [opq] object.
645+
#'
646+
#' @family queries
647+
#' @export
648+
#'
649+
#' @examples
650+
#' # Notice the "::user" and "::uid" fields in the oqp_csv()
651+
#' q_csv <- opq (bbox = "relation(id:11755232)", out = "meta", osm_type = "node") |>
652+
#' filter_osm_user (user = "jmaspons") |>
653+
#' add_osm_feature (key = "name") |>
654+
#' opq_csv (c ("::type", "::id", "name", "name:ca", "::user", "::uid"))
655+
#' cat (opq_string (q_csv))
656+
#' # Warning: csv queries can fail without errors in long running queries. For timeouts,
657+
#' # it returns empty results.
658+
#' \dontrun{
659+
#' d_csv <- osmdata_data_frame (q_csv)
660+
#' d_csv
661+
#' }
662+
#'
663+
#' q_touched <- opq (
664+
#' bbox = "relation(id:11755232)", out = "meta",
665+
#' osm_type = "node", timeout = 100
666+
#' ) |>
667+
#' filter_osm_user (user = "jmaspons", touched = TRUE) |>
668+
#' add_osm_feature (key = "name")
669+
#' cat (opq_string (q_touched))
670+
#' \dontrun{
671+
#' d_touched <- osmdata_data_frame (q_touched)
672+
#' d_touched
673+
#' }
674+
filter_osm_user <- function (opq, user, touched = FALSE, is_uid) {
675+
if (missing (is_uid)) {
676+
is_uid <- is.numeric (user) || all (grepl ("^[0-9]+$", user))
677+
}
678+
stopifnot (is.logical (is_uid))
679+
680+
opq$user <- if (is_uid) {
681+
user <- paste (user, collapse = ",")
682+
if (touched) {
683+
paste0 ("(uid_touched:", user, ")")
684+
} else {
685+
paste0 ("(uid:", user, ")")
686+
}
687+
} else {
688+
user <- paste (user, collapse = "\",\"")
689+
if (touched) {
690+
paste0 ("(user_touched:\"", user, "\")")
691+
} else {
692+
paste0 ("(user:\"", user, "\")")
693+
}
694+
}
695+
696+
return (opq)
697+
}
698+
699+
621700
#' Add a feature specified by OSM ID to an Overpass query
622701
#'
623702
#' @inheritParams opq
@@ -943,71 +1022,74 @@ opq_string_intern <- function (opq, quiet = TRUE) {
9431022
res <- NULL
9441023
if (!is.null (opq$features)) { # opq with add_osm_feature
9451024

946-
features <- opq$features
1025+
filters <- opq$features
9471026

948-
if (length (features) > 1L) { # from add_osm_features fn
1027+
if (length (filters) > 1L) { # from add_osm_features()
9491028

950-
features <- vapply (features, function (i) {
1029+
filters <- vapply (filters, function (i) {
9511030
paste (i, collapse = "")
9521031
},
953-
character (1),
1032+
FUN.VALUE = character (1),
9541033
USE.NAMES = FALSE
9551034
)
9561035
}
9571036

1037+
if (!is.null (opq$user)) { # from filter_osm_user()
1038+
filters <- paste (filters, opq$user)
1039+
}
1040+
9581041
if (!is.null (attr (opq, "enclosing"))) {
9591042

960-
if (length (features) > 1) {
1043+
if (length (filters) > 1) {
9611044
stop ("enclosing queries can only accept one feature")
9621045
}
9631046

9641047
lat <- strsplit (opq$bbox, ",") [[1]] [1]
9651048
lon <- strsplit (opq$bbox, ",") [[1]] [2]
966-
features <- paste0 (
1049+
filters <- paste0 (
9671050
"is_in(", lat, ",",
9681051
lon, ")->.a;",
9691052
attr (opq, "enclosing"),
9701053
"(pivot.a)",
971-
features,
1054+
filters,
9721055
";"
9731056
)
9741057

9751058
} else {
9761059

977-
types_features <- expand.grid (
1060+
types_filters <- expand.grid (
9781061
osm_types = opq$osm_types,
979-
features = features,
1062+
filters = filters,
9801063
stringsAsFactors = FALSE
9811064
)
9821065

9831066
if (!map_to_area) {
984-
features <- c (sprintf (
1067+
filters <- c (sprintf (
9851068
" %s %s (%s);\n",
986-
types_features$osm_types,
987-
types_features$features,
1069+
types_filters$osm_types,
1070+
types_filters$filters,
9881071
opq$bbox
9891072
))
990-
9911073
} else {
9921074
opq$prefix <- gsub ("\n$", "", opq$prefix)
9931075
search_area <- paste0 (
9941076
opq$bbox,
9951077
"; map_to_area->.searchArea; );\n(\n"
9961078
)
997-
features <- c (
1079+
filters <- c (
9981080
search_area,
9991081
sprintf (
10001082
" %s %s (area.searchArea);\n",
1001-
types_features$osm_types,
1002-
types_features$features
1083+
types_filters$osm_types,
1084+
types_filters$filters
10031085
)
10041086
)
10051087
}
10061088
}
10071089

10081090
res <- paste0 (
10091091
opq$prefix,
1010-
paste (features, collapse = ""),
1092+
paste (filters, collapse = ""),
10111093
opq$suffix
10121094
)
10131095

@@ -1022,7 +1104,7 @@ opq_string_intern <- function (opq, quiet = TRUE) {
10221104
id <- paste (id, collapse = "")
10231105
res <- paste0 (opq$prefix, id, opq$suffix)
10241106

1025-
} else { # straight opq with neither features nor ID specified
1107+
} else { # straight opq with neither tag filters nor ID specified
10261108

10271109
if (!quiet) {
10281110
message (
@@ -1034,14 +1116,14 @@ opq_string_intern <- function (opq, quiet = TRUE) {
10341116
}
10351117

10361118
if (!map_to_area) {
1037-
bbox <- sprintf (" %s (%s);\n", opq$osm_types, opq$bbox)
1119+
bbox <- sprintf (" %s (%s);\n", paste (opq$osm_types, opq$user), opq$bbox)
10381120
} else {
10391121
opq$prefix <- gsub ("\n$", "", opq$prefix)
10401122
search_area <-
10411123
paste0 (opq$bbox, "; map_to_area->.searchArea; );\n(\n")
10421124
bbox <- c (
10431125
search_area,
1044-
sprintf (" %s (area.searchArea);\n", opq$osm_types)
1126+
sprintf (" %s (area.searchArea);\n", paste (opq$osm_types, opq$user))
10451127
)
10461128
}
10471129

man/add_osm_feature.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/add_osm_features.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/bbox_to_string.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/filter_osm_user.Rd

Lines changed: 76 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/getbb.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/opq.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)