slatedb 0.3.2.beta.3-x86_64-linux

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,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlateDb
4
+ class Admin
5
+ class << self
6
+ # Create an admin handle for a database path/object store.
7
+ #
8
+ # @param path [String] Database path
9
+ # @param url [String, nil] Optional object store URL
10
+ # @return [Admin] The admin handle
11
+ #
12
+ # @example
13
+ # admin = SlateDb::Admin.new("/tmp/mydb")
14
+ # checkpoints = admin.list_checkpoints
15
+ #
16
+ def new(path, url: nil)
17
+ _new(path, url)
18
+ end
19
+ end
20
+
21
+ # Read the latest or a specific manifest as a JSON string.
22
+ #
23
+ # @param id [Integer, nil] Optional manifest id to read. If nil, reads the latest.
24
+ # @return [String, nil] JSON string of the manifest, or nil if no manifests exist
25
+ #
26
+ # @example
27
+ # json = admin.read_manifest
28
+ # json = admin.read_manifest(123)
29
+ #
30
+ def read_manifest(id = nil)
31
+ _read_manifest(id)
32
+ end
33
+
34
+ # List manifests within an optional [start, end) range as JSON.
35
+ #
36
+ # @param start [Integer, nil] Optional inclusive start id
37
+ # @param end_id [Integer, nil] Optional exclusive end id
38
+ # @return [String] JSON string containing a list of manifest metadata
39
+ #
40
+ # @example
41
+ # json = admin.list_manifests
42
+ # json = admin.list_manifests(start: 1, end_id: 10)
43
+ #
44
+ def list_manifests(start: nil, end_id: nil)
45
+ _list_manifests(start, end_id)
46
+ end
47
+
48
+ # Create a detached checkpoint.
49
+ #
50
+ # @param lifetime [Integer, nil] Checkpoint lifetime in milliseconds
51
+ # @param source [String, nil] Source checkpoint UUID string to extend/refresh
52
+ # @param name [String, nil] Checkpoint name
53
+ # @return [Hash] Hash with :id (UUID string) and :manifest_id (Integer)
54
+ #
55
+ # @example
56
+ # result = admin.create_checkpoint(name: "my_checkpoint")
57
+ # puts result[:id] # => "uuid-string"
58
+ # puts result[:manifest_id] # => 7
59
+ #
60
+ def create_checkpoint(lifetime: nil, source: nil, name: nil)
61
+ opts = {}
62
+ opts[:lifetime] = lifetime if lifetime
63
+ opts[:source] = source if source
64
+ opts[:name] = name if name
65
+ _create_checkpoint(opts)
66
+ end
67
+
68
+ # List known checkpoints for the database.
69
+ #
70
+ # @param name [String, nil] Optional checkpoint name filter
71
+ # @return [Array<Hash>] Array of checkpoint hashes
72
+ #
73
+ # @example
74
+ # checkpoints = admin.list_checkpoints
75
+ # checkpoints.each do |cp|
76
+ # puts "#{cp[:id]}: #{cp[:name]}"
77
+ # end
78
+ #
79
+ def list_checkpoints(name: nil)
80
+ _list_checkpoints(name)
81
+ end
82
+
83
+ # Refresh a checkpoint's lifetime.
84
+ #
85
+ # @param id [String] Checkpoint UUID string
86
+ # @param lifetime [Integer, nil] New lifetime in milliseconds
87
+ # @return [void]
88
+ #
89
+ # @example
90
+ # admin.refresh_checkpoint("uuid-here", lifetime: 60_000)
91
+ #
92
+ def refresh_checkpoint(id, lifetime: nil)
93
+ _refresh_checkpoint(id, lifetime)
94
+ end
95
+
96
+ # Delete a checkpoint.
97
+ #
98
+ # @param id [String] Checkpoint UUID string
99
+ # @return [void]
100
+ #
101
+ # @example
102
+ # admin.delete_checkpoint("uuid-here")
103
+ #
104
+ def delete_checkpoint(id)
105
+ _delete_checkpoint(id)
106
+ end
107
+
108
+ # Run garbage collection once.
109
+ #
110
+ # @param min_age [Integer, nil] Minimum age in milliseconds for objects to be collected
111
+ # @return [void]
112
+ #
113
+ # @example
114
+ # admin.run_gc(min_age: 3600_000) # 1 hour
115
+ #
116
+ def run_gc(min_age: nil)
117
+ opts = {}
118
+ opts[:min_age] = min_age if min_age
119
+ _run_gc(opts)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,498 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlateDb
4
+ class Database # rubocop:disable Metrics/ClassLength
5
+ private_class_method :new
6
+
7
+ class << self
8
+ # Open a database at the given path.
9
+ #
10
+ # @param path [String] The path identifier for the database
11
+ # @param url [String, nil] Optional object store URL (e.g., "s3://bucket/path")
12
+ # @param merge_operator [Symbol, String, Proc, nil] Optional merge operator.
13
+ # Can be a symbol/string ("string_concat" or "concat") or a Proc/lambda
14
+ # that takes (key, existing_value, new_value) and returns the merged value.
15
+ # @yield [db] If a block is given, yields the database and ensures it's closed
16
+ # @return [Database] The opened database (or block result if block given)
17
+ #
18
+ # @example Open a database
19
+ # db = SlateDb::Database.open("/tmp/mydb")
20
+ # db.put("key", "value")
21
+ # db.close
22
+ #
23
+ # @example Open with block (auto-close)
24
+ # SlateDb::Database.open("/tmp/mydb") do |db|
25
+ # db.put("key", "value")
26
+ # end # automatically closed
27
+ #
28
+ # @example Open with S3 backend
29
+ # db = SlateDb::Database.open("/tmp/mydb", url: "s3://mybucket/path")
30
+ #
31
+ # @example Open with a custom merge operator (Proc)
32
+ # # Custom merge that adds numbers
33
+ # db = SlateDb::Database.open("/tmp/mydb", merge_operator: ->(key, existing, new_val) {
34
+ # existing_num = existing ? existing.to_i : 0
35
+ # (existing_num + new_val.to_i).to_s
36
+ # })
37
+ # db.merge("counter", "5")
38
+ # db.merge("counter", "3")
39
+ # db.get("counter") # => "8"
40
+ #
41
+ def open(path, url: nil, merge_operator: nil)
42
+ opts = {}
43
+
44
+ case merge_operator
45
+ when Symbol, String
46
+ opts[:merge_operator] = merge_operator.to_s
47
+ when Proc
48
+ # Store the proc to prevent GC and pass to Rust
49
+ @_merge_operator_proc = merge_operator
50
+ opts[:merge_operator_proc] = merge_operator
51
+ end
52
+
53
+ db = _open(path, url, opts)
54
+
55
+ if block_given?
56
+ begin
57
+ yield db
58
+ ensure
59
+ begin
60
+ db.close
61
+ rescue StandardError
62
+ nil
63
+ end
64
+ end
65
+ else
66
+ db
67
+ end
68
+ end
69
+ end
70
+
71
+ # Get a value by key.
72
+ #
73
+ # @param key [String] The key to look up
74
+ # @param durability_filter [String, nil] Filter by durability level ("remote" or "memory")
75
+ # @param dirty [Boolean, nil] Whether to include uncommitted data
76
+ # @param cache_blocks [Boolean, nil] Whether to cache blocks
77
+ # @return [String, nil] The value, or nil if not found
78
+ #
79
+ # @example Basic get
80
+ # value = db.get("mykey")
81
+ #
82
+ # @example Get with options
83
+ # value = db.get("mykey", durability_filter: "memory", dirty: true)
84
+ #
85
+ def get(key, durability_filter: nil, dirty: nil, cache_blocks: nil)
86
+ opts = {}
87
+ opts[:durability_filter] = durability_filter.to_s if durability_filter
88
+ opts[:dirty] = dirty unless dirty.nil?
89
+ opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
90
+
91
+ if opts.empty?
92
+ _get(key)
93
+ else
94
+ _get_with_options(key, opts)
95
+ end
96
+ end
97
+
98
+ # Get a key-value pair with SlateDB metadata.
99
+ #
100
+ # @param key [String] The key to look up
101
+ # @param durability_filter [String, nil] Filter by durability level ("remote" or "memory")
102
+ # @param dirty [Boolean, nil] Whether to include uncommitted data
103
+ # @param cache_blocks [Boolean, nil] Whether to cache blocks
104
+ # @return [Hash, nil] A hash with :key, :value, :seq, :create_ts, and :expire_ts, or nil if not found
105
+ #
106
+ # @example Inspect metadata
107
+ # entry = db.get_key_value("mykey")
108
+ # entry[:value] # => "myvalue"
109
+ # entry[:seq] # => sequence number
110
+ #
111
+ def get_key_value(key, durability_filter: nil, dirty: nil, cache_blocks: nil)
112
+ opts = {}
113
+ opts[:durability_filter] = durability_filter.to_s if durability_filter
114
+ opts[:dirty] = dirty unless dirty.nil?
115
+ opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
116
+
117
+ if opts.empty?
118
+ _get_key_value(key)
119
+ else
120
+ _get_key_value_with_options(key, opts)
121
+ end
122
+ end
123
+
124
+ alias get_entry get_key_value
125
+
126
+ # Store a key-value pair.
127
+ #
128
+ # @param key [String] The key to store
129
+ # @param value [String] The value to store
130
+ # @param ttl [Integer, nil] Time-to-live in milliseconds
131
+ # @param await_durable [Boolean] Whether to wait for durability (default: true)
132
+ # @param seqnum [Integer, nil] User-supplied sequence number for this write.
133
+ # When provided (and non-zero), it is used instead of the internally
134
+ # generated sequence number. It must be strictly greater than the current
135
+ # maximum sequence number or the write fails. (Requires SlateDB >= 0.13.0)
136
+ # @return [void]
137
+ #
138
+ # @example Basic put
139
+ # db.put("mykey", "myvalue")
140
+ #
141
+ # @example Put with TTL
142
+ # db.put("mykey", "myvalue", ttl: 60_000) # expires in 60 seconds
143
+ #
144
+ # @example Put without waiting for durability
145
+ # db.put("mykey", "myvalue", await_durable: false)
146
+ #
147
+ # @example Put with an explicit sequence number
148
+ # db.put("mykey", "myvalue", seqnum: 42)
149
+ #
150
+ def put(key, value, ttl: nil, await_durable: nil, seqnum: nil)
151
+ opts = {}
152
+ opts[:ttl] = ttl if ttl
153
+ opts[:await_durable] = await_durable unless await_durable.nil?
154
+ opts[:seqnum] = seqnum if seqnum
155
+
156
+ if opts.empty?
157
+ _put(key, value)
158
+ else
159
+ _put_with_options(key, value, opts)
160
+ end
161
+ end
162
+
163
+ # Delete a key.
164
+ #
165
+ # @param key [String] The key to delete
166
+ # @param await_durable [Boolean] Whether to wait for durability (default: true)
167
+ # @param seqnum [Integer, nil] User-supplied sequence number for this write.
168
+ # See {#put} for semantics. (Requires SlateDB >= 0.13.0)
169
+ # @return [void]
170
+ #
171
+ # @example Basic delete
172
+ # db.delete("mykey")
173
+ #
174
+ # @example Delete without waiting for durability
175
+ # db.delete("mykey", await_durable: false)
176
+ #
177
+ def delete(key, await_durable: nil, seqnum: nil)
178
+ opts = {}
179
+ opts[:await_durable] = await_durable unless await_durable.nil?
180
+ opts[:seqnum] = seqnum if seqnum
181
+
182
+ if opts.empty?
183
+ _delete(key)
184
+ else
185
+ _delete_with_options(key, opts)
186
+ end
187
+ end
188
+
189
+ # Scan a range of keys.
190
+ #
191
+ # @param start_key [String] The start key (inclusive)
192
+ # @param end_key [String, nil] The end key (exclusive). If nil, scans to end.
193
+ # @param durability_filter [String, nil] Filter by durability level ("remote" or "memory")
194
+ # @param dirty [Boolean, nil] Whether to include uncommitted data
195
+ # @param read_ahead_bytes [Integer, nil] Number of bytes to read ahead
196
+ # @param cache_blocks [Boolean, nil] Whether to cache blocks
197
+ # @param max_fetch_tasks [Integer, nil] Maximum number of fetch tasks
198
+ # @param order [Symbol, String, nil] Iteration order (:asc/:ascending or :desc/:descending)
199
+ # @return [Iterator] An iterator over key-value pairs
200
+ #
201
+ # @example Basic scan
202
+ # iter = db.scan("a")
203
+ # while entry = iter.next_entry
204
+ # key, value = entry
205
+ # puts "#{key}: #{value}"
206
+ # end
207
+ #
208
+ # @example Scan with range
209
+ # iter = db.scan("a", "z")
210
+ #
211
+ # @example Scan with block
212
+ # db.scan("user:") do |key, value|
213
+ # puts "#{key}: #{value}"
214
+ # end
215
+ #
216
+ def scan(start_key, end_key = nil, durability_filter: nil, dirty: nil,
217
+ read_ahead_bytes: nil, cache_blocks: nil, max_fetch_tasks: nil, order: nil, &)
218
+ opts = scan_options(
219
+ durability_filter: durability_filter,
220
+ dirty: dirty,
221
+ read_ahead_bytes: read_ahead_bytes,
222
+ cache_blocks: cache_blocks,
223
+ max_fetch_tasks: max_fetch_tasks,
224
+ order: order
225
+ )
226
+
227
+ iter = if opts.empty?
228
+ _scan(start_key, end_key)
229
+ else
230
+ _scan_with_options(start_key, end_key, opts)
231
+ end
232
+
233
+ if block_given?
234
+ iter.each(&)
235
+ else
236
+ iter
237
+ end
238
+ end
239
+
240
+ # Scan all keys with a given prefix.
241
+ #
242
+ # @param prefix [String] The key prefix to scan
243
+ # @param durability_filter [String, nil] Filter by durability level ("remote" or "memory")
244
+ # @param dirty [Boolean, nil] Whether to include uncommitted data
245
+ # @param read_ahead_bytes [Integer, nil] Number of bytes to read ahead
246
+ # @param cache_blocks [Boolean, nil] Whether to cache blocks
247
+ # @param max_fetch_tasks [Integer, nil] Maximum number of fetch tasks
248
+ # @param order [Symbol, String, nil] Iteration order (:asc/:ascending or :desc/:descending)
249
+ # @return [Iterator] An iterator over key-value pairs
250
+ #
251
+ # @example Scan all user keys
252
+ # db.scan_prefix("user:") do |key, value|
253
+ # puts "#{key}: #{value}"
254
+ # end
255
+ #
256
+ def scan_prefix(prefix, durability_filter: nil, dirty: nil,
257
+ read_ahead_bytes: nil, cache_blocks: nil, max_fetch_tasks: nil, order: nil, &)
258
+ opts = scan_options(
259
+ durability_filter: durability_filter,
260
+ dirty: dirty,
261
+ read_ahead_bytes: read_ahead_bytes,
262
+ cache_blocks: cache_blocks,
263
+ max_fetch_tasks: max_fetch_tasks,
264
+ order: order
265
+ )
266
+
267
+ iter = if opts.empty?
268
+ _scan_prefix(prefix)
269
+ else
270
+ _scan_prefix_with_options(prefix, opts)
271
+ end
272
+
273
+ if block_given?
274
+ iter.each(&)
275
+ else
276
+ iter
277
+ end
278
+ end
279
+
280
+ def scan_options(durability_filter:, dirty:, read_ahead_bytes:, cache_blocks:,
281
+ max_fetch_tasks:, order:)
282
+ opts = {}
283
+ opts[:durability_filter] = durability_filter.to_s if durability_filter
284
+ opts[:dirty] = dirty unless dirty.nil?
285
+ opts[:read_ahead_bytes] = read_ahead_bytes if read_ahead_bytes
286
+ opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
287
+ opts[:max_fetch_tasks] = max_fetch_tasks if max_fetch_tasks
288
+ opts[:order] = order.to_s if order
289
+ opts
290
+ end
291
+
292
+ private :scan_options
293
+
294
+ # Write a batch of operations atomically.
295
+ #
296
+ # @param batch [WriteBatch] The batch to write
297
+ # @param await_durable [Boolean] Whether to wait for durability (default: true)
298
+ # @param seqnum [Integer, nil] User-supplied sequence number applied to the
299
+ # batch. See {#put} for semantics. (Requires SlateDB >= 0.13.0)
300
+ # @return [void]
301
+ #
302
+ # @example Write a batch
303
+ # batch = SlateDb::WriteBatch.new
304
+ # batch.put("key1", "value1")
305
+ # batch.put("key2", "value2")
306
+ # batch.delete("key3")
307
+ # db.write(batch)
308
+ #
309
+ # @example Using batch block helper
310
+ # db.batch do |b|
311
+ # b.put("key1", "value1")
312
+ # b.put("key2", "value2")
313
+ # end
314
+ #
315
+ def write(batch, await_durable: nil, seqnum: nil)
316
+ opts = {}
317
+ opts[:await_durable] = await_durable unless await_durable.nil?
318
+ opts[:seqnum] = seqnum if seqnum
319
+
320
+ if opts.empty?
321
+ _write(batch)
322
+ else
323
+ _write_with_options(batch, opts)
324
+ end
325
+ end
326
+
327
+ # Merge a value into the database.
328
+ #
329
+ # @param key [String] The key to merge into
330
+ # @param value [String] The merge operand to apply
331
+ # @param ttl [Integer, nil] Time-to-live in milliseconds
332
+ # @param await_durable [Boolean] Whether to wait for durability (default: true)
333
+ # @param seqnum [Integer, nil] User-supplied sequence number for this write.
334
+ # See {#put} for semantics. (Requires SlateDB >= 0.13.0)
335
+ # @return [void]
336
+ #
337
+ # @example Merge with string concatenation operator
338
+ # db = SlateDb::Database.open("/tmp/mydb", merge_operator: :string_concat)
339
+ # db.merge("key", "part1")
340
+ # db.merge("key", "part2")
341
+ #
342
+ def merge(key, value, ttl: nil, await_durable: nil, seqnum: nil)
343
+ opts = {}
344
+ opts[:ttl] = ttl if ttl
345
+ opts[:await_durable] = await_durable unless await_durable.nil?
346
+ opts[:seqnum] = seqnum if seqnum
347
+
348
+ if opts.empty?
349
+ _merge(key, value)
350
+ else
351
+ _merge_with_options(key, value, opts)
352
+ end
353
+ end
354
+
355
+ # Create and write a batch using a block.
356
+ #
357
+ # @param await_durable [Boolean] Whether to wait for durability (default: true)
358
+ # @param seqnum [Integer, nil] User-supplied sequence number applied to the
359
+ # batch. See {#put} for semantics. (Requires SlateDB >= 0.13.0)
360
+ # @yield [batch] Yields a WriteBatch to the block
361
+ # @return [void]
362
+ #
363
+ # @example
364
+ # db.batch do |b|
365
+ # b.put("key1", "value1")
366
+ # b.put("key2", "value2")
367
+ # b.delete("old_key")
368
+ # end
369
+ #
370
+ def batch(await_durable: nil, seqnum: nil)
371
+ b = WriteBatch.new
372
+ yield b
373
+ write(b, await_durable: await_durable, seqnum: seqnum)
374
+ end
375
+
376
+ # Begin a new transaction.
377
+ #
378
+ # @param isolation [Symbol, String] Isolation level (:snapshot or :serializable)
379
+ # @yield [txn] If a block is given, yields the transaction and auto-commits/rollbacks
380
+ # @return [Transaction, Object] The transaction (or block result if block given)
381
+ #
382
+ # @example Manual transaction management
383
+ # txn = db.begin_transaction
384
+ # txn.put("key", "value")
385
+ # txn.commit
386
+ #
387
+ # @example Block-based transaction (auto-commit)
388
+ # db.transaction do |txn|
389
+ # txn.put("key", "value")
390
+ # txn.get("other_key")
391
+ # end # automatically committed
392
+ #
393
+ # @example Serializable isolation
394
+ # db.transaction(isolation: :serializable) do |txn|
395
+ # val = txn.get("counter")
396
+ # txn.put("counter", (val.to_i + 1).to_s)
397
+ # end
398
+ #
399
+ def begin_transaction(isolation: nil)
400
+ isolation_str = isolation&.to_s
401
+ _begin_transaction(isolation_str)
402
+ end
403
+
404
+ # Execute a block within a transaction.
405
+ #
406
+ # The transaction is automatically committed if the block succeeds,
407
+ # or rolled back if an exception is raised.
408
+ #
409
+ # @param isolation [Symbol, String] Isolation level (:snapshot or :serializable)
410
+ # @yield [txn] Yields the transaction to the block
411
+ # @return [Object] The result of the block
412
+ #
413
+ # @example
414
+ # result = db.transaction do |txn|
415
+ # old_val = txn.get("counter") || "0"
416
+ # new_val = (old_val.to_i + 1).to_s
417
+ # txn.put("counter", new_val)
418
+ # new_val
419
+ # end
420
+ #
421
+ def transaction(isolation: nil)
422
+ txn = begin_transaction(isolation: isolation)
423
+ begin
424
+ result = yield txn
425
+ txn.commit
426
+ result
427
+ rescue StandardError
428
+ begin
429
+ txn.rollback
430
+ rescue StandardError
431
+ nil
432
+ end
433
+ raise
434
+ end
435
+ end
436
+
437
+ # Create a snapshot for consistent reads.
438
+ #
439
+ # @yield [snapshot] If a block is given, yields the snapshot and auto-closes
440
+ # @return [Snapshot, Object] The snapshot (or block result if block given)
441
+ #
442
+ # @example Manual snapshot management
443
+ # snapshot = db.snapshot
444
+ # snapshot.get("key")
445
+ # snapshot.close
446
+ #
447
+ # @example Block-based snapshot (auto-close)
448
+ # db.snapshot do |snap|
449
+ # snap.get("key1")
450
+ # snap.get("key2")
451
+ # end # automatically closed
452
+ #
453
+ def snapshot
454
+ snap = _snapshot
455
+
456
+ if block_given?
457
+ begin
458
+ yield snap
459
+ ensure
460
+ begin
461
+ snap.close
462
+ rescue StandardError
463
+ nil
464
+ end
465
+ end
466
+ else
467
+ snap
468
+ end
469
+ end
470
+
471
+ # Create a checkpoint of the database.
472
+ #
473
+ # @param lifetime [Integer, nil] Checkpoint lifetime in milliseconds
474
+ # @param name [String, nil] Optional name for the checkpoint
475
+ # @return [Hash] Hash with :id (UUID string) and :manifest_id (integer)
476
+ #
477
+ # @example Create a named checkpoint
478
+ # checkpoint = db.create_checkpoint(name: "before-migration")
479
+ # puts "Checkpoint ID: #{checkpoint[:id]}"
480
+ #
481
+ # @example Create a checkpoint with lifetime
482
+ # checkpoint = db.create_checkpoint(lifetime: 3600_000) # 1 hour
483
+ #
484
+ def create_checkpoint(lifetime: nil, name: nil)
485
+ opts = {}
486
+ opts[:lifetime] = lifetime if lifetime
487
+ opts[:name] = name if name
488
+ _create_checkpoint(opts)
489
+ end
490
+
491
+ # Get database metrics registry.
492
+ #
493
+ # @return [Metrics] Metrics registry
494
+ def metrics
495
+ _metrics
496
+ end
497
+ end
498
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlateDb
4
+ class Iterator
5
+ include Enumerable
6
+
7
+ # Iterate over all entries.
8
+ #
9
+ # @yield [key, value] Yields each key-value pair
10
+ # @return [self, Enumerator] Returns self if block given, otherwise an Enumerator
11
+ #
12
+ # @example
13
+ # iter.each do |key, value|
14
+ # puts "#{key}: #{value}"
15
+ # end
16
+ #
17
+ # @example With Enumerable methods
18
+ # iter.map { |k, v| [k.upcase, v] }
19
+ # iter.select { |k, v| k.start_with?("user:") }
20
+ #
21
+ def each
22
+ return to_enum(:each) unless block_given?
23
+
24
+ while (entry = next_entry)
25
+ yield entry
26
+ end
27
+
28
+ self
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlateDb
4
+ class Metrics
5
+ # Get a metric value by name.
6
+ #
7
+ # @param name [String] Metric name
8
+ # @return [Integer, nil] Current value or nil if not found
9
+ def [](name)
10
+ get(name)
11
+ end
12
+
13
+ # Convert all metrics to a hash.
14
+ #
15
+ # @return [Hash] Map of metric name to value
16
+ def to_h
17
+ names.to_h { |metric_name| [metric_name, get(metric_name)] }
18
+ end
19
+ end
20
+ end