familia 1.2.0 → 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 +4 -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 +76 -34
  12. data/README.md +39 -23
  13. data/bin/irb +3 -0
  14. data/docs/connection_pooling.md +317 -0
  15. data/familia.gemspec +9 -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 -110
  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 -7
  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} +60 -59
  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 +140 -43
  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
data/lib/familia/base.rb CHANGED
@@ -1,8 +1,8 @@
1
- # frozen_string_literal: true
1
+ # lib/familia/base.rb
2
2
 
3
3
  #
4
4
  module Familia
5
- # A common module for Familia::RedisType and Familia::Horreum to include.
5
+ # A common module for Familia::DataType and Familia::Horreum to include.
6
6
  #
7
7
  # This allows us to use a single comparison to check if a class is a
8
8
  # Familia class. e.g.
@@ -11,13 +11,23 @@ module Familia
11
11
  # klass.ancestors.member?(Familia::Base) # => true
12
12
  #
13
13
  # @see Familia::Horreum
14
- # @see Familia::RedisType
14
+ # @see Familia::DataType
15
15
  #
16
16
  module Base
17
17
  @features = nil
18
18
  @dump_method = :to_json
19
19
  @load_method = :from_json
20
20
 
21
+ # Returns a string representation of the object. Implementing classes
22
+ # are welcome to override this method to provide a more meaningful
23
+ # representation. Using this as a default via super is recommended.
24
+ #
25
+ # @return [String] A string representation of the object. Never nil.
26
+ #
27
+ def to_s
28
+ "#<#{self.class}:0x#{object_id.to_s(16)}>"
29
+ end
30
+
21
31
  class << self
22
32
  attr_reader :features
23
33
  attr_accessor :dump_method, :load_method
@@ -34,23 +44,23 @@ module Familia
34
44
  # with the :expiration feature's implementation.
35
45
  #
36
46
  # This is a no-op implementation that gets overridden by features like
37
- # :expiration. It accepts an optional ttl parameter to maintain interface
47
+ # :expiration. It accepts an optional default_expiration parameter to maintain interface
38
48
  # compatibility with the overriding implementations.
39
49
  #
40
- # @param ttl [Integer, nil] Time To Live in seconds (ignored in base implementation)
50
+ # @param default_expiration [Integer, nil] Time To Live in seconds (ignored in base implementation)
41
51
  # @return [nil] Always returns nil
42
52
  #
43
53
  # @note This is a no-op implementation. Classes that need expiration
44
54
  # functionality should include the :expiration feature.
45
55
  #
46
- def update_expiration(ttl: nil)
47
- Familia.ld "[update_expiration] Feature not enabled for #{self.class}. Key: #{rediskey} (caller: #{caller(1..1)})"
56
+ def update_expiration(default_expiration: nil)
57
+ Familia.ld "[update_expiration] Feature not enabled for #{self.class}. Key: #{dbkey} (caller: #{caller(1..1)})"
48
58
  nil
49
59
  end
50
60
 
51
61
  def generate_id
52
- @key ||= Familia.generate_id
53
- @key
62
+ @identifier ||= Familia.generate_id
63
+ @identifier
54
64
  end
55
65
 
56
66
  def uuid
@@ -1,103 +1,270 @@
1
- # frozen_string_literal: true
1
+ # lib/familia/connection.rb
2
2
 
3
- require_relative '../../lib/redis_middleware'
3
+ require_relative '../../lib/middleware/database_middleware'
4
+ require_relative 'multi_result'
4
5
 
6
+ # Familia
7
+ #
8
+ # A family warehouse for your keystore data.
5
9
  #
6
10
  module Familia
7
- @uri = URI.parse 'redis://127.0.0.1'
8
- @redis_clients = {}
9
- @redis_uri_by_class = {}
11
+ @uri = URI.parse 'redis://127.0.0.1:6379'
12
+ @database_clients = {}
10
13
 
11
- # The Connection module provides Redis connection management for Familia.
12
- # It allows easy setup and access to Redis clients across different URIs.
14
+ # The Connection module provides Database connection management for Familia.
15
+ # It allows easy setup and access to Database clients across different URIs
16
+ # with robust connection pooling for thread safety.
13
17
  module Connection
14
- # @return [Hash] A hash of Redis clients, keyed by server ID
15
- attr_reader :redis_clients
16
-
17
- # @return [URI] The default URI for Redis connections
18
+ # @return [URI] The default URI for Database connections
18
19
  attr_reader :uri
19
20
 
