aboutsummaryrefslogtreecommitdiffstats
path: root/document/src/main/java/com/yahoo/document/update/ValueUpdate.java
blob: 74f5ba9d30a4728c968d4ddb5588d736b36bebdc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.document.update;

import com.yahoo.document.DataType;
import com.yahoo.document.datatypes.FieldValue;
import com.yahoo.document.datatypes.WeightedSet;
import com.yahoo.document.serialization.DocumentUpdateWriter;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * A value update represents some action to perform to a value.
 *
 * @author Einar M R Rosenvinge
 * @see com.yahoo.document.update.FieldUpdate
 * @see com.yahoo.document.DocumentUpdate
 * @see AddValueUpdate
 * @see com.yahoo.document.update.ArithmeticValueUpdate
 * @see com.yahoo.document.update.AssignValueUpdate
 * @see com.yahoo.document.update.ClearValueUpdate
 * @see com.yahoo.document.update.MapValueUpdate
 * @see com.yahoo.document.update.RemoveValueUpdate
 */
public abstract class ValueUpdate<T extends FieldValue> {

    protected ValueUpdateClassID valueUpdateClassID;

    protected ValueUpdate(ValueUpdateClassID valueUpdateClassID) {
        this.valueUpdateClassID = valueUpdateClassID;
    }

    /** Returns the valueUpdateClassID of this value update. */
    public ValueUpdateClassID getValueUpdateClassID() {
        return valueUpdateClassID;
    }

    protected abstract void checkCompatibility(DataType fieldType);

    public abstract void serialize(DocumentUpdateWriter data, DataType superType);

    @Override
    public boolean equals(Object o) {
        return o instanceof ValueUpdate && valueUpdateClassID == ((ValueUpdate<?>) o).valueUpdateClassID;
    }

    @Override
    public int hashCode() {
        return valueUpdateClassID.id;
    }

    @Override
    public String toString() {
        return valueUpdateClassID.name;
    }

    public abstract FieldValue applyTo(FieldValue oldValue);

    /**
     * Creates a new value update specifying an addition of a value to an array or a key to a weighted set (with default weight 1).
     *
     * @param value the value to add to the array, or key to add to the weighted set
     * @return a ValueUpdate specifying the addition
     * @throws IllegalArgumentException      if the runtime type of newValue does not match the type required
     * @throws UnsupportedOperationException if the field type is not array or weighted set
     */
    public static ValueUpdate createAdd(FieldValue value) {
        return new AddValueUpdate(value);
    }

    /**
     * Creates a new value update specifying an addition of a key (with a specified weight) to a weighted set. If this
     * method is used on an array data type, the weight will be omitted.
     *
     * @param key    the key to add
     * @param weight the weight to associate with the given key
     * @return a ValueUpdate specifying the addition
     * @throws IllegalArgumentException      if the runtime type of key does not match the type required
     * @throws UnsupportedOperationException if the field type is not array or weighted set
     */
    public static ValueUpdate createAdd(FieldValue key, Integer weight) {
        return new AddValueUpdate(key, weight);
    }

    /**
     * Creates a new value update
     * specifying an addition of all values in a given list to an array. If this method is used on a weighted set data
     * type, the default weights will be 1. Note that this method is just a convenience method, it simply iterates
     * through the list and creates value updates by calling createAdd() for each element.
     *
     * @param values a List containing the values to add
     * @return a List of ValueUpdates specifying the addition
     * @throws IllegalArgumentException      if the runtime type of values does not match the type required
     * @throws UnsupportedOperationException if the field type is not array or weighted set
     * @see ValueUpdate#createAdd(FieldValue)
     */
    public static List<ValueUpdate> createAddAll(List<? extends FieldValue> values) {
        List<ValueUpdate> vupds = new ArrayList<>();
        for (FieldValue value : values) {
            vupds.add(ValueUpdate.createAdd(value));
        }
        return vupds;
    }

    /**
     * Creates a new value update
     * specifying an addition of all key/weight pairs in a weighted set to a weighted set. If this method
     * is used on an array data type, the weights will be omitted. Note that this method is just a convenience method,
     * it simply iterates through the set and creates value updates by calling createAdd() for each element.
     *
     * @param set a WeightedSet containing the key/weight pairs to add
     * @return a ValueUpdate specifying the addition
     * @throws IllegalArgumentException      if the runtime type of values does not match the type required
     * @throws UnsupportedOperationException if the field type is not weighted set or array
     * @see ValueUpdate#createAdd(FieldValue, Integer)
     */
    public static List<ValueUpdate> createAddAll(WeightedSet<? extends FieldValue> set) {
        List<ValueUpdate> vupds = new ArrayList<>();
        Iterator<? extends FieldValue> it = set.fieldValueIterator();
        while (it.hasNext()) {
            FieldValue key = it.next();
            vupds.add(ValueUpdate.createAdd(key, set.get(key)));
        }
        return vupds;
    }

