familia 1.2.3 → 2.0.0.pre.pre

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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +68 -0
  3. data/.github/workflows/docs.yml +64 -0
  4. data/.gitignore +3 -0
  5. data/.pre-commit-config.yaml +3 -1
  6. data/.rubocop.yml +16 -9
  7. data/.rubocop_todo.yml +177 -31
  8. data/.yardopts +9 -0
  9. data/CLAUDE.md +141 -0
  10. data/Gemfile +15 -2
  11. data/Gemfile.lock +61 -61
  12. data/README.md +39 -23
  13. data/bin/irb +3 -0
  14. data/docs/connection_pooling.md +317 -0
  15. data/familia.gemspec +8 -5
  16. data/lib/familia/base.rb +19 -9
  17. data/lib/familia/connection.rb +232 -65
  18. data/lib/familia/core_ext.rb +1 -1
  19. data/lib/familia/datatype/commands.rb +59 -0
  20. data/lib/familia/{redistype → datatype}/serialization.rb +9 -13
  21. data/lib/familia/{redistype → datatype}/types/hashkey.rb +25 -25
  22. data/lib/familia/{redistype → datatype}/types/list.rb +13 -13
  23. data/lib/familia/{redistype → datatype}/types/sorted_set.rb +20 -20
  24. data/lib/familia/{redistype → datatype}/types/string.rb +22 -21
  25. data/lib/familia/{redistype → datatype}/types/unsorted_set.rb +11 -11
  26. data/lib/familia/datatype.rb +243 -0
  27. data/lib/familia/errors.rb +5 -2
  28. data/lib/familia/features/expiration.rb +33 -34
  29. data/lib/familia/features/quantization.rb +9 -3
  30. data/lib/familia/features/safe_dump.rb +2 -3
  31. data/lib/familia/features.rb +2 -2
  32. data/lib/familia/horreum/class_methods.rb +97 -130
  33. data/lib/familia/horreum/commands.rb +46 -51
  34. data/lib/familia/horreum/connection.rb +82 -0
  35. data/lib/familia/horreum/{relations_management.rb → related_fields_management.rb} +37 -35
  36. data/lib/familia/horreum/serialization.rb +61 -198
  37. data/lib/familia/horreum/settings.rb +6 -17
  38. data/lib/familia/horreum/utils.rb +11 -10
  39. data/lib/familia/horreum.rb +69 -60
  40. data/lib/familia/logging.rb +12 -12
  41. data/lib/familia/multi_result.rb +72 -0
  42. data/lib/familia/refinements.rb +7 -44
  43. data/lib/familia/settings.rb +11 -11
  44. data/lib/familia/utils.rb +123 -90
  45. data/lib/familia/version.rb +4 -21
  46. data/lib/familia.rb +17 -12
  47. data/lib/middleware/database_middleware.rb +150 -0
  48. data/try/configuration/scenarios_try.rb +65 -0
  49. data/try/core/connection_try.rb +58 -0
  50. data/try/core/errors_try.rb +93 -0
  51. data/try/core/extensions_try.rb +26 -0
  52. data/try/{10_familia_try.rb → core/familia_extended_try.rb} +11 -10
  53. data/try/{00_familia_try.rb → core/familia_try.rb} +5 -3
  54. data/try/core/middleware_try.rb +68 -0
  55. data/try/core/refinements_try.rb +39 -0
  56. data/try/core/settings_try.rb +76 -0
  57. data/try/core/tools_try.rb +54 -0
  58. data/try/core/utils_try.rb +189 -0
  59. data/try/{26_redis_bool_try.rb → datatypes/boolean_try.rb} +4 -2
  60. data/try/datatypes/datatype_base_try.rb +69 -0
  61. data/try/{25_redis_type_hash_try.rb → datatypes/hash_try.rb} +5 -3
  62. data/try/{23_redis_type_list_try.rb → datatypes/list_try.rb} +5 -3
  63. data/try/{22_redis_type_set_try.rb → datatypes/set_try.rb} +5 -3
  64. data/try/{21_redis_type_zset_try.rb → datatypes/sorted_set_try.rb} +6 -4
  65. data/try/{24_redis_type_string_try.rb → datatypes/string_try.rb} +8 -8
  66. data/try/edge_cases/empty_identifiers_try.rb +48 -0
  67. data/try/{92_symbolize_try.rb → edge_cases/hash_symbolization_try.rb} +12 -8
  68. data/try/edge_cases/json_serialization_try.rb +85 -0
  69. data/try/edge_cases/race_conditions_try.rb +60 -0
  70. data/try/edge_cases/reserved_keywords_try.rb +59 -0
  71. data/try/{93_string_coercion_try.rb → edge_cases/string_coercion_try.rb} +63 -60
  72. data/try/edge_cases/ttl_side_effects_try.rb +51 -0
  73. data/try/features/expiration_try.rb +86 -0
  74. data/try/features/quantization_try.rb +90 -0
  75. data/try/{35_feature_safedump_try.rb → features/safe_dump_advanced_try.rb} +7 -6
  76. data/try/features/safe_dump_try.rb +137 -0
  77. data/try/{test_helpers.rb → helpers/test_helpers.rb} +25 -60
  78. data/try/{27_redis_horreum_try.rb → horreum/base_try.rb} +39 -14
  79. data/try/horreum/class_methods_try.rb +41 -0
  80. data/try/horreum/commands_try.rb +49 -0
  81. data/try/{29_redis_horreum_initialization_try.rb → horreum/initialization_try.rb} +9 -7
  82. data/try/horreum/relations_try.rb +146 -0
  83. data/try/{28_redis_horreum_serialization_try.rb → horreum/serialization_try.rb} +13 -11
  84. data/try/horreum/settings_try.rb +43 -0
  85. data/try/integration/cross_component_try.rb +46 -0
  86. data/try/{41_customer_safedump_try.rb → models/customer_safe_dump_try.rb} +9 -7
  87. data/try/{40_customer_try.rb → models/customer_try.rb} +20 -17
  88. data/try/models/datatype_base_try.rb +101 -0
  89. data/try/{30_familia_object_try.rb → models/familia_object_try.rb} +18 -16
  90. data/try/performance/benchmarks_try.rb +55 -0
  91. data/try/pooling/README.md +20 -0
  92. data/try/pooling/configurable_stress_test_try.rb +435 -0
  93. data/try/pooling/connection_pool_test_try.rb +273 -0
  94. data/try/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +192 -0
  95. data/try/pooling/lib/connection_pool_metrics.rb +372 -0
  96. data/try/pooling/lib/connection_pool_stress_test.rb +959 -0
  97. data/try/pooling/lib/connection_pool_threading_models.rb +421 -0
  98. data/try/pooling/lib/visualize_stress_results.rb +434 -0
  99. data/try/pooling/pool_siege_try.rb +509 -0
  100. data/try/pooling/run_stress_tests_try.rb +482 -0
  101. data/try/prototypes/atomic_saves_v1_context_proxy.rb +121 -0
  102. data/try/prototypes/atomic_saves_v2_connection_switching.rb +161 -0
  103. data/try/prototypes/atomic_saves_v3_connection_pool.rb +189 -0
  104. data/try/prototypes/atomic_saves_v4.rb +105 -0
  105. data/try/prototypes/lib/atomic_saves_v2_connection_switching_helpers.rb +124 -0
  106. data/try/prototypes/lib/atomic_saves_v3_connection_pool_helpers.rb +192 -0
  107. metadata +124 -38
  108. data/.github/workflows/ruby.yml +0 -71
  109. data/VERSION.yml +0 -4
  110. data/lib/familia/redistype/commands.rb +0 -59
  111. data/lib/familia/redistype.rb +0 -228
  112. data/lib/familia/tools.rb +0 -68
  113. data/lib/redis_middleware.rb +0 -109
  114. data/try/20_redis_type_try.rb +0 -70
  115. data/try/91_json_bug_try.rb +0 -86
