@@ -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
0 commit comments