001// -------------------------------------------------------------------------------- 002// Copyright 2002-2025 Echo Three, LLC 003// 004// Licensed under the Apache License, Version 2.0 (the "License"); 005// you may not use this file except in compliance with the License. 006// You may obtain a copy of the License at 007// 008// http://www.apache.org/licenses/LICENSE-2.0 009// 010// Unless required by applicable law or agreed to in writing, software 011// distributed under the License is distributed on an "AS IS" BASIS, 012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013// See the License for the specific language governing permissions and 014// limitations under the License. 015// -------------------------------------------------------------------------------- 016 017package com.echothree.model.control.search.server.logic; 018 019import com.echothree.model.control.core.common.EntityAttributeTypes; 020import com.echothree.model.control.core.common.exception.InvalidEntityAttributeTypeException; 021import com.echothree.model.control.core.server.control.CoreControl; 022import com.echothree.model.control.search.common.transfer.UserVisitSearchFacetIntegerTransfer; 023import com.echothree.model.control.search.common.transfer.UserVisitSearchFacetListItemTransfer; 024import com.echothree.model.control.search.common.transfer.UserVisitSearchFacetLongTransfer; 025import com.echothree.model.control.search.common.transfer.UserVisitSearchFacetTransfer; 026import com.echothree.model.control.search.server.database.EntityIntegerAttributeFacetQuery; 027import com.echothree.model.control.search.server.database.EntityListItemAttributeFacetQuery; 028import com.echothree.model.control.search.server.database.EntityLongAttributeFacetQuery; 029import com.echothree.model.control.search.server.database.EntityMultipleListItemAttributeFacetQuery; 030import com.echothree.model.control.search.server.graphql.UserVisitSearchFacetIntegerObject; 031import com.echothree.model.control.search.server.graphql.UserVisitSearchFacetListItemObject; 032import com.echothree.model.control.search.server.graphql.UserVisitSearchFacetLongObject; 033import com.echothree.model.control.search.server.graphql.UserVisitSearchFacetObject; 034import com.echothree.model.data.core.server.entity.EntityAttribute; 035import com.echothree.model.data.core.server.entity.EntityIntegerRangeDetail; 036import com.echothree.model.data.core.server.entity.EntityLongRangeDetail; 037import com.echothree.model.data.search.server.entity.UserVisitSearch; 038import com.echothree.util.common.message.ExecutionErrors; 039import com.echothree.util.common.transfer.ListWrapper; 040import com.echothree.util.server.control.BaseLogic; 041import com.echothree.util.server.message.ExecutionErrorAccumulator; 042import com.echothree.util.server.persistence.Session; 043import java.util.ArrayList; 044import java.util.List; 045import javax.enterprise.context.ApplicationScoped; 046import javax.enterprise.inject.spi.CDI; 047 048@ApplicationScoped 049public class UserVisitSearchFacetLogic 050 extends BaseLogic { 051 052 protected UserVisitSearchFacetLogic() { 053 super(); 054 } 055 056 public static UserVisitSearchFacetLogic getInstance() { 057 return CDI.current().select(UserVisitSearchFacetLogic.class).get(); 058 } 059 060 private List<EntityIntegerRangeDetail> getEntityIntegerRangeDetails(final EntityAttribute entityAttribute) { 061 final var coreControl = Session.getModelController(CoreControl.class); 062 final var entityIntegerRanges = coreControl.getEntityIntegerRanges(entityAttribute); 063 final var entityIntegerRangeDetails = new ArrayList<EntityIntegerRangeDetail>(entityIntegerRanges.size()); 064 065 entityIntegerRanges.forEach((entityIntegerRange) -> { 066 entityIntegerRangeDetails.add(entityIntegerRange.getLastDetail()); 067 }); 068 069 return entityIntegerRangeDetails; 070 } 071 072 private List<EntityLongRangeDetail> getEntityLongRangeDetails(final EntityAttribute entityAttribute) { 073 final var coreControl = Session.getModelController(CoreControl.class); 074 final var entityLongRanges = coreControl.getEntityLongRanges(entityAttribute); 075 final var entityLongRangeDetails = new ArrayList<EntityLongRangeDetail>(entityLongRanges.size()); 076 077 entityLongRanges.forEach((entityLongRange) -> { 078 entityLongRangeDetails.add(entityLongRange.getLastDetail()); 079 }); 080 081 return entityLongRangeDetails; 082 } 083 084 // Substantial portions of this are duplicated in getUserVisitSearchFacetObject(...). 085 public UserVisitSearchFacetTransfer getUserVisitSearchFacetTransfer(final ExecutionErrorAccumulator eea, final UserVisitSearch userVisitSearch, 086 final EntityAttribute entityAttribute) { 087 final var coreControl = Session.getModelController(CoreControl.class); 088 List<UserVisitSearchFacetListItemTransfer> userVisitSearchFacetListItemTransfers = null; 089 List<UserVisitSearchFacetIntegerTransfer> userVisitSearchFacetIntegerTransfers = null; 090 List<UserVisitSearchFacetLongTransfer> userVisitSearchFacetLongTransfers = null; 091 final var userVisit = userVisitSearch.getUserVisit(); 092 final var entityAttributeTypeName = entityAttribute.getLastDetail().getEntityAttributeType().getEntityAttributeTypeName(); 093 094 if(entityAttributeTypeName.equals(EntityAttributeTypes.LISTITEM.name())) { 095 final var entityListItemAttributeFacetResults = new EntityListItemAttributeFacetQuery(userVisitSearch).execute(entityAttribute); 096 097 userVisitSearchFacetListItemTransfers = new ArrayList<>(entityListItemAttributeFacetResults.size()); 098 099 for(var entityListItemAttributeFacetResult : entityListItemAttributeFacetResults) { 100 userVisitSearchFacetListItemTransfers.add( 101 new UserVisitSearchFacetListItemTransfer(coreControl.getEntityListItemTransfer(userVisit, entityListItemAttributeFacetResult.getEntityListItem(), null), 102 entityListItemAttributeFacetResult.getCount())); 103 } 104 } else if(entityAttributeTypeName.equals(EntityAttributeTypes.MULTIPLELISTITEM.name())) { 105 final var entityMultipleListItemAttributeFacetResults = new EntityMultipleListItemAttributeFacetQuery(userVisitSearch).execute(entityAttribute); 106 107 userVisitSearchFacetListItemTransfers = new ArrayList<>(entityMultipleListItemAttributeFacetResults.size()); 108 109 for(var entityListItemAttributeFacetResult : entityMultipleListItemAttributeFacetResults) { 110 userVisitSearchFacetListItemTransfers.add( 111 new UserVisitSearchFacetListItemTransfer(coreControl.getEntityListItemTransfer(userVisit, entityListItemAttributeFacetResult.getEntityListItem(), null), 112 entityListItemAttributeFacetResult.getCount())); 113 } 114 } else if(entityAttributeTypeName.equals(EntityAttributeTypes.INTEGER.name())) { 115 final var entityIntegerRangeDetails = getEntityIntegerRangeDetails(entityAttribute); 116 final var currentSize = entityIntegerRangeDetails.size(); 117 118 userVisitSearchFacetIntegerTransfers = new ArrayList<>(currentSize); // maximum size, may be smaller. 119 120 if(currentSize > 0) { 121 final var entityIntegerAttributeFacetResults = new EntityIntegerAttributeFacetQuery(userVisitSearch).execute(entityAttribute); 122 123 for(var entityIntegerAttributeFacetResult : entityIntegerAttributeFacetResults) { 124 final var addedUserVisitSearchFacetIntegerTransfers = new ArrayList<UserVisitSearchFacetIntegerTransfer>(); 125 final var integerAttribute = entityIntegerAttributeFacetResult.getIntegerAttribute(); 126 127 for(var iter = entityIntegerRangeDetails.iterator(); iter.hasNext(); ) { 128 final var entityIntegerRangeDetail = iter.next(); 129 final var minimumIntegerValue = entityIntegerRangeDetail.getMinimumIntegerValue(); 130 final var maximumIntegerValue = entityIntegerRangeDetail.getMaximumIntegerValue(); 131 132 if((minimumIntegerValue == null && maximumIntegerValue != null && integerAttribute <= maximumIntegerValue) 133 || (minimumIntegerValue != null && maximumIntegerValue == null && integerAttribute >= minimumIntegerValue) 134 || (minimumIntegerValue != null && maximumIntegerValue != null && integerAttribute >= minimumIntegerValue && integerAttribute <= maximumIntegerValue)) { 135 addedUserVisitSearchFacetIntegerTransfers.add( 136 new UserVisitSearchFacetIntegerTransfer(coreControl.getEntityIntegerRangeTransfer(userVisit, entityIntegerRangeDetail.getEntityIntegerRange(), null), 137 entityIntegerAttributeFacetResult.getCount())); 138 iter.remove(); 139 } 140 } 141 142 for(var userVisitSearchFacetIntegerTransfer : userVisitSearchFacetIntegerTransfers) { 143 final var entityIntegerRange = userVisitSearchFacetIntegerTransfer.getEntityIntegerRange(); 144 final var minimumIntegerValue = entityIntegerRange.getMinimumIntegerValue(); 145 final var maximumIntegerValue = entityIntegerRange.getMaximumIntegerValue(); 146 147 if((minimumIntegerValue == null && maximumIntegerValue != null && integerAttribute <= maximumIntegerValue) 148 || (minimumIntegerValue != null && maximumIntegerValue == null && integerAttribute >= minimumIntegerValue) 149 || (minimumIntegerValue != null && maximumIntegerValue != null && integerAttribute >= minimumIntegerValue && integerAttribute <= maximumIntegerValue)) { 150 userVisitSearchFacetIntegerTransfer.setCount(userVisitSearchFacetIntegerTransfer.getCount() + entityIntegerAttributeFacetResult.getCount()); 151 } 152 } 153 154 userVisitSearchFacetIntegerTransfers.addAll(addedUserVisitSearchFacetIntegerTransfers); 155 } 156 } 157 158 userVisitSearchFacetIntegerTransfers.sort( 159 (UserVisitSearchFacetIntegerTransfer o1, UserVisitSearchFacetIntegerTransfer o2) -> Long.compare(o2.getCount(), o1.getCount()) 160 ); 161 } else if(entityAttributeTypeName.equals(EntityAttributeTypes.LONG.name())) { 162 final var entityLongRangeDetails = getEntityLongRangeDetails(entityAttribute); 163 final var currentSize = entityLongRangeDetails.size(); 164 165 userVisitSearchFacetLongTransfers = new ArrayList<>(currentSize); // maximum size, may be smaller. 166 167 if(currentSize > 0) { 168 final var entityLongAttributeFacetResults = new EntityLongAttributeFacetQuery(userVisitSearch).execute(entityAttribute); 169 170 for(var entityLongAttributeFacetResult : entityLongAttributeFacetResults) { 171 final var addedUserVisitSearchFacetLongTransfers = new ArrayList<UserVisitSearchFacetLongTransfer>(); 172 final var longAttribute = entityLongAttributeFacetResult.getLongAttribute(); 173 174 for(var iter = entityLongRangeDetails.iterator(); iter.hasNext(); ) { 175 final var entityLongRangeDetail = iter.next(); 176 final var minimumLongValue = entityLongRangeDetail.getMinimumLongValue(); 177 final var maximumLongValue = entityLongRangeDetail.getMaximumLongValue(); 178 179 if((minimumLongValue == null && maximumLongValue != null && longAttribute <= maximumLongValue) 180 || (minimumLongValue != null && maximumLongValue == null && longAttribute >= minimumLongValue) 181 || (minimumLongValue != null && maximumLongValue != null && longAttribute >= minimumLongValue && longAttribute <= maximumLongValue)) { 182 addedUserVisitSearchFacetLongTransfers.add( 183 new UserVisitSearchFacetLongTransfer(coreControl.getEntityLongRangeTransfer(userVisit, entityLongRangeDetail.getEntityLongRange(), null), 184 entityLongAttributeFacetResult.getCount())); 185 iter.remove(); 186 } 187 } 188 189 for(var userVisitSearchFacetLongTransfer : userVisitSearchFacetLongTransfers) { 190 final var entityLongRange = userVisitSearchFacetLongTransfer.getEntityLongRange(); 191 final var minimumLongValue = entityLongRange.getMinimumLongValue(); 192 final var maximumLongValue = entityLongRange.getMaximumLongValue(); 193 194 if((minimumLongValue == null && maximumLongValue != null && longAttribute <= maximumLongValue) 195 || (minimumLongValue != null && maximumLongValue == null && longAttribute >= minimumLongValue) 196 || (minimumLongValue != null && maximumLongValue != null && longAttribute >= minimumLongValue && longAttribute <= maximumLongValue)) { 197 userVisitSearchFacetLongTransfer.setCount(userVisitSearchFacetLongTransfer.getCount() + entityLongAttributeFacetResult.getCount()); 198 } 199 } 200 201 userVisitSearchFacetLongTransfers.addAll(addedUserVisitSearchFacetLongTransfers); 202 } 203 } 204 205 userVisitSearchFacetLongTransfers.sort( 206 (UserVisitSearchFacetLongTransfer o1, UserVisitSearchFacetLongTransfer o2) -> Long.compare(o2.getCount(), o1.getCount()) 207 ); 208 } else { 209 handleExecutionError(InvalidEntityAttributeTypeException.class, eea, ExecutionErrors.InvalidEntityAttributeType.name(), entityAttributeTypeName); 210 } 211 212 return eea.hasExecutionErrors() ? null : new UserVisitSearchFacetTransfer(coreControl.getEntityAttributeTransfer(userVisit, entityAttribute, null), 213 userVisitSearchFacetListItemTransfers == null ? null : new ListWrapper<>(userVisitSearchFacetListItemTransfers), 214 userVisitSearchFacetIntegerTransfers == null ? null : new ListWrapper<>(userVisitSearchFacetIntegerTransfers), 215 userVisitSearchFacetLongTransfers == null ? null : new ListWrapper<>(userVisitSearchFacetLongTransfers)); 216 } 217 218 // Substantial portions of this are duplicated in getUserVisitSearchFacetTransfer(...). 219 public UserVisitSearchFacetObject getUserVisitSearchFacetObject(final ExecutionErrorAccumulator eea, final UserVisitSearch userVisitSearch, 220 final EntityAttribute entityAttribute) { 221 List<UserVisitSearchFacetListItemObject> userVisitSearchFacetListItemObjects = null; 222 List<UserVisitSearchFacetIntegerObject> userVisitSearchFacetIntegerObjects = null; 223 List<UserVisitSearchFacetLongObject> userVisitSearchFacetLongObjects = null; 224 final var entityAttributeTypeName = entityAttribute.getLastDetail().getEntityAttributeType().getEntityAttributeTypeName(); 225 226 if(entityAttributeTypeName.equals(EntityAttributeTypes.LISTITEM.name())) { 227 final var entityListItemAttributeFacetResults = new EntityListItemAttributeFacetQuery(userVisitSearch).execute(entityAttribute); 228 229 userVisitSearchFacetListItemObjects = new ArrayList<>(entityListItemAttributeFacetResults.size()); 230 231 for(var entityListItemAttributeFacetResult : entityListItemAttributeFacetResults) { 232 userVisitSearchFacetListItemObjects.add( 233 new UserVisitSearchFacetListItemObject(entityListItemAttributeFacetResult.getEntityListItem(), 234 entityListItemAttributeFacetResult.getCount())); 235 } 236 } else if(entityAttributeTypeName.equals(EntityAttributeTypes.MULTIPLELISTITEM.name())) { 237 final var entityMultipleListItemAttributeFacetResults = new EntityMultipleListItemAttributeFacetQuery(userVisitSearch).execute(entityAttribute); 238 239 userVisitSearchFacetListItemObjects = new ArrayList<>(entityMultipleListItemAttributeFacetResults.size()); 240 241 for(var entityListItemAttributeFacetResult : entityMultipleListItemAttributeFacetResults) { 242 userVisitSearchFacetListItemObjects.add( 243 new UserVisitSearchFacetListItemObject(entityListItemAttributeFacetResult.getEntityListItem(), 244 entityListItemAttributeFacetResult.getCount())); 245 } 246 } else if(entityAttributeTypeName.equals(EntityAttributeTypes.INTEGER.name())) { 247 final var entityIntegerRangeDetails = getEntityIntegerRangeDetails(entityAttribute); 248 final var currentSize = entityIntegerRangeDetails.size(); 249 250 userVisitSearchFacetIntegerObjects = new ArrayList<>(currentSize); // maximum size, may be smaller. 251 252 if(currentSize > 0) { 253 final var entityIntegerAttributeFacetResults = new EntityIntegerAttributeFacetQuery(userVisitSearch).execute(entityAttribute); 254 255 for(var entityIntegerAttributeFacetResult : entityIntegerAttributeFacetResults) { 256 final var addedUserVisitSearchFacetIntegerObjects = new ArrayList<UserVisitSearchFacetIntegerObject>(); 257 final var integerAttribute = entityIntegerAttributeFacetResult.getIntegerAttribute(); 258 259 for(var iter = entityIntegerRangeDetails.iterator(); iter.hasNext(); ) { 260 final var entityIntegerRangeDetail = iter.next(); 261 final var minimumIntegerValue = entityIntegerRangeDetail.getMinimumIntegerValue(); 262 final var maximumIntegerValue = entityIntegerRangeDetail.getMaximumIntegerValue(); 263 264 if((minimumIntegerValue == null && maximumIntegerValue != null && integerAttribute <= maximumIntegerValue) 265 || (minimumIntegerValue != null && maximumIntegerValue == null && integerAttribute >= minimumIntegerValue) 266 || (minimumIntegerValue != null && maximumIntegerValue != null && integerAttribute >= minimumIntegerValue && integerAttribute <= maximumIntegerValue)) { 267 addedUserVisitSearchFacetIntegerObjects.add( 268 new UserVisitSearchFacetIntegerObject(entityIntegerRangeDetail.getEntityIntegerRange(), 269 entityIntegerAttributeFacetResult.getCount())); 270 iter.remove(); 271 } 272 } 273 274 for(var userVisitSearchFacetIntegerObject : userVisitSearchFacetIntegerObjects) { 275 final var entityIntegerRange = userVisitSearchFacetIntegerObject.getEntityIntegerRange(); 276 final var minimumIntegerValue = entityIntegerRange.getLastDetail().getMinimumIntegerValue(); 277 final var maximumIntegerValue = entityIntegerRange.getLastDetail().getMaximumIntegerValue(); 278 279 if((minimumIntegerValue == null && maximumIntegerValue != null && integerAttribute <= maximumIntegerValue) 280 || (minimumIntegerValue != null && maximumIntegerValue == null && integerAttribute >= minimumIntegerValue) 281 || (minimumIntegerValue != null && maximumIntegerValue != null && integerAttribute >= minimumIntegerValue && integerAttribute <= maximumIntegerValue)) { 282 userVisitSearchFacetIntegerObject.setCount(userVisitSearchFacetIntegerObject.getCount() + entityIntegerAttributeFacetResult.getCount()); 283 } 284 } 285 286 userVisitSearchFacetIntegerObjects.addAll(addedUserVisitSearchFacetIntegerObjects); 287 } 288 } 289 290 userVisitSearchFacetIntegerObjects.sort( 291 (UserVisitSearchFacetIntegerObject o1, UserVisitSearchFacetIntegerObject o2) -> Long.compare(o2.getCount(), o1.getCount()) 292 ); 293 } else if(entityAttributeTypeName.equals(EntityAttributeTypes.LONG.name())) { 294 final var entityLongRangeDetails = getEntityLongRangeDetails(entityAttribute); 295 final var currentSize = entityLongRangeDetails.size(); 296 297 userVisitSearchFacetLongObjects = new ArrayList<>(currentSize); // maximum size, may be smaller. 298 299 if(currentSize > 0) { 300 final var entityLongAttributeFacetResults = new EntityLongAttributeFacetQuery(userVisitSearch).execute(entityAttribute); 301 302 for(var entityLongAttributeFacetResult : entityLongAttributeFacetResults) { 303 final var addedUserVisitSearchFacetLongObjects = new ArrayList<UserVisitSearchFacetLongObject>(); 304 final var longAttribute = entityLongAttributeFacetResult.getLongAttribute(); 305 306 for(var iter = entityLongRangeDetails.iterator(); iter.hasNext(); ) { 307 final var entityLongRangeDetail = iter.next(); 308 final var minimumLongValue = entityLongRangeDetail.getMinimumLongValue(); 309 final var maximumLongValue = entityLongRangeDetail.getMaximumLongValue(); 310 311 if((minimumLongValue == null && maximumLongValue != null && longAttribute <= maximumLongValue) 312 || (minimumLongValue != null && maximumLongValue == null && longAttribute >= minimumLongValue) 313 || (minimumLongValue != null && maximumLongValue != null && longAttribute >= minimumLongValue && longAttribute <= maximumLongValue)) { 314 addedUserVisitSearchFacetLongObjects.add( 315 new UserVisitSearchFacetLongObject(entityLongRangeDetail.getEntityLongRange(), 316 entityLongAttributeFacetResult.getCount())); 317 iter.remove(); 318 } 319 } 320 321 for(var userVisitSearchFacetLongObject : userVisitSearchFacetLongObjects) { 322 final var entityLongRange = userVisitSearchFacetLongObject.getEntityLongRange(); 323 final var minimumLongValue = entityLongRange.getLastDetail().getMinimumLongValue(); 324 final var maximumLongValue = entityLongRange.getLastDetail().getMaximumLongValue(); 325 326 if((minimumLongValue == null && maximumLongValue != null && longAttribute <= maximumLongValue) 327 || (minimumLongValue != null && maximumLongValue == null && longAttribute >= minimumLongValue) 328 || (minimumLongValue != null && maximumLongValue != null && longAttribute >= minimumLongValue && longAttribute <= maximumLongValue)) { 329 userVisitSearchFacetLongObject.setCount(userVisitSearchFacetLongObject.getCount() + entityLongAttributeFacetResult.getCount()); 330 } 331 } 332 333 userVisitSearchFacetLongObjects.addAll(addedUserVisitSearchFacetLongObjects); 334 } 335 } 336 337 userVisitSearchFacetLongObjects.sort( 338 (UserVisitSearchFacetLongObject o1, UserVisitSearchFacetLongObject o2) -> Long.compare(o2.getCount(), o1.getCount()) 339 ); 340 } else { 341 handleExecutionError(InvalidEntityAttributeTypeException.class, eea, ExecutionErrors.InvalidEntityAttributeType.name(), entityAttributeTypeName); 342 } 343 344 return (eea != null && eea.hasExecutionErrors()) ? null : new UserVisitSearchFacetObject(entityAttribute, 345 userVisitSearchFacetListItemObjects, userVisitSearchFacetIntegerObjects, userVisitSearchFacetLongObjects); 346 } 347 348}