aerospike 2.23.0 → 2.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1262 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014-2022 Aerospike, Inc.
3
+ #
4
+ # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
+ # license agreements.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may no
8
+ # use this file except in compliance with the License. You may obtain a copy of
9
+ # the License at http:#www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ module Aerospike
18
+ class Exp
19
+
20
+ # Expression type.
21
+ module Type
22
+ NIL = 0
23
+ BOOL = 1
24
+ INT = 2
25
+ STRING = 3
26
+ LIST = 4
27
+ MAP = 5
28
+ BLOB = 6
29
+ FLOAT = 7
30
+ GEO = 8
31
+ HLL = 9
32
+ end # module type
33
+
34
+ module WriteFlags
35
+ # Default. Allow create or update.
36
+ DEFAULT = 0
37
+
38
+ # If bin does not exist, a new bin will be created.
39
+ # If bin exists, the operation will be denied.
40
+ # If bin exists, fail with ResultCode#BIN_EXISTS_ERROR
41
+ # when #POLICY_NO_FAIL is not set.
42
+ CREATE_ONLY = 1
43
+
44
+ # If bin exists, the bin will be overwritten.
45
+ # If bin does not exist, the operation will be denied.
46
+ # If bin does not exist, fail with ResultCode#BIN_NOT_FOUND
47
+ # when #POLICY_NO_FAIL is not set.
48
+ UPDATE_ONLY = 2
49
+
50
+ # If expression results in nil value, then delete the bin. Otherwise, fail with
51
+ # ResultCode#OP_NOT_APPLICABLE when #POLICY_NO_FAIL is not set.
52
+ ALLOW_DELETE = 4
53
+
54
+ # Do not raise error if operation is denied.
55
+ POLICY_NO_FAIL = 8
56
+
57
+ # Ignore failures caused by the expression resolving to unknown or a non-bin type.
58
+ EVAL_NO_FAIL = 16
59
+ end # module WriteFlags
60
+
61
+ module ReadFlags
62
+ # Default.
63
+ DEFAULT = 0
64
+
65
+ # Ignore failures caused by the expression resolving to unknown or a non-bin type.
66
+ EVAL_NO_FAIL = 16
67
+ end # module ReadFlags
68
+
69
+ # Create record key expression of specified type.
70
+ #
71
+ # ==== Examples
72
+ # # Integer record key >= 100000
73
+ # Exp.ge(Exp.key(Type::INT), Exp.val(100000))
74
+ def self.key(type)
75
+ new CmdInt.new(KEY, type)
76
+ end
77
+
78
+ # Create expression that returns if the primary key is stored in the record meta data
79
+ # as a boolean expression. This would occur when {@link com.aerospike.client.policy.Policy#sendKey}
80
+ # is true on record write. This expression usually evaluates quickly because record
81
+ # meta data is cached in memory.
82
+ #
83
+ # ==== Examples
84
+ # # Key exists in record meta data
85
+ # Exp.key_exists
86
+ def self.key_exists
87
+ new Cmd.new(KEY_EXISTS)
88
+ end
89
+
90
+ #--------------------------------------------------
91
+ # Record Bin
92
+ #--------------------------------------------------
93
+
94
+ # Create bin expression of specified type.
95
+ #
96
+ # ==== Examples
97
+ # # String bin "a" == "views"
98
+ # Exp.eq(Exp.bin("a", Type::STRING), Exp.val("views"))
99
+ def self.bin(name, type)
100
+ new Bin.new(name, type)
101
+ end
102
+
103
+ # Create 64 bit integer bin expression.
104
+ #
105
+ # ==== Examples
106
+ # # Integer bin "a" == 200
107
+ # Exp.eq(Exp.int_bin("a"), Exp.val(200))
108
+ def self.int_bin(name)
109
+ new Bin.new(name, Type::INT)
110
+ end
111
+
112
+ # Create 64 bit float bin expression.
113
+ #
114
+ # ==== Examples
115
+ # # Float bin "a" >= 1.5
116
+ # Exp.ge(Exp.float_bin("a"), Exp.val(1.5))
117
+ def self.float_bin(name)
118
+ new Bin.new(name, Type::FLOAT)
119
+ end
120
+
121
+ # Create string bin expression.
122
+ #
123
+ # ==== Examples
124
+ # # String bin "a" == "views"
125
+ # Exp.eq(Exp.string_bin("a"), Exp.val("views"))
126
+ def self.string_bin(name)
127
+ new Bin.new(name, Type::STRING)
128
+ end
129
+
130
+ # Create boolean bin expression.
131
+ #
132
+ # ==== Examples
133
+ # # Boolean bin "a" == true
134
+ # Exp.eq(Exp.bool_bin("a"), Exp.val(true))
135
+ def self.bool_bin(name)
136
+ new Bin.new(name, Type::BOOL)
137
+ end
138
+
139
+ # Create bin expression.
140
+ #
141
+ # ==== Examples
142
+ # # Blob bin "a" == [1,2,3]
143
+ # Exp.eq(Exp.blob_bin("a"), Exp.val(new {1, 2, 3}))
144
+ def self.blob_bin(name)
145
+ new Bin.new(name, Type::BLOB)
146
+ end
147
+
148
+ # Create geospatial bin expression.
149
+ #
150
+ # ==== Examples
151
+ # # Geo bin "a" == region
152
+ # String region = "{ \"type\": \"AeroCircle\", \"coordinates\": [[-122.0, 37.5], 50000.0] }"
153
+ # Exp.geo_compare(Exp.geo_bin("loc"), Exp.geo(region))
154
+ def self.geo_bin(name)
155
+ new Bin.new(name, Type::GEO)
156
+ end
157
+
158
+ # Create list bin expression.
159
+ #
160
+ # ==== Examples
161
+ # # Bin a[2] == 3
162
+ # Exp.eq(ListExp.get_by_index(ListReturnType::VALUE, Type::INT, Exp.val(2), Exp.list_bin("a")), Exp.val(3))
163
+ def self.list_bin(name)
164
+ new Bin.new(name, Type::LIST)
165
+ end
166
+
167
+ # Create map bin expression.
168
+ #
169
+ # ==== Examples
170
+ # # Bin a["key"] == "value"
171
+ # Exp.eq(
172
+ # MapExp.get_by_key(MapReturnType::VALUE, Type::STRING, Exp.val("key"), Exp.map_bin("a")),
173
+ # Exp.val("value"))
174
+ def self.map_bin(name)
175
+ new Bin.new(name, Type::MAP)
176
+ end
177
+
178
+ # Create hll bin expression.
179
+ #
180
+ # ==== Examples
181
+ # # HLL bin "a" count > 7
182
+ # Exp.gt(HLLExp.get_count(Exp.hll_bin("a")), Exp.val(7))
183
+ def self.hll_bin(name)
184
+ new Bin.new(name, Type::HLL)
185
+ end
186
+
187
+ # Create expression that returns if bin of specified name exists.
188
+ #
189
+ # ==== Examples
190
+ # # Bin "a" exists in record
191
+ # Exp.bin_exists("a")
192
+ def self.bin_exists(name)
193
+ return Exp.ne(Exp.bin_type(name), Exp.val(0))
194
+ end
195
+
196
+ # Create expression that returns bin's integer particle type::
197
+ # See {@link com.aerospike.client.command.ParticleType}.
198
+ #
199
+ # ==== Examples
200
+ # # Bin "a" particle type is a list
201
+ # Exp.eq(Exp.bin_type("a"), Exp.val(ParticleType::LIST))
202
+ def self.bin_type(name)
203
+ new CmdStr.new(BIN_TYPE, name)
204
+ end
205
+
206
+ #--------------------------------------------------
207
+ # Misc
208
+ #--------------------------------------------------
209
+
210
+ # Create expression that returns record set name string. This expression usually
211
+ # evaluates quickly because record meta data is cached in memory.
212
+ #
213
+ # ==== Examples
214
+ # # Record set name == "myset"
215
+ # Exp.eq(Exp.set_name, Exp.val("myset"))
216
+ def self.set_name
217
+ new Cmd.new(SET_NAME)
218
+ end
219
+
220
+ # Create expression that returns record size on disk. If server storage-engine is
221
+ # memory, then zero is returned. This expression usually evaluates quickly because
222
+ # record meta data is cached in memory.
223
+ #
224
+ # ==== Examples
225
+ # # Record device size >= 100 KB
226
+ # Exp.ge(Exp.device_size, Exp.val(100 * 1024))
227
+ def self.device_size
228
+ new Cmd.new(DEVICE_SIZE)
229
+ end
230
+
231
+ # Create expression that returns record size in memory. If server storage-engine is
232
+ # not memory nor data-in-memory, then zero is returned. This expression usually evaluates
233
+ # quickly because record meta data is cached in memory.
234
+ # <p>
235
+ # Requires server version 5.3.0+
236
+ #
237
+ # ==== Examples
238
+ # # Record memory size >= 100 KB
239
+ # Exp.ge(Exp.memory_size, Exp.val(100 * 1024))
240
+ def self.memory_size
241
+ new Cmd.new(MEMORY_SIZE)
242
+ end
243
+
244
+ # Create expression that returns record last update time expressed as 64 bit integer
245
+ # nanoseconds since 1970-01-01 epoch. This expression usually evaluates quickly because
246
+ # record meta data is cached in memory.
247
+ #
248
+ # ==== Examples
249
+ # # Record last update time >= 2020-01-15
250
+ # Exp.ge(Exp.last_update, Exp.val(new GregorianCalendar(2020, 0, 15)))
251
+ def self.last_update
252
+ new Cmd.new(LAST_UPDATE)
253
+ end
254
+
255
+ # Create expression that returns milliseconds since the record was last updated.
256
+ # This expression usually evaluates quickly because record meta data is cached in memory.
257
+ #
258
+ # ==== Examples
259
+ # # Record last updated more than 2 hours ago
260
+ # Exp.gt(Exp.since_update, Exp.val(2 * 60 * 60 * 1000))
261
+ def self.since_update
262
+ new Cmd.new(SINCE_UPDATE)
263
+ end
264
+
265
+ # Create expression that returns record expiration time expressed as 64 bit integer
266
+ # nanoseconds since 1970-01-01 epoch. This expression usually evaluates quickly because
267
+ # record meta data is cached in memory.
268
+ #
269
+ # ==== Examples
270
+ # # Record expires on 2021-01-01
271
+ # Exp.and(
272
+ # Exp.ge(Exp.void_time, Exp.val(new GregorianCalendar(2021, 0, 1))),
273
+ # Exp.lt(Exp.void_time, Exp.val(new GregorianCalendar(2021, 0, 2))))
274
+ def self.void_time
275
+ new Cmd.new(VOID_TIME)
276
+ end
277
+
278
+ # Create expression that returns record expiration time (time to live) in integer seconds.
279
+ # This expression usually evaluates quickly because record meta data is cached in memory.
280
+ #
281
+ # ==== Examples
282
+ # # Record expires in less than 1 hour
283
+ # Exp.lt(Exp.ttl, Exp.val(60 * 60))
284
+ def self.ttl
285
+ new Cmd.new(TTL)
286
+ end
287
+
288
+ # Create expression that returns if record has been deleted and is still in tombstone state.
289
+ # This expression usually evaluates quickly because record meta data is cached in memory.
290
+ #
291
+ # ==== Examples
292
+ # # Deleted records that are in tombstone state.
293
+ # Exp.is_tombstone
294
+ def self.is_tombstone
295
+ new Cmd.new(IS_TOMBSTONE)
296
+ end
297
+
298
+ # Create expression that returns record digest modulo as integer. This expression usually
299
+ # evaluates quickly because record meta data is cached in memory.
300
+ #
301
+ # ==== Examples
302
+ # # Records that have digest(key) % 3 == 1
303
+ # Exp.eq(Exp.digest_modulo(3), Exp.val(1))
304
+ def self.digest_modulo(mod)
305
+ new CmdInt.new(DIGEST_MODULO, mod)
306
+ end
307
+
308
+ # Create expression that performs a regex match on a string bin or string value expression.
309
+ #
310
+ # ==== Examples
311
+ # # Select string bin "a" that starts with "prefix" and ends with "suffix".
312
+ # # Ignore case and do not match newline.
313
+ # Exp.regex_compare("prefix.*suffix", RegexFlag.ICASE | RegexFlag.NEWLINE, Exp.string_bin("a"))
314
+ #
315
+ # @param regex regular expression string
316
+ # @param flags regular expression bit flags. See {@link com.aerospike.client.query.RegexFlag}
317
+ # @param bin string bin or string value expression
318
+ def self.regex_compare(regex, flags, bin)
319
+ new Regex.new(bin, regex, flags)
320
+ end
321
+
322
+ #--------------------------------------------------
323
+ # GEO Spatial
324
+ #--------------------------------------------------
325
+
326
+ # Create compare geospatial operation.
327
+ #
328
+ # ==== Examples
329
+ # # Query region within coordinates.
330
+ # String region =
331
+ # "{ " +
332
+ # " \"type\": \"Polygon\", " +
333
+ # " \"coordinates\": [ " +
334
+ # " [[-122.500000, 37.000000],[-121.000000, 37.000000], " +
335
+ # " [-121.000000, 38.080000],[-122.500000, 38.080000], " +
336
+ # " [-122.500000, 37.000000]] " +
337
+ # " ] " +
338
+ # "}"
339
+ # Exp.geo_compare(Exp.geo_bin("a"), Exp.geo(region))
340
+ def self.geo_compare(left, right)
341
+ new CmdExp.new(GEO, left, right)
342
+ end
343
+
344
+ # Create geospatial json string value.
345
+ def self.geo(val)
346
+ new Geo.new(val)
347
+ end
348
+
349
+ #--------------------------------------------------
350
+ # Value
351
+ #--------------------------------------------------
352
+
353
+ # Create boolean value.
354
+ def self.val(val)
355
+ new Bool.new(val)
356
+ end
357
+
358
+ # Create 64 bit integer value.
359
+ def self.val(val)
360
+ new Int.new(val)
361
+ end
362
+
363
+ # Create 64 bit floating point value.
364
+ def self.val(val)
365
+ new Float.new(val)
366
+ end
367
+
368
+ # Create string value.
369
+ def self.val(val)
370
+ new Str.new(val)
371
+ end
372
+
373
+ # Create blob byte value.
374
+ def self.val(val)
375
+ new Blob.new(val)
376
+ end
377
+
378
+ # Create list value.
379
+ def self.val(list)
380
+ new ListVal.new(list)
381
+ end
382
+
383
+ # Create map value.
384
+ def self.val(map)
385
+ new MapVal.new(map)
386
+ end
387
+
388
+ # Create nil value.
389
+ def self.nil
390
+ new Nil.new
391
+ end
392
+
393
+ #--------------------------------------------------
394
+ # Boolean Operator
395
+ #--------------------------------------------------
396
+
397
+ # Create "not" operator expression.
398
+ #
399
+ # ==== Examples
400
+ # # ! (a == 0 || a == 10)
401
+ # Exp.not(
402
+ # Exp.or(
403
+ # Exp.eq(Exp.int_bin("a"), Exp.val(0)),
404
+ # Exp.eq(Exp.int_bin("a"), Exp.val(10))))
405
+ def self.not(exp)
406
+ new CmdExp.new(NOT, exp)
407
+ end
408
+
409
+ # Create "and" (&&) operator that applies to a variable number of expressions.
410
+ #
411
+ # ==== Examples
412
+ # # (a > 5 || a == 0) && b < 3
413
+ # Exp.and(
414
+ # Exp.or(
415
+ # Exp.gt(Exp.int_bin("a"), Exp.val(5)),
416
+ # Exp.eq(Exp.int_bin("a"), Exp.val(0))),
417
+ # Exp.lt(Exp.int_bin("b"), Exp.val(3)))
418
+ def self.and(*exps)
419
+ new CmdExp.new(AND, exps)
420
+ end
421
+
422
+ # Create "or" (||) operator that applies to a variable number of expressions.
423
+ #
424
+ # ==== Examples
425
+ # # a == 0 || b == 0
426
+ # Exp.or(
427
+ # Exp.eq(Exp.int_bin("a"), Exp.val(0)),
428
+ # Exp.eq(Exp.int_bin("b"), Exp.val(0)))
429
+ def self.or(*exps)
430
+ new CmdExp.new(OR, exps)
431
+ end
432
+
433
+ # Create expression that returns true if only one of the expressions are true.
434
+ # Requires server version 5.6.0+.
435
+ #
436
+ # ==== Examples
437
+ # # exclusive(a == 0, b == 0)
438
+ # Exp.exclusive(
439
+ # Exp.eq(Exp.int_bin("a"), Exp.val(0)),
440
+ # Exp.eq(Exp.int_bin("b"), Exp.val(0)))
441
+ def self.exclusive(*exps)
442
+ new CmdExp.new(EXCLUSIVE, exps)
443
+ end
444
+
445
+ # Create equal (==) expression.
446
+ #
447
+ # ==== Examples
448
+ # # a == 11
449
+ # Exp.eq(Exp.int_bin("a"), Exp.val(11))
450
+ def self.eq(left, right)
451
+ new CmdExp.new(EQ, left, right)
452
+ end
453
+
454
+ # Create not equal (!=) expression
455
+ #
456
+ # ==== Examples
457
+ # # a != 13
458
+ # Exp.ne(Exp.int_bin("a"), Exp.val(13))
459
+ def self.ne(left, right)
460
+ new CmdExp.new(NE, left, right)
461
+ end
462
+
463
+ # Create greater than (>) operation.
464
+ #
465
+ # ==== Examples
466
+ # # a > 8
467
+ # Exp.gt(Exp.int_bin("a"), Exp.val(8))
468
+ def self.gt(left, right)
469
+ new CmdExp.new(GT, left, right)
470
+ end
471
+
472
+ # Create greater than or equal (>=) operation.
473
+ #
474
+ # ==== Examples
475
+ # # a >= 88
476
+ # Exp.ge(Exp.int_bin("a"), Exp.val(88))
477
+ def self.ge(left, right)
478
+ new CmdExp.new(GE, left, right)
479
+ end
480
+
481
+ # Create less than (<) operation.
482
+ #
483
+ # ==== Examples
484
+ # # a < 1000
485
+ # Exp.lt(Exp.int_bin("a"), Exp.val(1000))
486
+ def self.lt(left, right)
487
+ new CmdExp.new(LT, left, right)
488
+ end
489
+
490
+ # Create less than or equals (<=) operation.
491
+ #
492
+ # ==== Examples
493
+ # # a <= 1
494
+ # Exp.le(Exp.int_bin("a"), Exp.val(1))
495
+ def self.le(left, right)
496
+ new CmdExp.new(LE, left, right)
497
+ end
498
+
499
+ #--------------------------------------------------
500
+ # Number Operator
501
+ #--------------------------------------------------
502
+
503
+ # Create "add" (+) operator that applies to a variable number of expressions.
504
+ # Return sum of all arguments. All arguments must resolve to the same type (or float).
505
+ # Requires server version 5.6.0+.
506
+ #
507
+ # ==== Examples
508
+ # # a + b + c == 10
509
+ # Exp.eq(
510
+ # Exp.add(Exp.int_bin("a"), Exp.int_bin("b"), Exp.int_bin("c")),
511
+ # Exp.val(10))
512
+ def self.add(*exps)
513
+ new CmdExp.new(ADD, exps)
514
+ end
515
+
516
+ # Create "subtract" (-) operator that applies to a variable number of expressions.
517
+ # If only one argument is provided, return the negation of that argument.
518
+ # Otherwise, return the sum of the 2nd to Nth argument subtracted from the 1st
519
+ # argument. All arguments must resolve to the same type (or float).
520
+ # Requires server version 5.6.0+.
521
+ #
522
+ # ==== Examples
523
+ # # a - b - c > 10
524
+ # Exp.gt(
525
+ # Exp.sub(Exp.int_bin("a"), Exp.int_bin("b"), Exp.int_bin("c")),
526
+ # Exp.val(10))
527
+ def self.sub(*exps)
528
+ new CmdExp.new(SUB, exps)
529
+ end
530
+
531
+ # Create "multiply" (*) operator that applies to a variable number of expressions.
532
+ # Return the product of all arguments. If only one argument is supplied, return
533
+ # that argument. All arguments must resolve to the same type (or float).
534
+ # Requires server version 5.6.0+.
535
+ #
536
+ # ==== Examples
537
+ # # a * b * c < 100
538
+ # Exp.lt(
539
+ # Exp.mul(Exp.int_bin("a"), Exp.int_bin("b"), Exp.int_bin("c")),
540
+ # Exp.val(100))
541
+ def self.mul(*exps)
542
+ new CmdExp.new(MUL, exps)
543
+ end
544
+
545
+ # Create "divide" (/) operator that applies to a variable number of expressions.
546
+ # If there is only one argument, returns the reciprocal for that argument.
547
+ # Otherwise, return the first argument divided by the product of the rest.
548
+ # All arguments must resolve to the same type (or float).
549
+ # Requires server version 5.6.0+.
550
+ #
551
+ # ==== Examples
552
+ # # a / b / c > 1
553
+ # Exp.gt(
554
+ # Exp.div(Exp.int_bin("a"), Exp.int_bin("b"), Exp.int_bin("c")),
555
+ # Exp.val(1))
556
+ def self.div(*exps)
557
+ new CmdExp.new(DIV, exps)
558
+ end
559
+
560
+ # Create "power" operator that raises a "base" to the "exponent" power.
561
+ # All arguments must resolve to floats.
562
+ # Requires server version 5.6.0+.
563
+ #
564
+ # ==== Examples
565
+ # # pow(a, 2.0) == 4.0
566
+ # Exp.eq(
567
+ # Exp.pow(Exp.float_bin("a"), Exp.val(2.0)),
568
+ # Exp.val(4.0))
569
+ def self.pow(base, exponent)
570
+ new CmdExp.new(POW, base, exponent)
571
+ end
572
+
573
+ # Create "log" operator for logarithm of "num" with base "base".
574
+ # All arguments must resolve to floats.
575
+ # Requires server version 5.6.0+.
576
+ #
577
+ # ==== Examples
578
+ # # log(a, 2.0) == 4.0
579
+ # Exp.eq(
580
+ # Exp.log(Exp.float_bin("a"), Exp.val(2.0)),
581
+ # Exp.val(4.0))
582
+ def self.log(num, base)
583
+ new CmdExp.new(LOG, num, base)
584
+ end
585
+
586
+ # Create "modulo" (%) operator that determines the remainder of "numerator"
587
+ # divided by "denominator". All arguments must resolve to integers.
588
+ # Requires server version 5.6.0+.
589
+ #
590
+ # ==== Examples
591
+ # # a % 10 == 0
592
+ # Exp.eq(
593
+ # Exp.mod(Exp.int_bin("a"), Exp.val(10)),
594
+ # Exp.val(0))
595
+ def self.mod(numerator, denominator)
596
+ new CmdExp.new(MOD, numerator, denominator)
597
+ end
598
+
599
+ # Create operator that returns absolute value of a number.
600
+ # All arguments must resolve to integer or float.
601
+ # Requires server version 5.6.0+.
602
+ #
603
+ # ==== Examples
604
+ # # abs(a) == 1
605
+ # Exp.eq(
606
+ # Exp.abs(Exp.int_bin("a")),
607
+ # Exp.val(1))
608
+ def self.abs(value)
609
+ new CmdExp.new(ABS, value)
610
+ end
611
+
612
+ # Create expression that rounds a floating point number down to the closest integer value.
613
+ # The return type is float. Requires server version 5.6.0+.
614
+ #
615
+ # ==== Examples
616
+ # # floor(2.95) == 2.0
617
+ # Exp.eq(
618
+ # Exp.floor(Exp.val(2.95)),
619
+ # Exp.val(2.0))
620
+ def self.floor(num)
621
+ new CmdExp.new(FLOOR, num)
622
+ end
623
+
624
+ # Create expression that rounds a floating point number up to the closest integer value.
625
+ # The return type is float. Requires server version 5.6.0+.
626
+ #
627
+ # ==== Examples
628
+ # # ceil(2.15) >= 3.0
629
+ # Exp.ge(
630
+ # Exp.ceil(Exp.val(2.15)),
631
+ # Exp.val(3.0))
632
+ def self.ceil(num)
633
+ new CmdExp.new(CEIL, num)
634
+ end
635
+
636
+ # Create expression that converts a float to an integer.
637
+ # Requires server version 5.6.0+.
638
+ #
639
+ # ==== Examples
640
+ # # int(2.5) == 2
641
+ # Exp.eq(
642
+ # Exp.to_int(Exp.val(2.5)),
643
+ # Exp.val(2))
644
+ def self.to_int(num)
645
+ new CmdExp.new(TO_INT, num)
646
+ end
647
+
648
+ # Create expression that converts an integer to a float.
649
+ # Requires server version 5.6.0+.
650
+ #
651
+ # ==== Examples
652
+ # # float(2) == 2.0
653
+ # Exp.eq(
654
+ # Exp.to_float(Exp.val(2))),
655
+ # Exp.val(2.0))
656
+ def self.to_float(num)
657
+ new CmdExp.new(TO_FLOAT, num)
658
+ end
659
+
660
+ # Create integer "and" (&) operator that is applied to two or more integers.
661
+ # All arguments must resolve to integers.
662
+ # Requires server version 5.6.0+.
663
+ #
664
+ # ==== Examples
665
+ # # a & 0xff == 0x11
666
+ # Exp.eq(
667
+ # Exp.int_and(Exp.int_bin("a"), Exp.val(0xff)),
668
+ # Exp.val(0x11))
669
+ def self.int_and(*exps)
670
+ new CmdExp.new(exps)
671
+ end
672
+
673
+ # Create integer "or" (|) operator that is applied to two or more integers.
674
+ # All arguments must resolve to integers.
675
+ # Requires server version 5.6.0+.
676
+ #
677
+ # ==== Examples
678
+ # # a | 0x10 != 0
679
+ # Exp.ne(
680
+ # Exp.int_or(Exp.int_bin("a"), Exp.val(0x10)),
681
+ # Exp.val(0))
682
+ def self.int_or(*exps)
683
+ new CmdExp.new(exps)
684
+ end
685
+
686
+ # Create integer "xor" (^) operator that is applied to two or more integers.
687
+ # All arguments must resolve to integers.
688
+ # Requires server version 5.6.0+.
689
+ #
690
+ # ==== Examples
691
+ # # a ^ b == 16
692
+ # Exp.eq(
693
+ # Exp.int_xor(Exp.int_bin("a"), Exp.int_bin("b")),
694
+ # Exp.val(16))
695
+ def self.int_xor(*exps)
696
+ new CmdExp.new(exps)
697
+ end
698
+
699
+ # Create integer "not" (~) operator.
700
+ # Requires server version 5.6.0+.
701
+ #
702
+ # ==== Examples
703
+ # # ~a == 7
704
+ # Exp.eq(
705
+ # Exp.int_not(Exp.int_bin("a")),
706
+ # Exp.val(7))
707
+ def self.int_not(exp)
708
+ new CmdExp.new(exp)
709
+ end
710
+
711
+ # Create integer "left shift" (<<) operator.
712
+ # Requires server version 5.6.0+.
713
+ #
714
+ # ==== Examples
715
+ # # a << 8 > 0xff
716
+ # Exp.gt(
717
+ # Exp.lshift(Exp.int_bin("a"), Exp.val(8)),
718
+ # Exp.val(0xff))
719
+ def self.lshift(value, shift)
720
+ new CmdExp.new(value, shift)
721
+ end
722
+
723
+ # Create integer "logical right shift" (>>>) operator.
724
+ # Requires server version 5.6.0+.
725
+ #
726
+ # ==== Examples
727
+ # # a >>> 8 > 0xff
728
+ # Exp.gt(
729
+ # Exp.rshift(Exp.int_bin("a"), Exp.val(8)),
730
+ # Exp.val(0xff))
731
+ def self.rshift(value, shift)
732
+ new CmdExp.new(value, shift)
733
+ end
734
+
735
+ # Create integer "arithmetic right shift" (>>) operator.
736
+ # Requires server version 5.6.0+.
737
+ #
738
+ # ==== Examples
739
+ # # a >> 8 > 0xff
740
+ # Exp.gt(
741
+ # Exp.arshift(Exp.int_bin("a"), Exp.val(8)),
742
+ # Exp.val(0xff))
743
+ def self.arshift(value, shift)
744
+ new CmdExp.new(value, shift)
745
+ end
746
+
747
+ # Create expression that returns count of integer bits that are set to 1.
748
+ # Requires server version 5.6.0+.
749
+ #
750
+ # ==== Examples
751
+ # # count(a) == 4
752
+ # Exp.eq(
753
+ # Exp.count(Exp.int_bin("a")),
754
+ # Exp.val(4))
755
+ def self.count(exp)
756
+ new CmdExp.new(exp)
757
+ end
758
+
759
+ # Create expression that scans integer bits from left (most significant bit) to
760
+ # right (least significant bit), looking for a search bit value. When the
761
+ # search value is found, the index of that bit (where the most significant bit is
762
+ # index 0) is returned. If "search" is true, the scan will search for the bit
763
+ # value 1. If "search" is false it will search for bit value 0.
764
+ # Requires server version 5.6.0+.
765
+ #
766
+ # ==== Examples
767
+ # # lscan(a, true) == 4
768
+ # Exp.eq(
769
+ # Exp.lscan(Exp.int_bin("a"), Exp.val(true)),
770
+ # Exp.val(4))
771
+ def self.lscan(value, search)
772
+ new CmdExp.new(value, search)
773
+ end
774
+
775
+ # Create expression that scans integer bits from right (least significant bit) to
776
+ # left (most significant bit), looking for a search bit value. When the
777
+ # search value is found, the index of that bit (where the most significant bit is
778
+ # index 0) is returned. If "search" is true, the scan will search for the bit
779
+ # value 1. If "search" is false it will search for bit value 0.
780
+ # Requires server version 5.6.0+.
781
+ #
782
+ # ==== Examples
783
+ # # rscan(a, true) == 4
784
+ # Exp.eq(
785
+ # Exp.rscan(Exp.int_bin("a"), Exp.val(true)),
786
+ # Exp.val(4))
787
+ def self.rscan(value, search)
788
+ new CmdExp.new(value, search)
789
+ end
790
+
791
+ # Create expression that returns the minimum value in a variable number of expressions.
792
+ # All arguments must be the same type (or float).
793
+ # Requires server version 5.6.0+.
794
+ #
795
+ # ==== Examples
796
+ # # min(a, b, c) > 0
797
+ # Exp.gt(
798
+ # Exp.min(Exp.int_bin("a"), Exp.int_bin("b"), Exp.int_bin("c")),
799
+ # Exp.val(0))
800
+ def self.min(*exps)
801
+ new CmdExp.new(MIN, exps)
802
+ end
803
+
804
+ # Create expression that returns the maximum value in a variable number of expressions.
805
+ # All arguments must be the same type (or float).
806
+ # Requires server version 5.6.0+.
807
+ #
808
+ # ==== Examples
809
+ # # max(a, b, c) > 100
810
+ # Exp.gt(
811
+ # Exp.max(Exp.int_bin("a"), Exp.int_bin("b"), Exp.int_bin("c")),
812
+ # Exp.val(100))
813
+ def self.max(*exps)
814
+ new CmdExp.new(MAX, exps)
815
+ end
816
+
817
+ #--------------------------------------------------
818
+ # Variables
819
+ #--------------------------------------------------
820
+
821
+ # Conditionally select an expression from a variable number of expression pairs
822
+ # followed by default expression action. Requires server version 5.6.0+.
823
+ #
824
+ # ==== Examples
825
+ # Args Format: bool exp1, action exp1, bool exp2, action exp2, ..., action-default
826
+ #
827
+ # # Apply operator based on type::
828
+ # Exp.cond(
829
+ # Exp.eq(Exp.int_bin("type"), Exp.val(0)), Exp.add(Exp.int_bin("val1"), Exp.int_bin("val2")),
830
+ # Exp.eq(Exp.int_bin("type"), Exp.val(1)), Exp.sub(Exp.int_bin("val1"), Exp.int_bin("val2")),
831
+ # Exp.eq(Exp.int_bin("type"), Exp.val(2)), Exp.mul(Exp.int_bin("val1"), Exp.int_bin("val2")),
832
+ # Exp.val(-1))
833
+ def self.cond(*exps)
834
+ new CmdExp.new(COND, exps)
835
+ end
836
+
837
+ # Define variables and expressions in scope.
838
+ # Requires server version 5.6.0+.
839
+ #
840
+ # ==== Examples
841
+ # Args Format: <def1>, <def2>, ..., <exp>
842
+ # def: {@link Exp#def(String, Exp)}
843
+ # exp: Scoped expression
844
+ #
845
+ # ==== Examples
846
+ # # 5 < a < 10
847
+ # Exp.let(
848
+ # Exp.def("x", Exp.int_bin("a")),
849
+ # Exp.and(
850
+ # Exp.lt(Exp.val(5), Exp.var("x")),
851
+ # Exp.lt(Exp.var("x"), Exp.val(10))))
852
+ def self.let(*exps)
853
+ new Let.new(exps)
854
+ end
855
+
856
+ # Assign variable to a {@link Exp#let(Exp...)} expression that can be accessed later.
857
+ # Requires server version 5.6.0+.
858
+ #
859
+ # ==== Examples
860
+ # # 5 < a < 10
861
+ # Exp.let(
862
+ # Exp.def("x", Exp.int_bin("a")),
863
+ # Exp.and(
864
+ # Exp.lt(Exp.val(5), Exp.var("x")),
865
+ # Exp.lt(Exp.var("x"), Exp.val(10))))
866
+ def self.def(name, value)
867
+ new Def.new(name, value)
868
+ end
869
+
870
+ # Retrieve expression value from a variable.
871
+ # Requires server version 5.6.0+.
872
+ #
873
+ # ==== Examples
874
+ # # 5 < a < 10
875
+ # Exp.let(
876
+ # Exp.def("x", Exp.int_bin("a")),
877
+ # Exp.and(
878
+ # Exp.lt(Exp.val(5), Exp.var("x")),
879
+ # Exp.lt(Exp.var("x"), Exp.val(10))))
880
+ def self.var(name)
881
+ new CmdStr.new(VAR, name)
882
+ end
883
+
884
+ #--------------------------------------------------
885
+ # Miscellaneous
886
+ #--------------------------------------------------
887
+
888
+ # Create unknown value. Used to intentionally fail an expression.
889
+ # The failure can be ignored with {@link com.aerospike.client.exp.exp_write_flags#EVAL_NO_FAIL}
890
+ # or {@link com.aerospike.client.exp.exp_read_flags#EVAL_NO_FAIL}.
891
+ # Requires server version 5.6.0+.
892
+ #
893
+ # ==== Examples
894
+ # # double v = balance - 100.0
895
+ # # return (v > 0.0)? v : unknown
896
+ # Exp.let(
897
+ # Exp.def("v", Exp.sub(Exp.float_bin("balance"), Exp.val(100.0))),
898
+ # Exp.cond(
899
+ # Exp.ge(Exp.var("v"), Exp.val(0.0)), Exp.var("v"),
900
+ # Exp.unknown))
901
+ def self.unknown
902
+ new Cmd.new(UNKNOWN)
903
+ end
904
+
905
+ # # Merge precompiled expression into a new expression tree.
906
+ # # Useful for storing common precompiled expressions and then reusing
907
+ # # these expressions as part of a greater expression.
908
+ # #
909
+ # # ==== Examples
910
+ # # # Merge precompiled expression into new expression.
911
+ # # Expression e = Exp.build(Exp.eq(Exp.int_bin("a"), Exp.val(200)))
912
+ # # Expression merged = Exp.build(Exp.and(Exp.expr(e), Exp.eq(Exp.int_bin("b"), Exp.val(100))))
913
+ # def self.expr(Expression e)
914
+ # new ExpBytes.new(e)
915
+ # end
916
+
917
+ #--------------------------------------------------
918
+ # Internal
919
+ #--------------------------------------------------
920
+ MODIFY = 0x40
921
+
922
+ private
923
+
924
+ UNKNOWN = 0
925
+ EQ = 1
926
+ NE = 2
927
+ GT = 3
928
+ GE = 4
929
+ LT = 5
930
+ LE = 6
931
+ REGEX = 7
932
+ GEO = 8
933
+ AND = 16
934
+ OR = 17
935
+ NOT = 18
936
+ EXCLUSIVE = 19
937
+ ADD = 20
938
+ SUB = 21
939
+ MUL = 22
940
+ DIV = 23
941
+ POW = 24
942
+ LOG = 25
943
+ MOD = 26
944
+ ABS = 27
945
+ FLOOR = 28
946
+ CEIL = 29
947
+ TO_INT = 30
948
+ TO_FLOAT = 31
949
+ INT_AND = 32
950
+ INT_OR = 33
951
+ INT_XOR = 34
952
+ INT_NOT = 35
953
+ INT_LSHIFT = 36
954
+ INT_RSHIFT = 37
955
+ INT_ARSHIFT = 38
956
+ INT_COUNT = 39
957
+ INT_LSCAN = 40
958
+ INT_RSCAN = 41
959
+ MIN = 50
960
+ MAX = 51
961
+ DIGEST_MODULO = 64
962
+ DEVICE_SIZE = 65
963
+ LAST_UPDATE = 66
964
+ SINCE_UPDATE = 67
965
+ VOID_TIME = 68
966
+ TTL = 69
967
+ SET_NAME = 70
968
+ KEY_EXISTS = 71
969
+ IS_TOMBSTONE = 72
970
+ MEMORY_SIZE = 73
971
+ KEY = 80
972
+ BIN = 81
973
+ BIN_TYPE = 82
974
+ COND = 123
975
+ VAR = 124
976
+ LET = 125
977
+ QUOTED = 126
978
+ CALL = 127
979
+ NANOS_PER_MILLIS = 1000000
980
+
981
+ def pack(packer)
982
+ raise "Unreachable"
983
+ end
984
+
985
+ # For internal use only.
986
+ class Module < Exp
987
+ attr_reader :bin
988
+ attr_reader :bytes
989
+ attr_reader :ret_type
990
+ attr_reader :module
991
+
992
+ def initialize(bin, bytes, ret_type, modul)
993
+ @bin = bin
994
+ @bytes = bytes
995
+ @ret_type = ret_type
996
+ @module = modul
997
+ end
998
+
999
+ def pack(packer)
1000
+ packer.pack_array_begin(5)
1001
+ packer.pack_int(Exp::CALL)
1002
+ packer.pack_int(ret_type)
1003
+ packer.pack_int(modul)
1004
+ packer.pack_byte_array(bytes, 0, bytes.length)
1005
+ bin.pack(packer)
1006
+ end
1007
+ end
1008
+
1009
+ class Bin < Exp
1010
+ attr_reader :name
1011
+ attr_reader :type
1012
+
1013
+ def initialize(name, type)
1014
+ @name = name
1015
+ @type = type
1016
+ end
1017
+
1018
+ def pack(packer)
1019
+ packer.pack_array_begin(3)
1020
+ packer.pack_int(BIN)
1021
+ packer.pack_int(type.code)
1022
+ packer.pack_string(name)
1023
+ end
1024
+ end
1025
+
1026
+ class Regex < Exp
1027
+ attr_reader :bin
1028
+ attr_reader :regex
1029
+ attr_reader :flags
1030
+
1031
+ def initialize(bin, regex, flags)
1032
+ @bin = bin
1033
+ @regex = regex
1034
+ @flags = flags
1035
+ end
1036
+
1037
+ def pack(packer)
1038
+ packer.pack_array_begin(4)
1039
+ packer.pack_int(REGEX)
1040
+ packer.pack_int(flags)
1041
+ packer.pack_string(regex)
1042
+ bin.pack(packer)
1043
+ end
1044
+ end
1045
+
1046
+ class Let < Exp
1047
+ attr_reader :exps
1048
+
1049
+ def initialize(exps)
1050
+ @exps = exps
1051
+ end
1052
+
1053
+ def pack(packer)
1054
+ # Let wire format: LET <defname1>, <defexp1>, <defname2>, <defexp2>, ..., <scope exp>
1055
+ count = (exps.length - 1) * 2 + 2
1056
+ packer.pack_array_begin(count)
1057
+ packer.pack_int(LET)
1058
+
1059
+ exps.each do |exp|
1060
+ exp.pack(packer)
1061
+ end
1062
+ end
1063
+ end
1064
+
1065
+ class Def < Exp
1066
+ attr_reader :name
1067
+ attr_reader :exp
1068
+
1069
+ def initialize(name, exp)
1070
+ @name = name
1071
+ @exp = exp
1072
+ end
1073
+
1074
+ def pack(packer)
1075
+ packer.pack_string(name)
1076
+ exp::pack(packer)
1077
+ end
1078
+ end
1079
+
1080
+ class CmdExp < Exp
1081
+ attr_reader :exps
1082
+ attr_reader :cmd
1083
+
1084
+ def initialize(cmd, exps)
1085
+ @exps = exps
1086
+ @cmd = cmd
1087
+ end
1088
+
1089
+ def pack(packer)
1090
+ packer.pack_array_begin(exps.length + 1)
1091
+ packer.pack_int(cmd)
1092
+
1093
+ exps.each do |exp|
1094
+ exp.pack(packer)
1095
+ end
1096
+ end
1097
+ end
1098
+
1099
+ class CmdInt < Exp
1100
+ attr_reader :cmd
1101
+ attr_reader :val
1102
+
1103
+ def initialize(cmd, val)
1104
+ @cmd = cmd
1105
+ @val = val
1106
+ end
1107
+
1108
+ def pack(packer)
1109
+ packer.pack_array_begin(2)
1110
+ packer.pack_int(cmd)
1111
+ packer.pack_int(val)
1112
+ end
1113
+ end
1114
+
1115
+ class CmdStr < Exp
1116
+ attr_reader :str
1117
+ attr_reader :cmd
1118
+
1119
+ def initialize(cmd, str)
1120
+ @str = str
1121
+ @cmd = cmd
1122
+ end
1123
+
1124
+ def pack(packer)
1125
+ packer.pack_array_begin(2)
1126
+ packer.pack_int(cmd)
1127
+ packer.pack_string(str)
1128
+ end
1129
+ end
1130
+
1131
+ class Cmd < Exp
1132
+ attr_reader :cmd
1133
+
1134
+ def initialize(cmd)
1135
+ @cmd = cmd
1136
+ end
1137
+
1138
+ def pack(packer)
1139
+ packer.pack_array_begin(1)
1140
+ packer.pack_int(cmd)
1141
+ end
1142
+ end
1143
+
1144
+ class Bool < Exp
1145
+ attr_reader :val
1146
+
1147
+ def initialize(val)
1148
+ @val = val
1149
+ end
1150
+
1151
+ def pack(packer)
1152
+ packer.pack_boolean(val)
1153
+ end
1154
+ end
1155
+
1156
+ class Int < Exp
1157
+ attr_reader :val
1158
+
1159
+ def initialize(val)
1160
+ @val = val
1161
+ end
1162
+
1163
+ def pack(packer)
1164
+ packer.pack_long(val)
1165
+ end
1166
+ end
1167
+
1168
+ class Float < Exp
1169
+ attr_reader :val
1170
+
1171
+ def initialize(val)
1172
+ @val = val
1173
+ end
1174
+
1175
+ def pack(packer)
1176
+ packer.pack_double(val)
1177
+ end
1178
+ end
1179
+
1180
+ class Str < Exp
1181
+ attr_reader :val
1182
+
1183
+ def initialize(val)
1184
+ @val = val
1185
+ end
1186
+
1187
+ def pack(packer)
1188
+ packer.pack_particle_string(val)
1189
+ end
1190
+ end
1191
+
1192
+ class Geo < Exp
1193
+ attr_reader :val
1194
+
1195
+ def initialize(val)
1196
+ @val = val
1197
+ end
1198
+
1199
+ def pack(packer)
1200
+ packer.pack_geo_json(val)
1201
+ end
1202
+ end
1203
+
1204
+ class Blob < Exp
1205
+ attr_reader :val
1206
+
1207
+ def initialize(val)
1208
+ @val = val
1209
+ end
1210
+
1211
+ def pack(packer)
1212
+ packer.pack_particle_bytes(val)
1213
+ end
1214
+ end
1215
+
1216
+ class ListVal < Exp
1217
+ attr_reader :list
1218
+
1219
+ def initialize(list)
1220
+ @list = list
1221
+ end
1222
+
1223
+ def pack(packer)
1224
+ # List values need an extra array and QUOTED in order to distinguish
1225
+ # between a multiple argument array call and a local list.
1226
+ packer.pack_array_begin(2)
1227
+ packer.pack_int(QUOTED)
1228
+ packer.pack_list(list)
1229
+ end
1230
+ end
1231
+
1232
+ class MapVal < Exp
1233
+ attr_reader :map
1234
+
1235
+ def initialize(map)
1236
+ @map = map
1237
+ end
1238
+
1239
+ def pack(packer)
1240
+ packer.pack_map(map)
1241
+ end
1242
+ end
1243
+
1244
+ class Nil < Exp
1245
+ def pack(packer)
1246
+ packer.pack_nil
1247
+ end
1248
+ end
1249
+
1250
+ class ExpBytes < Exp
1251
+ attr_reader :bytes
1252
+
1253
+ def initialize(e)
1254
+ @bytes = e.getBytes
1255
+ end
1256
+
1257
+ def pack(packer)
1258
+ packer.pack_byte_array(bytes, 0, bytes.length)
1259
+ end
1260
+ end
1261
+ end # class Exp
1262
+ end # module