    /**
     * Creates a new value update that increments a value. Note that the data type must be a numeric
     * type.
     *
     * @param increment the number to increment by
     * @return a ValueUpdate specifying the increment
     * @throws UnsupportedOperationException if the data type is non-numeric
     */
    public static ValueUpdate createIncrement(Number increment) {
        return new ArithmeticValueUpdate(ArithmeticValueUpdate.Operator.ADD, increment);
    }

    /**
     * Creates a new value update that increments a weight in a weighted set. Note that this method is just a convenience
     * method, it simply creates an increment value update by calling createIncrement() and then creates a map value
     * update by calling createMap() with the key and the increment value update as parameters.
     *
     * @param key the key whose weight in the weighted set to increment
     * @param increment the number to increment by
     * @return a ValueUpdate specifying the increment
     * @see ValueUpdate#createIncrement(Number)
     * @see ValueUpdate#createMap(FieldValue, ValueUpdate)
     */
    public static ValueUpdate createIncrement(FieldValue key, Number increment) {
        return createMap(key, createIncrement(increment));
    }

    /**
     * Creates a new value update that decrements a value. Note that the data type must be a numeric
     * type.
     *
     * @param decrement the number to decrement by
     * @return a ValueUpdate specifying the decrement
     * @throws UnsupportedOperationException if the data type is non-numeric
     */
    public static ValueUpdate createDecrement(Number decrement) {
        return new ArithmeticValueUpdate(ArithmeticValueUpdate.Operator.SUB, decrement);
    }

    /**
     * Creates a new value update that decrements a weight in a weighted set. Note that this method is just a convenience
     * method, it simply creates a decrement value update by calling createDecrement() and then creates a map value
     * update by calling createMap() with the key and the decrement value update as parameters.
     *
     * @param key the key whose weight in the weighted set to decrement
     * @param decrement the number to decrement by
     * @return a ValueUpdate specifying the decrement
     * @see ValueUpdate#createDecrement(Number)
     * @see ValueUpdate#createMap(FieldValue, ValueUpdate)
     */
    public static ValueUpdate createDecrement(FieldValue key, Number decrement) {
        return createMap(key, createDecrement(decrement));
    }

    /**
     * Creates a new value update that multiplies a value. Note that the data type must be a numeric
     * type.
     *
     * @param factor the number to multiply by
     * @return a ValueUpdate specifying the multiplication
     * @throws UnsupportedOperationException if the data type is non-numeric
     */
    public static ValueUpdate createMultiply(Number factor) {
        return new ArithmeticValueUpdate(ArithmeticValueUpdate.Operator.MUL, factor);
    }

    /**
     * Creates a new value update that multiplies a weight in a weighted set. Note that this method is just a convenience
     * method, it simply creates a multiply value update by calling createMultiply() and then creates a map value
     * update by calling createMap() with the key and the multiply value update as parameters.
     *
     * @param key the key whose weight in the weighted set to multiply
     * @param factor the number to multiply by
     * @return a ValueUpdate specifying the multiplication
     * @see ValueUpdate#createMultiply(Number)
     * @see ValueUpdate#createMap(FieldValue, ValueUpdate)
     */
    public static ValueUpdate createMultiply(FieldValue key, Number factor) {
        return createMap(key, createMultiply(factor));
    }


    /**
     * Creates a new value update that divides a value. Note that the data type must be a numeric
     * type.
     *
     * @param divisor the number to divide by
     * @return a ValueUpdate specifying the division
     * @throws UnsupportedOperationException if the data type is non-numeric
     */
    public static ValueUpdate createDivide(Number divisor) {
        return new ArithmeticValueUpdate(ArithmeticValueUpdate.Operator.DIV, divisor);
    }

    /**
     * Creates a new value update that divides a weight in a weighted set. Note that this method is just a convenience
     * method, it simply creates a divide value update by calling createDivide() and then creates a map value
     * update by calling createMap() with the key and the divide value update as parameters.
     *
     * @param key the key whose weight in the weighted set to divide
     * @param divisor the number to divide by
     * @return a ValueUpdate specifying the division
     * @see ValueUpdate#createDivide(Number)
     * @see ValueUpdate#createMap(FieldValue, ValueUpdate)
     */
    public static ValueUpdate createDivide(FieldValue key, Number divisor) {
        return createMap(key, createDivide(divisor));
    }