@@ -1,62 +1,61 @@
1
- # frozen_string_literal: true
1
+ # lib/familia/horreum/class_methods.rb
2
2
 
3
- require_relative 'relations_management'
3
+ require_relative 'related_fields_management'
4
4
 
5
5
  module Familia
6
6
  class Horreum
7
7
  # Class-level instance variables
8
8
  # These are set up as nil initially and populated later
9
- @redis = nil
10
- @identifier = nil
11
- @ttl = nil
12
- @db = nil
9
+ @dbclient = nil # TODO
10
+ @identifier_field = nil
11
+ @default_expiration = nil
12
+ @logical_database = nil
13
13
  @uri = nil
14
14
  @suffix = nil
15
15
  @prefix = nil
16
16
  @fields = nil # []
17
- @class_redis_types = nil # {}
18
- @redis_types = nil # {}
17
+ @class_related_fields = nil # {}
18
+ @related_fields = nil # {}
19
19
  @dump_method = nil
20
20
  @load_method = nil
21
21
 
22
22
  # ClassMethods: Provides class-level functionality for Horreum
23
23
  #
24
24
  # This module is extended into classes that include Familia::Horreum,
25
- # providing methods for Redis operations and object management.
25
+ # providing methods for Database operations and object management.
26
26
  #
27
27
  # Key features:
