familia 1.0.0.pre.rc7 → 1.1.0.pre.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -1
- data/Gemfile.lock +3 -1
- data/README.md +5 -5
- data/VERSION.yml +2 -2
- data/familia.gemspec +1 -2
- data/lib/familia/base.rb +11 -11
- data/lib/familia/connection.rb +18 -2
- data/lib/familia/errors.rb +14 -0
- data/lib/familia/features/expiration.rb +13 -2
- data/lib/familia/features/quantization.rb +1 -1
- data/lib/familia/horreum/class_methods.rb +31 -21
- data/lib/familia/horreum/commands.rb +53 -14
- data/lib/familia/horreum/relations_management.rb +9 -2
- data/lib/familia/horreum/serialization.rb +32 -23
- data/lib/familia/horreum.rb +5 -1
- data/lib/familia/redistype/commands.rb +5 -2
- data/lib/familia/redistype/serialization.rb +17 -16
- data/lib/familia/redistype/types/hashkey.rb +166 -0
- data/lib/familia/{types → redistype/types}/list.rb +19 -14
- data/lib/familia/{types → redistype/types}/sorted_set.rb +23 -19
- data/lib/familia/{types → redistype/types}/string.rb +8 -6
- data/lib/familia/{types → redistype/types}/unsorted_set.rb +16 -12
- data/lib/familia/redistype.rb +19 -9
- data/lib/familia.rb +5 -1
- data/try/10_familia_try.rb +1 -1
- data/try/20_redis_type_try.rb +1 -1
- data/try/21_redis_type_zset_try.rb +1 -1
- data/try/22_redis_type_set_try.rb +1 -1
- data/try/23_redis_type_list_try.rb +2 -2
- data/try/24_redis_type_string_try.rb +3 -3
- data/try/25_redis_type_hash_try.rb +1 -1
- data/try/26_redis_bool_try.rb +2 -2
- data/try/27_redis_horreum_try.rb +2 -2
- data/try/30_familia_object_try.rb +8 -5
- data/try/40_customer_try.rb +6 -6
- metadata +15 -15
- data/lib/familia/types/hashkey.rb +0 -108
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7e5fe48e629eab30af342be4ad81f6afe5854b33b678b926b9c3470c0515627
|
4
|
+
data.tar.gz: 1d938baae35feb17f3d9855055152fdb0ba441317315fd3b2de6932e3c47e0cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 707e9aba376653fa439ab1ffc85c4b794f1f52444dbed86a093f1d9c93a1952d8f84fe465cdcf8798bf0f72e5a4099586f1895cad5225f6d81899deeedcbf3a5
|
7
|
+
data.tar.gz: a9323482330bef4a632d92fd6828da32f0be7aa4f107d659e4440a2e3a09ad3dd0c2011d90a5e1a3380ca85fdf5afe47fb4634e9cf21951986d92115523bfbba
|
data/Gemfile
CHANGED
@@ -5,7 +5,9 @@ source 'https://rubygems.org'
|
|
5
5
|
gemspec
|
6
6
|
|
7
7
|
group :development, :test do
|
8
|
-
|
8
|
+
# byebug only works with MRI
|
9
|
+
gem 'byebug', '~> 11.0', require: false if RUBY_ENGINE == 'ruby'
|
10
|
+
gem 'pry-byebug', '~> 3.10.1', require: false if RUBY_ENGINE == 'ruby'
|
9
11
|
gem 'rubocop', require: false
|
10
12
|
gem 'rubocop-performance', require: false
|
11
13
|
gem 'rubocop-thread_safety', require: false
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
familia (1.
|
4
|
+
familia (1.1.0.pre.rc1)
|
5
5
|
redis (>= 4.8.1, < 6.0)
|
6
|
+
stringio (~> 3.1.1)
|
6
7
|
uri-redis (~> 1.3)
|
7
8
|
|
8
9
|
GEM
|
@@ -55,6 +56,7 @@ GEM
|
|
55
56
|
rubocop (>= 0.90.0)
|
56
57
|
ruby-progressbar (1.13.0)
|
57
58
|
storable (0.10.0)
|
59
|
+
stringio (3.1.1)
|
58
60
|
strscan (3.1.0)
|
59
61
|
sysinfo (0.10.0)
|
60
62
|
drydock (< 1.0)
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Familia - 1.
|
1
|
+
# Familia - 1.1.0-rc1 (November 2024)
|
2
2
|
|
3
3
|
**Organize and store Ruby objects in Redis. A powerful Ruby ORM (of sorts) for Redis.**
|
4
4
|
|
@@ -9,7 +9,7 @@ Familia provides a flexible and feature-rich way to interact with Redis using Ru
|
|
9
9
|
|
10
10
|
Get it in one of the following ways:
|
11
11
|
|
12
|
-
* In your Gemfile: `gem 'familia', '>= 1.
|
12
|
+
* In your Gemfile: `gem 'familia', '>= 1.1.0-rc1'`
|
13
13
|
* Install it by hand: `gem install familia --pre`
|
14
14
|
* Or for development: `git clone git@github.com:delano/familia.git`
|
15
15
|
|
@@ -152,11 +152,11 @@ end
|
|
152
152
|
|
153
153
|
```ruby
|
154
154
|
class ComplexObject < Familia::Horreum
|
155
|
-
def
|
155
|
+
def serialize_value
|
156
156
|
custom_serialization_method
|
157
157
|
end
|
158
158
|
|
159
|
-
def self.
|
159
|
+
def self.deserialize_value(data)
|
160
160
|
custom_deserialization_method(data)
|
161
161
|
end
|
162
162
|
end
|
@@ -188,7 +188,7 @@ flower.save
|
|
188
188
|
### Retrieving and Updating Objects
|
189
189
|
|
190
190
|
```ruby
|
191
|
-
rose = Flower.
|
191
|
+
rose = Flower.find_by_id("rrose")
|
192
192
|
rose.name = "Pink Rose"
|
193
193
|
rose.save
|
194
194
|
```
|
data/VERSION.yml
CHANGED
data/familia.gemspec
CHANGED
@@ -20,9 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.required_ruby_version = Gem::Requirement.new('>= 2.7.8')
|
21
21
|
|
22
22
|
spec.add_dependency 'redis', '>= 4.8.1', '< 6.0'
|
23
|
+
spec.add_dependency 'stringio', '~> 3.1.1'
|
23
24
|
spec.add_dependency 'uri-redis', '~> 1.3'
|
24
25
|
|
25
|
-
# byebug only works with MRI
|
26
|
-
spec.add_development_dependency 'byebug', '~> 11.0' if RUBY_ENGINE == 'ruby'
|
27
26
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
28
27
|
end
|
data/lib/familia/base.rb
CHANGED
@@ -30,21 +30,21 @@ module Familia
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
#
|
34
|
-
#
|
33
|
+
# Base implementation of update_expiration that maintains API compatibility
|
34
|
+
# with the :expiration feature's implementation.
|
35
35
|
#
|
36
|
-
#
|
37
|
-
#
|
36
|
+
# This is a no-op implementation that gets overridden by features like
|
37
|
+
# :expiration. It accepts an optional ttl parameter to maintain interface
|
38
|
+
# compatibility with the overriding implementations.
|
38
39
|
#
|
39
|
-
# @
|
40
|
+
# @param ttl [Integer, nil] Time To Live in seconds (ignored in base implementation)
|
41
|
+
# @return [nil] Always returns nil
|
40
42
|
#
|
41
|
-
# @
|
42
|
-
#
|
43
|
+
# @note This is a no-op implementation. Classes that need expiration
|
44
|
+
# functionality should include the :expiration feature.
|
43
45
|
#
|
44
|
-
|
45
|
-
|
46
|
-
def update_expiration(*)
|
47
|
-
Familia.info "[update_expiration] Skipped for #{rediskey}. #{self.class} data is immortal!"
|
46
|
+
def update_expiration(ttl: nil)
|
47
|
+
Familia.ld "[update_expiration] Feature not enabled for #{self.class}. Key: #{rediskey} (caller: #{caller(1..1)})"
|
48
48
|
nil
|
49
49
|
end
|
50
50
|
|
data/lib/familia/connection.rb
CHANGED
@@ -6,6 +6,7 @@ require_relative '../../lib/redis_middleware'
|
|
6
6
|
module Familia
|
7
7
|
@uri = URI.parse 'redis://127.0.0.1'
|
8
8
|
@redis_clients = {}
|
9
|
+
@redis_uri_by_class = {}
|
9
10
|
|
10
11
|
# The Connection module provides Redis connection management for Familia.
|
11
12
|
# It allows easy setup and access to Redis clients across different URIs.
|
@@ -25,17 +26,20 @@ module Familia
|
|
25
26
|
# Establishes a connection to a Redis server.
|
26
27
|
#
|
27
28
|
# @param uri [String, URI, nil] The URI of the Redis server to connect to.
|
28
|
-
# If nil, uses the default URI.
|
29
|
-
# @return [Redis] The connected Redis client
|
29
|
+
# If nil, uses the default URI from `@redis_uri_by_class` or `Familia.uri`.
|
30
|
+
# @return [Redis] The connected Redis client.
|
31
|
+
# @raise [ArgumentError] If no URI is specified.
|
30
32
|
# @example
|
31
33
|
# Familia.connect('redis://localhost:6379')
|
32
34
|
def connect(uri = nil)
|
33
35
|
uri = URI.parse(uri) if uri.is_a?(String)
|
36
|
+
uri ||= @redis_uri_by_class[self]
|
34
37
|
uri ||= Familia.uri
|
35
38
|
|
36
39
|
raise ArgumentError, 'No URI specified' unless uri
|
37
40
|
|
38
41
|
conf = uri.conf
|
42
|
+
@redis_uri_by_class[self] = uri.serverid
|
39
43
|
|
40
44
|
if Familia.enable_redis_logging
|
41
45
|
RedisLogger.logger = Familia.logger
|
@@ -49,6 +53,9 @@ module Familia
|
|
49
53
|
end
|
50
54
|
|
51
55
|
redis = Redis.new(conf)
|
56
|
+
|
57
|
+
# Close the existing connection if it exists
|
58
|
+
@redis_clients[uri.serverid].close if @redis_clients[uri.serverid]
|
52
59
|
@redis_clients[uri.serverid] = redis
|
53
60
|
end
|
54
61
|
|
@@ -72,6 +79,15 @@ module Familia
|
|
72
79
|
@redis_clients[uri.serverid]
|
73
80
|
end
|
74
81
|
|
82
|
+
# Retrieves the Redis client associated with the given class.
|
83
|
+
#
|
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)
|
89
|
+
end
|
90
|
+
|
75
91
|
# Sets the default URI for Redis connections.
|
76
92
|
#
|
77
93
|
# @param v [String, URI] The new default URI
|
data/lib/familia/errors.rb
CHANGED
@@ -30,4 +30,18 @@ module Familia
|
|
30
30
|
"No client for #{uri.serverid}"
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
# Raised when attempting to refresh an object whose key doesn't exist in Redis
|
35
|
+
class KeyNotFoundError < Problem
|
36
|
+
attr_reader :key
|
37
|
+
|
38
|
+
def initialize(key)
|
39
|
+
@key = key
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
def message
|
44
|
+
"Key not found in Redis: #{key}"
|
45
|
+
end
|
46
|
+
end
|
33
47
|
end
|
@@ -49,7 +49,7 @@ module Familia::Features
|
|
49
49
|
# false otherwise.
|
50
50
|
#
|
51
51
|
# @example Setting an expiration of one day
|
52
|
-
# object.update_expiration(86400)
|
52
|
+
# object.update_expiration(ttl: 86400)
|
53
53
|
#
|
54
54
|
# @note If TTL is set to zero, the expiration will be removed, making the
|
55
55
|
# data persist indefinitely.
|
@@ -57,8 +57,19 @@ module Familia::Features
|
|
57
57
|
# @raise [Familia::Problem] Raises an error if the TTL is not a non-negative
|
58
58
|
# integer.
|
59
59
|
#
|
60
|
-
|
60
|
+
def update_expiration(ttl: nil)
|
61
61
|
ttl ||= self.ttl
|
62
|
+
|
63
|
+
if self.class.has_relations?
|
64
|
+
Familia.ld "[update_expiration] #{self.class} has relations: #{self.class.redis_types.keys}"
|
65
|
+
self.class.redis_types.each do |name, definition|
|
66
|
+
next if definition.opts[:ttl].nil?
|
67
|
+
obj = send(name)
|
68
|
+
Familia.ld "[update_expiration] Updating expiration for #{name} (#{obj.rediskey}) to #{ttl}"
|
69
|
+
obj.update_expiration(ttl: ttl)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
62
73
|
# It's important to raise exceptions here and not just log warnings. We
|
63
74
|
# don't want to silently fail at setting expirations and cause data
|
64
75
|
# retention issues (e.g. not removed in a timely fashion).
|
@@ -46,7 +46,7 @@ module Familia::Features
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def qstamp(quantum = nil, pattern: nil, time: nil)
|
49
|
-
self.class.qstamp(quantum || ttl, pattern: pattern, time: time)
|
49
|
+
self.class.qstamp(quantum || self.class.ttl, pattern: pattern, time: time)
|
50
50
|
end
|
51
51
|
|
52
52
|
extend ClassMethods
|
@@ -33,9 +33,6 @@ module Familia
|
|
33
33
|
include Familia::Settings
|
34
34
|
include Familia::Horreum::RelationsManagement
|
35
35
|
|
36
|
-
attr_accessor :parent
|
37
|
-
attr_writer :redis, :dump_method, :load_method
|
38
|
-
|
39
36
|
# Returns the Redis connection for the class.
|
40
37
|
#
|
41
38
|
# This method retrieves the Redis connection instance for the class. If no
|
@@ -156,7 +153,7 @@ module Familia
|
|
156
153
|
Familia.trace :FAST_WRITER, redis, "#{name}: #{val.inspect}", caller(1..1) if Familia.debug?
|
157
154
|
|
158
155
|
# Convert the provided value to a format suitable for Redis storage.
|
159
|
-
prepared =
|
156
|
+
prepared = serialize_value(val)
|
160
157
|
Familia.ld "[.fast_attribute!] #{name} val: #{val.class} prepared: #{prepared.class}"
|
161
158
|
|
162
159
|
# Use the existing accessor method to set the attribute value.
|
@@ -196,6 +193,10 @@ module Familia
|
|
196
193
|
@redis_types
|
197
194
|
end
|
198
195
|
|
196
|
+
def has_relations?
|
197
|
+
@has_relations ||= false
|
198
|
+
end
|
199
|
+
|
199
200
|
def db(v = nil)
|
200
201
|
@db = v unless v.nil?
|
201
202
|
@db || parent&.db
|
@@ -209,16 +210,20 @@ module Familia
|
|
209
210
|
def all(suffix = nil)
|
210
211
|
suffix ||= self.suffix
|
211
212
|
# objects that could not be parsed will be nil
|
212
|
-
keys(suffix).filter_map { |k|
|
213
|
+
keys(suffix).filter_map { |k| find_by_key(k) }
|
213
214
|
end
|
214
215
|
|
215
216
|
def any?(filter = '*')
|
216
|
-
|
217
|
+
matching_keys_count(filter) > 0
|
217
218
|
end
|
218
219
|
|
219
|
-
|
220
|
+
# Returns the number of Redis keys matching the given filter pattern
|
221
|
+
# @param filter [String] Redis key pattern to match (default: '*')
|
222
|
+
# @return [Integer] Number of matching keys
|
223
|
+
def matching_keys_count(filter = '*')
|
220
224
|
redis.keys(rediskey(filter)).compact.size
|
221
225
|
end
|
226
|
+
alias size matching_keys_count # For backwards compatibility
|
222
227
|
|
223
228
|
def suffix(a = nil, &blk)
|
224
229
|
@suffix = a || blk if a || !blk.nil?
|
@@ -312,17 +317,17 @@ module Familia
|
|
312
317
|
# debugging.
|
313
318
|
#
|
314
319
|
# @example
|
315
|
-
# User.
|
320
|
+
# User.find_by_key("user:123") # Returns a User instance if it exists,
|
316
321
|
# nil otherwise
|
317
322
|
#
|
318
|
-
def
|
323
|
+
def find_by_key(objkey)
|
319
324
|
raise ArgumentError, 'Empty key' if objkey.to_s.empty?
|
320
325
|
|
321
326
|
# We use a lower-level method here b/c we're working with the
|
322
327
|
# full key and not just the identifier.
|
323
328
|
does_exist = redis.exists(objkey).positive?
|
324
329
|
|
325
|
-
Familia.ld "[.
|
330
|
+
Familia.ld "[.find_by_key] #{self} from key #{objkey} (exists: #{does_exist})"
|
326
331
|
Familia.trace :FROM_KEY, redis, objkey, caller(1..1) if Familia.debug?
|
327
332
|
|
328
333
|
# This is the reason for calling exists first. We want to definitively
|
@@ -337,6 +342,7 @@ module Familia
|
|
337
342
|
|
338
343
|
new(**obj)
|
339
344
|
end
|
345
|
+
alias from_rediskey find_by_key # deprecated
|
340
346
|
|
341
347
|
# Retrieves and instantiates an object from Redis using its identifier.
|
342
348
|
#
|
@@ -347,7 +353,7 @@ module Familia
|
|
347
353
|
# @return [Object, nil] An instance of the class if found, nil otherwise.
|
348
354
|
#
|
349
355
|
# This method constructs the full Redis key using the provided identifier
|
350
|
-
# and suffix, then delegates to `
|
356
|
+
# and suffix, then delegates to `find_by_key` for the actual retrieval and
|
351
357
|
# instantiation.
|
352
358
|
#
|
353
359
|
# It's a higher-level method that abstracts away the key construction,
|
@@ -355,19 +361,21 @@ module Familia
|
|
355
361
|
# identifier.
|
356
362
|
#
|
357
363
|
# @example
|
358
|
-
# User.
|
364
|
+
# User.find_by_id(123) # Equivalent to User.find_by_key("user:123:object")
|
359
365
|
#
|
360
|
-
def
|
366
|
+
def find_by_id(identifier, suffix = nil)
|
361
367
|
suffix ||= self.suffix
|
362
368
|
return nil if identifier.to_s.empty?
|
363
369
|
|
364
370
|
objkey = rediskey(identifier, suffix)
|
365
371
|
|
366
|
-
Familia.ld "[.
|
367
|
-
Familia.trace :
|
368
|
-
|
372
|
+
Familia.ld "[.find_by_id] #{self} from key #{objkey})"
|
373
|
+
Familia.trace :FIND_BY_ID, Familia.redis(uri), objkey, caller(1..1).first if Familia.debug?
|
374
|
+
find_by_key objkey
|
369
375
|
end
|
370
|
-
alias
|
376
|
+
alias find find_by_id
|
377
|
+
alias load find_by_id # deprecated
|
378
|
+
alias from_identifier find_by_id # deprecated
|
371
379
|
|
372
380
|
# Checks if an object with the given identifier exists in Redis.
|
373
381
|
#
|
@@ -399,8 +407,10 @@ module Familia
|
|
399
407
|
# @param suffix [Symbol, nil] The suffix to use in the Redis key (default: class suffix).
|
400
408
|
# @return [Boolean] true if the object was successfully destroyed, false otherwise.
|
401
409
|
#
|
402
|
-
# This method
|
403
|
-
#
|
410
|
+
# This method is part of Familia's high-level object lifecycle management. While `delete!`
|
411
|
+
# operates directly on Redis keys, `destroy!` operates at the object level and is used for
|
412
|
+
# ORM-style operations. Use `destroy!` when removing complete objects from the system, and
|
413
|
+
# `delete!` when working directly with Redis keys.
|
404
414
|
#
|
405
415
|
# @example
|
406
416
|
# User.destroy!(123) # Removes user:123:object from Redis
|
@@ -412,7 +422,7 @@ module Familia
|
|
412
422
|
objkey = rediskey identifier, suffix
|
413
423
|
|
414
424
|
ret = redis.del objkey
|
415
|
-
Familia.trace :
|
425
|
+
Familia.trace :DESTROY!, redis, "#{objkey} #{ret.inspect}", caller(1..1) if Familia.debug?
|
416
426
|
ret.positive?
|
417
427
|
end
|
418
428
|
|
@@ -428,7 +438,7 @@ module Familia
|
|
428
438
|
# User.find # Returns all keys matching user:*:object
|
429
439
|
# User.find('active') # Returns all keys matching user:*:active
|
430
440
|
#
|
431
|
-
def
|
441
|
+
def find_keys(suffix = '*')
|
432
442
|
redis.keys(rediskey('*', suffix)) || []
|
433
443
|
end
|
434
444
|
|
@@ -18,11 +18,35 @@ module Familia
|
|
18
18
|
#
|
19
19
|
module Commands
|
20
20
|
|
21
|
+
def move(db)
|
22
|
+
redis.move rediskey, db
|
23
|
+
end
|
24
|
+
|
25
|
+
# Checks if the calling object's key exists in Redis and has a non-zero size.
|
26
|
+
#
|
27
|
+
# This method retrieves the Redis URI associated with the calling object's class
|
28
|
+
# using `Familia.redis_uri_by_class`. It then checks if the specified key exists
|
29
|
+
# in Redis and that its size is not zero. If debugging is enabled, it logs the
|
30
|
+
# existence check using `Familia.trace`.
|
31
|
+
#
|
32
|
+
# @return [Boolean] Returns `true` if the key exists in Redis and its size is not zero, otherwise `false`.
|
33
|
+
# @example
|
34
|
+
# if some_object.exists?
|
35
|
+
# # perform action
|
36
|
+
# end
|
21
37
|
def exists?
|
22
|
-
|
23
|
-
|
38
|
+
true_or_false = self.class.redis.exists?(rediskey) && !size.zero?
|
39
|
+
Familia.trace :EXISTS, redis, "#{key} #{true_or_false.inspect}", caller(1..1) if Familia.debug?
|
40
|
+
true_or_false
|
24
41
|
end
|
25
42
|
|
43
|
+
# Returns the number of fields in the main object hash
|
44
|
+
# @return [Integer] number of fields
|
45
|
+
def field_count
|
46
|
+
redis.hlen rediskey
|
47
|
+
end
|
48
|
+
alias size field_count
|
49
|
+
|
26
50
|
# Sets a timeout on key. After the timeout has expired, the key will
|
27
51
|
# automatically be deleted. Returns 1 if the timeout was set, 0 if key
|
28
52
|
# does not exist or the timeout could not be set.
|
@@ -33,20 +57,27 @@ module Familia
|
|
33
57
|
redis.expire rediskey, ttl.to_i
|
34
58
|
end
|
35
59
|
|
60
|
+
# Retrieves the remaining time to live (TTL) for the object's Redis key.
|
61
|
+
#
|
62
|
+
# This method accesses the ovjects Redis client to obtain the TTL of `rediskey`.
|
63
|
+
# If debugging is enabled, it logs the TTL retrieval operation using `Familia.trace`.
|
64
|
+
#
|
65
|
+
# @return [Integer] The TTL of the key in seconds. Returns -1 if the key does not exist
|
66
|
+
# or has no associated expire time.
|
36
67
|
def realttl
|
37
68
|
Familia.trace :REALTTL, redis, redisuri, caller(1..1) if Familia.debug?
|
38
69
|
redis.ttl rediskey
|
39
70
|
end
|
40
71
|
|
41
|
-
#
|
72
|
+
# Removes a field from the hash stored at the Redis key.
|
42
73
|
#
|
43
|
-
# @param field [String] The field to
|
74
|
+
# @param field [String] The field to remove from the hash.
|
44
75
|
# @return [Integer] The number of fields that were removed from the hash (0 or 1).
|
45
|
-
|
46
|
-
def hdel!(field)
|
76
|
+
def remove_field(field)
|
47
77
|
Familia.trace :HDEL, redis, field, caller(1..1) if Familia.debug?
|
48
78
|
redis.hdel rediskey, field
|
49
79
|
end
|
80
|
+
alias remove remove_field # deprecated
|
50
81
|
|
51
82
|
def redistype
|
52
83
|
Familia.trace :REDISTYPE, redis, redisuri, caller(1..1) if Familia.debug?
|
@@ -59,6 +90,15 @@ module Familia
|
|
59
90
|
redis.rename rediskey, newkey
|
60
91
|
end
|
61
92
|
|
93
|
+
# Retrieves the prefix for the current instance by delegating to its class.
|
94
|
+
#
|
95
|
+
# @return [String] The prefix associated with the class of the current instance.
|
96
|
+
# @example
|
97
|
+
# instance.prefix
|
98
|
+
def prefix
|
99
|
+
self.class.prefix
|
100
|
+
end
|
101
|
+
|
62
102
|
# For parity with RedisType#hgetall
|
63
103
|
def hgetall
|
64
104
|
Familia.trace :HGETALL, redis, redisuri, caller(1..1) if Familia.debug?
|
@@ -78,8 +118,10 @@ module Familia
|
|
78
118
|
redis.hset rediskey, field, value
|
79
119
|
end
|
80
120
|
|
81
|
-
def hmset
|
82
|
-
|
121
|
+
def hmset(hsh={})
|
122
|
+
hsh ||= self.to_h
|
123
|
+
Familia.trace :HMSET, redis, hsh, caller(1..1) if Familia.debug?
|
124
|
+
redis.hmset rediskey(suffix), hsh
|
83
125
|
end
|
84
126
|
|
85
127
|
def hkeys
|
@@ -116,11 +158,6 @@ module Familia
|
|
116
158
|
end
|
117
159
|
alias decrement decr
|
118
160
|
|
119
|
-
def hlen
|
120
|
-
redis.hlen rediskey(suffix)
|
121
|
-
end
|
122
|
-
alias hlength hlen
|
123
|
-
|
124
161
|
def hstrlen(field)
|
125
162
|
redis.hstrlen rediskey(suffix), field
|
126
163
|
end
|
@@ -131,12 +168,14 @@ module Familia
|
|
131
168
|
end
|
132
169
|
alias has_key? key?
|
133
170
|
|
171
|
+
# Deletes the entire Redis key
|
172
|
+
# @return [Boolean] true if the key was deleted, false otherwise
|
134
173
|
def delete!
|
135
174
|
Familia.trace :DELETE!, redis, redisuri, caller(1..1) if Familia.debug?
|
136
175
|
ret = redis.del rediskey
|
137
176
|
ret.positive?
|
138
177
|
end
|
139
|
-
|
178
|
+
alias clear delete!
|
140
179
|
|
141
180
|
end
|
142
181
|
|
@@ -16,6 +16,10 @@ module Familia
|
|
16
16
|
# Call setup_relations_accessors to initialize the feature
|
17
17
|
#
|
18
18
|
module RelationsManagement
|
19
|
+
# A practical flag to indicate that a Horreum member has relations,
|
20
|
+
# not just theoretically but actually at least one list/haskey/etc.
|
21
|
+
@has_relations = nil
|
22
|
+
|
19
23
|
def self.included(base)
|
20
24
|
base.extend(ClassMethods)
|
21
25
|
base.setup_relations_accessors
|
@@ -31,14 +35,17 @@ module Familia
|
|
31
35
|
|
32
36
|
# Dynamically define instance-level relation methods
|
33
37
|
#
|
34
|
-
# Once defined, these methods can be used at the
|
38
|
+
# Once defined, these methods can be used at the instance-level of a
|
35
39
|
# Familia member to define *instance-level* relations to any of the
|
36
40
|
# RedisType types (e.g. set, list, hash, etc).
|
37
41
|
#
|
38
42
|
define_method :"#{kind}" do |*args|
|
39
43
|
name, opts = *args
|
44
|
+
|
45
|
+
# As log as we have at least one relation, we can set this flag.
|
46
|
+
@has_relations = true
|
47
|
+
|
40
48
|
attach_instance_redis_object_relation name, klass, opts
|
41
|
-
redis_types[name.to_s.to_sym]
|
42
49
|
end
|
43
50
|
define_method :"#{kind}?" do |name|
|
44
51
|
obj = redis_types[name.to_s.to_sym]
|