Module: ActiveMocker::Mock::Queries

Included in:
Base, HasMany, Relation
Defined in:
lib/active_mocker/mock/queries.rb

Defined Under Namespace

Classes: Find, WhereNotChain

Instance Method Summary collapse

Instance Method Details

#allObject



320
321
322
# File 'lib/active_mocker/mock/queries.rb', line 320

def all
  new_relation(to_a || [])
end

#average(key) ⇒ Object

Calculates the average value on a given column. Returns nil if there’s no row.

PersonMock.average(:age) # => 35.8


282
283
284
285
286
# File 'lib/active_mocker/mock/queries.rb', line 282

def average(key)
  values = values_by_key(key)
  total = values.inject { |sum, n| sum + n }
  BigDecimal.new(total) / BigDecimal.new(values.count)
end

#count(column_name = nil) ⇒ Object

Count the records.

PersonMock.count
# => the total count of all people

PersonMock.count(:age)
# => returns the total count of all people whose age is present in database


253
254
255
256
# File 'lib/active_mocker/mock/queries.rb', line 253

def count(column_name = nil)
  return all.size if column_name.nil?
  where.not(column_name => nil).size
end

#delete_all(conditions = nil) ⇒ Object Also known as: destroy_all

Deletes the records matching conditions by instantiating each record and calling its delete method.

Parameters

  • conditions - A string, array, or hash that specifies which records to destroy. If omitted, all records are destroyed.

Examples

PersonMock.destroy_all(status: "inactive")
PersonMock.where(age: 0..18).destroy_all

If a limit scope is supplied, delete_all raises an ActiveMocker error:

Post.limit(100).delete_all
# => ActiveMocker::Mock::Error: delete_all doesn't support limit scope


65
66
67
68
69
70
71
72
# File 'lib/active_mocker/mock/queries.rb', line 65

def delete_all(conditions=nil)
  raise ActiveMocker::Mock::Error.new("delete_all doesn't support limit scope") if from_limit?
  if conditions.nil?
    to_a.map(&:delete)
    return to_a.clear
  end
  where(conditions).map { |r| r.delete }.count
end

#find(ids) ⇒ Object

Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key is an integer, find by id coerces its arguments using to_i.

Person.find(1)          # returns the object for ID = 1
Person.find(1, 2, 6)    # returns an array for objects with IDs in (1, 2, 6)
Person.find([7, 17])    # returns an array for objects with IDs in (7, 17)
Person.find([1])        # returns an array for the object with ID = 1

ActiveMocker::Mock::RecordNotFound will be raised if one or more ids are not found.

Raises:



135
136
137
138
139
140
141
142
# File 'lib/active_mocker/mock/queries.rb', line 135

def find(ids)
  raise RecordNotFound.new("Couldn't find #{self.name} without an ID") if ids.nil?
  results = [*ids].map do |id|
    find_by!(id: id.to_i)
  end
  return new_relation(results) if ids.class == Array
  results.first
end

#find_by(conditions = {}) ⇒ Object

Finds the first record matching the specified conditions. There is no implied ordering so if order matters, you should specify it yourself.

If no record is found, returns nil.

Post.find_by name: 'Spartacus', rating: 4


197
198
199
200
201
# File 'lib/active_mocker/mock/queries.rb', line 197

def find_by(conditions = {})
  to_a.detect do |record|
    Find.new(record).is_of(conditions)
  end
end

#find_by!(conditions = {}) ⇒ Object

Like find_by, except that if no record is found, raises an ActiveRecord::RecordNotFound error.



205
206
207
208
209
210
211
# File 'lib/active_mocker/mock/queries.rb', line 205

def find_by!(conditions={})
  result = find_by(conditions)
  if result.nil?
    raise RecordNotFound.new("Couldn't find #{self.name} with '#{conditions.keys.first}'=#{conditions.values.first}")
  end
  result
end

#find_or_create_by(attributes, &block) ⇒ Object Also known as: find_or_create_by!

Finds the first record with the given attributes, or creates a record with the attributes if one is not found:

# Find the first user named "Penélope" or create a new one.
UserMock.find_or_create_by(first_name: 'Penélope')
# => #<User id: 1, first_name: "Penélope", last_name: nil>

# Find the first user named "Penélope" or create a new one.
# We already have one so the existing record will be returned.
UserMock.find_or_create_by(first_name: 'Penélope')
# => #<User id: 1, first_name: "Penélope", last_name: nil>

This method accepts a block, which is passed down to create. The last example above can be alternatively written this way:

# Find the first user named "Scarlett" or create a new one with a
# different last name.
User.find_or_create_by(first_name: 'Scarlett') do |user|
  user.last_name = 'Johansson'
end
# => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">


235
236
237
# File 'lib/active_mocker/mock/queries.rb', line 235

def find_or_create_by(attributes, &block)
  find_by(attributes) || create(attributes, &block)
end

#find_or_initialize_by(attributes, &block) ⇒ Object

Like find_or_create_by, but calls new instead of create.



242
243
244
# File 'lib/active_mocker/mock/queries.rb', line 242

def find_or_initialize_by(attributes, &block)
  find_by(attributes) || new(attributes, &block)
end

#limit(num) ⇒ Object

