001/*-
002 * #%L
003 * HAPI FHIR JPA - Search Parameters
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.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(
078                        String theUnsupportedParameter, String theUnsupportedReason) {
079                return new InMemoryMatchResult(theUnsupportedParameter, theUnsupportedReason);
080        }
081
082        public static InMemoryMatchResult noMatch() {
083                return new InMemoryMatchResult(false);
084        }
085
086        public boolean supported() {
087                return mySupported;
088        }
089
090        public boolean matched() {
091                return myMatch;
092        }
093
094        public String getUnsupportedReason() {
095                if (myUnsupportedParameter != null) {
096                        return "Parameter: <" + myUnsupportedParameter + "> Reason: " + myUnsupportedReason;
097                }
098                return myUnsupportedReason;
099        }
100
101        public boolean isInMemory() {
102                return myInMemory;
103        }
104
105        public void setInMemory(boolean theInMemory) {
106                myInMemory = theInMemory;
107        }
108
109        public static InMemoryMatchResult and(InMemoryMatchResult theLeft, InMemoryMatchResult theRight) {
110                if (theLeft == null) {
111                        return theRight;
112                }
113                if (theRight == null) {
114                        return theLeft;
115                }
116                if (theLeft.supported() && theRight.supported()) {
117                        return InMemoryMatchResult.fromBoolean(theLeft.matched() && theRight.matched());
118                }
119                if (!theLeft.supported() && !theRight.supported()) {
120                        return InMemoryMatchResult.unsupportedFromReason(
121                                        List.of(theLeft.getUnsupportedReason(), theRight.getUnsupportedReason())
122                                                        .toString());
123                }
124                if (!theLeft.supported()) {
125                        return theLeft;
126                }
127                return theRight;
128        }
129
130        public static InMemoryMatchResult or(InMemoryMatchResult theLeft, InMemoryMatchResult theRight) {
131                if (theLeft == null) {
132                        return theRight;
133                }
134                if (theRight == null) {
135                        return theLeft;
136                }
137                if (theLeft.matched() || theRight.matched()) {
138                        return InMemoryMatchResult.successfulMatch();
139                }
140                if (!theLeft.supported() && !theRight.supported()) {
141                        return InMemoryMatchResult.unsupportedFromReason(
142                                        List.of(theLeft.getUnsupportedReason(), theRight.getUnsupportedReason())
143                                                        .toString());
144                }
145                if (!theLeft.supported()) {
146                        return theLeft;
147                }
148                return theRight;
149        }
150}