
dm-types: incorect select query with Flag type
Reported by kgiszczak | June 3rd, 2010 @ 08:33 AM
Gemfile:
source 'http://rubygems.org'
gem 'dm-migrations', '~> 1.0.0.rc3', :git => 'git://github.com/datamapper/dm-migrations.git'
gem 'dm-types', '~> 1.0.0.rc3', :git => 'git://github.com/datamapper/dm-types.git'
gem 'dm-postgres-adapter', '~> 1.0.0.rc3', :git => 'git://github.com/datamapper/dm-postgres-adapter.git'
gem 'dm-types', '~> 1.0.0.rc3', :git => 'git://github.com/datamapper/dm-types.git'
gem 'dm-core', '~> 1.0.0.rc3', :git => 'git://github.com/datamapper/dm-core.git'
gem 'dm-do-adapter', '~> 1.0.0.rc3', :git => 'git://github.com/datamapper/dm-do-adapter.git'
test.rb
require 'bundler'
Bundler.setup
Bundler.require
DataMapper.logger = DataMapper::Logger.new STDOUT, :debug
DataMapper.setup(:default, 'postgres://root@localhost/test')
class Test
include DataMapper::Resource
property :id, Serial
property :flags, Flag[ :one, :two, :three ]
end
DataMapper.auto_migrate!
Test.create :flags => [ :one, :three ]
Test.first :flags => [ :one, :three ]
SELECT query generated by Test.first method is incorect. SQL looks like this:
SELECT "id", "flags" FROM "tests" WHERE "flags" IN (1, 4) ORDER BY "id" LIMIT 1
WHERE clause contains "flags" IN (1, 4) but should be: "flags" = 5
Comments and changes to this ticket
-
kgiszczak June 3rd, 2010 @ 08:39 AM
- Assigned user set to Piotr Solnica (solnic)
-
Todd Richmond November 1st, 2013 @ 02:09 PM
This makes single flag checks impossible and is still occurring in the most recent DataMapper Release. The workaround from a few different web posts is to use
:conditions => ['flags & 1 != 0'], but that requires converting Flag symbols to integers manually
Test.first :flags -> [:one] must create this SQL to return any item with that bit set in the bitmask
SELECT "id", "flags" FROM "tests" WHERE "flags" & 1 != 0 ORDER BY "id" LIMIT 1
Multiple flags would create an AND set of bit checks
-
Todd Richmond November 7th, 2013 @ 01:03 PM
Here is a very ugly monkey patch because the comparison logic is in dm-core, but the new Flag type is in dm-types. However, it gives a clear example of the logic I implemented to match all operators
module DataMapper
module Adapters class DataObjectsAdapter < AbstractAdapter alias_method :override_comparison_statement, :comparison_statementdef comparison_statement(comparison, qualify) subject = comparison.subject value = comparison.value if subject.respond_to?(:model) && subject.model.properties[subject.name].options[:flags] && value.is_a?(Array) ? value.first.is_a?(Fixnum) : value.is_a?(Fixnum) column_name = property_to_column_name(subject, qualify) value = value.inject(0, :+) if value.is_a?(Array) case comparison.slug when :eql then "#{column_name} = #{value}" when :gt then "#{column_name} & #{value} = #{value} AND #{column_name} != #{value}" when :gte then "#{column_name} & #{value} = #{value}" when :in, :like then value == 0 ? 'TRUE' : "#{column_name} & #{value} != 0" when :lt then "#{column_name} & #{value} != #{value}" when :lte then "#{column_name} & #{value} <= #{value}" else 'FALSE' end else override_comparison_statement(comparison, qualify) end end end
end end
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »