Module: Familia::Features::Relationships::Membership::ClassMethods

Defined in:
lib/familia/features/relationships/membership.rb

Instance Method Summary collapse

Instance Method Details

#member_of(owner_class, collection_name, score: nil, type: :sorted_set) ⇒ Object

Define a member_of relationship

Examples:

Basic membership

member_of Customer, :domains

Membership with scoring

member_of Team, :projects, score: -> { permission_encode(Time.now, permission_level) }

Parameters:

  • owner_class (Class)

    The class that owns the collection

  • collection_name (Symbol)

    Name of the collection on the owner

  • score (Symbol, Proc, nil) (defaults to: nil)

    How to calculate the score for sorted sets

  • type (Symbol) (defaults to: :sorted_set)

    Type of Redis collection (:sorted_set, :set, :list)



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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
107
108
# File 'lib/familia/features/relationships/membership.rb', line 29

def member_of(owner_class, collection_name, score: nil, type: :sorted_set)
  owner_class_name = owner_class.is_a?(Class) ? owner_class.name : owner_class.to_s.camelize

  # Store metadata for this membership relationship
  membership_relationships << {
    owner_class: owner_class,
    owner_class_name: owner_class_name,
    collection_name: collection_name,
    score: score,
    type: type
  }

  # Generate instance methods with collision-free naming
  owner_class_name_lower = owner_class_name.downcase

  # Method to add this object to the owner's collection
  # e.g., domain.add_to_customer_domains(customer)
  define_method("add_to_#{owner_class_name_lower}_#{collection_name}") do |owner_instance, score = nil|
    collection_key = "#{owner_class_name_lower}:#{owner_instance.identifier}:#{collection_name}"

    case type
    when :sorted_set
      score ||= calculate_membership_score(owner_class, collection_name)
      dbclient.zadd(collection_key, score, identifier)
    when :set
      dbclient.sadd(collection_key, identifier)
    when :list
      dbclient.lpush(collection_key, identifier)
    end
  end

  # Method to remove this object from the owner's collection
  # e.g., domain.remove_from_customer_domains(customer)
  define_method("remove_from_#{owner_class_name_lower}_#{collection_name}") do |owner_instance|
    collection_key = "#{owner_class_name_lower}:#{owner_instance.identifier}:#{collection_name}"

    case type
    when :sorted_set
      dbclient.zrem(collection_key, identifier)
    when :set
      dbclient.srem(collection_key, identifier)
    when :list
      dbclient.lrem(collection_key, 0, identifier)
    end
  end

  # Method to check if this object is in the owner's collection
  # e.g., domain.in_customer_domains?(customer)
  define_method("in_#{owner_class_name_lower}_#{collection_name}?") do |owner_instance|
    collection_key = "#{owner_class_name_lower}:#{owner_instance.identifier}:#{collection_name}"

    case type
    when :sorted_set
      !dbclient.zscore(collection_key, identifier).nil?
    when :set
      dbclient.sismember(collection_key, identifier)
    when :list
      dbclient.lpos(collection_key, identifier) != nil
    end
  end

  # Method to get score in the owner's collection (for sorted sets)
  # e.g., domain.score_in_customer_domains(customer)
  if type == :sorted_set
    define_method("score_in_#{owner_class_name_lower}_#{collection_name}") do |owner_instance|
      collection_key = "#{owner_class_name_lower}:#{owner_instance.identifier}:#{collection_name}"
      dbclient.zscore(collection_key, identifier)
    end
  end

  # Method to get position in the owner's collection (for lists)
  # e.g., domain.position_in_customer_domain_list(customer)
  return unless type == :list

  define_method("position_in_#{owner_class_name_lower}_#{collection_name}") do |owner_instance|
    collection_key = "#{owner_class_name_lower}:#{owner_instance.identifier}:#{collection_name}"
    position = dbclient.lpos(collection_key, identifier)
    position
  end
end

#membership_relationshipsObject

Get all membership relationships for this class



111
112
113
# File 'lib/familia/features/relationships/membership.rb', line 111

def membership_relationships
  @membership_relationships ||= []
end