28
- # * Includes RelationsManagement for Redis-type field handling
29
- # * Defines methods for managing fields, identifiers, and Redis keys
30
- # * Provides utility methods for working with Redis objects
28
+ # * Includes RelatedFieldsManagement for DataType field handling
29
+ # * Defines methods for managing fields, identifiers, and dbkeys
30
+ # * Provides utility methods for working with Database objects
31
31
  #
32
32
  module ClassMethods
33
33
  include Familia::Settings
34
- include Familia::Horreum::RelationsManagement
35
-
36
- # Returns the Redis connection for the class.
37
- #
38
- # This method retrieves the Redis connection instance for the class. If no
39
- # connection is set, it initializes a new connection using the provided URI
40
- # or database configuration.
41
- #
42
- # @return [Redis] the Redis connection instance.
43
- #
44
- def redis
45
- @redis || Familia.redis(uri || db)
46
- end
47
-
48
- # Sets or retrieves the unique identifier for the class.
49
- #
50
- # This method defines or returns the unique identifier used to generate the
51
- # Redis key for the object. If a value is provided, it sets the identifier;
52
- # otherwise, it returns the current identifier.
53
- #
54
- # @param [Object] val the value to set as the identifier (optional).
55
- # @return [Object] the current identifier.
56
- #
57
- def identifier(val = nil)
58
- @identifier = val if val
59
- @identifier
34
+ include Familia::Horreum::RelatedFieldsManagement
35
+
36
+ # Sets or retrieves the unique identifier field for the class.
37
+ #
38
+ # This method defines or returns the field or method that contains the unique
39
+ # identifier used to generate the dbkey for the object. If a value is provided,
40
+ # it sets the identifier field; otherwise, it returns the current identifier field.
41
+ #
42
+ # @param [Object] val the field name or method to set as the identifier field (optional).
43
+ # @return [Object] the current identifier field.
44
+ #
45
+ def identifier_field(val = nil)
46
+ if val
47
+ # Validate identifier field definition at class definition time
48
+ case val
49
+ when Symbol, String, Proc
50
+ @identifier_field = val
51
+ else
52
+ raise Problem, <<~ERROR
53
+ Invalid identifier field definition: #{val.inspect}.
54
+ Use a field name (Symbol/String) or Proc.
55
+ ERROR
56
+ end
57
+ end
58
+ @identifier_field
60
59
  end
61
60
 
62
61
  # Defines a field for the class and creates accessor methods.
@@ -84,12 +83,12 @@ module Familia
84
83
  # The dynamically defined method performs the following:
85
84
  # - Acts as both a reader and a writer method.
86
85
  # - When called without arguments, retrieves the current value from Redis.
87
- # - When called with an argument, persists the value to Redis immediately.
86
+ # - When called with an argument, persists the value to Database immediately.
88
87
  # - Checks if the correct number of arguments is provided (zero or one).
89
- # - Converts the provided value to a format suitable for Redis storage.
88
+ # - Converts the provided value to a format suitable for Database storage.
90
89
  # - Uses the existing accessor method to set the attribute value when
91
90
  # writing.
92
- # - Persists the value to Redis immediately using the hset command when
91
+ # - Persists the value to Database immediately using the hset command when
93
92
  # writing.
94
93
  # - Includes custom error handling to raise an ArgumentError if the wrong
95
94
  # number of arguments is given.
@@ -138,34 +137,28 @@ module Familia
138
137
  # # Method implementation
139
138
  # end
140
139
  #
141
- if method_defined?(:"#{name}!")
142
- warn "Method #{name}! is already defined for #{self}"
143
- return
144
- end
145
-
146
140
  define_method :"#{name}!" do |*args|
147
-
148
141
  # Check if the correct number of arguments is provided (exactly one).
149
142
  raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0 or 1)" if args.size > 1
150
143
 
151
144
  val = args.first
152
145
 
153
146
  # If no value is provided to this fast attribute method, make a call
154
- # to redis to return the current stored value of the hash field.
147
+ # to the db to return the current stored value of the hash field.
155
148
  return hget name if val.nil?
156
149
 
157
150
  begin
158
151
  # Trace the operation if debugging is enabled.
159
- Familia.trace :FAST_WRITER, redis, "#{name}: #{val.inspect}", caller(1..1) if Familia.debug?
152
+ Familia.trace :FAST_WRITER, dbclient, "#{name}: #{val.inspect}", caller(1..1) if Familia.debug?
160
153
 
161
- # Convert the provided value to a format suitable for Redis storage.
154
+ # Convert the provided value to a format suitable for Database storage.
162
155
  prepared = serialize_value(val)
163
156
  Familia.ld "[.fast_attribute!] #{name} val: #{val.class} prepared: #{prepared.class}"
164
157
 
165
158
  # Use the existing accessor method to set the attribute value.
166
159
  send :"#{name}=", val
167
160
 
