Module: Familia::Features::Relationships::TargetMethods::Builder
- Extended by:
- CollectionOperations
- Defined in:
- lib/familia/features/relationships/participation/target_methods.rb
Overview
Visual Guide for methods added to TARGET instances:
When Domain calls: participates_in Customer, :domains
Customer instances (TARGET) get these methods: ├── domains # Get the domains collection ├── add_domain(domain, score) # Add a domain to my collection ├── remove_domain(domain) # Remove a domain from my collection ├── add_domains([...]) # Bulk add domains └── domains_with_permission(level) # Query with score filtering (sorted_set only)
Class Method Summary collapse
-
.build(target_class, collection_name, type) ⇒ Object
Build all target methods for a participation relationship.
-
.build_add_item(target_class, collection_name, type) ⇒ Object
Build method to add an item to the collection Creates: customer.add_domains_instance(domain, score).
-
.build_bulk_add(target_class, collection_name, type) ⇒ Object
Build method for bulk adding items Creates: customer.add_domains([domain1, domain2, ...]).
-
.build_class_add_method(target_class, collection_name, type) ⇒ Object
Build class-level add method Creates: User.add_to_all_users(user, score).
-
.build_class_collection_getter(target_class, collection_name, type) ⇒ Object
Build class-level collection getter Creates: User.all_users (class method).
-
.build_class_level(target_class, collection_name, type) ⇒ Object
Build class-level collection methods (for class_participates_in).
-
.build_class_remove_method(target_class, collection_name) ⇒ Object
Build class-level remove method Creates: User.remove_from_all_users(user).
-
.build_collection_getter(target_class, collection_name, type) ⇒ Object
Build method to get the collection Creates: customer.domains.
-
.build_permission_query(target_class, collection_name) ⇒ Object
Build permission query for sorted sets Creates: customer.domains_with_permission(min_level).
-
.build_remove_item(target_class, collection_name, type) ⇒ Object
Build method to remove an item from the collection Creates: customer.remove_domains_instance(domain).
Methods included from CollectionOperations
add_to_collection, bulk_add_to_collection, ensure_collection_field, member_of_collection?, remove_from_collection
Class Method Details
.build(target_class, collection_name, type) ⇒ Object
Build all target methods for a participation relationship
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 37 def self.build(target_class, collection_name, type) # FIRST: Ensure the DataType field is defined on the target class TargetMethods::Builder.ensure_collection_field(target_class, collection_name, type) # Core target methods build_collection_getter(target_class, collection_name, type) build_add_item(target_class, collection_name, type) build_remove_item(target_class, collection_name, type) build_bulk_add(target_class, collection_name, type) # Type-specific methods return unless type == :sorted_set (target_class, collection_name) end |
.build_add_item(target_class, collection_name, type) ⇒ Object
Build method to add an item to the collection Creates: customer.add_domains_instance(domain, score)
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 78 def self.build_add_item(target_class, collection_name, type) method_name = "add_#{collection_name}_instance" target_class.define_method(method_name) do |item, score = nil| collection = send(collection_name) # Calculate score if needed and not provided if type == :sorted_set && score.nil? && item.respond_to?(:calculate_participation_score) score = item.calculate_participation_score(self.class, collection_name) end # Use transaction for atomicity between collection add and reverse index tracking # All operations use Horreum's DataType methods (not direct Redis calls) transaction do |_tx| # Add to collection using DataType method (ZADD/SADD/RPUSH) TargetMethods::Builder.add_to_collection( collection, item, score: score, type: type, target_class: self.class, collection_name: collection_name, ) # Track participation in reverse index using DataType method (SADD) item.track_participation_in(collection.dbkey) if item.respond_to?(:track_participation_in) end end end |
.build_bulk_add(target_class, collection_name, type) ⇒ Object
Build method for bulk adding items Creates: customer.add_domains([domain1, domain2, ...])
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 130 def self.build_bulk_add(target_class, collection_name, type) method_name = "add_#{collection_name}" target_class.define_method(method_name) do |items| return if items.empty? collection = send(collection_name) # Use transaction for atomicity across all bulk additions and reverse index tracking # All operations use Horreum's DataType methods (not direct Redis calls) transaction do |_tx| # Bulk add to collection using DataType methods (multiple ZADD/SADD/RPUSH) TargetMethods::Builder.bulk_add_to_collection(collection, items, type: type, target_class: self.class, collection_name: collection_name) # Track all participations using DataType methods (multiple SADD) items.each do |item| item.track_participation_in(collection.dbkey) if item.respond_to?(:track_participation_in) end end end end |
.build_class_add_method(target_class, collection_name, type) ⇒ Object
Build class-level add method Creates: User.add_to_all_users(user, score)
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 183 def self.build_class_add_method(target_class, collection_name, type) method_name = "add_to_#{collection_name}" target_class.define_singleton_method(method_name) do |item, score = nil| collection = send(collection_name.to_s) # Calculate score if needed if type == :sorted_set && score.nil? score = if item.respond_to?(:calculate_participation_score) item.calculate_participation_score('class', collection_name) elsif item.respond_to?(:current_score) item.current_score else Familia.now.to_f end end TargetMethods::Builder.add_to_collection( collection, item, score: score, type: type, target_class: self.class, collection_name: collection_name, ) end end |
.build_class_collection_getter(target_class, collection_name, type) ⇒ Object
Build class-level collection getter Creates: User.all_users (class method)
174 175 176 177 178 179 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 174 def self.build_class_collection_getter(target_class, collection_name, type) # No need to define the method - Horreum automatically creates it # when we call class_#{type} above. This method is kept for # backwards compatibility but now does nothing. # The field definition (class_sorted_set :all_users) creates the accessor automatically. end |
.build_class_level(target_class, collection_name, type) ⇒ Object
Build class-level collection methods (for class_participates_in)
57 58 59 60 61 62 63 64 65 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 57 def self.build_class_level(target_class, collection_name, type) # FIRST: Ensure the class-level DataType field is defined target_class.send("class_#{type}", collection_name) # Class-level collection getter (e.g., User.all_users) build_class_collection_getter(target_class, collection_name, type) build_class_add_method(target_class, collection_name, type) build_class_remove_method(target_class, collection_name) end |
.build_class_remove_method(target_class, collection_name) ⇒ Object
Build class-level remove method Creates: User.remove_from_all_users(user)
213 214 215 216 217 218 219 220 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 213 def self.build_class_remove_method(target_class, collection_name) method_name = "remove_from_#{collection_name}" target_class.define_singleton_method(method_name) do |item| collection = send(collection_name.to_s) TargetMethods::Builder.remove_from_collection(collection, item) end end |
.build_collection_getter(target_class, collection_name, type) ⇒ Object
Build method to get the collection Creates: customer.domains
69 70 71 72 73 74 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 69 def self.build_collection_getter(target_class, collection_name, type) # No need to define the method - Horreum automatically creates it # when we call ensure_collection_field above. This method is # kept for backwards compatibility but now does nothing. # The field definition (sorted_set :domains) creates the accessor automatically. end |
.build_permission_query(target_class, collection_name) ⇒ Object
Build permission query for sorted sets Creates: customer.domains_with_permission(min_level)
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 155 def self.(target_class, collection_name) method_name = "#{collection_name}_with_permission" target_class.define_method(method_name) do | = :read| collection = send(collection_name) # Assumes ScoreEncoding module is available if defined?(ScoreEncoding) = ScoreEncoding.(0, ) collection.zrangebyscore(, '+inf', with_scores: true) else # Fallback to all members if ScoreEncoding not available collection.members(with_scores: true) end end end |
.build_remove_item(target_class, collection_name, type) ⇒ Object
Build method to remove an item from the collection Creates: customer.remove_domains_instance(domain)
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/familia/features/relationships/participation/target_methods.rb', line 110 def self.build_remove_item(target_class, collection_name, type) method_name = "remove_#{collection_name}_instance" target_class.define_method(method_name) do |item| collection = send(collection_name) # Use transaction for atomicity between collection remove and reverse index untracking # All operations use Horreum's DataType methods (not direct Redis calls) transaction do |_tx| # Remove from collection using DataType method (ZREM/SREM/LREM) TargetMethods::Builder.remove_from_collection(collection, item, type: type) # Remove from participation tracking using DataType method (SREM) item.untrack_participation_in(collection.dbkey) if item.respond_to?(:untrack_participation_in) end end end |