
module CDQ
  describe "CDQ Query" do

    before do
      @query = CDQQuery.new
    end

    it "creates a query with a simple true predicate" do
      @query.predicate.should == nil
      @query.limit.should == nil
      @query.offset.should == nil
    end

    it "can set a limit on a query" do
      @query = CDQQuery.new(limit: 1)
      @query.limit.should == 1
      @query.offset.should == nil
    end

    it "can set a offset on a query" do
      @query = CDQQuery.new(offset: 1)
      @query.limit.should == nil
      @query.offset.should == 1
    end

    it "can 'and' itself with another query" do
      @query = CDQQuery.new(limit: 1, offset: 1)
      @other = CDQQuery.new(predicate: NSPredicate.predicateWithValue(false), limit: 2)
      @compound = @query.and(@other)
      @compound.predicate.should == NSPredicate.predicateWithValue(false)
      @compound.limit.should == 2
      @compound.offset.should == 1
    end

    it "can 'and' itself with an NSPredicate" do
      @compound = @query.and(NSPredicate.predicateWithValue(false))
      @compound.predicate.should == NSPredicate.predicateWithValue(false)
    end

    it "can 'and' itself with a string-based predicate query" do
      query = @query.where(:name).begins_with('foo')
      compound = query.and("name != %@", 'fool')
      compound.predicate.predicateFormat.should == 'name BEGINSWITH "foo" AND name != "fool"'
    end

    it "can 'and' itself with a hash" do
      compound = @query.and(name: "foo", fee: 2)
      compound.predicate.predicateFormat.should == 'name == "foo" AND fee == 2'
    end

    it "starts a partial predicate when 'and'-ing a symbol" do
      ppred = @query.and(:name)
      ppred.class.should == CDQPartialPredicate
      ppred.key.should == :name
    end

    it "can 'or' itself with another query" do
      @query = CDQQuery.new(limit: 1, offset: 1)
      @other = CDQQuery.new(predicate: NSPredicate.predicateWithValue(false), limit: 2)
      @compound = @query.or(@other)
      @compound.predicate.should == NSPredicate.predicateWithValue(false)
      @compound.limit.should == 2
      @compound.offset.should == 1
    end

    it "can 'or' itself with an NSPredicate" do
      @compound = @query.or(NSPredicate.predicateWithValue(false))
      @compound.predicate.should == NSPredicate.predicateWithValue(false)
    end

    it "can 'or' itself with a string-based predicate query" do
      query = @query.where(:name).begins_with('foo')
      compound = query.or("name != %@", 'fool')
      compound.predicate.predicateFormat.should == 'name BEGINSWITH "foo" OR name != "fool"'
    end

    it "can sort by a key" do
      @query.sort_by(:name).sort_descriptors.should == [
        NSSortDescriptor.sortDescriptorWithKey('name', ascending: true)
      ]
    end

    it "can sort descending" do
      @query.sort_by(:name, order: :desc).sort_descriptors.should == [
        NSSortDescriptor.sortDescriptorWithKey('name', ascending: false)
      ]
    end

    it "can sort descending (older API)" do
      @query.sort_by(:name, :desc).sort_descriptors.should == [
        NSSortDescriptor.sortDescriptorWithKey('name', ascending: false)
      ]
    end

    it "can sort case insensitive" do
      @query.sort_by(:name, case_insensitive: true).sort_descriptors.should == [
        NSSortDescriptor.sortDescriptorWithKey('name', ascending: true, selector: "localizedCaseInsensitiveCompare:")
      ]
    end

    it "can chain sorts" do
      @query.sort_by(:name).sort_by(:title).sort_descriptors.should == [
        NSSortDescriptor.sortDescriptorWithKey('name', ascending: true),
        NSSortDescriptor.sortDescriptorWithKey('title', ascending: true)
      ]
    end

    it "reuses the previous key when calling 'and' or 'or' with no arguments" do
      compound = @query.where(:name).begins_with('foo').and.ne('fool')
      compound.predicate.predicateFormat.should == 'name BEGINSWITH "foo" AND name != "fool"'

      compound = @query.where(:name).begins_with('foo').or.eq('loofa')
      compound.predicate.predicateFormat.should == 'name BEGINSWITH "foo" OR name == "loofa"'
    end

    it "handles complex examples" do
      query1 = CDQQuery.new
      query2 = query1.where(CDQQuery.new.where(:name).ne('bob', NSCaseInsensitivePredicateOption).or(:amount).gt(42).sort_by(:name))
      query3 = query1.where(CDQQuery.new.where(:enabled).eq(true).and(:'job.title').ne(nil).sort_by(:amount, order: :desc))

      query4 = query3.where(query2)
      query4.predicate.predicateFormat.should == '(enabled == 1 AND job.title != nil) AND (name !=[c] "bob" OR amount > 42)'
      query4.sort_descriptors.should == [
        NSSortDescriptor.alloc.initWithKey('amount', ascending:false),
        NSSortDescriptor.alloc.initWithKey('name', ascending:true)
      ]
    end

    it "can make a new query with a new limit" do:w
    @query = CDQQuery.new
    new_query = @query.limit(1)

    new_query.limit.should == 1
    new_query.offset.should == nil
  end

end
end
