Query class represents a query which will be run against the data-store. Generally Query objects can be found inside Collection objects.
Returns the conditions of the query
In the following example:
@example
Team.all(:wins.gt => 30, :conference => 'East')
Conditions are "greater than" operator for "wins" field and exact match operator for "conference".
@return [Array]
the conditions that will be used to scope the results
@api semipublic
Returns the fields
Set in cases like the following:
@example
Document.all(:fields => [:title, :vernacular_title, :abstract])
@return [PropertySet]
the properties in the Model that will be retrieved
@api semipublic
Returns the limit query uses
Set in cases like the following:
@example
Document.all(:limit => 10)
@return [Integer, nil]
the maximum number of results
@api semipublic
Returns the links (associations) query fetches
@return [Array<DataMapper::Associations::Relationship>]
the relationships that will be used to scope the results
@api private
Returns model (class) that is used to instantiate objects from query result returned by adapter
@return [Model]
the Model to retrieve results from
@api semipublic
Returns the offset query uses
Set in cases like the following:
@example
Document.all(:offset => page.offset)
@return [Integer]
the offset of the results
@api semipublic
Initializes a Query instance
@example
JournalIssue.all(:repository => :medline, :created_on.gte => Date.today - 7)
initialized a query with repository defined with name :medline, model JournalIssue and options { :created_on.gte => Date.today - 7 }
@param [Repository] repository
the Repository to retrieve results from
@param [Model] model
the Model to retrieve results from
@param [Hash] options
the conditions and scope
@api semipublic
# File lib/dm-core/query.rb, line 714 def initialize(repository, model, options = {}) assert_kind_of 'repository', repository, Repository assert_kind_of 'model', model, Model @repository = repository @model = model @options = options.dup.freeze repository_name = repository.name @properties = @model.properties(repository_name) @relationships = @model.relationships(repository_name) assert_valid_options(@options) @fields = @options.fetch :fields, @properties.defaults @links = @options.key?(:links) ? @options[:links].dup : [] @conditions = Conditions::Operation.new(:null) @offset = @options.fetch :offset, 0 @limit = @options.fetch :limit, nil @order = @options.fetch :order, @model.default_order(repository_name) @unique = @options.fetch :unique, true @add_reversed = @options.fetch :add_reversed, false @reload = @options.fetch :reload, false @raw = false merge_conditions([ DataMapper::Ext::Hash.except(@options, *OPTIONS), @options[:conditions] ]) normalize_options end
Extract conditions to match a Resource or Collection
@param [Array, Collection, Resource] source
the source to extract the values from
@param [ProperySet] source_key
the key to extract the value from the resource
@param [ProperySet] target_key
the key to match the resource with
@return [AbstractComparison, AbstractOperation]
the conditions to match the resources with
@api private
# File lib/dm-core/query.rb, line 49 def self.target_conditions(source, source_key, target_key) target_key_size = target_key.size source_values = [] if source.nil? source_values << [ nil ] * target_key_size else Array(source).each do |resource| next unless source_key.loaded?(resource) source_value = source_key.get!(resource) next unless target_key.valid?(source_value) source_values << source_value end end source_values.uniq! if target_key_size == 1 target_key = target_key.first source_values.flatten! if source_values.size == 1 Conditions::EqualToComparison.new(target_key, source_values.first) else Conditions::InclusionComparison.new(target_key, source_values) end else or_operation = Conditions::OrOperation.new source_values.each do |source_value| and_operation = Conditions::AndOperation.new target_key.zip(source_value) do |property, value| and_operation << Conditions::EqualToComparison.new(property, value) end or_operation << and_operation end or_operation end end
@param [Repository] repository
the default repository to scope the query within
@param [Model] model
the default model for the query
@param [query, Enumerable] source
the source to generate the query with
@return [Query]
the query to match the resources with
@api private
# File lib/dm-core/query.rb, line 103 def self.target_query(repository, model, source) if source.respond_to?(:query) source.query elsif source.kind_of?(Enumerable) key = model.key(repository.name) conditions = Query.target_conditions(source, key, key) repository.new_query(model, :conditions => conditions) else raise ArgumentError, "+source+ must respond to #query or be an Enumerable, but was #{source.class}" end end
Indicates if each result should be returned in reverse order
Set in cases like the following:
@example
Document.all(:limit => 5).reverse
Note that :add_reversed option may be used in conditions directly, but this is rarely the case
@return [Boolean]
true if the results should be reversed, false if not
@api private
# File lib/dm-core/query.rb, line 248 def add_reversed? @add_reversed end
Clear conditions
@return [self]
@api semipublic
# File lib/dm-core/query.rb, line 472 def clear @conditions = Conditions::Operation.new(:null) self end
Get the properties used in the conditions
@return [Set<Property>]
Set of properties used in the conditions
@api private
# File lib/dm-core/query.rb, line 627 def condition_properties properties = Set.new each_comparison do |comparison| next unless comparison.respond_to?(:subject) subject = comparison.subject properties << subject if subject.kind_of?(Property) end properties end
Return the difference with another query
@param [Query] other
the other query
@return [Query]
the difference of the query and other
@api semipublic
# File lib/dm-core/query.rb, line 461 def difference(other) set_operation(:difference, other) end
Takes an Enumerable of records, and destructively filters it. First finds all matching conditions, then sorts it, then does offset & limit
@param [Enumerable] records
The set of records to be filtered
@return [Enumerable]
Whats left of the given array after the filtering
@api semipublic
# File lib/dm-core/query.rb, line 488 def filter_records(records) records = records.uniq if unique? records = match_records(records) if conditions records = sort_records(records) if order records = limit_records(records) if limit || offset > 0 records end
Returns detailed human readable string representation of the query
@return [String] detailed string representation of the query
@api semipublic
# File lib/dm-core/query.rb, line 604 def inspect attrs = [ [ :repository, repository.name ], [ :model, model ], [ :fields, fields ], [ :links, links ], [ :conditions, conditions ], [ :order, order ], [ :limit, limit ], [ :offset, offset ], [ :reload, reload? ], [ :unique, unique? ], ] "#<#{self.class.name} #{attrs.map { |key, value| "@#{key}=#{value.inspect}" }.join(' ')}>" end
Return the intersection with another query
@param [Query] other
the other query
@return [Query]
the intersection of the query and other
@api semipublic
# File lib/dm-core/query.rb, line 445 def intersection(other) return dup if self == other set_operation(:intersection, other) end
Limits a set of records by the offset and/or limit
@param [Enumerable] records
A list of records to sort
@return [Enumerable]
The offset & limited records
@api semipublic
# File lib/dm-core/query.rb, line 538 def limit_records(records) offset = self.offset limit = self.limit size = records.size if offset > size - 1 [] elsif (limit && limit != size) || offset > 0 records[offset, limit || size] || [] else records.dup end end
Filter a set of records by the conditions
@param [Enumerable] records
The set of records to be filtered
@return [Enumerable]
Whats left of the given array after the matching
@api semipublic
# File lib/dm-core/query.rb, line 505 def match_records(records) conditions = self.conditions records.select { |record| conditions.matches?(record) } end
Similar to Query#update, but acts on a duplicate.
@param [Query, Hash] other
other query to merge with
@return [Query]
updated duplicate of original query
@api semipublic
# File lib/dm-core/query.rb, line 385 def merge(other) dup.update(other) end
Indicates if the Query has raw conditions
@return [Boolean]
true if the query has raw conditions, false if not
@api semipublic
# File lib/dm-core/query.rb, line 282 def raw? @raw end
Builds and returns new query that merges original with one given, and slices the result with respect to :limit and :offset options
This method is used by Collection to concatenate options from multiple chained calls in cases like the following:
@example
author.books.all(:year => 2009).all(:published => false)
@api semipublic
# File lib/dm-core/query.rb, line 402 def relative(options) options = options.to_hash offset = nil limit = self.limit if options.key?(:offset) && (options.key?(:limit) || limit) options = options.dup offset = options.delete(:offset) limit = options.delete(:limit) || limit - offset end query = merge(options) query = query.slice!(offset, limit) if offset query end
Indicates if the Query results should replace the results in the Identity Map
TODO: needs example
@return [Boolean]
true if the results should be reloaded, false if not
@api semipublic
# File lib/dm-core/query.rb, line 260 def reload? @reload end
Returns a new Query with a reversed order
@example
Document.all(:limit => 5).reverse
Will execute a single query with correct order
@return [Query]
new Query with reversed order
@api semipublic
# File lib/dm-core/query.rb, line 308 def reverse dup.reverse! end
Reverses the sort order of the Query
@example
Document.all(:limit => 5).reverse
Will execute a single query with original order and then reverse collection in the Ruby space
@return [Query]
self
@api semipublic
# File lib/dm-core/query.rb, line 325 def reverse! # reverse the sort order @order.map! { |direction| direction.dup.reverse! } # copy the order to the options @options = @options.merge(:order => @order).freeze self end
Slices collection by adding limit and offset to the query, so a single query is executed
@example
Journal.all(:limit => 10).slice(3, 5)
will execute query with the following limit and offset (when repository uses DataObjects adapter, and thus queries use SQL):
LIMIT 5 OFFSET 3
@api semipublic
# File lib/dm-core/query.rb, line 566 def slice(*args) dup.slice!(*args) end
Slices collection by adding limit and offset to the query, so a single query is executed
@example
Journal.all(:limit => 10).slice!(3, 5)
will execute query with the following limit (when repository uses DataObjects adapter, and thus queries use SQL):
LIMIT 10
and then takes a slice of collection in the Ruby space
@api semipublic
# File lib/dm-core/query.rb, line 588 def slice!(*args) offset, limit = extract_slice_arguments(*args) if self.limit || self.offset > 0 offset, limit = get_relative_position(offset, limit) end update(:offset => offset, :limit => limit) end
Sorts a list of Records by the order
@param [Enumerable] records
A list of Resources to sort
@return [Enumerable]
The sorted records
@api semipublic
# File lib/dm-core/query.rb, line 519 def sort_records(records) sort_order = order.map { |direction| [ direction.target, direction.operator == :asc ] } records.sort_by do |record| sort_order.map do |(property, ascending)| Sort.new(record_value(record, property), ascending) end end end
Return a list of fields in predictable order
@return [Array<Property>]
list of fields sorted in deterministic order
@api private
# File lib/dm-core/query.rb, line 645 def sorted_fields fields.sort_by { |property| property.hash } end
Hash representation of a Query
@return [Hash]
Hash representation of a Query
@api private
# File lib/dm-core/query.rb, line 666 def to_hash { :repository => repository.name, :model => model.name, :fields => fields, :links => links, :conditions => conditions, :offset => offset, :limit => limit, :order => order, :unique => unique?, :add_reversed => add_reversed?, :reload => reload?, } end
Extract options from a Query
@param [Query] query
the query to extract options from
@return [Hash]
the options to use to initialize the new query
@api private
# File lib/dm-core/query.rb, line 691 def to_relative_hash DataMapper::Ext::Hash.only(to_hash, :fields, :order, :unique, :add_reversed, :reload) end
Transform Query into subquery conditions
@return [AndOperation]
a subquery for the Query
@api private
# File lib/dm-core/query.rb, line 655 def to_subquery collection = model.all(merge(:fields => model_key)) Conditions::Operation.new(:and, Conditions::Comparison.new(:in, self_relationship, collection)) end
Return the union with another query
@param [Query] other
the other query
@return [Query]
the union of the query and other
@api semipublic
# File lib/dm-core/query.rb, line 428 def union(other) return dup if self == other set_operation(:union, other) end
Indicates if the Query results should be unique
TODO: needs example
@return [Boolean]
true if the results should be unique, false if not
@api semipublic
# File lib/dm-core/query.rb, line 272 def unique? @unique end
Updates the Query with another Query or conditions
Pretty unrealistic example:
@example
Journal.all(:limit => 2).query.limit # => 2 Journal.all(:limit => 2).query.update(:limit => 3).limit # => 3
@param [Query, Hash] other
other Query or conditions
@return [Query]
self
@api semipublic
# File lib/dm-core/query.rb, line 351 def update(other) other_options = if kind_of?(other.class) return self if self.eql?(other) assert_valid_other(other) other.options else other = other.to_hash return self if other.empty? other end @options = @options.merge(other_options).freeze assert_valid_options(@options) normalize = DataMapper::Ext::Hash.only(other_options, *OPTIONS - [ :conditions ]).map do |attribute, value| instance_variable_set("@#{attribute}", DataMapper::Ext.try_dup(value)) attribute end merge_conditions([ DataMapper::Ext::Hash.except(other_options, *OPTIONS), other_options[:conditions] ]) normalize_options(normalize | [ :links, :unique ]) self end
Indicates if the Query is valid
@return [Boolean]
true if the query is valid
@api semipublic
# File lib/dm-core/query.rb, line 292 def valid? conditions.valid? end
Generated with the Darkfish Rdoc Generator 2.