168
- # Persist the value to Redis immediately using the hset command.
161
+ # Persist the value to Database immediately using the hset command.
169
162
  hset name, prepared
170
163
  rescue Familia::Problem => e
171
164
  # Raise a custom error message if an exception occurs during the execution of the method.
@@ -181,36 +174,24 @@ module Familia
181
174
  @fields
182
175
  end
183
176
 
184
- def class_redis_types
185
- @class_redis_types ||= {}
186
- @class_redis_types
187
- end
188
-
189
- def class_redis_types?(name)
190
- class_redis_types.key? name.to_s.to_sym
177
+ def class_related_fields
178
+ @class_related_fields ||= {}
179
+ @class_related_fields
191
180
  end
192
181
 
193
- def redis_object?(name)
194
- redis_types.key? name.to_s.to_sym
195
- end
196
-
197
- def redis_types
198
- @redis_types ||= {}
199
- @redis_types
182
+ def related_fields
183
+ @related_fields ||= {}
184
+ @related_fields
200
185
  end
201
186
 
202
187
  def has_relations?
203
188
  @has_relations ||= false
204
189
  end
205
190
 
206
- def db(v = nil)
207
- @db = v unless v.nil?
208
- @db || parent&.db
209
- end
210
-
211
- def uri(v = nil)
212
- @uri = v unless v.nil?
213
- @uri || parent&.uri
191
+ def logical_database(v = nil)
192
+ Familia.trace :DB, Familia.dbclient, "#{@logical_database} #{v}", caller(1..1) if Familia.debug?
193
+ @logical_database = v unless v.nil?
194
+ @logical_database || parent&.logical_database
214
195
  end
215
196
 
216
197
  def all(suffix = nil)
@@ -223,11 +204,11 @@ module Familia
223
204
  matching_keys_count(filter) > 0
224
205
  end
225
206
 
226
- # Returns the number of Redis keys matching the given filter pattern
227
- # @param filter [String] Redis key pattern to match (default: '*')
207
+ # Returns the number of dbkeys matching the given filter pattern
208
+ # @param filter [String] dbkey pattern to match (default: '*')
228
209
  # @return [Integer] Number of matching keys
229
210
  def matching_keys_count(filter = '*')
230
- redis.keys(rediskey(filter)).compact.size
211
+ dbclient.keys(dbkey(filter)).compact.size
231
212
  end
232
213
  alias size matching_keys_count # For backwards compatibility
233
214
 
@@ -241,20 +222,6 @@ module Familia
241
222
  @prefix || name.downcase.gsub('::', Familia.delim).to_sym
242
223
  end
243
224
 
244
- # Converts the class name into a string that can be used to look up
245
- # configuration values. This is particularly useful when mapping
246
- # familia models with specific database numbers in the configuration.
247
- #
248
- # @example V2::Session.config_name => 'session'
249
- #
250
- # @return [String] The underscored class name as a string
251
- def config_name
252
- name.split('::').last
253
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
254
- .gsub(/([a-z\d])([A-Z])/, '\1_\2')
255
- .downcase
256
- end
257
-
258
225
  # Creates and persists a new instance of the class.
259
226
  #
260
227
  # @param *args [Array] Variable number of positional arguments to be passed
@@ -293,7 +260,7 @@ module Familia
293
260
  #
294
261
  def create *args, **kwargs
295
262
  fobj = new(*args, **kwargs)
296
- raise Familia::Problem, "#{self} already exists: #{fobj.rediskey}" if fobj.exists?
263
+ raise Familia::Problem, "#{self} already exists: #{fobj.dbkey}" if fobj.exists?
297
264
 
298
265
  fobj.save
299
266
  fobj
@@ -305,17 +272,17 @@ module Familia
305
272
  end
306
273
 
307
274
  def rawmultiget(*ids)
308
- ids.collect! { |objid| rediskey(objid) }
275
+ ids.collect! { |objid| dbkey(objid) }
309
276
  return [] if ids.compact.empty?
310
277
 
311
- Familia.trace :MULTIGET, redis, "#{ids.size}: #{ids}", caller(1..1) if Familia.debug?
312
- redis.mget(*ids)
278
+ Familia.trace :MULTIGET, dbclient, "#{ids.size}: #{ids}", caller(1..1) if Familia.debug?
279
+ dbclient.mget(*ids)
313
280
  end
314
281
 
315
- # Retrieves and instantiates an object from Redis using the full object
282
+ # Retrieves and instantiates an object from Database using the full object
316
283
  # key.
317
284
  #
318
- # @param objkey [String] The full Redis key for the object.
285
+ # @param objkey [String] The full dbkey for the object.
319
286
  # @return [Object, nil] An instance of the class if the key exists, nil
320
287
  # otherwise.
