Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Distinct with ArelExtensions on mssql returns TOP(1) 1 AS one #1009

Open
jmlevesque333 opened this issue Feb 28, 2022 · 0 comments
Open

Distinct with ArelExtensions on mssql returns TOP(1) 1 AS one #1009

jmlevesque333 opened this issue Feb 28, 2022 · 0 comments

Comments

@jmlevesque333
Copy link

Issue

Doing the following query Model.distinct.to_sql returns the following query SELECT DISTINCT TOP(1) 1 AS [one] FROM [models]
This happens when running with mssql on Windows with arel_extensions (https://github.com/Faveod/arel-extensions).
The issue is caused by this piece of code:

def distinct_One_As_One_Is_So_Not_Fetch o
  core = o.cores.first
  distinct = Nodes::Distinct === core.set_quantifier
  oneasone = core.projections.all? { |x| x == ActiveRecord::FinderMethods::ONE_AS_ONE }
  limitone = [nil, 0, 1].include? node_value(o.limit)
  if distinct && oneasone && limitone && !o.offset
    core.projections = [Arel.sql("TOP(1) 1 AS [one]")]
    o.limit = nil
  end
end

interacting with the overriding of the == operator from ArelExtensions:

def ==(other)
  Arel::Nodes::Equality.new self, Arel::Nodes.build_quoted(other, self)
end

so when it's running the .all? block, x == ActiveRecord::FinderMethods::ONE_AS_ONE creates a query from the operator, which is truthy no matter what.

Expected behavior

Should return all distinct models

Actual behavior

Returns one model with its only attribute being 1

How to reproduce

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"
  gem "tiny_tds", "2.1.3.pre"
  gem "rails", "6.0.4.1"
  gem "activerecord", "6.0.4.1"
  gem "activerecord-sqlserver-adapter", "6.0.2"
  gem "arel_extensions", "2.1.0"
end

require "active_record"
require "minitest/autorun"
require "logger"


ENV["RAILS_ENV"] = "production"

ActiveRecord::Base.configurations = {
  "test": {
    adapter:  "sqlserver",
    timeout:  5000,
    pool:     100,
    encoding: "utf8",
    database: "test_database",
    username: "admin",
    password: "admin",
    host:     "localhost",
    port:     1433,
  }
}

ActiveRecord::Base.establish_connection

ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  drop_table :machines rescue nil
  drop_table :capabilities rescue nil

  create_table :machines, force: true do |t|
    t.string :sn

    t.timestamps
  end

  create_table :capabilities, force: true do |t|
    t.string :name
    t.belongs_to :machine

    t.timestamps
  end
end

class Machine < ActiveRecord::Base
  has_many :capabilities
end

class Capability < ActiveRecord::Base
  has_one :machine
end

class TestEerValueTest < Minitest::Test
  def setup
    capabilities = [
      {name: 'cap_1'},
      {name: 'cap_2'},
      {name: 'cap_3'},
      {name: 'cap_4'}
    ]

    machines = [
      {
        sn: 'test_1',
        capabilities: %w[cap_1 cap_2]
      },
      {
        name: 'test_2',
        capabilities: %w[cap_2 cap_3]
      },
      {
        name: 'test_3',
        capabilities: %w[cap_4]
      }
    ]

    Capability.create!(capabilities)

    machines.each do |machine|
      m = Machine.new(sn: machine[:sn])
      m.capabilities = Capability.where(name: machine[:capabilities])
      m.save!
    end
  end

  def test_count
    assert_equal 'SELECT DISTINCT TOP(1) 1 AS [one] FROM [machines]', Machine.distinct.to_sql
  end
end

Details

  • Rails version: 6.0.4.1
  • SQL Server adapter version: 6.0.2
  • TinyTDS version: 2.1.3.pre
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant