001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.rest.gclient;
021
022import ca.uhn.fhir.context.FhirContext;
023import org.apache.commons.lang3.Validate;
024import org.hl7.fhir.instance.model.api.IIdType;
025
026import java.util.Arrays;
027import java.util.Collection;
028
029import static org.apache.commons.lang3.StringUtils.isNotBlank;
030
031public class ReferenceClientParam extends BaseClientParam implements IParam {
032
033        private String myName;
034
035        public ReferenceClientParam(String theName) {
036                myName = theName;
037        }
038
039        @Override
040        public String getParamName() {
041                return myName;
042        }
043
044        /**
045         * Include a chained search. For example:
046         * <pre>
047         * Bundle resp = ourClient
048         *   .search()
049         *   .forResource(QuestionnaireResponse.class)
050         *   .where(QuestionnaireResponse.SUBJECT.hasChainedProperty(Patient.FAMILY.matches().value("SMITH")))
051         *   .returnBundle(Bundle.class)
052         *   .execute();
053         * </pre>
054         */
055        public ICriterion<ReferenceClientParam> hasChainedProperty(ICriterion<?> theCriterion) {
056                return new ReferenceChainCriterion(getParamName(), theCriterion);
057        }
058
059        /**
060         * Include a chained search with a resource type. For example:
061         * <pre>
062         * Bundle resp = ourClient
063         *   .search()
064         *   .forResource(QuestionnaireResponse.class)
065         *   .where(QuestionnaireResponse.SUBJECT.hasChainedProperty("Patient", Patient.FAMILY.matches().value("SMITH")))
066         *   .returnBundle(Bundle.class)
067         *   .execute();
068         * </pre>
069         */
070        public ICriterion<ReferenceClientParam> hasChainedProperty(String theResourceType, ICriterion<?> theCriterion) {
071                return new ReferenceChainCriterion(getParamName(), theResourceType, theCriterion);
072        }
073
074        /**
075         * Match the referenced resource if the resource has the given ID (this can be
076         * the logical ID or the absolute URL of the resource)
077         */
078        public ICriterion<ReferenceClientParam> hasId(IIdType theId) {
079                return new StringCriterion<>(getParamName(), theId.getValue());
080        }
081
082        /**
083         * Match the referenced resource if the resource has the given ID (this can be
084         * the logical ID or the absolute URL of the resource)
085         */
086        public ICriterion<ReferenceClientParam> hasId(String theId) {
087                return new StringCriterion<>(getParamName(), theId);
088        }
089
090        /**
091         * Match the referenced resource if the resource has ANY of the given IDs
092         * (this is an OR search, not an AND search), (this can be the logical ID or
093         * the absolute URL of the resource). Note that to specify an AND search,
094         * simply add a subsequent {@link IQuery#where(ICriterion) where} criteria
095         * with the same parameter.
096         */
097        public ICriterion<ReferenceClientParam> hasAnyOfIds(Collection<String> theIds) {
098                return new StringCriterion<>(getParamName(), theIds);
099        }
100
101        /**
102         * Match the referenced resource if the resource has ANY of the given IDs
103         * (this is an OR search, not an AND search), (this can be the logical ID or
104         * the absolute URL of the resource). Note that to specify an AND search,
105         * simply add a subsequent {@link IQuery#where(ICriterion) where} criteria
106         * with the same parameter.
107         */
108        public ICriterion<ReferenceClientParam> hasAnyOfIds(String... theIds) {
109                Validate.notNull(theIds, "theIds must not be null");
110                return hasAnyOfIds(Arrays.asList(theIds));
111        }
112
113        private static class ReferenceChainCriterion implements ICriterion<ReferenceClientParam>, ICriterionInternal {
114
115                private final String myResourceTypeQualifier;
116                private String myParamName;
117                private ICriterionInternal myWrappedCriterion;
118
119                ReferenceChainCriterion(String theParamName, ICriterion<?> theWrappedCriterion) {
120                        this(theParamName, null, theWrappedCriterion);
121                }
122
123                ReferenceChainCriterion(String theParamName, String theResourceType, ICriterion<?> theWrappedCriterion) {
124                        myParamName = theParamName;
125                        myResourceTypeQualifier = isNotBlank(theResourceType) ? ":" + theResourceType : "";
126                        myWrappedCriterion = (ICriterionInternal) theWrappedCriterion;
127                }
128
129                @Override
130                public String getParameterName() {
131                        return myParamName + myResourceTypeQualifier + "." + myWrappedCriterion.getParameterName();
132                }
133
134                @Override
135                public String getParameterValue(FhirContext theContext) {
136                        return myWrappedCriterion.getParameterValue(theContext);
137                }
138        }
139}