# File lib/dm-core/query.rb, line 205
    def initialize(repository, model, options = {})
      assert_kind_of 'repository', repository, Repository
      assert_kind_of 'model',      model,      Model
      assert_kind_of 'options',    options,    Hash

      options.each_pair { |k,v| options[k] = v.call if v.is_a? Proc } if options.is_a? Hash

      assert_valid_options(options)

      @repository = repository
      @properties = model.properties(@repository.name)

      @model        = model                               # must be Class that includes DM::Resource
      @reload       = options.fetch :reload,       false  # must be true or false
      @unique       = options.fetch :unique,       false  # must be true or false
      @offset       = options.fetch :offset,       0      # must be an Integer greater than or equal to 0
      @limit        = options.fetch :limit,        nil    # must be an Integer greater than or equal to 1
      @order        = options.fetch :order,        model.default_order(@repository.name)   # must be an Array of Symbol, DM::Query::Direction or DM::Property
      @add_reversed = options.fetch :add_reversed, false  # must be true or false
      @fields       = options.fetch :fields,       @properties.defaults  # must be an Array of Symbol, String or DM::Property
      @links        = options.fetch :links,        []     # must be an Array of Tuples - Tuple [DM::Query,DM::Assoc::Relationship]
      @includes     = options.fetch :includes,     []     # must be an Array of DM::Query::Path
      @conditions   = []                                  # must be an Array of triplets (or pairs when passing in raw String queries)

      # normalize order and fields
      @order  = normalize_order(@order)
      @fields = normalize_fields(@fields)

      # XXX: should I validate that each property in @order corresponds
      # to something in @fields?  Many DB engines require they match,
      # and I can think of no valid queries where a field would be so
      # important that you sort on it, but not important enough to
      # return.

      # normalize links and includes.
      # NOTE: this must be done after order and fields
      @links    = normalize_links(@links)
      @includes = normalize_includes(@includes)

      # treat all non-options as conditions
      (options.keys - OPTIONS).each do |k|
        append_condition(k, options[k])
      end

      # parse raw options[:conditions] differently
      if conditions = options[:conditions]
        if conditions.kind_of?(Hash)
          conditions.each do |k,v|
            append_condition(k, v)
          end
        elsif conditions.kind_of?(Array)
          raw_query, *bind_values = conditions
          @conditions << if bind_values.empty?
            [ :raw, raw_query ]
          else
            [ :raw, raw_query, bind_values ]
          end
        end
      end
    end