Class: DataMapper::Query

### Home Classes Methods

### In Files

- lib/dm-core/query.rb
- lib/dm-core/query/conditions/comparison.rb
- lib/dm-core/query/conditions/operation.rb
- lib/dm-core/query/direction.rb
- lib/dm-core/query/operator.rb
- lib/dm-core/query/path.rb
- lib/dm-core/query/sort.rb

### Parent

Object

### Namespace

- MODULE DataMapper::Query::Conditions
- CLASS DataMapper::Query::Direction
- CLASS DataMapper::Query::Operator
- CLASS DataMapper::Query::Path
- CLASS DataMapper::Query::Sort

### Methods

- ::new
- ::target_conditions
- ::target_query
- #&
- #+
- #-
- #[]
- #add_reversed?
- #clear
- #condition_properties
- #difference
- #filter_records
- #inspect
- #intersection
- #limit_records
- #match_records
- #merge
- #raw?
- #relative
- #reload?
- #reverse
- #reverse!
- #slice
- #slice!
- #sort_records
- #sorted_fields
- #to_hash
- #to_relative_hash
- #to_subquery
- #union
- #unique?
- #update
- #valid?
- #|

### Included Modules

- DataMapper::Assertions

### Files

- LICENSE
- README.rdoc

### Class/Module Index

Quicksearch

- DataMapper
- DataMapper::Adapters
- DataMapper::Adapters::AbstractAdapter
- DataMapper::Adapters::InMemoryAdapter
- DataMapper::Assertions
- DataMapper::Associations
- DataMapper::Associations::ManyToMany
- DataMapper::Associations::ManyToMany::Collection
- DataMapper::Associations::ManyToMany::Relationship
- DataMapper::Associations::ManyToOne
- DataMapper::Associations::ManyToOne::Relationship
- DataMapper::Associations::OneToMany
- DataMapper::Associations::OneToMany::Collection
- DataMapper::Associations::OneToMany::Relationship
- DataMapper::Associations::OneToOne
- DataMapper::Associations::OneToOne::Relationship
- DataMapper::Associations::Relationship
- DataMapper::Chainable
- DataMapper::Collection
- DataMapper::Deprecate
- DataMapper::DescendantSet
- DataMapper::Equalizer
- DataMapper::Ext
- DataMapper::Ext::Array
- DataMapper::Ext::Hash
- DataMapper::Ext::Module
- DataMapper::Ext::Object
- DataMapper::Ext::String
- DataMapper::Hook
- DataMapper::Hook::ClassMethods
- DataMapper::IdentityMap
- DataMapper::ImmutableDeletedError
- DataMapper::ImmutableError
- DataMapper::IncompleteModelError
- DataMapper::Inflector
- DataMapper::Inflector::Inflections
- DataMapper::LocalObjectSpace
- DataMapper::Logger
- DataMapper::Mash
- DataMapper::Model
- DataMapper::Model::Hook
- DataMapper::Model::Hook::MethodCommand
- DataMapper::Model::Hook::Methods
- DataMapper::Model::Hook::ProcCommand
- DataMapper::Model::Is
- DataMapper::Model::Property
- DataMapper::Model::Relationship
- DataMapper::Model::Scope
- DataMapper::NamingConventions
- DataMapper::NamingConventions::Field
- DataMapper::NamingConventions::Field::Underscored
- DataMapper::NamingConventions::Field::UnderscoredAndPluralized
- DataMapper::NamingConventions::Field::UnderscoredAndPluralizedWithoutModule
- DataMapper::NamingConventions::Field::Yaml
- DataMapper::NamingConventions::Resource
- DataMapper::NamingConventions::Resource::Underscored
- DataMapper::NamingConventions::Resource::UnderscoredAndPluralized
- DataMapper::NamingConventions::Resource::UnderscoredAndPluralizedWithoutLeadingModule
- DataMapper::NamingConventions::Resource::UnderscoredAndPluralizedWithoutModule
- DataMapper::NamingConventions::Resource::Yaml
- DataMapper::ObjectNotFoundError
- DataMapper::OrderedSet
- DataMapper::OrderedSet::Cache
- DataMapper::OrderedSet::Cache::API
- DataMapper::PersistenceError
- DataMapper::PluginNotFoundError
- DataMapper::Property
- DataMapper::Property::Binary
- DataMapper::Property::Boolean
- DataMapper::Property::Class
- DataMapper::Property::Date
- DataMapper::Property::DateTime
- DataMapper::Property::Decimal
- DataMapper::Property::Discriminator
- DataMapper::Property::Discriminator::Model
- DataMapper::Property::Float
- DataMapper::Property::Integer
- DataMapper::Property::Lookup
- DataMapper::Property::Numeric
- DataMapper::Property::Object
- DataMapper::Property::PassThroughLoadDump
- DataMapper::Property::Serial
- DataMapper::Property::String
- DataMapper::Property::Text
- DataMapper::Property::Time
- DataMapper::Property::Typecast
- DataMapper::Property::Typecast::Numeric
- DataMapper::Property::Typecast::Time
- DataMapper::PropertySet
- DataMapper::Query
- DataMapper::Query::Conditions
- DataMapper::Query::Conditions::AbstractComparison
- DataMapper::Query::Conditions::AbstractOperation
- DataMapper::Query::Conditions::AndOperation
- DataMapper::Query::Conditions::Comparison
- DataMapper::Query::Conditions::EqualToComparison
- DataMapper::Query::Conditions::FlattenOperation
- DataMapper::Query::Conditions::GreaterThanComparison
- DataMapper::Query::Conditions::GreaterThanOrEqualToComparison
- DataMapper::Query::Conditions::InclusionComparison
- DataMapper::Query::Conditions::LessThanComparison
- DataMapper::Query::Conditions::LessThanOrEqualToComparison
- DataMapper::Query::Conditions::LikeComparison
- DataMapper::Query::Conditions::NotOperation
- DataMapper::Query::Conditions::NullOperation
- DataMapper::Query::Conditions::Operation
- DataMapper::Query::Conditions::OrOperation
- DataMapper::Query::Conditions::RegexpComparison
- DataMapper::Query::Conditions::RelationshipHandler
- DataMapper::Query::Direction
- DataMapper::Query::Operator
- DataMapper::Query::Path
- DataMapper::Query::Sort
- DataMapper::RelationshipSet
- DataMapper::Repository
- DataMapper::RepositoryNotSetupError
- DataMapper::Resource
- DataMapper::Resource::PersistenceState
- DataMapper::Resource::PersistenceState::Clean
- DataMapper::Resource::PersistenceState::Deleted
- DataMapper::Resource::PersistenceState::Dirty
- DataMapper::Resource::PersistenceState::Immutable
- DataMapper::Resource::PersistenceState::Persisted
- DataMapper::Resource::PersistenceState::Transient
- DataMapper::SaveFailureError
- DataMapper::Spec
- DataMapper::Spec::Adapters
- DataMapper::Spec::Adapters::Adapter
- DataMapper::Spec::Adapters::Helpers
- DataMapper::Spec::Adapters::InMemoryAdapter
- DataMapper::Spec::CollectionHelpers
- DataMapper::Spec::CollectionHelpers::GroupMethods
- DataMapper::Spec::Helpers
- DataMapper::Spec::PendingHelpers
- DataMapper::Subject
- DataMapper::SubjectSet
- DataMapper::SubjectSet::NameCache
- DataMapper::Undefined
- DataMapper::UnknownRelationshipError
- DataMapper::UnsavedParentError
- DataMapper::UpdateConflictError
- Blog
- Blog::Article
- ChildSubType
- CounterAdapter
- Heffalump
- Kernel
- LazyArray
- Object
- OtherComparison
- Pathname
- SubType
- Symbol

