Class: ActiveHash::Relation

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/active_hash/relation.rb

Defined Under Namespace

Classes: Condition, Conditions, WhereChain

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass, all_records, conditions = nil, order_values = nil) ⇒ Relation

Returns a new instance of Relation.



14
15
16
17
18
19
# File 'lib/active_hash/relation.rb', line 14

def initialize(klass, all_records, conditions = nil, order_values = nil)
  self.klass = klass
  self.all_records = all_records
  self.conditions = Conditions.wrap(conditions || [])
  self.order_values = order_values || []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args) ⇒ Object



185
186
187
188
189
# File 'lib/active_hash/relation.rb', line 185

def method_missing(method_name, *args)
  return super unless klass.scopes&.key?(method_name)

  instance_exec(*args, &klass.scopes[method_name])
end

Instance Attribute Details

#all_recordsObject

Returns the value of attribute all_records.



12
13
14
# File 'lib/active_hash/relation.rb', line 12

def all_records
  @all_records
end

#conditionsObject

Returns the value of attribute conditions.



12
13
14
# File 'lib/active_hash/relation.rb', line 12

def conditions
  @conditions
end

#klassObject

Returns the value of attribute klass.



12
13
14
# File 'lib/active_hash/relation.rb', line 12

def klass
  @klass
end

#order_valuesObject

Returns the value of attribute order_values.



12
13
14
# File 'lib/active_hash/relation.rb', line 12

def order_values
  @order_values
end

Instance Method Details

#all(options = {}) ⇒ Object



113
114
115
116
117
118
119
# File 'lib/active_hash/relation.rb', line 113

def all(options = {})
  if options.key?(:conditions)
    where(options[:conditions])
  else
    where({})
  end
end

#countObject



155
156
157
158
# File 'lib/active_hash/relation.rb', line 155

def count
  return super if block_given?
  length
end

#find(id = nil, *args, &block) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/active_hash/relation.rb', line 129

def find(id = nil, *args, &block)
  case id
    when :all
      all
    when :first
      all(*args).first
    when Array
      id.map { |i| find(i) }
    when nil
      raise RecordNotFound.new("Couldn't find #{klass.name} without an ID", klass.name, "id") unless block_given?
      records.find(&block) # delegate to Enumerable#find if a block is given
    else
      find_by_id(id) || begin
        raise RecordNotFound.new("Couldn't find #{klass.name} with ID=#{id}", klass.name, "id", id)
      end
  end
end

#find_by(options) ⇒ Object



121
122
123
# File 'lib/active_hash/relation.rb', line 121

def find_by(options)
  where(options).first
end

#find_by!(options) ⇒ Object



125
126
127
# File 'lib/active_hash/relation.rb', line 125

def find_by!(options)
  find_by(options) || (raise RecordNotFound.new("Couldn't find #{klass.name}", klass.name))
end

#find_by_id(id) ⇒ Object



147
148
149
150
151
152
153
# File 'lib/active_hash/relation.rb', line 147

def find_by_id(id)
  index = klass.send(:record_index)[id.to_s] # TODO: Make index in Base publicly readable instead of using send?
  return unless index

  record = all_records[index]
  record if conditions.matches?(record)
end

#idsObject



173
174
175
# File 'lib/active_hash/relation.rb', line 173

def ids
  pluck(:id)
end

#invert_whereObject



73
74
75
# File 'lib/active_hash/relation.rb', line 73

def invert_where
  spawn.invert_where!
end

#invert_where!Object



77
78
79
80
# File 'lib/active_hash/relation.rb', line 77

def invert_where!
  conditions.map(&:invert!)
  self
end

#or(other) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/active_hash/relation.rb', line 27

def or(other)
  unless other.is_a?(self.class)
    raise ArgumentError, "or() expects an ActiveHash::Relation"
  end

  unless other.klass == klass
    raise ArgumentError, "or() expects relations for the same model"
  end

  merged = (records + other.records).uniq do |record|
    record.respond_to?(:id) ? record.id : record.object_id
  end

  self.class.new(klass, merged, [], order_values)
end

#order(*options) ⇒ Object



60
61
62
# File 'lib/active_hash/relation.rb', line 60

def order(*options)
  spawn.order!(*options)
end

#order!(*options) ⇒ Object



86
87
88
89
90
# File 'lib/active_hash/relation.rb', line 86

def order!(*options)
  check_if_method_has_arguments!(:order, options)
  self.order_values += preprocess_order_args(options)
  self
end

#pick(*column_names) ⇒ Object



177
178
179
# File 'lib/active_hash/relation.rb', line 177

def pick(*column_names)
  pluck(*column_names).first
end

#pluck(*column_names) ⇒ Object



164
165
166
167
168
169
170
171
# File 'lib/active_hash/relation.rb', line 164

def pluck(*column_names)
  if column_names.length == 1
    column_name = column_names.first
    all.map { |record| record.public_send(column_name) }
  else
    all.map { |record| column_names.map { |column_name| record.public_send(column_name) } }
  end
end

#pretty_print(pp) ⇒ Object



43
44
45
# File 'lib/active_hash/relation.rb', line 43

def pretty_print(pp)
  pp.pp(entries.to_ary)
end

#recordsObject



101
102
103
104
105
106
# File 'lib/active_hash/relation.rb', line 101

def records
  @records ||= begin
    filtered_records = apply_conditions(all_records, conditions)
    ordered_records = apply_order_values(filtered_records, order_values) # rubocop:disable Lint/UselessAssignment
  end
end

#reloadObject



108
109
110
111
# File 'lib/active_hash/relation.rb', line 108

def reload
  @records = nil # Reset records
  self
end

#reorder(*options) ⇒ Object



64
65
66
# File 'lib/active_hash/relation.rb', line 64

def reorder(*options)
  spawn.reorder!(*options)
end

#reorder!(*options) ⇒ Object



92
93
94
95
96
97
98
99
# File 'lib/active_hash/relation.rb', line 92

def reorder!(*options)
  check_if_method_has_arguments!(:order, options)

  self.order_values = preprocess_order_args(options)
  @records = apply_order_values(records, order_values)

  self
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


191
192
193
# File 'lib/active_hash/relation.rb', line 191

def respond_to_missing?(method_name, include_private = false)
  klass.scopes&.key?(method_name) || super
end

#sizeObject



160
161
162
# File 'lib/active_hash/relation.rb', line 160

def size
  length
end

#spawnObject



82
83
84
# File 'lib/active_hash/relation.rb', line 82

def spawn
  self.class.new(klass, all_records, conditions, order_values)
end

#to_aryObject



181
182
183
# File 'lib/active_hash/relation.rb', line 181

def to_ary
  records.dup
end

#where(conditions_hash = :chain) ⇒ Object



21
22
23
24
25
# File 'lib/active_hash/relation.rb', line 21

def where(conditions_hash = :chain)
  return WhereChain.new(self) if conditions_hash == :chain

  spawn.where!(conditions_hash)
end

#where!(conditions_hash, inverted = false) ⇒ Object



68
69
70
71
# File 'lib/active_hash/relation.rb', line 68

def where!(conditions_hash, inverted = false)
  self.conditions << Condition.new(conditions_hash)
  self
end