20
- # @return [Boolean] Whether Redis command logging is enabled
21
- attr_accessor :enable_redis_logging
21
+ # @return [Hash] A hash of Database clients, keyed by server ID
22
+ attr_reader :database_clients
23
+
24
+ # @return [Boolean] Whether Database command logging is enabled
25
+ attr_accessor :enable_database_logging
26
+
27
+ # @return [Boolean] Whether Database command counter is enabled
28
+ attr_accessor :enable_database_counter
22
29
 
23
- # @return [Boolean] Whether Redis command counter is enabled
24
- attr_accessor :enable_redis_counter
30
+ # @return [Proc] A callable that provides Database connections
31
+ attr_accessor :connection_provider
32
+
33
+ # @return [Boolean] Whether to require external connections (no fallback)
34
+ attr_accessor :connection_required
35
+
36
+ # Sets the default URI for Database connections.
37
+ #
38
+ # NOTE: uri is not a property of the Settings module b/c it's not
39
+ # configured in class defintions like default_expiration or logical DB index.
40
+ #
41
+ # @param v [String, URI] The new default URI
42
+ # @example
43
+ # Familia.uri = 'redis://localhost:6379'
44
+ def uri=(uri)
45
+ @uri = normalize_uri(uri)
46
+ end
47
+ alias url uri
48
+ alias url= uri=
25
49
 
26
- # Establishes a connection to a Redis server.
50
+ # Establishes a connection to a Database server.
27
51
  #
28
- # @param uri [String, URI, nil] The URI of the Redis server to connect to.
29
- # If nil, uses the default URI from `@redis_uri_by_class` or `Familia.uri`.
30
- # @return [Redis] The connected Redis client.
52
+ # @param uri [String, URI, nil] The URI of the Database server to connect to.
53
+ # If nil, uses the default URI from `@database_clients` or `Familia.uri`.
54
+ # @return [Redis] The connected Database client.
31
55
  # @raise [ArgumentError] If no URI is specified.
32
56
  # @example
33
57
  # Familia.connect('redis://localhost:6379')
34
58
  def connect(uri = nil)
35
- uri = URI.parse(uri) if uri.is_a?(String)
36
- uri ||= @redis_uri_by_class[self]
37
- uri ||= Familia.uri
38
-
39
- raise ArgumentError, 'No URI specified' unless uri
59
+ parsed_uri = normalize_uri(uri)
60
+ serverid = parsed_uri.serverid
40
61
 
41
- conf = uri.conf
42
- @redis_uri_by_class[self] = uri.serverid
62
+ if Familia.enable_database_logging
63
+ DatabaseLogger.logger = Familia.logger
64
+ RedisClient.register(DatabaseLogger)
65
+ end
43
66
 
44
- if Familia.enable_redis_logging
45
- RedisLogger.logger = Familia.logger
46
- RedisClient.register(RedisLogger)
67
+ if Familia.enable_database_counter
68
+ # NOTE: This middleware uses AtommicFixnum from concurrent-ruby which is
69
+ # less contentious than Mutex-based counters. Safe for
70
+ RedisClient.register(DatabaseCommandCounter)
47
71
  end
48
72
 
49
- if Familia.enable_redis_counter
50
- # NOTE: This middleware stays thread-safe with a mutex so it will
51
- # be a bottleneck when enabled in multi-threaded environments.
52
- RedisClient.register(RedisCommandCounter)
73
+ dbclient = Redis.new(parsed_uri.conf)
74
+
75
+ if @database_clients.key?(serverid)
76
+ msg = "Overriding existing connection for #{serverid}"
77
+ Familia.warn(msg)
53
78
  end
54
79
 
55
- redis = Redis.new(conf)
80
+ @database_clients[serverid] = dbclient
81
+ end
82
+
83
+ def reconnect(uri = nil)
84
+ parsed_uri = normalize_uri(uri)
85
+ serverid = parsed_uri.serverid
56
86
 
57
87
  # Close the existing connection if it exists
58
- @redis_clients[uri.serverid].close if @redis_clients[uri.serverid]
59
- @redis_clients[uri.serverid] = redis
88
+ @database_clients[serverid].close if @database_clients.key?(serverid)
89
+
90
+ connect(parsed_uri)
60
91
  end
61
92
 
62
- # Retrieves or creates a Redis client for the given URI.
93
+ # Retrieves a Database connection from the appropriate pool.
94
+ # Handles DB selection automatically based on the URI.
63
95
  #
64
- # @param uri [String, URI, nil] The URI of the Redis server.
65
- # If nil, uses the default URI.
66
- # @return [Redis] The Redis client for the specified URI
96
+ # @return [Redis] The Database client for the specified URI
67
97
  # @example
