All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.redisson.liveobject.LiveObjectSearch Maven / Gradle / Ivy

Go to download

Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC

The newest version!
/**
 * Copyright (c) 2013-2024 Nikita Koksharov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.redisson.liveobject;

import org.redisson.RedissonObject;
import org.redisson.RedissonScoredSortedSet;
import org.redisson.RedissonSet;
import org.redisson.RedissonSetMultimap;
import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RSet;
import org.redisson.api.RSetMultimap;
import org.redisson.api.condition.Condition;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.liveobject.condition.*;
import org.redisson.liveobject.resolver.NamingScheme;

import java.util.*;
import java.util.Map.Entry;
import java.util.function.BiFunction;

/**
 * 
 * @author Nikita Koksharov
 *
 */
public class LiveObjectSearch {
    
    private final CommandAsyncExecutor commandExecutor;

    public LiveObjectSearch(CommandAsyncExecutor commandExecutor) {
        this.commandExecutor = commandExecutor;
    }

    private Set traverseAnd(ANDCondition condition, NamingScheme namingScheme, Class entityClass) {
        Set allIds = new HashSet();
        
        List eqNames = new ArrayList();
        
        Map, Number> gtNumericNames = new HashMap<>();
        Map, Number> geNumericNames = new HashMap<>();
        Map, Number> ltNumericNames = new HashMap<>();
        Map, Number> leNumericNames = new HashMap<>();
        Map, Number> eqNumericNames = new HashMap<>();
        
        for (Condition cond : condition.getConditions()) {
            if (cond instanceof EQCondition) {
                EQCondition eqc = (EQCondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, eqc.getName());
                if (eqc.getValue() instanceof Number) {
                    RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                    eqNumericNames.put(values, (Number) eqc.getValue());
                } else {
                    RSetMultimap map = new RedissonSetMultimap<>(namingScheme.getCodec(), commandExecutor, indexName);
                    RSet values = map.get(eqc.getValue());
                    eqNames.add(((RedissonObject) values).getRawName());
                }
            }
            if (cond instanceof LTCondition) {
                LTCondition ltc = (LTCondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, ltc.getName());
                RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                ltNumericNames.put(values, ltc.getValue());
            }
            if (cond instanceof LECondition) {
                LECondition lec = (LECondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, lec.getName());
                RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                leNumericNames.put(values, lec.getValue());
            }
            if (cond instanceof GECondition) {
                GECondition gec = (GECondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, gec.getName());
                RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                geNumericNames.put(values, gec.getValue());
            }
            if (cond instanceof GTCondition) {
                GTCondition gtc = (GTCondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, gtc.getName());
                RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                gtNumericNames.put(values, gtc.getValue());
            }
            
            if (cond instanceof ORCondition) {
                Collection ids = traverseOr((ORCondition) cond, namingScheme, entityClass);
                if (ids.isEmpty()) {
                    return Collections.emptySet();
                }
                if (!allIds.isEmpty()) {
                    allIds.retainAll(ids);
                } else {
                    allIds.addAll(ids);
                }
                if (allIds.isEmpty()) {
                    return Collections.emptySet();
                }
            }
        }
        
        if (!eqNames.isEmpty()) {
            RSet set = new RedissonSet<>(commandExecutor, eqNames.get(0), null);
            Set intersect = set.readIntersection(eqNames.toArray(new String[eqNames.size()]));
            if (!allIds.isEmpty()) {
                allIds.retainAll(intersect);
                if (allIds.isEmpty()) {
                    return Collections.emptySet();
                }
            } else {
                allIds.addAll(intersect);
            }
            if (allIds.isEmpty()) {
                return allIds;
            }
        }

        if (!checkValueRange(allIds, eqNumericNames, (r, v) -> {
            return r.valueRange(v.doubleValue(), true, v.doubleValue(), true);
        })) {
            return Collections.emptySet();
        }

        if (!checkValueRange(allIds, gtNumericNames, (r, v) -> {
            return r.valueRange(v.doubleValue(), false, Double.POSITIVE_INFINITY, false);
        })) {
            return Collections.emptySet();
        }

        if (!checkValueRange(allIds, geNumericNames, (r, v) -> {
            return r.valueRange(v.doubleValue(), true, Double.POSITIVE_INFINITY, false);
        })) {
            return Collections.emptySet();
        }
        
        if (!checkValueRange(allIds, ltNumericNames, (r, v) -> {
            return r.valueRange(Double.NEGATIVE_INFINITY, false, v.doubleValue(), false);
        })) {
            return Collections.emptySet();
        }

        if (!checkValueRange(allIds, leNumericNames, (r, v) -> {
            return r.valueRange(Double.NEGATIVE_INFINITY, false, v.doubleValue(), true);
        })) {
            return Collections.emptySet();
        }
        
        return allIds;
    }

    private boolean checkValueRange(Set allIds, Map, Number> numericNames, 
                        BiFunction, Number, Collection> func) {
        if (numericNames.isEmpty()) {
            return true;
        }

        for (Entry, Number> e : numericNames.entrySet()) {
            Collection gtIds = func.apply(e.getKey(), e.getValue());
            if (gtIds.isEmpty()) {
                return false;
            }
            if (!allIds.isEmpty()) {
                allIds.retainAll(gtIds);
                if (allIds.isEmpty()) {
                    return false;
                }
            } else {
                allIds.addAll(gtIds);
            }
        }
        return true;
    }

