rzane / baby_squeel

:pig: An expressive query DSL for Active Record
MIT License
500 stars 50 forks source link

[Error] When using `joining` with `on`, DSL refers the association to wrong table name or undefined table alias #65

Open Looooong opened 7 years ago

Looooong commented 7 years ago

Issue

Course.joining{ enrollments.on(id == enrollments.course_id) }.where.has{ enrollments.progress == 100 }

will produce the following query:

SELECT "courses".*
FROM "courses"
    INNER JOIN "enrollments" ON "courses"."id" = "enrollments"."course_id"
WHERE "enrollments_courses"."progress" = 100.0 // <-- Error here

Notice the WHERE condition, it's enrollments_courses instead of enrollments, or the table alias enrollments_courses is not defined.

On the other hand, this code generates query correctly:

Course.joining{ enrollments.on(id == enrollments.course_id) }.where(Enrollment.arel_table[:progress].eq(100.0))

The expected query is:

SELECT "courses".*
FROM "courses"
    INNER JOIN "enrollments" ON "courses"."id" = "enrollments"."course_id"
WHERE "enrollments"."progress" = 100.0

I'm using Rails version 4.2.7.1, Ruby version 2.3.3, Baby Squeel version 1.1.4.

rzane commented 7 years ago

Hmm this is interesting. Could you create a reproducible test case based on this example: https://github.com/rzane/baby_squeel/blob/master/ISSUE_TEMPLATE.md

Looooong commented 7 years ago
require 'bundler/inline'
require 'minitest/spec'
require 'minitest/autorun'

gemfile true do
  source 'https://rubygems.org'
  gem 'activerecord', '~> 4.2.7.1' # which Active Record version?
  gem 'sqlite3'
  gem 'baby_squeel', github: 'rzane/baby_squeel'
end

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')

ActiveRecord::Schema.define do
  create_table :courses, force: true do |t|
  end

  create_table :enrollments, force: true do |t|
    t.references :course, index: true, foreign_key: true
    t.float :progress, default: 0, null: false
  end
end

class Course < ActiveRecord::Base
  has_many :enrollments
end

class Enrollment < ActiveRecord::Base
  belongs_to :course
end

class BabySqueelTest < Minitest::Spec
  it 'works' do
    scope = Course.joining{ enrollments.on(id == enrollments.course_id) }.where.has{ enrollments.progress == 100 }

    scope.to_sql.must_equal <<-SQL.squish
      SELECT "courses".*
      FROM "courses"
          INNER JOIN "enrollments" ON "courses"."id" = "enrollments"."course_id"
      WHERE "enrollments"."progress" = 100.0
    SQL
  end
end

Test result

Run options: --seed 35788

# Running:

F

Finished in 0.135758s, 7.3660 runs/s, 7.3660 assertions/s.

  1) Failure:
BabySqueelTest#test_0001_works [test.rb:36]:
--- expected
+++ actual
@@ -1 +1 @@
-"SELECT \"courses\".* FROM \"courses\" INNER JOIN \"enrollments\" ON \"courses\".\"id\" = \"enrollments\".\"course_id\" WHERE \"enrollments\".\"progress\" = 100.0"
+"SELECT \"courses\".* FROM \"courses\" INNER JOIN \"enrollments\" ON \"courses\".\"id\" = \"enrollments\".\"course_id\" WHERE \"enrollments_courses\".\"progress\" = 100.0"

1 runs, 1 assertions, 1 failures, 0 errors, 0 skips
Looooong commented 7 years ago

The problem also exists on Rails 5

passalini commented 6 years ago

+1 rails 4.1.0

kbighorse commented 5 years ago

+1 rails 5.2.2.1, baby_squeel 1.3.1

kbighorse commented 5 years ago

using @Looooong's syntax in the meantime:

Course.joining{ enrollments.on(id == enrollments.course_id)}.where(Enrollment.arel_table[:progress].eq(100.0))