68
- # Familia.redis('redis://localhost:6379')
69
- def redis(uri = nil)
70
- if uri.is_a?(Integer)
71
- tmp = Familia.uri
72
- tmp.db = uri
73
- uri = tmp
74
- elsif uri.is_a?(String)
75
- uri &&= URI.parse uri
98
+ # Familia.dbclient('redis://localhost:6379/1')
99
+ # Familia.dbclient(2) # Use DB 2 with default server
100
+ def dbclient(uri = nil)
101
+ # First priority: Thread-local connection (middleware pattern)
102
+ return Thread.current[:familia_connection] if Thread.current.key?(:familia_connection)
103
+
104
+ # Second priority: Connection provider
105
+ if connection_provider
106
+ # Always pass normalized URI with database to provider
107
+ # Provider MUST return connection already on the correct database
108
+ parsed_uri = normalize_uri(uri)
109
+ connection = connection_provider.call(parsed_uri.to_s)
110
+
111
+ # In debug mode, verify the provider honored the contract
112
+ if Familia.debug? && connection.respond_to?(:client)
113
+ current_db = connection.client.db
114
+ expected_db = parsed_uri.db || 0
115
+ if current_db != expected_db
116
+ Familia.warn "Connection provider returned connection on DB #{current_db}, expected #{expected_db}"
117
+ end
118
+ end
119
+
120
+ return connection
121
+ end
122
+
123
+ # Third priority: Fallback behavior or error
124
+ raise Familia::NoConnectionAvailable, 'No connection available.' if connection_required
125
+
126
+ # Legacy behavior: create connection
127
+ parsed_uri = normalize_uri(uri)
128
+
129
+ # Only cache when no specific URI/DB is requested to avoid DB conflicts
130
+ if uri.nil?
131
+ @dbclient ||= connect(parsed_uri)
132
+ @dbclient.select(parsed_uri.db) if parsed_uri.db
133
+ @dbclient
134
+ else
135
+ # When a specific DB is requested, create a new connection
136
+ # to avoid conflicts with cached connections
137
+ connection = connect(parsed_uri)
138
+ connection.select(parsed_uri.db) if parsed_uri.db
139
+ connection
76
140
  end
77
- uri ||= Familia.uri
78
- connect(uri) unless @redis_clients[uri.serverid]
79
- @redis_clients[uri.serverid]
80
141
  end
81
142
 
82
- # Retrieves the Redis client associated with the given class.
143
+ # Executes Database commands atomically within a transaction (MULTI/EXEC).
144
+ #
145
+ # Database transactions queue commands and execute them atomically as a single unit.
146
+ # All commands succeed together or all fail together, ensuring data consistency.
83
147
  #
84
- # @param klass [Class] The class for which to retrieve the Redis client.
85
- # @return [Redis] The Redis client associated with the given class.
86
- def redis_uri_by_class(klass)
87
- uri = @redis_uri_by_class[klass]
88
- connect(uri)
148
+ # @yield [Redis] The Database transaction connection
149
+ # @return [Array] Results of all commands executed in the transaction
150
+ #
151
+ # @example Basic transaction usage
152
+ # Familia.transaction do |trans|
153
+ # trans.set("key1", "value1")
154
+ # trans.incr("counter")
155
+ # trans.lpush("list", "item")
156
+ # end
157
+ # # Returns: ["OK", 2, 1] - results of all commands
158
+ #
159
+ # @note **Comparison of Database batch operations:**
160
+ #
161
+ # | Feature | Multi/Exec | Pipeline |
162
+ # |-----------------|-----------------|-----------------|
163
+ # | Atomicity | Yes | No |
164
+ # | Performance | Good | Better |
165
+ # | Error handling | All-or-nothing | Per-command |
166
+ # | Use case | Data consistency| Bulk operations |
167
+ #
168
+ def transaction(&)
169
+ block_result = nil
170
+ result = dbclient.multi do |conn|
171
+ Fiber[:familia_transaction] = conn
172
+ begin
173
+ block_result = yield(conn) # rubocop:disable Lint/UselessAssignment
174
+ ensure
175
+ Fiber[:familia_transaction] = nil # cleanup reference
176
+ end
177
+ end
178
+ # Return the multi result which contains the transaction results
179
+ result
89
180
  end
181
+ alias multi transaction
90
182
 
91
- # Sets the default URI for Redis connections.
183
+ # Executes Database commands in a pipeline for improved performance.
92
184
  #
