001/*-
002 * #%L
003 * HAPI FHIR Search Parameters
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.jpa.searchparam.matcher;
021
022import java.util.List;
023
024public class InMemoryMatchResult {
025        public static final String PARSE_FAIL = "Failed to translate parse query string";
026        public static final String STANDARD_PARAMETER = "Standard parameters not supported";
027        public static final String CHAIN = "Chained parameters are not supported";
028        public static final String PARAM = "Parameter not supported";
029        public static final String QUALIFIER = "Qualified parameter not supported";
030        public static final String LOCATION_NEAR = "Location.position near not supported";
031
032        private final boolean myMatch;
033        /**
034         * True if it is expected that a search will be performed in-memory
035         */
036        private final boolean mySupported;
037        /**
038         * if mySupported is false, then the parameter responsible for in-memory search not being supported
039         */
040        private final String myUnsupportedParameter;
041        /**
042         * if mySupported is false, then the reason in-memory search is not supported
043         */
044        private final String myUnsupportedReason;
045        /**
046         * Only used by CompositeInMemoryDaoSubscriptionMatcher to track whether we had to go
047         * out to the database to resolve the match.
048         */
049        private boolean myInMemory = false;
050
051        private InMemoryMatchResult(boolean theMatch) {
052                this.myMatch = theMatch;
053                this.mySupported = true;
054                this.myUnsupportedParameter = null;
055                this.myUnsupportedReason = null;
056        }
057
058        private InMemoryMatchResult(String theUnsupportedParameter, String theUnsupportedReason) {
059                myMatch = false;
060                mySupported = false;
061                myUnsupportedParameter = theUnsupportedParameter;
062                myUnsupportedReason = theUnsupportedReason;
063        }
064
065        public static InMemoryMatchResult successfulMatch() {
066                return new InMemoryMatchResult(true);
067        }
068
069        public static InMemoryMatchResult fromBoolean(boolean theMatched) {
070                return new InMemoryMatchResult(theMatched);
071        }
072
073        public static InMemoryMatchResult unsupportedFromReason(String theUnsupportedReason) {
074                return new InMemoryMatchResult(null, theUnsupportedReason);
075        }
076
077        public static InMemoryMatchResult unsupportedFromParameterAndReason(String theUnsupportedParameter, String theUnsupportedReason) {
078                return new InMemoryMatchResult(theUnsupportedParameter, theUnsupportedReason);
079        }
080
081        public static InMemoryMatchResult noMatch() {
082                return new InMemoryMatchResult(false);
083        }
084
085        public boolean supported() {
086                return mySupported;
087        }
088
089        public boolean matched() {
090                return myMatch;
091        }
092
093        public String getUnsupportedReason() {
094                if (myUnsupportedParameter != null) {
095                        return "Parameter: <" + myUnsupportedParameter + "> Reason: " + myUnsupportedReason;
096                }
097                return myUnsupportedReason;
098        }
099
100        public boolean isInMemory() {
101                return myInMemory;
102        }
103
104        public void setInMemory(boolean theInMemory) {
105                myInMemory = theInMemory;
106        }
107
108        public static InMemoryMatchResult and(InMemoryMatchResult theLeft, InMemoryMatchResult theRight) {
109                if (theLeft == null) {
110                        return theRight;
111                }
112                if (theRight == null) {
113                        return theLeft;
114                }
115                if (theLeft.supported() && theRight.supported()) {
116                        return InMemoryMatchResult.fromBoolean(theLeft.matched() && theRight.matched());
117                }
118                if (!theLeft.supported() && !theRight.supported()) {
119                        return InMemoryMatchResult.unsupportedFromReason(List.of(theLeft.getUnsupportedReason(), theRight.getUnsupportedReason()).toString());
120                }
121                if (!theLeft.supported()) {
122                        return theLeft;
123                }
124                return theRight;
125        }
126
127        public static InMemoryMatchResult or(InMemoryMatchResult theLeft, InMemoryMatchResult theRight) {
128                if (theLeft == null) {
129                        return theRight;
130                }
131                if (theRight == null) {
132                        return theLeft;
133                }
134                if (theLeft.matched() || theRight.matched()) {
135                        return InMemoryMatchResult.successfulMatch();
136                }
137                if (!theLeft.supported() && !theRight.supported()) {
138                        return InMemoryMatchResult.unsupportedFromReason(List.of(theLeft.getUnsupportedReason(), theRight.getUnsupportedReason()).toString());
139                }
140                if (!theLeft.supported()) {
141                        return theLeft;
142                }
143                return theRight;
144        }
145
146}