#1301 new
kgiszczak

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

    kgiszczak June 3rd, 2010 @ 08:39 AM

    • Assigned user set to “Piotr Solnica (solnic)”
  • Todd Richmond

    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

    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_statement

      def 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.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

Pages