93
- # @param v [String, URI] The new default URI
94
- # @example
95
- # Familia.uri = 'redis://localhost:6379'
96
- def uri=(val)
97
- @uri = val.is_a?(URI) ? v : URI.parse(val)
185
+ # Pipelines send multiple commands without waiting for individual responses,
186
+ # reducing network round-trips. Commands execute independently and can
187
+ # succeed or fail without affecting other commands in the pipeline.
188
+ #
189
+ # @yield [Redis] The Database pipeline connection
190
+ # @return [Array] Results of all commands executed in the pipeline
191
+ #
192
+ # @example Basic pipeline usage
193
+ # Familia.pipeline do |pipe|
194
+ # pipe.set("key1", "value1")
195
+ # pipe.incr("counter")
196
+ # pipe.lpush("list", "item")
197
+ # end
198
+ # # Returns: ["OK", 2, 1] - results of all commands
199
+ #
200
+ # @example Error handling - commands succeed/fail independently
201
+ # results = Familia.pipeline do |conn|
202
+ # conn.set("valid_key", "value") # This will succeed
203
+ # conn.incr("string_key") # This will fail (wrong type)
204
+ # conn.set("another_key", "value2") # This will still succeed
205
+ # end
206
+ # # Returns: ["OK", Redis::CommandError, "OK"]
207
+ # # Notice how the error doesn't prevent other commands from executing
208
+ #
209
+ # @example Contrast with transaction behavior
210
+ # results = Familia.transaction do |conn|
211
+ # conn.set("inventory:item1", 100)
212
+ # conn.incr("invalid_key") # Fails, rolls back everything
213
+ # conn.set("inventory:item2", 200) # Won't be applied
214
+ # end
215
+ # # Result: neither item1 nor item2 are set due to the error
216
+ #
217
+ def pipeline(&)
218
+ block_result = nil
219
+ result = dbclient.pipelined do |conn|
220
+ Fiber[:familia_pipeline] = conn
221
+ begin
222
+ block_result = yield(conn) # rubocop:disable Lint/UselessAssignment
223
+ ensure
224
+ Fiber[:familia_pipeline] = nil # cleanup reference
225
+ end
226
+ end
227
+ # Return the pipeline result which contains the command results
228
+ result
98
229
  end
99
230
 
100
- alias url uri
101
- alias url= uri=
231
+ # Provides explicit access to a Database connection.
232
+ #
233
+ # This method is useful when you need direct access to a connection
234
+ # for operations not covered by other methods. The connection is
235
+ # properly managed and returned to the pool (if using connection_provider).
236
+ #
237
+ # @yield [Redis] A Database connection
238
+ # @return The result of the block
239
+ #
240
+ # @example Using with_connection for custom operations
241
+ # Familia.with_connection do |conn|
242
+ # conn.set("custom_key", "value")
243
+ # conn.expire("custom_key", 3600)
244
+ # end
245
+ #
246
+ def with_connection(&block)
247
+ yield dbclient
248
+ end
249
+
250
+ private
251
+
252
+ # Normalizes various URI formats to a consistent URI object
253
+ def normalize_uri(uri)
254
+ case uri
255
+ when Integer
256
+ new_uri = Familia.uri.dup
257
+ new_uri.db = uri
258
+ new_uri
259
+ when ->(obj) { obj.is_a?(String) || obj.instance_of?(::String) }
260
+ URI.parse(uri)
261
+ when URI
262
+ uri
263
+ when nil
264
+ Familia.uri
265
+ else
266
+ raise ArgumentError, "Invalid URI type: #{uri.class.name}"
267
+ end
268
+ end
102
269
  end
103
270
  end
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: true
1
+ # lib/familia/core_ext.rb
2
2
 
3
3
  # Extends the String class with time-related functionality
4
4
  #
@@ -0,0 +1,59 @@
1
+ # lib/familia/datatype/commands.rb
2
+
3
+ class Familia::DataType
4
+
5
+ # Must be included in all DataType classes to provide Redis
6
+ # commands. The class must have a dbkey method.
7
+ module Commands
8
+
9
+ def move(logical_database)
10
+ dbclient.move dbkey, logical_database
11
+ end
12
+
13
+ def rename(newkey)
14
+ dbclient.rename dbkey, newkey
15
+ end
16
+
17
+ def renamenx(newkey)
18
+ dbclient.renamenx dbkey, newkey
19
+ end
20
+
21
+ def type
22
+ dbclient.type dbkey
23
+ end
24
+
25
+ # Deletes the entire dbkey
26
+ # @return [Boolean] true if the key was deleted, false otherwise
27
+ def delete!
28
+ Familia.trace :DELETE!, dbclient, uri, caller(1..1) if Familia.debug?
29
+ ret = dbclient.del dbkey
30
+ ret.positive?
31
+ end
32
+ alias clear delete!
33
+
34
+ def exists?
35
+ dbclient.exists(dbkey) && !size.zero?
36
+ end
37
+
38
+ def current_expiration
39
+ dbclient.ttl dbkey
40
+ end
41
+
42
+ def expire(sec)
43
+ dbclient.expire dbkey, sec.to_i
44
+ end
45
+
46
+ def expireat(unixtime)
47
+ dbclient.expireat dbkey, unixtime
48
+ end
49
+
50
+ def persist
51
+ dbclient.persist dbkey
52
+ end
53
+
54
+ def echo(meth, trace)
55
+ dbclient.echo "[#{self.class}\##{meth}] #{trace} (#{@opts[:class]}\#)"
56
+ end
57
+
58
+ end
59
+ end
@@ -1,6 +1,6 @@
1
- # rubocop:disable all
1
+ # lib/familia/datatype/serialization.rb
2
2
 
