Module: Familia::Horreum::ManagementMethods
- Includes:
- RelatedFieldsManagement
- Defined in:
- lib/familia/horreum/subclass/management.rb
Overview
ManagementMethods: Provides class-level functionality for Horreum records.
This module is extended into classes that include Familia::Horreum, providing methods for Database operations and object management.
Key features:
- Includes RelatedFieldsManagement for DataType field handling
- Provides utility methods for working with Database objects
Instance Method Summary collapse
-
#all(suffix = nil) ⇒ Object
-
#any?(filter = '*') ⇒ Boolean
-
#create ⇒ Object
Creates and persists a new instance of the class.
-
#dbkey(identifier, suffix = self.suffix) ⇒ Object
+identifier+ can be a value or an Array of values used to create the index.
-
#destroy!(identifier, suffix = nil) ⇒ Boolean
Destroys an object in Database with the given identifier.
-
#exists?(identifier, suffix = nil) ⇒ Boolean
Checks if an object with the given identifier exists in Redis.
-
#find_by_id(identifier, suffix = nil) ⇒ Object?
(also: #find, #load, #from_identifier)
Retrieves and instantiates an object from Database using its identifier.
-
#find_by_key(objkey) ⇒ Object?
(also: #from_dbkey)
Retrieves and instantiates an object from Database using the full object key.
-
#find_keys(suffix = '*') ⇒ Array<String>
Finds all keys in Database matching the given suffix pattern.
-
#matching_keys_count(filter = '*') ⇒ Integer
(also: #size)
Returns the number of dbkeys matching the given filter pattern.
-
#multiget(*ids) ⇒ Object
-
#rawmultiget(*ids) ⇒ Object
Methods included from RelatedFieldsManagement
#attach_class_related_field, #attach_instance_related_field
Instance Method Details
#all(suffix = nil) ⇒ Object
245 246 247 248 249 |
# File 'lib/familia/horreum/subclass/management.rb', line 245 def all(suffix = nil) suffix ||= self.suffix # objects that could not be parsed will be nil keys(suffix).filter_map { |k| find_by_key(k) } end |
#any?(filter = '*') ⇒ Boolean
251 252 253 |
# File 'lib/familia/horreum/subclass/management.rb', line 251 def any?(filter = '*') matching_keys_count(filter) > 0 end |
#create ⇒ Object
The behavior of this method depends on the implementation of #new, #exists?, and #save in the class and its superclasses.
Creates and persists a new instance of the class.
This method serves as a factory method for creating and persisting new instances of the class. It combines object instantiation, existence checking, and persistence in a single operation.
The method is flexible in accepting both positional and keyword arguments: - Positional arguments (*args) are passed directly to the constructor. - Keyword arguments (**kwargs) are passed as a hash to the constructor.
After instantiation, the method checks if an object with the same identifier already exists. If it does, a Familia::Problem exception is raised to prevent overwriting existing data.
Finally, the method saves the new instance returns it.
56 57 58 59 60 |
# File 'lib/familia/horreum/subclass/management.rb', line 56 def create(*, **) fobj = new(*, **) fobj.save_if_not_exists fobj end |
#dbkey(identifier, suffix = self.suffix) ⇒ Object
+identifier+ can be a value or an Array of values used to create the index. We don’t enforce a default suffix; that’s left up to the instance. The suffix is used to differentiate between different types of objects.
+suffix+ If a nil value is explicitly passed in, it won’t appear in the redis key that’s returned. If no suffix is passed in, the class’ suffix is used as the default (via the class method self.suffix). It’s an important distinction b/c passing in an explicitly nil is how DataType objects at the class level are created without the global default ‘object’ suffix. See DataType#dbkey “parent_class?” for more details.
236 237 238 239 240 241 242 243 |
# File 'lib/familia/horreum/subclass/management.rb', line 236 def dbkey(identifier, suffix = self.suffix) if identifier.to_s.empty? raise NoIdentifier, "#{self} requires non-empty identifier, got: #{identifier.inspect}" end identifier &&= identifier.to_s Familia.dbkey(prefix, identifier, suffix) end |
#destroy!(identifier, suffix = nil) ⇒ Boolean
Destroys an object in Database with the given identifier.
This method is part of Familia’s high-level object lifecycle management. While delete!
operates directly on dbkeys, destroy!
operates at the object level and is used for
ORM-style operations. Use destroy!
when removing complete objects from the system, and
delete!
when working directly with dbkeys.
198 199 200 201 202 203 204 205 206 207 |
# File 'lib/familia/horreum/subclass/management.rb', line 198 def destroy!(identifier, suffix = nil) suffix ||= self.suffix return false if identifier.to_s.empty? objkey = dbkey identifier, suffix ret = dbclient.del objkey Familia.trace :DESTROY!, dbclient, "#{objkey} #{ret.inspect}", caller(1..1) if Familia.debug? ret.positive? end |
#exists?(identifier, suffix = nil) ⇒ Boolean
Checks if an object with the given identifier exists in Redis.
This method constructs the full dbkey using the provided identifier and suffix, then checks if the key exists in Redis.
172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/familia/horreum/subclass/management.rb', line 172 def exists?(identifier, suffix = nil) raise NoIdentifier, "Empty identifier" if identifier.to_s.empty? suffix ||= self.suffix objkey = dbkey identifier, suffix ret = dbclient.exists objkey Familia.trace :EXISTS, dbclient, "#{objkey} #{ret.inspect}", caller(1..1) if Familia.debug? ret.positive? # differs from Valkey API but I think it's okay bc `exists?` is a predicate method. end |
#find_by_id(identifier, suffix = nil) ⇒ Object? Also known as: find, load, from_identifier
Retrieves and instantiates an object from Database using its identifier.
This method constructs the full dbkey using the provided identifier
and suffix, then delegates to find_by_key
for the actual retrieval and
instantiation.
It’s a higher-level method that abstracts away the key construction, making it easier to retrieve objects when you only have their identifier.
146 147 148 149 150 151 152 153 154 155 |
# File 'lib/familia/horreum/subclass/management.rb', line 146 def find_by_id(identifier, suffix = nil) suffix ||= self.suffix return nil if identifier.to_s.empty? objkey = dbkey(identifier, suffix) Familia.ld "[.find_by_id] #{self} from key #{objkey})" Familia.trace :FIND_BY_ID, Familia.dbclient(uri), objkey, caller(1..1).first if Familia.debug? find_by_key objkey end |
#find_by_key(objkey) ⇒ Object? Also known as: from_dbkey
Retrieves and instantiates an object from Database using the full object key.
This method performs a two-step process to safely retrieve and instantiate objects:
- It first checks if the key exists in Redis. This is crucial because:
- It provides a definitive answer about the object’s existence.
- It prevents ambiguity that could arise from
hgetall
returning an empty hash for non-existent keys, which could lead to the creation of “empty” objects.
- If the key exists, it retrieves the object’s data and instantiates it.
This approach ensures that we only attempt to instantiate objects that actually exist in Redis, improving reliability and simplifying debugging.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/familia/horreum/subclass/management.rb', line 103 def find_by_key(objkey) raise ArgumentError, 'Empty key' if objkey.to_s.empty? # We use a lower-level method here b/c we're working with the # full key and not just the identifier. does_exist = dbclient.exists(objkey).positive? Familia.ld "[.find_by_key] #{self} from key #{objkey} (exists: #{does_exist})" Familia.trace :FROM_KEY, dbclient, objkey, caller(1..1) if Familia.debug? # This is the reason for calling exists first. We want to definitively # and without any ambiguity know if the object exists in Redis. If it # doesn't, we return nil. If it does, we proceed to load the object. # Otherwise, hgetall will return an empty hash, which will be passed to # the constructor, which will then be annoying to debug. return unless does_exist obj = dbclient.hgetall(objkey) # horreum objects are persisted as database hashes Familia.trace :FROM_KEY2, dbclient, "#{objkey}: #{obj.inspect}", caller(1..1) if Familia.debug? new(**obj) end |
#find_keys(suffix = '*') ⇒ Array<String>
Finds all keys in Database matching the given suffix pattern.
This method searches for all dbkeys that match the given suffix pattern. It uses the class’s dbkey method to construct the search pattern.
221 222 223 |
# File 'lib/familia/horreum/subclass/management.rb', line 221 def find_keys(suffix = '*') dbclient.keys(dbkey('*', suffix)) || [] end |
#matching_keys_count(filter = '*') ⇒ Integer Also known as: size
Returns the number of dbkeys matching the given filter pattern
259 260 261 |
# File 'lib/familia/horreum/subclass/management.rb', line 259 def matching_keys_count(filter = '*') dbclient.keys(dbkey(filter)).compact.size end |
#multiget(*ids) ⇒ Object
62 63 64 65 |
# File 'lib/familia/horreum/subclass/management.rb', line 62 def multiget(*ids) ids = rawmultiget(*ids) ids.filter_map { |json| from_json(json) } end |
#rawmultiget(*ids) ⇒ Object
67 68 69 70 71 72 73 |
# File 'lib/familia/horreum/subclass/management.rb', line 67 def rawmultiget(*ids) ids.collect! { |objid| dbkey(objid) } return [] if ids.compact.empty? Familia.trace :MULTIGET, dbclient, "#{ids.size}: #{ids}", caller(1..1) if Familia.debug? dbclient.mget(*ids) end |