datamapper / dm-types

DataMapper plugin providing extra data types
http://datamapper.org/
MIT License
55 stars 80 forks source link

Flag should be searchable bitwise #44

Open agios opened 13 years ago

agios commented 13 years ago

When one is using a flag field, they should be able to search for records that have a specific flag set. This can be done with a bitwise "and" query, using the ampersand operator.

I don't know what the correct way to do this is, but a method that works for me is defining a new Comparison, as such: http://pastebin.com/xWU62iT2

That way one can do a search like this:

User.all('role.hasflag' => :moderator)

and it will match users with that AND other roles, not just the specific combination

maxsum-corin commented 12 years ago

This does not work for me (I'm using MS SQL Server) because the operator & doesn't return a boolean result (it's a number). I am using "& #{value} =" instead of '&'.

I would like to see the addition of a :has operator to the adapter(s).

Note that my definition is different to yours ("role" & ? = ? cf. "role" & ? <> 0). I am interpreting User.all('role.hasflag' => [:moderator, :editor]) as "all users that have both moderator and editor roles" as opposed to "all users that have either moderator and editor roles."

Edit: I made a new version of your pastebin: http://pastebin.com/Bak81f2Q

todd-richmond commented 10 years ago

Here is a more complete version of comparison_statement for Flags that handles all operators

      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