321
288
  # @raise [ArgumentError] If the provided key is empty.
@@ -345,10 +312,10 @@ module Familia
345
312
 
346
313
  # We use a lower-level method here b/c we're working with the
347
314
  # full key and not just the identifier.
348
- does_exist = redis.exists(objkey).positive?
315
+ does_exist = dbclient.exists(objkey).positive?
349
316
 
350
317
  Familia.ld "[.find_by_key] #{self} from key #{objkey} (exists: #{does_exist})"
351
- Familia.trace :FROM_KEY, redis, objkey, caller(1..1) if Familia.debug?
318
+ Familia.trace :FROM_KEY, dbclient, objkey, caller(1..1) if Familia.debug?
352
319
 
353
320
  # This is the reason for calling exists first. We want to definitively
354
321
  # and without any ambiguity know if the object exists in Redis. If it
@@ -357,22 +324,22 @@ module Familia
357
324
  # the constructor, which will then be annoying to debug.
358
325
  return unless does_exist
359
326
 
360
- obj = redis.hgetall(objkey) # horreum objects are persisted as redis hashes
361
- Familia.trace :FROM_KEY2, redis, "#{objkey}: #{obj.inspect}", caller(1..1) if Familia.debug?
327
+ obj = dbclient.hgetall(objkey) # horreum objects are persisted as database hashes
328
+ Familia.trace :FROM_KEY2, dbclient, "#{objkey}: #{obj.inspect}", caller(1..1) if Familia.debug?
362
329
 
363
330
  new(**obj)
364
331
  end
365
- alias from_rediskey find_by_key # deprecated
332
+ alias from_dbkey find_by_key # deprecated
366
333
 
367
- # Retrieves and instantiates an object from Redis using its identifier.
334
+ # Retrieves and instantiates an object from Database using its identifier.
368
335
  #
369
336
  # @param identifier [String, Integer] The unique identifier for the
370
337
  # object.
371
- # @param suffix [Symbol] The suffix to use in the Redis key (default:
338
+ # @param suffix [Symbol] The suffix to use in the dbkey (default:
372
339
  # :object).
373
340
  # @return [Object, nil] An instance of the class if found, nil otherwise.
374
341
  #
375
- # This method constructs the full Redis key using the provided identifier
342
+ # This method constructs the full dbkey using the provided identifier
376
343
  # and suffix, then delegates to `find_by_key` for the actual retrieval and
377
344
  # instantiation.
378
345
  #
@@ -387,10 +354,10 @@ module Familia
387
354
  suffix ||= self.suffix
388
355
  return nil if identifier.to_s.empty?
389
356
 
390
- objkey = rediskey(identifier, suffix)
357
+ objkey = dbkey(identifier, suffix)
391
358
 
392
359
  Familia.ld "[.find_by_id] #{self} from key #{objkey})"
393
- Familia.trace :FIND_BY_ID, Familia.redis(uri), objkey, caller(1..1).first if Familia.debug?
360
+ Familia.trace :FIND_BY_ID, Familia.dbclient(uri), objkey, caller(1..1).first if Familia.debug?
394
361
  find_by_key objkey
395
362
  end
396
363
  alias find find_by_id
@@ -400,10 +367,10 @@ module Familia
400
367
  # Checks if an object with the given identifier exists in Redis.
401
368
  #
402
369
  # @param identifier [String, Integer] The unique identifier for the object.
403
- # @param suffix [Symbol, nil] The suffix to use in the Redis key (default: class suffix).
370
+ # @param suffix [Symbol, nil] The suffix to use in the dbkey (default: class suffix).
404
371
  # @return [Boolean] true if the object exists, false otherwise.
405
372
  #
406
- # This method constructs the full Redis key using the provided identifier and suffix,
373
+ # This method constructs the full dbkey using the provided identifier and suffix,
407
374
  # then checks if the key exists in Redis.
408
375
  #
409
376
  # @example
@@ -413,24 +380,24 @@ module Familia
413
380
  suffix ||= self.suffix
414
381
  return false if identifier.to_s.empty?
415
382
 
416
- objkey = rediskey identifier, suffix
383
+ objkey = dbkey identifier, suffix
417
384
 
418
- ret = redis.exists objkey
419
- Familia.trace :EXISTS, redis, "#{objkey} #{ret.inspect}", caller(1..1) if Familia.debug?
385
+ ret = dbclient.exists objkey
386
+ Familia.trace :EXISTS, dbclient, "#{objkey} #{ret.inspect}", caller(1..1) if Familia.debug?
420
387
 
421
- ret.positive? # differs from redis API but I think it's okay bc `exists?` is a predicate method.
388
+ ret.positive? # differs from Valkey API but I think it's okay bc `exists?` is a predicate method.
422
389
  end
