aerospike 2.23.0 → 2.25.0

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