Skip to content

Commit 7d18310

Browse files
authored
Merge pull request #116 from OHDSI/develop
Prep v2.1.1 release
2 parents 335bf37 + 3dfd3ac commit 7d18310

160 files changed

Lines changed: 1649 additions & 170 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/R_CMD_check_Hades.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
config:
2323
- {os: windows-latest, r: 'release'}
2424
- {os: macOS-latest, r: 'release'}
25-
- {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
25+
- {os: ubuntu-24.04, r: 'release'}
2626

2727
env:
2828
GITHUB_PAT: ${{ secrets.GH_TOKEN }}
@@ -76,7 +76,7 @@ jobs:
7676
while read -r cmd
7777
do
7878
eval sudo $cmd
79-
done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))')
79+
done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "22.04"))')
8080
8181
- uses: r-lib/actions/setup-r-dependencies@v2
8282
with:

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: Capr
22
Title: Cohort Definition Application Programming
3-
Version: 2.1.0
3+
Version: 2.1.1
44
Authors@R: c(
55
person("Martin", "Lavallee", , "martin.lavallee@boehringer-ingelheim.com", role = c("aut", "cre")),
66
person("Adam", "Black", , "black@ohdsi.org", role = c("aut")),

NAMESPACE

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export(cohort)
1212
export(compile)
1313
export(conditionEra)
1414
export(conditionOccurrence)
15+
export(conditionSourceConcept)
1516
export(conditionStatus)
1617
export(conditionType)
1718
export(continuousObservation)
@@ -26,6 +27,7 @@ export(drugExit)
2627
export(drugExposure)
2728
export(drugQuantity)
2829
export(drugRefills)
30+
export(drugSourceConcept)
2931
export(drugType)
3032
export(duringInterval)
3133
export(endDate)
@@ -60,16 +62,20 @@ export(observation)
6062
export(observationExit)
6163
export(observationPeriod)
6264
export(observationPeriodType)
65+
export(observationSourceConcept)
6366
export(observationType)
6467
export(procedure)
68+
export(procedureSourceConcept)
6569
export(procedureType)
6670
export(rangeHigh)
6771
export(rangeLow)
6872
export(readConceptSet)
6973
export(startDate)
7074
export(toCirce)
75+
export(valueAsConcept)
7176
export(valueAsNumber)
7277
export(visit)
78+
export(visitSourceConcept)
7379
export(visitType)
7480
export(withAll)
7581
export(withAny)

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
Capr 2.1.1
2+
==========
3+
- add functions to include source concepts as attributes to a query
4+
- add demographic criteria for Inclusion rules
5+
- add value as concept attribute
6+
7+
18
Capr 2.1.0
29
==========
310
- add observation period query

R/Capr.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2025 Observational Health Data Sciences and Informatics
1+
# Copyright 2026 Observational Health Data Sciences and Informatics
22
#
33
# This file is part of Capr
44
#

R/attributes-concept.R

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
# Concept Set Attribute class ----------------------------
2+
3+
#' An S4 class for a concept set attribute that holds a reference to a concept set ID
4+
#' @slot
5+
#' name the name of the attribute
6+
#' @slot
7+
#' conceptSet a ConceptSet object that provides the ID reference
8+
#' @include conceptSet.R
9+
setClass("conceptSetAttribute",
10+
slots = c(name = "character",
11+
conceptSet = "ConceptSet"),
12+
prototype = list(name = NA_character_, conceptSet = new("ConceptSet")))
13+
14+
setValidity("conceptSetAttribute", function(object) {
15+
stopifnot(is.character(object@name), length(object@name) == 1)
16+
TRUE
17+
})
18+
19+
# Console Print ---------------
20+
21+
setMethod("show", "conceptSetAttribute", function(object) {
22+
cli::cat_bullet(paste("Capr Concept Set Attribute:", object@name, "- ID:", object@conceptSet@id), bullet = "sup_plus")
23+
})
24+
125
# Concept Attribute class ----------------------------
226

327
#' An S4 class for a concept attribute
@@ -107,6 +131,23 @@ buildConceptAttribute <- function(ids, attributeName, connection, vocabularyData
107131
return(attr_concept)
108132
}
109133

134+
135+
#' Add a value as concept attribute
136+
#' @param ids the concept ids for the attribute
137+
#' @param connection a connection to an OMOP dbms to get vocab info about the concept
138+
#' @param vocabularyDatabaseSchema the database schema for the vocabularies
139+
#' @return
140+
#' An attribute that can be used in a query function
141+
#' @export
142+
#'
143+
valueAsConcept <- function(ids, connection, vocabularyDatabaseSchema) {
144+
res <- buildConceptAttribute(ids = ids, attributeName = "ValueAsConcept",
145+
connection = connection,
146+
vocabularyDatabaseSchema = vocabularyDatabaseSchema)
147+
return(res)
148+
}
149+
150+
110151
#' Add a drug type attribute to determine the provenance of the record
111152
#' @param ids the concept ids for the attribute
112153
#' @param connection a connection to an OMOP dbms to get vocab info about the concept
@@ -217,6 +258,94 @@ conditionStatus <- function(ids, connection, vocabularyDatabaseSchema) {
217258
return(res)
218259
}
219260

261+
#' Add a condition source concept attribute
262+
#' @param conceptSet a ConceptSet object containing the source concepts
263+
#' @return
264+
#' An attribute that can be used in a query function
265+
#' @export
266+
#'
267+
conditionSourceConcept <- function(conceptSet) {
268+
if (!methods::is(conceptSet, "ConceptSet")) {
269+
rlang::abort("conditionSourceConcept requires a ConceptSet object")
270+
}
271+
272+
res <- methods::new("conceptSetAttribute",
273+
name = "ConditionSourceConcept",
274+
conceptSet = conceptSet)
275+
return(res)
276+
}
277+
278+
#' Add a drug source concept attribute
279+
#' @param conceptSet a ConceptSet object containing the source concepts
280+
#' @return
281+
#' An attribute that can be used in a query function
282+
#' @export
283+
#'
284+
drugSourceConcept <- function(conceptSet) {
285+
if (!methods::is(conceptSet, "ConceptSet")) {
286+
rlang::abort("drugSourceConcept requires a ConceptSet object")
287+
}
288+
289+
res <- methods::new("conceptSetAttribute",
290+
name = "DrugSourceConcept",
291+
conceptSet = conceptSet)
292+
return(res)
293+
}
294+
295+
296+
#' Add a procedure source concept attribute
297+
#' @param conceptSet a ConceptSet object containing the source concepts
298+
#' @return
299+
#' An attribute that can be used in a query function
300+
#' @export
301+
#'
302+
procedureSourceConcept <- function(conceptSet) {
303+
if (!methods::is(conceptSet, "ConceptSet")) {
304+
rlang::abort("procedureSourceConcept requires a ConceptSet object")
305+
}
306+
307+
res <- methods::new("conceptSetAttribute",
308+
name = "ProcedureSourceConcept",
309+
conceptSet = conceptSet)
310+
return(res)
311+
}
312+
313+
314+
315+
#' Add a observation source concept attribute
316+
#' @param conceptSet a ConceptSet object containing the source concepts
317+
#' @return
318+
#' An attribute that can be used in a query function
319+
#' @export
320+
#'
321+
observationSourceConcept <- function(conceptSet) {
322+
if (!methods::is(conceptSet, "ConceptSet")) {
323+
rlang::abort("observationSourceConcept requires a ConceptSet object")
324+
}
325+
326+
res <- methods::new("conceptSetAttribute",
327+
name = "ObservationSourceConcept",
328+
conceptSet = conceptSet)
329+
return(res)
330+
}
331+
332+
#' Add a visit source concept attribute
333+
#' @param conceptSet a ConceptSet object containing the source concepts
334+
#' @return
335+
#' An attribute that can be used in a query function
336+
#' @export
337+
#'
338+
visitSourceConcept <- function(conceptSet) {
339+
if (!methods::is(conceptSet, "ConceptSet")) {
340+
rlang::abort("visitSourceConcept requires a ConceptSet object")
341+
}
342+
343+
res <- methods::new("conceptSetAttribute",
344+
name = "VisitSourceConcept",
345+
conceptSet = conceptSet)
346+
return(res)
347+
}
348+
220349
#' Add a observation period type attribute to determine the provenance of the record
221350
#' @param ids the concept ids for the attribute
222351
#' @param connection a connection to an OMOP dbms to get vocab info about the concept
@@ -281,6 +410,11 @@ measurementUnit <- function(x) {
281410

282411
# Coercion ------------------
283412

413+
setMethod("as.list", "conceptSetAttribute", function(x) {
414+
nm <- x@name
415+
tibble::lst(`:=`(!!nm, x@conceptSet@id))
416+
})
417+
284418
setMethod("as.list", "conceptAttribute", function(x) {
285419

286420
concepts <- purrr::map(x@conceptSet, ~as.list(.x))

R/collectCodesetId.R

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ replaceGuid <- function(x, y) {
1515

1616
setGeneric("collectGuid", function(x) standardGeneric("collectGuid"))
1717

18+
setMethod("collectGuid", "conceptSetAttribute", function(x) {
19+
getGuid(x)
20+
})
21+
22+
setMethod("collectGuid", "conceptAttribute", function(x) {
23+
return(NULL)
24+
})
25+
26+
setMethod("collectGuid", "opAttributeSuper", function(x) {
27+
return(NULL)
28+
})
1829

1930
# setMethod("collectGuid", "Query", function(x) {
2031
# getGuid(x)
@@ -37,6 +48,14 @@ setMethod("collectGuid", "Query", function(x) {
3748

3849
ids <- dplyr::bind_rows(ids, id2)
3950
}
51+
52+
# collect guids for conceptSetAttribute objects
53+
conceptSetAttrs <- purrr::keep(x@attributes, ~methods::is(.x, "conceptSetAttribute"))
54+
if (length(conceptSetAttrs) > 0) {
55+
conceptSetIds <- purrr::map_dfr(conceptSetAttrs, ~collectGuid(.x))
56+
ids <- dplyr::bind_rows(ids, conceptSetIds)
57+
}
58+
4059
return(ids)
4160

4261
})
@@ -99,6 +118,29 @@ setMethod("collectGuid", "Cohort", function(x) {
99118
## TODO HASH table implementation of find/replace
100119
setGeneric("replaceCodesetId", function(x, guidTable) standardGeneric("replaceCodesetId"))
101120

121+
setMethod("replaceCodesetId", "conceptSetAttribute", function(x, guidTable) {
122+
123+
if (nrow(getGuid(x)) > 0) {
124+
y <- getGuid(x) |>
125+
dplyr::inner_join(guidTable, by = c("guid")) |>
126+
dplyr::pull(.data$codesetId)
127+
} else {
128+
y <- NULL
129+
}
130+
131+
x <- replaceGuid(x, y)
132+
133+
return(x)
134+
})
135+
136+
setMethod("replaceCodesetId", "conceptAttribute", function(x, guidTable) {
137+
return(x)
138+
})
139+
140+
setMethod("replaceCodesetId", "opAttributeSuper", function(x, guidTable) {
141+
return(x)
142+
})
143+
102144

103145
setMethod("replaceCodesetId", "Query", function(x, guidTable) {
104146

@@ -122,6 +164,14 @@ setMethod("replaceCodesetId", "Query", function(x, guidTable) {
122164

123165
x@attributes[[ii]]@group <- nest
124166
}
167+
168+
# replace codeset ids for conceptSetAttribute objects
169+
conceptSetAttrIndices <- which(purrr::map_lgl(x@attributes, ~methods::is(.x, "conceptSetAttribute")))
170+
if (length(conceptSetAttrIndices) > 0) {
171+
for (i in conceptSetAttrIndices) {
172+
x@attributes[[i]] <- replaceCodesetId(x@attributes[[i]], guidTable)
173+
}
174+
}
125175

126176
return(x)
127177
})
@@ -204,6 +254,19 @@ setMethod("replaceCodesetId", "Cohort", function(x, guidTable = guidTable) {
204254

205255
setGeneric("listConceptSets", function(x) standardGeneric("listConceptSets"))
206256

257+
setMethod("listConceptSets", "conceptSetAttribute", function(x) {
258+
as.list(x@conceptSet)
259+
})
260+
261+
setMethod("listConceptSets", "conceptAttribute", function(x) {
262+
return(NULL)
263+
})
264+
265+
setMethod("listConceptSets", "opAttributeSuper", function(x) {
266+
return(NULL)
267+
})
268+
269+
207270
#' @include query.R
208271
setMethod("listConceptSets", "Query", function(x) {
209272
qs <- as.list(x@conceptSet)
@@ -219,6 +282,13 @@ setMethod("listConceptSets", "Query", function(x) {
219282
} else {
220283
out <- list(qs)
221284
}
285+
286+
# handle listing concept sets from conceptSetAttribute objects
287+
conceptSetAttrs <- purrr::keep(x@attributes, ~methods::is(.x, "conceptSetAttribute"))
288+
if (length(conceptSetAttrs) > 0) {
289+
conceptSetsFromAttrs <- purrr::map(conceptSetAttrs, ~listConceptSets(.x))
290+
out <- c(out, conceptSetsFromAttrs)
291+
}
222292

223293
return(out)
224294
})

R/conceptSet.R

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,7 @@ setClass("ConceptSet",
114114
Expression = "list"))
115115

116116
setValidity("ConceptSet", function(object) {
117-
stopifnot(is.character(object@id),
118-
length(object@id) == 1,
119-
#is.character(object@id),
120-
length(object@id) == 1,
117+
stopifnot(length(object@id) == 1,
121118
is.list(object@Expression),
122119
all(purrr::map_lgl(object@Expression, ~is(., "ConceptSetItem")))
123120
)

R/criteria.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ setClass("Group",
6060

6161
# Class Type ----
6262
is.Criteria <- function(x) {
63-
methods::is(x) == "Criteria"
63+
any(methods::is(x) == "Criteria")
6464
}
6565

6666
is.Group <- function(x) {
67-
methods::is(x) == "Group"
67+
any(methods::is(x) == "Group")
6868
}
6969

7070
# Constructors -----------------------

0 commit comments

Comments
 (0)