3
- class Familia::RedisType
3
+ class Familia::DataType
4
4
 
5
5
  module Serialization
6
6
 
@@ -29,7 +29,7 @@ class Familia::RedisType
29
29
  def serialize_value(val, strict_values: true)
30
30
  prepared = nil
31
31
 
32
- Familia.trace :TOREDIS, redis, "#{val}<#{val.class}|#{opts[:class]}>", caller(1..1) if Familia.debug?
32
+ Familia.trace :TOREDIS, dbclient, "#{val}<#{val.class}|#{opts[:class]}>", caller(1..1) if Familia.debug?
33
33
 
34
34
  if opts[:class]
35
35
  prepared = Familia.distinguisher(opts[:class], strict_values: strict_values)
@@ -42,12 +42,11 @@ class Familia::RedisType
42
42
  Familia.ld " from <#{val.class}> => <#{prepared.class}>"
43
43
  end
44
44
 
45
- Familia.trace :TOREDIS, redis, "#{val}<#{val.class}|#{opts[:class]}> => #{prepared}<#{prepared.class}>", caller(1..1) if Familia.debug?
45
+ Familia.trace :TOREDIS, dbclient, "#{val}<#{val.class}|#{opts[:class]}> => #{prepared}<#{prepared.class}>", caller(1..1) if Familia.debug?
46
46
 
47
47
  Familia.warn "[#{self.class}\#serialize_value] nil returned for #{opts[:class]}\##{name}" if prepared.nil?
48
48
  prepared
49
49
  end
50
- alias to_redis serialize_value
51
50
 
52
51
  # Deserializes multiple values from Redis, removing nil values.
53
52
  #
@@ -63,7 +62,6 @@ class Familia::RedisType
63
62
  # expected value.
64
63
  deserialize_values_with_nil(*values).compact
65
64
  end
66
- alias from_redis deserialize_values
67
65
 
68
66
  # Deserializes multiple values from Redis, preserving nil values.
69
67
  #
@@ -97,16 +95,15 @@ class Familia::RedisType
97
95
  val
98
96
  rescue StandardError => e
99
97
  Familia.info val
100
- Familia.info "Parse error for #{rediskey} (#{load_method}): #{e.message}"
98
+ Familia.info "Parse error for #{dbkey} (#{load_method}): #{e.message}"
101
99
  Familia.info e.backtrace
102
100
  nil
103
101
  end
104
102
 
105
103
  values
106
104
  end
107
- alias from_redis_with_nil deserialize_values_with_nil
108
105
 
109
- # Deserializes a single value from Redis.
106
+ # Deserializes a single value from the database.
110
107
  #
111
108
  # @param val [String, nil] The value to deserialize.
112
109
  # @return [Object, nil] The deserialized object, the default value if
@@ -115,10 +112,10 @@ class Familia::RedisType
115
112
  # @note If no class option is specified, the original value is
116
113
  # returned unchanged.
117
114
  #
118
- # NOTE: Currently only the RedisType class uses this method. Horreum
115
+ # NOTE: Currently only the DataType class uses this method. Horreum
119
116
  # fields are a newer addition and don't support the full range of
120
- # deserialization options that RedisType supports. It uses to_redis
121
- # for serialization since everything becomes a string in Redis.
117
+ # deserialization options that DataType supports. It uses serialize_value
118
+ # for serialization since everything becomes a string in Valkey.
122
119
  #
123
120
  def deserialize_value(val)
124
121
  return @opts[:default] if val.nil?
@@ -127,7 +124,6 @@ class Familia::RedisType
127
124
  ret = deserialize_values val
128
125
  ret&.first # return the object or nil
129
126
  end
130
- alias from_redis deserialize_value
131
127
  end
132
128
 
133
129
  end