423
390
 
424
- # Destroys an object in Redis with the given identifier.
391
+ # Destroys an object in Database with the given identifier.
425
392
  #
426
393
  # @param identifier [String, Integer] The unique identifier for the object to destroy.
427
- # @param suffix [Symbol, nil] The suffix to use in the Redis key (default: class suffix).
394
+ # @param suffix [Symbol, nil] The suffix to use in the dbkey (default: class suffix).
428
395
  # @return [Boolean] true if the object was successfully destroyed, false otherwise.
429
396
  #
430
397
  # This method is part of Familia's high-level object lifecycle management. While `delete!`
431
- # operates directly on Redis keys, `destroy!` operates at the object level and is used for
398
+ # operates directly on dbkeys, `destroy!` operates at the object level and is used for
432
399
  # ORM-style operations. Use `destroy!` when removing complete objects from the system, and
433
- # `delete!` when working directly with Redis keys.
400
+ # `delete!` when working directly with dbkeys.
434
401
  #
435
402
  # @example
436
403
  # User.destroy!(123) # Removes user:123:object from Redis
@@ -439,27 +406,27 @@ module Familia
439
406
  suffix ||= self.suffix
440
407
  return false if identifier.to_s.empty?
441
408
 
442
- objkey = rediskey identifier, suffix
409
+ objkey = dbkey identifier, suffix
443
410
 
444
- ret = redis.del objkey
445
- Familia.trace :DESTROY!, redis, "#{objkey} #{ret.inspect}", caller(1..1) if Familia.debug?
411
+ ret = dbclient.del objkey
412
+ Familia.trace :DESTROY!, dbclient, "#{objkey} #{ret.inspect}", caller(1..1) if Familia.debug?
446
413
  ret.positive?
447
414
  end
448
415
 
449
- # Finds all keys in Redis matching the given suffix pattern.
416
+ # Finds all keys in Database matching the given suffix pattern.
450
417
  #
451
418
  # @param suffix [String] The suffix pattern to match (default: '*').
452
- # @return [Array<String>] An array of matching Redis keys.
419
+ # @return [Array<String>] An array of matching dbkeys.
453
420
  #
454
- # This method searches for all Redis keys that match the given suffix pattern.
455
- # It uses the class's rediskey method to construct the search pattern.
421
+ # This method searches for all dbkeys that match the given suffix pattern.
422
+ # It uses the class's dbkey method to construct the search pattern.
456
423
  #
457
424
  # @example
458
425
  # User.find # Returns all keys matching user:*:object
459
426
  # User.find('active') # Returns all keys matching user:*:active
460
427
  #
461
428
  def find_keys(suffix = '*')
462
- redis.keys(rediskey('*', suffix)) || []
429
+ dbclient.keys(dbkey('*', suffix)) || []
463
430
  end
464
431
 
465
432
  # +identifier+ can be a value or an Array of values used to create the index.
@@ -469,15 +436,15 @@ module Familia
469
436
  # +suffix+ If a nil value is explicitly passed in, it won't appear in the redis
470
437
  # key that's returned. If no suffix is passed in, the class' suffix is used
471
438
  # as the default (via the class method self.suffix). It's an important
472
- # distinction b/c passing in an explicitly nil is how RedisType objects
439
+ # distinction b/c passing in an explicitly nil is how DataType objects
473
440
  # at the class level are created without the global default 'object'
474
- # suffix. See RedisType#rediskey "parent_class?" for more details.
475
- def rediskey(identifier, suffix = self.suffix)
476
- # Familia.ld "[.rediskey] #{identifier} for #{self} (suffix:#{suffix})"
441
+ # suffix. See DataType#dbkey "parent_class?" for more details.
442
+ def dbkey(identifier, suffix = self.suffix)
443
+ # Familia.ld "[.dbkey] #{identifier} for #{self} (suffix:#{suffix})"
477
444
  raise NoIdentifier, self if identifier.to_s.empty?
478
445
 
479
446
  identifier &&= identifier.to_s
480
- Familia.rediskey(prefix, identifier, suffix)
447
+ Familia.dbkey(prefix, identifier, suffix)
481
448
  end
482
449
 
483
450
  def dump_method
@@ -488,6 +455,6 @@ module Familia
488
455
  @load_method || :from_json # Familia.load_method
489
456
  end
490
457
  end
491
- # End of ClassMethods module
458
+
492
459
  end
493
460
  end
@@ -1,25 +1,25 @@
1
- # rubocop:disable all
2
- #
1
+ # lib/familia/horreum/commands.rb
2
+
3
3
  module Familia
4
4
  # InstanceMethods - Module containing instance-level methods for Familia
5
5
  #
6
6
  # This module is included in classes that include Familia, providing
