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

com.bazaarvoice.emodb.sor.delta.impl.MapDeltaBuilderImpl Maven / Gradle / Ivy

The newest version!
package com.bazaarvoice.emodb.sor.delta.impl;

import com.bazaarvoice.emodb.sor.condition.Conditions;
import com.bazaarvoice.emodb.sor.delta.ConditionalDelta;
import com.bazaarvoice.emodb.sor.delta.Delete;
import com.bazaarvoice.emodb.sor.delta.Delta;
import com.bazaarvoice.emodb.sor.delta.DeltaVisitor;
import com.bazaarvoice.emodb.sor.delta.Deltas;
import com.bazaarvoice.emodb.sor.delta.Literal;
import com.bazaarvoice.emodb.sor.delta.MapDelta;
import com.bazaarvoice.emodb.sor.delta.MapDeltaBuilder;
import com.bazaarvoice.emodb.sor.delta.NoopDelta;
import com.bazaarvoice.emodb.sor.delta.SetDelta;
import com.bazaarvoice.emodb.sor.delta.eval.DeltaEvaluator;
import com.bazaarvoice.emodb.sor.delta.eval.Intrinsics;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;

import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Map;

import static com.google.common.base.Preconditions.checkArgument;

public class MapDeltaBuilderImpl implements MapDeltaBuilder {

    private boolean _removeRest;
    private final Map _entries = Maps.newHashMap();
    private boolean _deleteIfEmpty;

    @Override
    public MapDeltaBuilder remove(String key) {
        return update(key, Deltas.delete());
    }

    @Override
    public MapDeltaBuilder removeAll(String... key) {
        return removeAll(Arrays.asList(key));
    }

    @Override
    public MapDeltaBuilder removeAll(Iterable keys) {
        for (String key : keys) {
            remove(key);
        }
        return this;
    }

    @Override
    public MapDeltaBuilder remove(String key, @Nullable Object json) {
        return update(key, Deltas.conditional(Conditions.equal(json), Deltas.delete()));
    }

    @Override
    public MapDeltaBuilder removeAll(Map json) {
        for (Map.Entry entry : json.entrySet()) {
            remove(entry.getKey(), entry.getValue());
        }
        return this;
    }

    @Override
    public MapDeltaBuilder put(String key, @Nullable Object json) {
        return update(key, Deltas.literal(json));
    }

    @Override
    public MapDeltaBuilder putAll(Map json) {
        for (Map.Entry entry : json.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
        return this;
    }

    @Override
    public MapDeltaBuilder putIfAbsent(String key, @Nullable Object json) {
        return update(key, Deltas.conditional(Conditions.isUndefined(), Deltas.literal(json)));
    }

    @Override
    public MapDeltaBuilder update(String key, Delta delta) {
        checkArgument(!_entries.containsKey(key), "Multiple operations against the same key are not allowed: %s", key);
        _entries.put(key, delta);
        return this;
    }

    @Override
    public MapDeltaBuilder updateAll(Map deltas) {
        for (Map.Entry entry : deltas.entrySet()) {
            update(entry.getKey(), entry.getValue());
        }
        return this;
    }

    @Override
    public MapDeltaBuilder updateIfExists(String key, Delta delta) {
        return update(key, Deltas.conditional(Conditions.isDefined(), delta));
    }

    @Override
    public MapDeltaBuilder retain(String key) {
        return update(key, Deltas.noop());
    }

    @Override
    public MapDeltaBuilder retainAll(String... keys) {
        return retainAll(Arrays.asList(keys));
    }

    @Override
    public MapDeltaBuilder retainAll(Iterable keys) {
        for (String key : keys) {
            retain(key);
        }
        return this;
    }

    @Override
    public MapDeltaBuilder deleteIfEmpty() {
        return deleteIfEmpty(true);
    }

    @Override
    public MapDeltaBuilder deleteIfEmpty(boolean deleteIfEmpty) {
        _deleteIfEmpty = deleteIfEmpty;
        return this;
    }

    @Override
    public MapDeltaBuilder removeRest() {
        return removeRest(true);
    }

    @Override
    public MapDeltaBuilder removeRest(boolean removeRest) {
        _removeRest = removeRest;
        return this;
    }

    @Override
    public Delta build() {
        // an add can no-op only if it evaluates to a delete operation.  if we're guaranteed that
        // at least one add doesn't delete, no point in deleting if empty.
        if (_deleteIfEmpty && !_entries.isEmpty() && Iterables.any(_entries.values(), NeverDeletePredicate.INSTANCE)) {
            _deleteIfEmpty = false;
        }
        Delta delta = new MapDeltaImpl(_removeRest, _entries, _deleteIfEmpty);
        if (delta.isConstant()) {
            delta = evalAsConstant(delta);
        }
        return delta;
    }

    private Delta evalAsConstant(Delta delta) {
        Intrinsics intrinsics = null;  // Intrinsics are only referred to by non-constant deltas, so ok to pass null.
        Object result = DeltaEvaluator.eval(delta, DeltaEvaluator.UNDEFINED, intrinsics);
        return (result == DeltaEvaluator.UNDEFINED) ? Deltas.delete() : Deltas.literal(result);
    }

    /**
     * Returns true if a {@link Delta} will never evaluate to {@link DeltaEvaluator#UNDEFINED}.
     */
    private static class NeverDeletePredicate implements Predicate, DeltaVisitor {
        private static final NeverDeletePredicate INSTANCE = new NeverDeletePredicate();

        @Override
        public boolean apply(Delta delta) {
            return delta.visit(this, null);
        }

        @Override
        public Boolean visit(Literal delta, @Nullable Void context) {
            return true;
        }

        @Override
        public Boolean visit(NoopDelta delta, @Nullable Void context) {
            return false;
        }

        @Override
        public Boolean visit(Delete delta, @Nullable Void context) {
            return false;
        }

        @Override
        public Boolean visit(MapDelta delta, @Nullable Void context) {
            return !delta.getDeleteIfEmpty();
        }

        @Override
        public Boolean visit(ConditionalDelta delta, @Nullable Void context) {
            return delta.getThen().visit(this, null) && delta.getElse().visit(this, null);
        }

        @Override
        public Boolean visit(SetDelta delta, @Nullable Void context) {
            return !delta.getDeleteIfEmpty();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy