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

com.pushtechnology.diffusion.client.features.UpdateConstraint Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2018, 2023 DiffusionData Ltd., All Rights Reserved.
 *
 * Use is subject to licence terms.
 *
 * NOTICE: All information contained herein is, and remains the
 * property of DiffusionData. The intellectual and technical
 * concepts contained herein are proprietary to DiffusionData and
 * may be covered by U.S. and Foreign Patents, patents in process, and
 * are protected by trade secret or copyright law.
 *******************************************************************************/

package com.pushtechnology.diffusion.client.features;

import static com.pushtechnology.diffusion.client.features.UpdateConstraint.Operator.IS;

import com.pushtechnology.diffusion.client.session.Session;
import com.pushtechnology.diffusion.client.topics.details.TopicType;
import com.pushtechnology.diffusion.datatype.Bytes;
import com.pushtechnology.diffusion.datatype.DataTypes;
import com.pushtechnology.diffusion.datatype.json.JSON;

/**
 * A constraint to be applied to an update operation or the creation of an
 * update stream.
 * 

* Constraints describe a condition that must be satisfied for an operation to * succeed. Constraints can be applied to the setting of a value or creation of * an update stream. Constraints are only evaluated on the server. *

* The constraints are evaluated using the: *

    *
  • active session locks *
  • existence of the topic *
  • current value of the topic *
*

* The value of a topic can be described in several ways. The value can be * described as an exact value, a partial value or an unset value. *

* Constraints can be composed with one another using logical ANDs or ORs. It is * possible to compose a constraint that can never be satisfied although certain * combinations, such as ANDing two incompatible constraints are prevented. * Multiple session locks can be held but a topic can only have a single value. *

* Constraints can be created using a {@link UpdateConstraint.Factory}, an * instance of which can be obtained using * {@link com.pushtechnology.diffusion.client.Diffusion#updateConstraints update * constraints}. For example: * *

 * 
 * UpdateConstraint.Factory factory = Diffusion.updateConstraints();
 * UpdateConstraint constraint = factory.locked(lock).and(factory.value(EQ, expectedValue));
 * 
 * 
* * @author DiffusionData Limited * @since 6.2 */ public interface UpdateConstraint { /** * An operator used in a constraint comparison. * * @since 6.10 */ enum Operator { /** * Strict binary equality. *

* This operator requires that the binary topic value is exactly * equivalent to the value supplied for comparison. */ IS, /** * Lenient equals. *

* This operator requires that the topic value is logically equal to the * supplied value. *

* If the supplied value is a string the string representation of the * specified topic value is compared for string equality. *

* If the supplied value is a number ({@link Long} or {@link Double}) * the corresponding topic value may be a number or a string containing * a parseable number and will be compared for numeric equality. *

* If the supplied value is null the condition will be satisfied if the * value at a specified pointer is JSON null. */ EQ, /** * Lenient not equals. *

* This operator requires that the topic value is logically not equal to * the supplied value. *

* If the supplied value is a string the string representation of the * specified topic value is compared for string equality. *

* If the supplied value is a number ({@link Long} or {@link Double}) * the corresponding topic value may be a number or a string containing * a parseable number and will be compared for numeric equality. *

* If the supplied value is null the condition will be satisfied if the * value at a specified pointer not JSON null. */ NE, /** * Lenient greater than. *

* This operator requires that the topic value is greater than the * supplied value. *

* The supplied value must be a number ({@link Long} or {@link Double}). * The corresponding topic value may be a number or a string containing * a parseable number and the condition will be satisfied if the topic * value is greater than the supplied value. */ GT, /** * Lenient greater than or equals. *

* This operator requires that the topic value is greater than or equal * to the supplied value. *

* The supplied value must be a number ({@link Long} or {@link Double}). * The corresponding topic value may be a number or a string containing * a parseable number and the condition will be satisfied if the topic * value is greater than or equal to the supplied value. */ GE, /** * Lenient less than. *

* This operator requires that the topic value is less than the supplied * value. *

* The supplied value must be a number ({@link Long} or {@link Double}). * The corresponding topic value may be a number or a string containing * a parseable number and the condition will be satisfied if the topic * value is less than the supplied value. */ LT, /** * Lenient less than or equals. *

* This operator requires that the topic value is less than or equal to * the supplied value. *

* The supplied value must be a number ({@link Long} or {@link Double}). * The corresponding topic value may be a number or a string containing * a parseable number and the condition will be satisfied if the topic * value is less than or equal to the supplied value. */ LE; } /** * Returns a composed constraint that represents a logical AND of this * constraint and another. * * @param other a constraint that will be logically-ANDed with this * constraint * @return a composed constraint that represents a logical AND of this * constraint and the {@code other} constraint * @throws IllegalArgumentException if the composed constraint would be * unsatisfiable */ UpdateConstraint and(UpdateConstraint other); /** * Returns a composed constraint that represents a logical OR of this * constraint and another. * * @param other a constraint that will be logically-ORed with this * constraint * @return a composed constraint that represents a logical OR of this * constraint and the {@code other} constraint * @since 6.10 */ UpdateConstraint or(UpdateConstraint other); /** * A constraint requiring the current value of a {@link TopicType#JSON JSON} * topic to match the partially described value. *

* The code: * *

     * 
     * Constraint.Factory factory = Diffusion.updateConstraints();
     * PartialJSON constraint =
     *     factory.jsonValue()
     *         .with("/id", String.class, idValue)
     *         .without("/cancellation");
     * 
     * 
* * creates a constraint for a JSON object with a specific ID value and no * value for a "cancellation" property. *

* Missing keys are matched differently to keys that are present with null * values. */ interface PartialJSON extends UpdateConstraint { /** * Require a value at a specific position in the JSON object. *

* This is equivalent to calling {@code with(String, Operator, Object)} * with an operator of {@link Operator#IS IS}. * * @param pointer the pointer expression * * @param valueClass this parameter is no longer used and is ignored * * @param value the value * * @param the value type of the value at the pointer * * @return a new constraint * * @throws IllegalArgumentException if the {@code pointer} parameter * cannot be parsed as a JSON pointer or if the class of the * supplied value is not supported * * @deprecated since 6.10 *

* Rather use the {@code with(String, Operator, Object)} * method with the {@link Operator#IS IS} operator. */ @Deprecated PartialJSON with(String pointer, Class valueClass, V value); /** * Compares a location within the JSON topic value to a specified value. *

* If there is no value found at the specified pointer position, the * constraint will be unsatisfied. *

* If a {@link String} value is supplied and the operator is * {@link Operator#EQ EQ} or {@link Operator#NE NE}, the string * representation of the topic value at the given pointer will be * compared to the supplied value. If the value at the pointer position * is not a string or number the constraint will be unsatisfied. Other * operators (other than {@link Operator#IS IS}) are not permitted with * String values. *

* If a number value ({@link Integer}, {@link Long} or {@link Double}) * is supplied the value will be compared with the number value at the * topic location. This will work with JSON string or number values * only. JSON strings can only be compared if they contain a value that * can be parsed as a number. If a string value at the location cannot * be parsed as a number, the constraint will be unsatisfied. Any of the * operators (other than {@link Operator#IS IS}) can be used with such * number comparisons. Decimal numbers can be compared with integral * numbers so {@code 1} is equal to {@code 1.0}, {@code "1"}, or * {@code "1.0"}. *

* If a {@code null} value is supplied and the operator is * {@link Operator#EQ EQ} or {@link Operator#NE NE}, the topic value at * the given pointer will be compared to JSON null. Other operators * (other than {@link Operator#IS IS}) are not permitted with a * {@code null} value. *

* If a {@link Boolean} value is supplied and the operator is * {@link Operator#EQ EQ}, the topic value at the given pointer will be * compared to the boolean value. Other operators are not permitted with * a boolean value. *

* If the {@link Operator#IS IS} operator is specified the supplied * value will be compared to the topic value for strict binary equality. * In this case the value must be of type {@link String}, * {@link Integer}, {@link Long}, {@link Double}, {@link Bytes}, or * {@code null}. This is slightly more efficient than the lenient * comparisons described above. * * @param pointer a JSON * Pointer specifying the location of the {@code value} in * the JSON object. * * @param operator the operator that determines the type of comparison * * @param value the value * * @return a new constraint * * @throws IllegalArgumentException if the {@code pointer} parameter * cannot be parsed as a JSON pointer, the {@code value} type is * not supported, or the operator is not compatible with the * {@code value} type * * @since 6.10 */ PartialJSON with( String pointer, Operator operator, Object value); /** * Require a specific position in the JSON object to be absent. This * does not match positions that have null values. *

* The {@code pointer} is a * JSON Pointer syntax * reference that should have no value in the JSON object. * * @param pointer the pointer expression * @return a new constraint * @throws IllegalArgumentException if the {@code pointer} parameter * cannot be parsed as a JSON pointer */ PartialJSON without(String pointer); } /** * Factory for the constraint types. *

* An instance can be obtained by calling * {@link com.pushtechnology.diffusion.client.Diffusion#updateConstraints() * Diffusion.updateConstraints()}. */ interface Factory { /** * Create a constraint requiring a lock to be held by the session. *

* This can be used to coordinate operations between multiple sessions. * * @param lock the lock * @return the constraint */ UpdateConstraint locked(Session.SessionLock lock); /** * Create a constraint requiring the current value of a topic to exactly * match the supplied value. *

* This is exactly equivalent to calling * {@link #value(UpdateConstraint.Operator, Object)} specifying the * {@link UpdateConstraint.Operator#IS IS} operator. * * @param value the value * * @return the constraint * * @throws IllegalArgumentException if the value type is not supported */ default UpdateConstraint value(Object value) throws IllegalArgumentException { return value(IS, value); } /** * Create a constraint comparing the current value of a topic to a * supplied value. *

* If a {@link String} value is supplied and the operator is * {@link UpdateConstraint.Operator#EQ EQ} or * {@link UpdateConstraint.Operator#NE NE}, the string representation of * the topic will be compared to the supplied value. This can only be * used with primitive topic types (or {@link TopicType#TIME_SERIES * TIME_SERIES} topics with a primitive event type). Other operators * (other than {@link UpdateConstraint.Operator#IS IS}) are not * permitted with String values. *

* If a number value is supplied ({@link Integer}, {@link Long} or * {@link Double}) the value will be compared with the number value of * the topic. This will work with {@link TopicType#STRING STRING}, * {@link TopicType#INT64 INT64} or {@link TopicType#DOUBLE DOUBLE} * topics (or {@link TopicType#TIME_SERIES TIME_SERIES} topics with a * primitive event type) only. {@link TopicType#STRING STRING} topics * can only be compared if they contain a value that can be parsed as a * number. If the value of a {@link TopicType#STRING STRING} topic * cannot be parsed as a number, or the topic is of any other non-number * type the constraint will be unsatisfied. Any of the operators (other * than {@link UpdateConstraint.Operator#IS IS}) can be used with such * number comparisons. Decimal numbers can be compared with integral * numbers so {@code 1} is equal to {@code 1.0}, {@code "1"}, or * {@code "1.0"}. *

* If the {@link UpdateConstraint.Operator#IS IS} operator is specified * the specified value will be compared to the topic value for strict * binary equality. The value type can be any value type supported by * {@link DataTypes} ({@link Integer} is allowed and is treated as a * {@link Long}) or any {@link Bytes} value and can be used to compare * against any topic type. *

* When a {@link TopicType#STRING STRING}, {@link TopicType#INT64 INT64} * or {@link TopicType#DOUBLE DOUBLE} topic is updated to a {@code null} * value, the topic is set to have no value. Use the {@link #noValue()} * constraint to check if the topic has no value. *

* This constraint is unsatisfied if no topic is present at the path. * * @param operator the operator that determines the type of comparison * * @param value the value * * @return the constraint * * @throws IllegalArgumentException if the the operator is not * compatible with the value type or the value type is not * supported * * @since 6.10 */ UpdateConstraint value( UpdateConstraint.Operator operator, Object value); /** * Create a constraint requiring the topic to have no value. *

* This constraint is unsatisfied if no topic is present at the path. * * @return the constraint */ UpdateConstraint noValue(); /** * Create a constraint requiring the path to have no topic. *

* This is useful when setting the first value of a topic being added * using {@link TopicUpdate#addAndSet addAndSet} without changing the * value if the topic already exists. This constraint is unsatisfied if * a topic is present at the path. * * @return the constraint */ UpdateConstraint noTopic(); /** * Create a constraint that partially matches the current topic value. *

* The topic must be a {@link TopicType#JSON JSON} topic (or a * {@link TopicType#TIME_SERIES TIME_SERIES} topic with a json event * type). The {@link PartialJSON} partially describes the structure of a * {@link JSON} value. The * {@link PartialJSON#with(String, UpdateConstraint.Operator, Object) * with} or {@link PartialJSON#without without} methods must be used to * fully qualify the constraint. *

* The constraint is unsatisfied if no topic is present at the path. * * @return the constraint */ PartialJSON jsonValue(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy