aerospike 2.19.0 → 2.26.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +354 -244
  3. data/lib/aerospike/atomic/atomic.rb +1 -1
  4. data/lib/aerospike/cdt/context.rb +137 -70
  5. data/lib/aerospike/cdt/list_return_type.rb +4 -0
  6. data/lib/aerospike/cdt/map_operation.rb +6 -6
  7. data/lib/aerospike/cdt/map_policy.rb +16 -2
  8. data/lib/aerospike/cdt/map_return_type.rb +13 -1
  9. data/lib/aerospike/client.rb +137 -115
  10. data/lib/aerospike/cluster/create_connection.rb +1 -1
  11. data/lib/aerospike/cluster.rb +41 -4
  12. data/lib/aerospike/command/admin_command.rb +368 -52
  13. data/lib/aerospike/command/batch_index_command.rb +4 -8
  14. data/lib/aerospike/command/batch_index_exists_command.rb +1 -1
  15. data/lib/aerospike/command/batch_index_node.rb +1 -1
  16. data/lib/aerospike/command/batch_item.rb +1 -1
  17. data/lib/aerospike/command/command.rb +180 -123
  18. data/lib/aerospike/command/field_type.rb +25 -24
  19. data/lib/aerospike/command/login_command.rb +164 -0
  20. data/lib/aerospike/command/multi_command.rb +25 -2
  21. data/lib/aerospike/command/operate_args.rb +99 -0
  22. data/lib/aerospike/command/operate_command.rb +6 -11
  23. data/lib/aerospike/command/read_command.rb +2 -2
  24. data/lib/aerospike/connection/authenticate.rb +36 -3
  25. data/lib/aerospike/exp/exp.rb +1329 -0
  26. data/lib/aerospike/exp/exp_bit.rb +388 -0
  27. data/lib/aerospike/exp/exp_hll.rb +169 -0
  28. data/lib/aerospike/exp/exp_list.rb +403 -0
  29. data/lib/aerospike/exp/exp_map.rb +493 -0
  30. data/lib/aerospike/exp/operation.rb +56 -0
  31. data/lib/aerospike/features.rb +22 -9
  32. data/lib/aerospike/host/parse.rb +2 -2
  33. data/lib/aerospike/key.rb +10 -1
  34. data/lib/aerospike/node/refresh/info.rb +1 -1
  35. data/lib/aerospike/node/verify/name.rb +1 -1
  36. data/lib/aerospike/node/verify/partition_generation.rb +1 -1
  37. data/lib/aerospike/node/verify/peers_generation.rb +1 -1
  38. data/lib/aerospike/node/verify/rebalance_generation.rb +1 -1
  39. data/lib/aerospike/node_validator.rb +6 -1
  40. data/lib/aerospike/operation.rb +20 -22
  41. data/lib/aerospike/policy/auth_mode.rb +36 -0
  42. data/lib/aerospike/policy/client_policy.rb +4 -1
  43. data/lib/aerospike/policy/policy.rb +29 -13
  44. data/lib/aerospike/policy/query_policy.rb +35 -2
  45. data/lib/aerospike/policy/scan_policy.rb +19 -2
  46. data/lib/aerospike/privilege.rb +133 -0
  47. data/lib/aerospike/query/filter.rb +44 -32
  48. data/lib/aerospike/query/node_partitions.rb +39 -0
  49. data/lib/aerospike/query/partition_filter.rb +66 -0
  50. data/lib/aerospike/{command/roles.rb → query/partition_status.rb} +16 -19
  51. data/lib/aerospike/query/partition_tracker.rb +347 -0
  52. data/lib/aerospike/query/query_command.rb +20 -10
  53. data/lib/aerospike/query/query_executor.rb +71 -0
  54. data/lib/aerospike/query/query_partition_command.rb +267 -0
  55. data/lib/aerospike/query/recordset.rb +9 -9
  56. data/lib/aerospike/query/scan_command.rb +3 -2
  57. data/lib/aerospike/query/scan_executor.rb +71 -0
  58. data/lib/aerospike/query/scan_partition_command.rb +49 -0
  59. data/lib/aerospike/query/statement.rb +8 -1
  60. data/lib/aerospike/query/stream_command.rb +17 -0
  61. data/lib/aerospike/result_code.rb +83 -8
  62. data/lib/aerospike/role.rb +55 -0
  63. data/lib/aerospike/task/execute_task.rb +19 -16
  64. data/lib/aerospike/task/index_task.rb +1 -1
  65. data/lib/aerospike/user_role.rb +26 -1
  66. data/lib/aerospike/utils/buffer.rb +93 -29
  67. data/lib/aerospike/utils/packer.rb +7 -6
  68. data/lib/aerospike/utils/pool.rb +1 -1
  69. data/lib/aerospike/value/particle_type.rb +1 -12
  70. data/lib/aerospike/value/value.rb +35 -60
  71. data/lib/aerospike/version.rb +1 -1
  72. data/lib/aerospike.rb +156 -136
  73. metadata +24 -6
@@ -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