Class: Lotus::Model::Adapters::Memory::Query

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Enumerable
Defined in:
lib/lotus/model/adapters/memory/query.rb

Overview

Query the in-memory database with a powerful API.

All the methods are chainable, it allows advanced composition of conditions.

This works as a lazy filtering mechanism: the records are fetched from the database only when needed.

It implements Ruby’s Enumerable and borrows some methods from Array. Expect a query to act like them.

Examples:


query.where(language: 'ruby')
     .and(framework: 'lotus')
     .desc(:users_count).all

# the records are fetched only when we invoke #all

Since:

  • 0.1.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dataset, collection, &blk) ⇒ Query

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initialize a query

Parameters:

Since:

  • 0.1.0



55
56
57
58
59
60
61
# File 'lib/lotus/model/adapters/memory/query.rb', line 55

def initialize(dataset, collection, &blk)
  @dataset    = dataset
  @collection = collection
  @conditions = []
  @modifiers  = []
  instance_eval(&blk) if block_given?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &blk) ⇒ Object (protected)

Since:

  • 0.1.0



444
445
446
447
448
449
450
# File 'lib/lotus/model/adapters/memory/query.rb', line 444

def method_missing(m, *args, &blk)
  if @context.respond_to?(m)
    apply @context.public_send(m, *args, &blk)
  else
    super
  end
end

Instance Attribute Details

#conditionsObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 0.1.0



38
39
40
# File 'lib/lotus/model/adapters/memory/query.rb', line 38

def conditions
  @conditions
end

#modifiersObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 0.1.0



44
45
46
# File 'lib/lotus/model/adapters/memory/query.rb', line 44

def modifiers
  @modifiers
end

Instance Method Details

#allArray

Resolves the query by fetching records from the database and translating them into entities.

Returns:

  • (Array)

    a collection of entities

Since:

  • 0.1.0



69
70
71
# File 'lib/lotus/model/adapters/memory/query.rb', line 69

def all
  @collection.deserialize(run)
end

#average(column) ⇒ Numeric Also known as: avg

Returns the average of the values for the given column.

Examples:


query.average(:comments_count)

Parameters:

  • column (Symbol)

    the column name

Returns:

  • (Numeric)

Since:

  • 0.1.0



328
329
330
331
332
# File 'lib/lotus/model/adapters/memory/query.rb', line 328

def average(column)
  if s = sum(column)
    s / _all_with_present_column(column).count.to_f
  end
end

#countFixnum

Returns a count of the records for the current conditions.

Examples:


query.where(author_id: 23).count # => 5

Returns:

  • (Fixnum)

Since:

  • 0.1.0



426
427
428
# File 'lib/lotus/model/adapters/memory/query.rb', line 426

def count
  run.count
end

#desc(*columns) ⇒ Object

Specify the descending order of the records, sorted by the given columns.

Examples:

Single column


query.desc(:name)

Multiple columns


query.desc(:name, :year)

Multiple invokations


query.desc(:name).desc(:year)

Parameters:

  • columns (Array<Symbol>)

    the column names

Returns:

  • self

See Also:

Since:

  • 0.1.0



252
253
254
255
256
257
258
# File 'lib/lotus/model/adapters/memory/query.rb', line 252

def desc(*columns)
  Lotus::Utils::Kernel.Array(columns).each do |column|
    modifiers.push(Proc.new{ sort_by!{|r| r.fetch(column)}.reverse! })
  end

  self
end

#exclude(condition) ⇒ Object Also known as: not

Logical negation of a #where condition.

It accepts a Hash with only one pair. The key must be the name of the column expressed as a Symbol. The value is the one used by the internal filtering logic.

Examples:

Fixed value


query.exclude(language: 'java')

Array


query.exclude(id: [4, 9])

Range


query.exclude(year: 1900..1982)

Multiple conditions


query.exclude(language: 'java')
     .exclude(company: 'enterprise')

Parameters:

  • condition (Hash)

Returns:

  • self

Since:

  • 0.1.0



168
169
170
171
172
# File 'lib/lotus/model/adapters/memory/query.rb', line 168

def exclude(condition)
  column, value = _expand_condition(condition)
  conditions.push([:where, Proc.new{ reject {|r| r.fetch(column) == value} }])
  self
end

#exist?TrueClass, FalseClass

Checks if at least one record exists for the current conditions.

Examples:


query.where(author_id: 23).exists? # => true

Returns:

  • (TrueClass, FalseClass)

Since:

  • 0.1.0



413
414
415
# File 'lib/lotus/model/adapters/memory/query.rb', line 413

def exist?
  !count.zero?
end

#interval(column) ⇒ Numeric

Returns the difference between the MAX and MIN for the given column.

Examples:


query.interval(:comments_count)

Parameters:

  • column (Symbol)

    the column name

Returns:

  • (Numeric)

See Also:

Since:

  • 0.1.0



380
381
382
383
# File 'lib/lotus/model/adapters/memory/query.rb', line 380

def interval(column)
  max(column) - min(column)
rescue NoMethodError
end

#limit(number) ⇒ Object

Limit the number of records to return.

Examples:


query.limit(1)

Parameters:

  • number (Fixnum)

Returns:

  • self

Since:

  • 0.1.0



271
272
273
274
# File 'lib/lotus/model/adapters/memory/query.rb', line 271

def limit(number)
  modifiers.push(Proc.new{ replace(flatten.first(number)) })
  self