    /**
     * Creates a new value update that assigns a new value, completely overwriting
     * the previous value.
     *
     * @param newValue the value to assign
     * @return a ValueUpdate specifying the assignment
     * @throws IllegalArgumentException if the runtime type of newValue does not match the type required
     */
    public static ValueUpdate createAssign(FieldValue newValue) {
        return new AssignValueUpdate(newValue);
    }

    /**
     * Creates a new value update that clears the field fromthe document.
     *
     * @return a ValueUpdate specifying the removal
     */
    public static ValueUpdate createClear() {
        return new ClearValueUpdate();
    }

    /**
     * Creates a map value update, which is able to map an update to a value to a subvalue in an array or a
     * weighted set. If this update is to be applied to an array, the value parameter must be an integer specifying
     * the index in the array that the update parameter is to be applied to, and the update parameter must be
     * compatible with the sub-datatype of the array. If this update is to be applied on a weighted set, the value
     * parameter must be the key in the set that the update parameter is to be applied to, and the update parameter
     * must be compatible with the INT data type.
     *
     * @param value the index in case of array, or key in case of weighted set
     * @param update the update to apply to the target sub-value
     * @throws IllegalArgumentException in case data type is an array type and value is not an Integer; in case data type is a weighted set type and value is not equal to the nested type of the weighted set; or the encapsulated update throws such an exception
     * @throws UnsupportedOperationException if superType is a single-value type, or anything else than array or weighted set; or the encapsulated update throws such an exception
     * @return a ValueUpdate specifying the sub-update
     */
    public static ValueUpdate createMap(FieldValue value, ValueUpdate update) {
        return new MapValueUpdate(value, update);
    }

    /**
     * Creates a new value update specifying the removal of a value from an array or a key/weight from a weighted set.
     *
     * @param value the value to remove from the array, or key to remove from the weighted set
     * @return a ValueUpdate specifying the removal
     * @throws IllegalArgumentException      if the runtime type of newValue does not match the type required
     * @throws UnsupportedOperationException if the field type is not array or weighted set
     */
    public static ValueUpdate createRemove(FieldValue value) {
        return new RemoveValueUpdate(value);
    }

    /**
     * Creates a new value update
     * specifying the removal of all values in a given list from an array or weighted set. Note that this method
     * is just a convenience method, it simply iterates
     * through the list and creates value updates by calling createRemove() for each element.
     *
     * @param values a List containing the values to remove
     * @return a List of ValueUpdates specifying the removal
     * @throws IllegalArgumentException      if the runtime type of values does not match the type required
     * @throws UnsupportedOperationException if the field type is not array or weighted set
     * @see ValueUpdate#createRemove(FieldValue)
     */
    public static List<ValueUpdate> createRemoveAll(List<? extends FieldValue> values) {
        List<ValueUpdate> vupds = new ArrayList<>();
        for (FieldValue value : values) {
            vupds.add(ValueUpdate.createRemove(value));
        }
        return vupds;
    }

    /**
     * Creates a new value update
     * specifying the removal of all values in a given list from an array or weighted set. Note that this method
     * is just a convenience method, it simply iterates
     * through the list and creates value updates by calling createRemove() for each element.
     *
     * @param values a List containing the values to remove
     * @return a List of ValueUpdates specifying the removal
     * @throws IllegalArgumentException      if the runtime type of values does not match the type required
     * @throws UnsupportedOperationException if the field type is not array or weighted set
     * @see ValueUpdate#createRemove(FieldValue)
     */
    public static List<ValueUpdate> createRemoveAll(WeightedSet<? extends FieldValue> values) {
        List<ValueUpdate> vupds = new ArrayList<>();
        for (FieldValue value : values.keySet()) {
            vupds.add(ValueUpdate.createRemove(value));
        }
        return vupds;
    }

    /** Returns the primary "value" of this update, or null if this kind of update has no value */
    public abstract T getValue();

    /** Sets the value of this. Ignored by update who have no value */
    public abstract void setValue(T value);

    public enum ValueUpdateClassID {
        //DO NOT change anything here unless you change src/vespa/document/util/identifiableid.h as well!!
        ADD(25, "add"),
        ARITHMETIC(26, "arithmetic"),
        ASSIGN(27, "assign"),
        CLEAR(28, "clear"),
        MAP(29, "map"),
        REMOVE(30, "remove"),
        TENSORMODIFY(100, "tensormodify"),
        TENSORADD(101, "tensoradd"),
        TENSORREMOVE(102, "tensorremove");

        public final int id;
        public final String name;

        ValueUpdateClassID(int id, String name) {
            this.id = 0x1000 + id;
            this.name = name;
        }

        public static ValueUpdateClassID getID(int id) {
            for (ValueUpdateClassID vucid : ValueUpdateClassID.values()) {
                if (vucid.id == id) {
                    return vucid;
                }
            }
            return null;
        }
    }
}