No matching classes.

# DataMapper::Query

Query class represents a query which will be run against the data-store. Generally Query objects can be found inside Collection objects.

### Constants

OPTIONS

### Attributes

conditions[R]

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

fields[R]

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

limit[R]

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

links[R]

Returns the links (associations) query fetches

@return [Array<DataMapper::Associations::Relationship>]

    the relationships that will be used to scope the results

@api private

model[R]

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

offset[R]

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

options[R]

Returns the original options

@return [Hash]

    the original options

@api private

order[R]

Returns the order

Set in cases like the following:

@example

    Document.all(:order => [:created_at.desc, :length.desc])

query order is a set of two ordering rules, descending on "created_at" field and descending again on "length" field

@return [Array]

    the order of results

@api semipublic

repository[R]

Returns the repository query should be executed in

Set in cases like the following:

@example

    Document.all(:repository => :medline)

@return [Repository]

    the Repository to retrieve results from

@api semipublic

### Public Class Methods

new(repository, model, options = {}) click to toggle source

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

target_conditions(source, source_key, target_key) click to toggle source

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

target_query(repository, model, source) click to toggle source

@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

### Public Instance Methods

&(other) click to toggle source
Alias for: intersection
+(other) click to toggle source
Alias for: union
-(other) click to toggle source
Alias for: difference
[](*args) click to toggle source
Alias for: slice
add_reversed?() click to toggle source

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() click to toggle source

Clear conditions

@return [self]

@api semipublic

    # File lib/dm-core/query.rb, line 472
    def clear
      @conditions = Conditions::Operation.new(:null)
      self
    end

condition_properties() click to toggle source

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

difference(other) click to toggle source

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

Also aliased as: -
filter_records(records) click to toggle source

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

inspect() click to toggle source

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

intersection(other) click to toggle source

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

Also aliased as: &
limit_records(records) click to toggle source

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

match_records(records) click to toggle source

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

merge(other) click to toggle source

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

raw?() click to toggle source

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

relative(options) click to toggle source

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

reload?() click to toggle source

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

reverse() click to toggle source

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

reverse!() click to toggle source

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

slice(*args) click to toggle source

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

Also aliased as: []
slice!(*args) click to toggle source

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

sort_records(records) click to toggle source

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

sorted_fields() click to toggle source

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

to_hash() click to toggle source

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

to_relative_hash() click to toggle source

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

to_subquery() click to toggle source

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

union(other) click to toggle source

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

Also aliased as: |, +
unique?() click to toggle source

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

update(other) click to toggle source

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

valid?() click to toggle source

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

|(other) click to toggle source
Alias for: union

[Validate]

Generated with the Darkfish Rdoc Generator 2.