require File.expand_path(File.dirname(__FILE__)) + "/test_helper"
require 'schema'
require 'relata/dsl'

class DSLTest < ActiveSupport::TestCase
  
  setup do
    setup_db
    @caelum = Post.create :body => "CaelumObjects training and inovation"
    @guilherme = Post.create :body => "Guilherme Silveira"
  end
  
  test "given an attribute and expectation, gives the results" do
    posts = Post.where(:body).like?("%caelum%").all
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  
    posts = Post.where { body.like? "%caelum%" }
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end
  
  test "given an attribute and constraint expectation, gives the results" do
    posts = Post.where { body.length < 22 }
    assert_equal @guilherme, posts[0]
    assert_equal 1, posts.size
  end
  
  test "given an attribute and between expectation, gives the results" do
    posts = Post.where { body.length.between(10,20) }
    assert_equal @guilherme, posts[0]
    assert_equal 1, posts.size
  end
  
  test "exists posts with comments" do
    @caelum.update_attributes(:comments => [Comment.create]) 
    posts = Post.where(:comments).count.exists?
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end
  
  test "exists posts with comments can be shortcuted with exists?" do
    @caelum.update_attributes(:comments => [Comment.create]) 
    posts = Post.where(:comments).exists?
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  
    posts = Post.where { comments.exists? }
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end
  
  test "exists posts with more than 2 comments" do
    @caelum.update_attributes(:comments => [Comment.create, Comment.create, Comment.create]) 
    posts = Post.where(:comments).count.gt(2)
    assert_equal @caelum, posts.first
    assert_equal 3, posts.first.comments.size
  end
  
  test "exists posts with less than 2 comments" do
    @caelum.update_attributes(:comments => [Comment.create]) 
    posts = Post.where(:comments).count.lt(2)
    assert_equal @caelum, posts.first
    assert_equal 1, posts.first.comments.size
  end
  
  test "exists posts with more than or equals 2 comments" do
    @caelum.update_attributes(:comments => [Comment.create, Comment.create]) 
    @guilherme.update_attributes(:comments => [Comment.create, Comment.create, Comment.create])
  
    posts = Post.where(:comments).count.ge(2).all
    assert_equal 2, posts.size
    assert_equal @caelum, posts[0]
    assert_equal @guilherme, posts[1]
  end
   
  test "dsl query supports first" do
    @caelum.update_attributes(:comments => [Comment.create, Comment.create]) 
    @guilherme.update_attributes(:comments => [Comment.create, Comment.create, Comment.create])
  
    posts = Post.where(:comments).count.ge(2).first
    assert_equal @caelum, posts
  end
   
  test "exists posts using strict extended methods" do
    @caelum.update_attributes(:comments => [Comment.create, Comment.create]) 
    @guilherme.update_attributes(:comments => [Comment.create, Comment.create, Comment.create])
    posts = Post.where { comments >= 2 }
    assert_equal @caelum, posts[0]
    assert_equal 2, posts.size
    assert_equal @guilherme, posts[1]
  end
  
  test "strict block supports first" do
    @caelum.update_attributes(:comments => [Comment.create, Comment.create]) 
    @guilherme.update_attributes(:comments => [Comment.create, Comment.create, Comment.create])
    post = Post.where { comments >= 2 }.first
    assert_equal @caelum, post
  end
  
  test "exists posts using range expectations" do
    @caelum.update_attributes :published_at => 1.year.ago
    
    posts = Post.where { published_at.between(2.years.ago, 6.months.ago) }
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end
  
  test "accepts two conditions inline" do
    @caelum.update_attributes :published_at => 1.year.ago
    @guilherme.update_attributes :published_at => 1.year.ago
    
    posts = Post.where { 
      published_at.between(2.years.ago, 6.months.ago)
      body.like?("%lum%")
    }
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end
  
  test "supports two conditions in dsl mixing everything together" do
    @caelum.update_attributes(:comments => [Comment.create, Comment.create]) 
    @guilherme.update_attributes(:comments => [Comment.create, Comment.create, Comment.create])
    posts = Post.where { comments >= 1 }.where(:body).like?("%lum%")
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end
  
  test "supports == with relation count" do
    @caelum.update_attributes(:comments => [Comment.create, Comment.create]) 
    posts = Post.where { comments == 2 }
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end
  
  test "supports == with simple field" do
    posts = Post.where { body == "CaelumObjects training and inovation" }
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end

  # test "supports != with simple field" do
  #   posts = Post.where { body != "diff" }
  #   assert_equal @caelum, posts[0]
  #   assert_equal @guilherme, posts[1]    
  #   assert_equal 2, posts.size
  # end

  test "accepts two conditions one after the other" do
    @caelum.update_attributes :published_at => 1.year.ago
    @guilherme.update_attributes :published_at => 1.year.ago
    
    posts = Post.where { published_at.between(2.years.ago, 6.months.ago) }
    assert_equal @caelum, posts[0]
    assert_equal 2, posts.size
    posts = posts.where { body.like?("%lum%") }
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end

  test "accepts any custom condition" do
    posts = Post.where { body "like ?", "%lum%" }
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end

  test "give records with nil fields" do
    @caelum.update_attributes :body => nil
    posts = Post.where(:body).is_null
    assert_equal @caelum, posts[0]
    assert_equal 1, posts.size
  end


  # test "second level relation in a dsl" do
  #   comment = Comment.create :description => "dsl test"
  #   @caelum.update_attributes :comments => [comment]
  # 
  #   posts = Post.where{ comments.description.like?("%dsl test%") }
  #   assert_equal @caelum, posts[0]
  #   assert_equal 1, posts.size
  # 
  # end

    # Author.where(:posts).comments.count.gt(2)
    
end