Specifies a limit for the number of records to retrieve.

User.limit(10)


261
262
263
264
265
# File 'lib/active_mocker/mock/queries.rb', line 261

def limit(num)
  relation = new_relation(all.take(num))
  relation.send(:set_from_limit)
  relation
end

#maximum(key) ⇒ Object

Calculates the maximum value on a given column. The value is returned with the same data type of the column, or nil if there’s no row.

Person.maximum(:age) # => 93


300
301
302
# File 'lib/active_mocker/mock/queries.rb', line 300

def maximum(key)
  values_by_key(key).max_by { |i| i }
end

#minimum(key) ⇒ Object

Calculates the minimum value on a given column. The value is returned with the same data type of the column, or nil if there’s no row.

Person.minimum(:age) # => 7


292
293
294
# File 'lib/active_mocker/mock/queries.rb', line 292

def minimum(key)
  values_by_key(key).min_by { |i| i }
end

#noneObject

Returns a chainable relation with zero records.

Any subsequent condition chained to the returned relation will continue generating an empty relation.

Used in cases where a method or scope could return zero records but the result needs to be chainable.

For example:

@posts = current_user.visible_posts.where(name: params[:name])
# => the visible_posts method is expected to return a chainable Relation

def visible_posts
  case role
  when 'Country Manager'
    Post.where(country: country)
  when 'Reviewer'
    Post.published
  when 'Bad User'
    Post.none # It can't be chained if [] is returned.
  end
end


348
349
350
# File 'lib/active_mocker/mock/queries.rb', line 348

def none
  new_relation([])
end

#order(key) ⇒ Object

Allows to specify an order attribute:

User.order('name')

User.order(:name)


309
310
311
# File 'lib/active_mocker/mock/queries.rb', line 309

def order(key)
  new_relation(all.sort_by { |item| item.send(key) })
end

#reverse_orderObject

Reverse the existing order clause on the relation.

User.order('name').reverse_order


316
317
318
# File 'lib/active_mocker/mock/queries.rb', line 316

def reverse_order
  new_relation(to_a.reverse)
end

#sum(key) ⇒ Object

Calculates the sum of values on a given column. The value is returned with the same data type of the column, 0 if there’s no row.

Person.sum(:age) # => 4562


271
272
273
274
275
276
# File 'lib/active_mocker/mock/queries.rb', line 271

def sum(key)
  values = values_by_key(key)
  values.inject(0) do |sum, n|
    sum + (n || 0)
  end
end

#update(id, attributes) ⇒ Object

Updates an object (or multiple objects) and saves it.

Parameters

  • id - This should be the id or an array of ids to be updated.

  • attributes - This should be a hash of attributes or an array of hashes.

Examples

# Updates one record
Person.update(15, user_name: 'Samuel', group: 'expert')

# Updates multiple records
people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
Person.update(people.keys, people.values)


180
181
182
183
184
185
186
187
188
# File 'lib/active_mocker/mock/queries.rb', line 180

def update(id, attributes)
  if id.is_a?(Array)
    id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
  else
    object = find(id)
    object.update(attributes)
    object
  end
end

#update_all(attributes) ⇒ Object

Updates all records with details given if they match a set of conditions supplied, limits and order can also be supplied.

Parameters

  • updates - A string, array, or hash.

Examples

# Update all customers with the given attributes
Customer.update_all wants_email: true

# Update all books with 'Rails' in their title
BookMock.where(title: 'Rails').update_all(author: 'David')

# Update all books that match conditions, but limit it to 5 ordered by date
BookMock.where(title: 'Rails').order(:created_at).limit(5).update_all(author: 'David')


161
162
163
# File 'lib/active_mocker/mock/queries.rb', line 161

def update_all(attributes)
  all.each { |i| i.update(attributes) }
end

#where(conditions = nil) ⇒ Object

Returns a new relation, which is the result of filtering the current relation according to the conditions in the arguments.

hash

#where will accept a hash condition, in which the keys are fields and the values are values to be searched for.

Fields can be symbols or strings. Values can be single values, arrays, or ranges.

User.where({ name: "Joe", email: "[email protected]" })

User.where({ name: ["Alice", "Bob"]})

User.where({ created_at: (Time.now.midnight - 1.day)..Time.now.midnight })

In the case of a belongs_to relationship, an association key can be used to specify the model if an ActiveRecord object is used as the value.

author = Author.find(1)

# The following queries will be equivalent:
Post.where(author: author)
Post.where(author_id: author)

This also works with polymorphic belongs_to relationships:

treasure = Treasure.create(name: 'gold coins')
treasure.price_estimates << PriceEstimate.create(price: 125)

# The following queries will be equivalent:
PriceEstimate.where(estimate_of: treasure)
PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: treasure)

no argument

If no argument is passed, #where returns a new instance of WhereChain, that can be chained with #not to return a new relation that negates the where clause.

User.where.not(name: "Jon")

See WhereChain for more details on #not.



118
119
120
121
122
123
# File 'lib/active_mocker/mock/queries.rb', line 118

def where(conditions=nil)
  return WhereNotChain.new(all, method(:new_relation)) if conditions.nil?
  new_relation(to_a.select do |record|
    Find.new(record).is_of(conditions)
  end)
end