001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2023 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
031
032public class ReferenceClientParam extends BaseClientParam  implements IParam {
033
034        private String myName;
035
036        public ReferenceClientParam(String theName) {
037                myName = theName;
038        }
039
040        @Override
041        public String getParamName() {
042                return myName;
043        }
044
045        /**
046         * Include a chained search. For example:
047         * <pre>
048         * Bundle resp = ourClient
049         *   .search()
050         *   .forResource(QuestionnaireResponse.class)
051         *   .where(QuestionnaireResponse.SUBJECT.hasChainedProperty(Patient.FAMILY.matches().value("SMITH")))
052         *   .returnBundle(Bundle.class)
053         *   .execute();
054         * </pre>
055         */
056        public ICriterion<ReferenceClientParam> hasChainedProperty(ICriterion<?> theCriterion) {
057                return new ReferenceChainCriterion(getParamName(), theCriterion);
058        }
059
060        /**
061         * Include a chained search with a resource type. For example:
062         * <pre>
063         * Bundle resp = ourClient
064         *   .search()
065         *   .forResource(QuestionnaireResponse.class)
066         *   .where(QuestionnaireResponse.SUBJECT.hasChainedProperty("Patient", Patient.FAMILY.matches().value("SMITH")))
067         *   .returnBundle(Bundle.class)
068         *   .execute();
069         * </pre>
070         */
071        public ICriterion<ReferenceClientParam> hasChainedProperty(String theResourceType, ICriterion<?> theCriterion) {
072                return new ReferenceChainCriterion(getParamName(), theResourceType, theCriterion);
073        }
074
075        /**
076         * Match the referenced resource if the resource has the given ID (this can be
077         * the logical ID or the absolute URL of the resource)
078         */
079        public ICriterion<ReferenceClientParam> hasId(IIdType theId) {
080                return new StringCriterion<>(getParamName(), theId.getValue());
081        }
082
083        /**
084         * Match the referenced resource if the resource has the given ID (this can be
085         * the logical ID or the absolute URL of the resource)
086         */
087        public ICriterion<ReferenceClientParam> hasId(String theId) {
088                return new StringCriterion<>(getParamName(), theId);
089        }
090
091        /**
092         * Match the referenced resource if the resource has ANY of the given IDs
093         * (this is an OR search, not an AND search), (this can be the logical ID or
094         * the absolute URL of the resource). Note that to specify an AND search,
095         * simply add a subsequent {@link IQuery#where(ICriterion) where} criteria
096         * with the same parameter.
097         */
098        public ICriterion<ReferenceClientParam> hasAnyOfIds(Collection<String> theIds) {
099                return new StringCriterion<>(getParamName(), theIds);
100        }
101
102        /**
103         * Match the referenced resource if the resource has ANY of the given IDs
104         * (this is an OR search, not an AND search), (this can be the logical ID or
105         * the absolute URL of the resource). Note that to specify an AND search,
106         * simply add a subsequent {@link IQuery#where(ICriterion) where} criteria
107         * with the same parameter.
108         */
109        public ICriterion<ReferenceClientParam> hasAnyOfIds(String... theIds) {
110                Validate.notNull(theIds, "theIds must not be null");
111                return hasAnyOfIds(Arrays.asList(theIds));
112        }
113
114        private static class ReferenceChainCriterion implements ICriterion<ReferenceClientParam>, ICriterionInternal {
115
116                private final String myResourceTypeQualifier;
117                private String myParamName;
118                private ICriterionInternal myWrappedCriterion;
119
120                ReferenceChainCriterion(String theParamName, ICriterion<?> theWrappedCriterion) {
121                        this(theParamName, null, theWrappedCriterion);
122                }
123
124                ReferenceChainCriterion(String theParamName, String theResourceType, ICriterion<?> theWrappedCriterion) {
125                        myParamName = theParamName;
126                        myResourceTypeQualifier = isNotBlank(theResourceType) ? ":" + theResourceType : "";
127                        myWrappedCriterion = (ICriterionInternal) theWrappedCriterion;
128                }
129
130                @Override
131                public String getParameterName() {
132                        return myParamName + myResourceTypeQualifier + "." + myWrappedCriterion.getParameterName();
133                }
134
135                @Override
136                public String getParameterValue(FhirContext theContext) {
137                        return myWrappedCriterion.getParameterValue(theContext);
138                }
139
140        }
141
142}