7
- # instance-level functionality for Redis operations and object management.
7
+ # instance-level functionality for Database operations and object management.
8
8
  #
9
9
  class Horreum
10
10
 
11
- # Methods that call Redis commands (InstanceMethods)
11
+ # Methods that call Database commands (InstanceMethods)
12
12
  #
13
13
  # NOTE: There is no hgetall for Horreum. This is because Horreum
14
- # is a single hash in Redis that we aren't meant to have be working
14
+ # is a single hash in Database that we aren't meant to have be working
15
15
  # on in memory for more than, making changes -> committing. To
16
16
  # emphasize this, instead of "refreshing" the object with hgetall,
17
17
  # just load the object again.
18
18
  #
19
19
  module Commands
20
20
 
21
- def move(db)
22
- redis.move rediskey, db
21
+ def move(logical_database)
22
+ dbclient.move dbkey, logical_database
23
23
  end
24
24
 
25
25
  # Checks if the calling object's key exists in Redis.
@@ -39,7 +39,7 @@ module Familia
39
39
  # @note The default behavior maintains backward compatibility by treating empty hashes
40
40
  # as non-existent. Use `check_size: false` for pure key existence checking.
41
41
  def exists?(check_size: true)
42
- key_exists = self.class.redis.exists?(rediskey)
42
+ key_exists = self.class.dbclient.exists?(dbkey)
43
43
  return key_exists unless check_size
44
44
  key_exists && !size.zero?
45
45
  end
@@ -47,7 +47,7 @@ module Familia
47
47
  # Returns the number of fields in the main object hash
48
48
  # @return [Integer] number of fields
49
49
  def field_count
50
- redis.hlen rediskey
50
+ dbclient.hlen dbkey
51
51
  end
52
52
  alias size field_count
53
53
 
@@ -55,44 +55,39 @@ module Familia
55
55
  # automatically be deleted. Returns 1 if the timeout was set, 0 if key
56
56
  # does not exist or the timeout could not be set.
57
57
  #
58
- def expire(ttl = nil)
59
- ttl ||= self.class.ttl
60
- Familia.trace :EXPIRE, redis, ttl, caller(1..1) if Familia.debug?
61
- redis.expire rediskey, ttl.to_i
58
+ def expire(default_expiration = nil)
59
+ default_expiration ||= self.class.default_expiration
60
+ Familia.trace :EXPIRE, dbclient, default_expiration, caller(1..1) if Familia.debug?
61
+ dbclient.expire dbkey, default_expiration.to_i
62
62
  end
63
63
 
64
- # Retrieves the remaining time to live (TTL) for the object's Redis key.
64
+ # Retrieves the remaining time to live (TTL) for the object's dbkey.
65
65
  #
66
- # This method accesses the ovjects Redis client to obtain the TTL of `rediskey`.
66
+ # This method accesses the ovjects Database client to obtain the TTL of `dbkey`.
67
67
  # If debugging is enabled, it logs the TTL retrieval operation using `Familia.trace`.
68
68
  #
69
69
  # @return [Integer] The TTL of the key in seconds. Returns -1 if the key does not exist
70
70
  # or has no associated expire time.
71
- def realttl
72
- Familia.trace :REALTTL, redis, redisuri, caller(1..1) if Familia.debug?
73
- redis.ttl rediskey
71
+ def current_expiration
72
+ Familia.trace :CURRENT_EXPIRATION, dbclient, uri, caller(1..1) if Familia.debug?
73
+ dbclient.ttl dbkey
74
74
  end
75
75
 
76
- # Removes a field from the hash stored at the Redis key.
76
+ # Removes a field from the hash stored at the dbkey.
77
77
  #
78
78
  # @param field [String] The field to remove from the hash.
79
79
  # @return [Integer] The number of fields that were removed from the hash (0 or 1).
80
80
  def remove_field(field)
81
- Familia.trace :HDEL, redis, field, caller(1..1) if Familia.debug?
82
- redis.hdel rediskey, field
81
+ Familia.trace :HDEL, dbclient, field, caller(1..1) if Familia.debug?
82
+ dbclient.hdel dbkey, field
83
83
  end
84
84
  alias remove remove_field # deprecated
85
85
 
86
- def redistype
87
- Familia.trace :REDISTYPE, redis, redisuri, caller(1..1) if Familia.debug?
88
- redis.type rediskey(suffix)
86
+ def datatype
87
+ Familia.trace :DATATYPE, dbclient, uri, caller(1..1) if Familia.debug?
88
+ dbclient.type dbkey(suffix)
89
89
  end
90
90
 
91
- # Parity with RedisType#rename
92
- def rename(newkey)
93
- Familia.trace :RENAME, redis, "#{rediskey} -> #{newkey}", caller(1..1) if Familia.debug?
94
- redis.rename rediskey, newkey
95
- end
96
91
 