end

#max(column) ⇒ Object

Returns the maximum value for the given column.

Examples:


query.max(:comments_count)

Parameters:

  • column (Symbol)

    the column name

Returns:

  • result

Since:

  • 0.1.0



347
348
349
# File 'lib/lotus/model/adapters/memory/query.rb', line 347

def max(column)
  _all_with_present_column(column).max
end

#min(column) ⇒ Object

Returns the minimum value for the given column.

Examples:


query.min(:comments_count)

Parameters:

  • column (Symbol)

    the column name

Returns:

  • result

Since:

  • 0.1.0



362
363
364
# File 'lib/lotus/model/adapters/memory/query.rb', line 362

def min(column)
  _all_with_present_column(column).min
end

#negate!Object

This method is defined in order to make the interface of Memory::Query identical to Sql::Query, but this feature is NOT implemented

Raises:

  • (NotImplementedError)

See Also:

Since:

  • 0.1.0



439
440
441
# File 'lib/lotus/model/adapters/memory/query.rb', line 439

def negate!
  raise NotImplementedError
end

#offset(number) ⇒ Object

Simulate an OFFSET clause, without the need of specify a limit.

Examples:


query.offset(10)

Parameters:

  • number (Fixnum)

Returns:

  • self

Since:

  • 0.1.0



287
288
289
290
# File 'lib/lotus/model/adapters/memory/query.rb', line 287

def offset(number)
  modifiers.unshift(Proc.new{ replace(flatten.drop(number)) })
  self
end

#or(condition = nil, &blk) ⇒ Object

Adds a condition that behaves like SQL OR.

It accepts a Hash with only one pair. The key must be the name of the column expressed as a Symbol. The value is the one used by the SQL query

This condition will be ignored if not used with WHERE.

Examples:

Fixed value


query.where(language: 'ruby').or(framework: 'lotus')

Array


query.where(id: 1).or(author_id: [15, 23])

Range


query.where(country: 'italy').or(year: 1900..1982)

Parameters:

  • condition (Hash) (defaults to: nil)

Returns:

  • self

Since:

  • 0.1.0



134
135
136
137
138
# File 'lib/lotus/model/adapters/memory/query.rb', line 134

def or(condition=nil, &blk)
  column, value = _expand_condition(condition)
  conditions.push([:or, Proc.new{ find_all{|r| r.fetch(column) == value} }])
  self
end

#order(*columns) ⇒ Object Also known as: asc

Specify the ascending order of the records, sorted by the given columns.

Examples:

Single column


query.order(:name)

Multiple columns


query.order(:name, :year)

Multiple invokations


query.order(:name).order(:year)

Parameters:

  • columns (Array<Symbol>)

    the column names

Returns:

  • self

See Also:

Since:

  • 0.1.0



220
221
222
223
224
225
226
# File 'lib/lotus/model/adapters/memory/query.rb', line 220

def order(*columns)
  Lotus::Utils::Kernel.Array(columns).each do |column|
    modifiers.push(Proc.new{ sort_by!{|r| r.fetch(column)} })
  end

  self
end

#range(column) ⇒ Range

Returns a range of values between the MAX and the MIN for the given column.

Examples:


query.range(:comments_count)

Parameters:

  • column (Symbol)

    the column name

Returns:

  • (Range)

See Also:

Since:

  • 0.1.0



400
401
402
# File 'lib/lotus/model/adapters/memory/query.rb', line 400

def range(column)
  min(column)..max(column)
end

#select(*columns) ⇒ Object

Select only the specified columns.

By default a query selects all the mapped columns.

Examples:

Single column


query.select(:name)

Multiple columns


query.select(:name, :year)

Parameters:

  • columns (Array<Symbol>)

Returns:

  • self

Since:

  • 0.1.0



193
194
195
196
# File 'lib/lotus/model/adapters/memory/query.rb', line 193

def select(*columns)
  columns = Lotus::Utils::Kernel.Array(columns)
  modifiers.push(Proc.new{ flatten!; each {|r| r.delete_if {|k,_| !columns.include?(k)} } })
end

#sum(column) ⇒ Numeric

Returns the sum of the values for the given column.

Examples:


query.sum(:comments_count)

Parameters:

  • column (Symbol)

    the column name

Returns:

  • (Numeric)

Since:

  • 0.1.0



303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/lotus/model/adapters/memory/query.rb', line 303

def sum(column)
  result = all

  if result.any?
    result.inject(0.0) do |acc, record|
      if value = record.public_send(column)
        acc += value
      end

      acc
    end
  end
end

#where(condition) ⇒ Object Also known as: and

Adds a condition that behaves like SQL WHERE.

It accepts a Hash with only one pair. The key must be the name of the column expressed as a Symbol. The value is the one used by the internal filtering logic.

Examples:

Fixed value


query.where(language: 'ruby')

Array


query.where(id: [1, 3])

Range


query.where(year: 1900..1982)

Multiple conditions


query.where(language: 'ruby')
     .where(framework: 'lotus')

Parameters:

  • condition (Hash)

Returns:

  • self

Since:

  • 0.1.0



101
102
103
104
105
# File 'lib/lotus/model/adapters/memory/query.rb', line 101

def where(condition)
  column, value = _expand_condition(condition)
  conditions.push([:where, Proc.new{ find_all{|r| r.fetch(column) == value} }])
  self
end