Class: Mongory::QueryBuilder

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Utils
Defined in:
lib/mongory/query_builder.rb

Overview

QueryBuilder provides a Mongo-like in-memory query interface.

It supports condition chaining (where, or, not), limiting, and plucking fields.

Internally it compiles all conditions and invokes QueryMatcher.

Examples:

Basic query

records.mongory
  .where(:age.gte => 18)
  .or({ :name => /J/ }, { :name.eq => 'Bob' })
  .limit(2)
  .to_a

Complex query

records.mongory
  .where(:status => 'active')
  .not(:age.lt => 18)
  .any_of({ :role => 'admin' }, { :role => 'moderator' })
  .pluck(:name, :email)

Instance Method Summary collapse

Methods included from Utils

included, included_classes, #is_blank?, #is_present?

Constructor Details

#initialize(records, context: Utils::Context.new) ⇒ QueryBuilder

Initializes a new query builder with the given record set.

Parameters:

  • records (Enumerable)

    the collection to query against



33
34
35
36
37
# File 'lib/mongory/query_builder.rb', line 33

def initialize(records, context: Utils::Context.new)
  @records = records
  @context = context
  set_matcher
end

Instance Method Details

#and(*conditions) ⇒ QueryBuilder

Adds one or more conditions combined with $and. All conditions must match for a record to be included.

Parameters:

  • conditions (Array<Hash>)

    the conditions to add

Returns:



95
96
97
98
99
# File 'lib/mongory/query_builder.rb', line 95

def and(*conditions)
  dup_instance_exec do
    add_conditions('$and', conditions)
  end
end

#any_of(*conditions) ⇒ QueryBuilder

Adds a $or query combined inside an $and block. This is a semantic alias for .and('$or' => [...])

Parameters:

  • conditions (Array<Hash>)

    the conditions to add

Returns:



122
123
124
# File 'lib/mongory/query_builder.rb', line 122

def any_of(*conditions)
  self.and('$or' => conditions)
end

#each {|record| ... } ⇒ Enumerator, void

Iterates through all records that match the current matcher. Uses the standard matcher implementation.

Yield Parameters:

  • record (Object)

    each matching record

Returns:

  • (Enumerator)

    if no block given

  • (void)

    if block given



45
46
47
48
49
50
51
52
53
# File 'lib/mongory/query_builder.rb', line 45

def each
  return to_enum(:each) unless block_given?

  @matcher.prepare_query
  @records.each do |record|
    @context.current_record = record
    yield record if @matcher.match?(record)
  end
end

#explainvoid

This method returns an undefined value.

Prints the internal matcher tree structure for the current query. Will output a human-readable visual tree of matchers. This is useful for debugging and visualizing complex conditions.



196
197
198
199
200
# File 'lib/mongory/query_builder.rb', line 196

def explain
  @matcher.match?(@records.first)
  @matcher.render_tree
  nil
end

#fast {|record| ... } ⇒ Enumerator, void

Iterates through all records that match the current matcher. Uses a compiled Proc for faster matching.

Yield Parameters:

  • record (Object)

    each matching record

Returns:

  • (Enumerator)

    if no block given

  • (void)

    if block given



61
62
63
64
65
66
67
68
69
70
# File 'lib/mongory/query_builder.rb', line 61

def fast
  return to_enum(:fast) unless block_given?

  @context.need_convert = false
  @matcher.prepare_query
  matcher_block = @matcher.to_proc
  @records.each do |record|
    yield record if matcher_block.call(record)
  end
end

#in(condition) ⇒ QueryBuilder

Adds an $in condition to the query. Matches records where the field value is in the given array.

Parameters:

  • condition (Hash)

    the field and values to match

Returns:



131
132
133
# File 'lib/mongory/query_builder.rb', line 131

def in(condition)
  self.and(wrap_values_with_key(condition, '$in'))
end

#limit(count) ⇒ QueryBuilder

Limits the number of records returned by the query.

Parameters:

  • count (Integer)

    the maximum number of records to return

Returns:



148
149
150
151
152
# File 'lib/mongory/query_builder.rb', line 148

def limit(count)
  dup_instance_exec do
    @records = take(count)
  end
end

#nin(condition) ⇒ QueryBuilder

Adds a $nin condition to the query. Matches records where the field value is not in the given array.

Parameters:

  • condition (Hash)

    the field and values to exclude

Returns:



140
141
142
# File 'lib/mongory/query_builder.rb', line 140

def nin(condition)
  self.and(wrap_values_with_key(condition, '$nin'))
end

#not(condition) ⇒ QueryBuilder

Adds a negated condition to the current query. Wraps the condition in a $not operator.

Parameters:

  • condition (Hash)

    the condition to negate

Returns:



86
87
88
# File 'lib/mongory/query_builder.rb', line 86

def not(condition)
  self.and('$not' => condition)
end

#or(*conditions) ⇒ QueryBuilder

Adds one or more conditions combined with $or. Any condition can match for a record to be included.

Parameters:

  • conditions (Array<Hash>)

    the conditions to add

Returns:



106
107
108
109
110
111
112
113
114
115
# File 'lib/mongory/query_builder.rb', line 106

def or(*conditions)
  operator = '$or'
  dup_instance_exec do
    if @matcher.condition.each_key.all? { |k| k == operator }
      add_conditions(operator, conditions)
    else
      set_matcher(operator => [@matcher.condition.dup, *conditions])
    end
  end
end

#pluck(field, *fields) ⇒ Array<Object>+

Extracts selected fields from matching records.

Parameters:

  • field (Symbol, String)

    the first field to extract

  • fields (Array<Symbol, String>)

    additional fields to extract

Returns:

  • (Array<Object>)

    array of single field values if one field given

  • (Array<Array<Object>>)

    array of field value arrays if multiple fields given



160
161
162
163
164
165
166
167
# File 'lib/mongory/query_builder.rb', line 160

def pluck(field, *fields)
  if fields.empty?
    map { |record| record[field] }
  else
    fields.unshift(field)
    map { |record| fields.map { |key| record[key] } }
  end
end

#raw_conditionHash

Returns the raw parsed condition for this query.

Returns:

  • (Hash)

    the raw compiled condition



172
173
174
# File 'lib/mongory/query_builder.rb', line 172

def raw_condition
  @matcher.condition
end

#where(condition) ⇒ QueryBuilder

Adds a condition to filter records using the given condition. This is an alias for and.

Parameters:

  • condition (Hash)

    the condition to add

Returns:



77
78
79
# File 'lib/mongory/query_builder.rb', line 77

def where(condition)
  self.and(condition)
end

#with_context(addon_context = {}) ⇒ QueryBuilder

Note:

Creates a new query builder with the current matcher's condition and merged context

Creates a new query builder with additional context configuration.

Examples:

query.with_context(need_convert: false) #=> Returns a new query builder with conversion disabled

Parameters:

  • addon_context (Hash) (defaults to: {})

    Additional context configuration to merge

Returns:

  • (QueryBuilder)

    A new query builder instance with merged context



183
184
185
186
187
188
189
# File 'lib/mongory/query_builder.rb', line 183

def with_context(addon_context = {})
  dup_instance_exec do
    @context = @context.dup
    @context.config.merge!(addon_context)
    set_matcher(@matcher.condition)
  end
end