@@ -53,25 +53,53 @@ MappingsResource <- R6::R6Class(
5353 # ' @description
5454 # ' Map concepts to a target vocabulary.
5555 # '
56- # ' @param source_concepts Vector of OMOP concept IDs to map.
57- # ' @param target_vocabulary Target vocabulary ID (e.g., "ICD10CM", "SNOMED").
58- # ' @param mapping_type Mapping type (direct, equivalent, broader, narrower).
56+ # ' @param target_vocabulary Target vocabulary ID (e.g., "ICD10CM", "SNOMED", "RxNorm").
57+ # ' @param source_concepts Vector of OMOP concept IDs to map. Use this OR source_codes, not both.
58+ # ' @param source_codes List of vocabulary/code pairs to map. Each element should be a list
59+ # ' with `vocabulary_id` and `concept_code`. Use this OR source_concepts, not both.
60+ # ' @param mapping_type Mapping type filter (direct, equivalent, broader, narrower).
5961 # ' @param include_invalid Include invalid mappings. Default `FALSE`.
6062 # ' @param vocab_release Specific vocabulary release version (e.g., "2025.1"). Default `NULL`.
6163 # '
6264 # ' @returns Mapping results with summary.
63- map = function (source_concepts ,
64- target_vocabulary ,
65+ map = function (target_vocabulary ,
66+ source_concepts = NULL ,
67+ source_codes = NULL ,
6568 mapping_type = NULL ,
6669 include_invalid = FALSE ,
6770 vocab_release = NULL ) {
68- checkmate :: assert_integerish(source_concepts , min.len = 1 )
6971 checkmate :: assert_string(target_vocabulary , min.chars = 1 )
7072
71- body <- list (
72- source_concepts = as.integer(source_concepts ),
73- target_vocabulary = target_vocabulary
74- )
73+ # Validate: exactly one of source_concepts or source_codes required
74+ has_concepts <- ! is.null(source_concepts ) && length(source_concepts ) > 0
75+ has_codes <- ! is.null(source_codes ) && length(source_codes ) > 0
76+
77+ if (! has_concepts && ! has_codes ) {
78+ abort_validation(" Either source_concepts or source_codes is required" )
79+ }
80+ if (has_concepts && has_codes ) {
81+ abort_validation(" Cannot use both source_concepts and source_codes" )
82+ }
83+
84+ body <- list (target_vocabulary = target_vocabulary )
85+
86+ if (has_concepts ) {
87+ checkmate :: assert_integerish(source_concepts , min.len = 1 )
88+ body $ source_concepts <- as.integer(source_concepts )
89+ }
90+
91+ if (has_codes ) {
92+ checkmate :: assert_list(source_codes , min.len = 1 )
93+ # Validate each code entry has required fields
94+ for (i in seq_along(source_codes )) {
95+ if (! all(c(" vocabulary_id" , " concept_code" ) %in% names(source_codes [[i ]]))) {
96+ abort_validation(
97+ sprintf(" source_codes[%d] must have 'vocabulary_id' and 'concept_code'" , i )
98+ )
99+ }
100+ }
101+ body $ source_codes <- source_codes
102+ }
75103
76104 if (! is.null(mapping_type )) {
77105 body $ mapping_type <- mapping_type
0 commit comments