97
92
  # Retrieves the prefix for the current instance by delegating to its class.
98
93
  #
@@ -103,80 +98,80 @@ module Familia
103
98
  self.class.prefix
104
99
  end
105
100
 
106
- # For parity with RedisType#hgetall
101
+ # For parity with DataType#hgetall
107
102
  def hgetall
108
- Familia.trace :HGETALL, redis, redisuri, caller(1..1) if Familia.debug?
109
- redis.hgetall rediskey(suffix)
103
+ Familia.trace :HGETALL, dbclient, uri, caller(1..1) if Familia.debug?
104
+ dbclient.hgetall dbkey(suffix)
110
105
  end
111
106
  alias all hgetall
112
107
 
113
108
  def hget(field)
114
- Familia.trace :HGET, redis, field, caller(1..1) if Familia.debug?
115
- redis.hget rediskey(suffix), field
109
+ Familia.trace :HGET, dbclient, field, caller(1..1) if Familia.debug?
110
+ dbclient.hget dbkey(suffix), field
116
111
  end
117
112
 
118
113
  # @return The number of fields that were added to the hash. If the
119
114
  # field already exists, this will return 0.
120
115
  def hset(field, value)
121
- Familia.trace :HSET, redis, field, caller(1..1) if Familia.debug?
122
- redis.hset rediskey, field, value
116
+ Familia.trace :HSET, dbclient, field, caller(1..1) if Familia.debug?
117
+ dbclient.hset dbkey, field, value
123
118
  end
124
119
 
125
120
  def hmset(hsh={})
126
121
  hsh ||= self.to_h
127
- Familia.trace :HMSET, redis, hsh, caller(1..1) if Familia.debug?
128
- redis.hmset rediskey(suffix), hsh
122
+ Familia.trace :HMSET, dbclient, hsh, caller(1..1) if Familia.debug?
123
+ dbclient.hmset dbkey(suffix), hsh
129
124
  end
130
125
 
131
126
  def hkeys
132
- Familia.trace :HKEYS, redis, 'redisuri', caller(1..1) if Familia.debug?
133
- redis.hkeys rediskey(suffix)
127
+ Familia.trace :HKEYS, dbclient, 'uri', caller(1..1) if Familia.debug?
128
+ dbclient.hkeys dbkey(suffix)
134
129
  end
135
130
 
136
131
  def hvals
137
- redis.hvals rediskey(suffix)
132
+ dbclient.hvals dbkey(suffix)
138
133
  end
139
134
 
140
135
  def incr(field)
141
- redis.hincrby rediskey(suffix), field, 1
136
+ dbclient.hincrby dbkey(suffix), field, 1
142
137
  end
143
138
  alias increment incr
144
139
 
145
140
  def incrby(field, increment)
146
- redis.hincrby rediskey(suffix), field, increment
141
+ dbclient.hincrby dbkey(suffix), field, increment
147
142
  end
148
143
  alias incrementby incrby
149
144
 
150
145
  def incrbyfloat(field, increment)
151
- redis.hincrbyfloat rediskey(suffix), field, increment
146
+ dbclient.hincrbyfloat dbkey(suffix), field, increment
152
147
  end
153
148
  alias incrementbyfloat incrbyfloat
154
149
 
155
150
  def decrby(field, decrement)
156
- redis.decrby rediskey(suffix), field, decrement
151
+ dbclient.decrby dbkey(suffix), field, decrement
157
152
  end
158
153
  alias decrementby decrby
159
154
 
160
155
  def decr(field)
161
- redis.hdecr field
156
+ dbclient.hdecr field
162
157
  end
163
158
  alias decrement decr
164
159
 
165
160
  def hstrlen(field)
166
- redis.hstrlen rediskey(suffix), field
161
+ dbclient.hstrlen dbkey(suffix), field
167
162
  end
168
163
  alias hstrlength hstrlen
169
164
 
170
165
  def key?(field)
171
- redis.hexists rediskey(suffix), field
166
+ dbclient.hexists dbkey(suffix), field
172
167
  end
173
168
  alias has_key? key?
174
169
 
175
- # Deletes the entire Redis key
170
+ # Deletes the entire dbkey
176
171
  # @return [Boolean] true if the key was deleted, false otherwise
177
172
  def delete!
178
- Familia.trace :DELETE!, redis, redisuri, caller(1..1) if Familia.debug?
179
- ret = redis.del rediskey
173
+ Familia.trace :DELETE!, dbclient, uri, caller(1..1) if Familia.debug?
174
+ ret = dbclient.del dbkey
180
175
  ret.positive?
181
176
  end
182
177
  alias clear delete!