    private Set traverseOr(ORCondition condition, NamingScheme namingScheme, Class entityClass) {
        Set allIds = new HashSet();
        
        List eqNames = new ArrayList();

        Map, Number> ltNumericNames = new HashMap<>();
        Map, Number> leNumericNames = new HashMap<>();
        Map, Number> gtNumericNames = new HashMap<>();
        Map, Number> geNumericNames = new HashMap<>();
        Map, Number> eqNumericNames = new HashMap<>();
        
        for (Condition cond : condition.getConditions()) {
            if (cond instanceof EQCondition) {
                EQCondition eqc = (EQCondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, eqc.getName());
                if (eqc.getValue() instanceof Number) {
                    RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                    eqNumericNames.put(values, (Number) eqc.getValue());
                } else {
                    RSetMultimap map = new RedissonSetMultimap<>(namingScheme.getCodec(), commandExecutor, indexName);
                    RSet values = map.get(eqc.getValue());
                    eqNames.add(((RedissonObject) values).getRawName());
                }
            }
            if (cond instanceof GTCondition) {
                GTCondition gtc = (GTCondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, gtc.getName());
                RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                gtNumericNames.put(values, gtc.getValue());
            }
            if (cond instanceof GECondition) {
                GECondition gec = (GECondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, gec.getName());
                RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                geNumericNames.put(values, gec.getValue());
            }
            if (cond instanceof LTCondition) {
                LTCondition ltc = (LTCondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, ltc.getName());
                RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                ltNumericNames.put(values, ltc.getValue());
            }
            if (cond instanceof LECondition) {
                LECondition lec = (LECondition) cond;
                
                String indexName = namingScheme.getIndexName(entityClass, lec.getName());
                RScoredSortedSet values = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                leNumericNames.put(values, lec.getValue());
            }
            if (cond instanceof ANDCondition) {
                Collection ids = traverseAnd((ANDCondition) cond, namingScheme, entityClass);
                allIds.addAll(ids);
            }
        }

        if (!eqNames.isEmpty()) {
            RSet set = new RedissonSet<>(commandExecutor, eqNames.get(0), null);
            allIds.addAll(set.readUnion(eqNames.toArray(new String[eqNames.size()])));
        }
        
        for (Entry, Number> e : eqNumericNames.entrySet()) {
            Collection ids = e.getKey().valueRange(e.getValue().doubleValue(), true, e.getValue().doubleValue(), true);
            allIds.addAll(ids);
        }
        
        for (Entry, Number> e : gtNumericNames.entrySet()) {
            Collection ids = e.getKey().valueRange(e.getValue().doubleValue(), false, Double.POSITIVE_INFINITY, false);
            allIds.addAll(ids);
        }

        for (Entry, Number> e : geNumericNames.entrySet()) {
            Collection ids = e.getKey().valueRange(e.getValue().doubleValue(), true, Double.POSITIVE_INFINITY, false);
            allIds.addAll(ids);
        }
        
        for (Entry, Number> e : ltNumericNames.entrySet()) {
            Collection ids = e.getKey().valueRange(Double.NEGATIVE_INFINITY, false, e.getValue().doubleValue(), false);
            allIds.addAll(ids);
        }

        for (Entry, Number> e : leNumericNames.entrySet()) {
            Collection ids = e.getKey().valueRange(Double.NEGATIVE_INFINITY, false, e.getValue().doubleValue(), true);
            allIds.addAll(ids);
        }

        return allIds;
    }
    
    public Set find(Class entityClass, Condition condition) {
        NamingScheme namingScheme = commandExecutor.getObjectBuilder().getNamingScheme(entityClass);

        if (condition instanceof EQCondition) {
            EQCondition c = (EQCondition) condition;
            String indexName = namingScheme.getIndexName(entityClass, c.getName());
            
            if (c.getValue() instanceof Number) {
                RScoredSortedSet set = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
                double v = ((Number) c.getValue()).doubleValue();
                Collection gtIds = set.valueRange(v, true, v, true);
                return new HashSet<>(gtIds);
            } else {
                RSetMultimap map = new RedissonSetMultimap<>(namingScheme.getCodec(), commandExecutor, indexName);
                return map.getAll(c.getValue());
            }
        } else if (condition instanceof GTCondition) {
            GTCondition c = (GTCondition) condition;
            String indexName = namingScheme.getIndexName(entityClass, c.getName());
            RScoredSortedSet set = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
            Collection gtIds = set.valueRange(c.getValue().doubleValue(), false, Double.POSITIVE_INFINITY, false);
            return new HashSet<>(gtIds);
        } else if (condition instanceof GECondition) {
            GECondition c = (GECondition) condition;
            String indexName = namingScheme.getIndexName(entityClass, c.getName());
            RScoredSortedSet set = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
            Collection gtIds = set.valueRange(c.getValue().doubleValue(), true, Double.POSITIVE_INFINITY, false);
            return new HashSet<>(gtIds);
        } else if (condition instanceof LTCondition) {
            LTCondition c = (LTCondition) condition;
            String indexName = namingScheme.getIndexName(entityClass, c.getName());
            RScoredSortedSet set = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
            Collection gtIds = set.valueRange(Double.NEGATIVE_INFINITY, false, c.getValue().doubleValue(), false);
            return new HashSet<>(gtIds);
        } else if (condition instanceof LECondition) {
            LECondition c = (LECondition) condition;
            String indexName = namingScheme.getIndexName(entityClass, c.getName());
            RScoredSortedSet set = new RedissonScoredSortedSet<>(namingScheme.getCodec(), commandExecutor, indexName, null);
            Collection gtIds = set.valueRange(Double.NEGATIVE_INFINITY, false, c.getValue().doubleValue(), true);
            return new HashSet<>(gtIds);
        } else if (condition instanceof ORCondition) {
            return traverseOr((ORCondition) condition, namingScheme, entityClass);
        } else if (condition instanceof ANDCondition) {
            return traverseAnd((ANDCondition) condition, namingScheme, entityClass);
        }

        throw new IllegalArgumentException();
    }

    
}