1

I'm interested in storing multiple values in a single column, rather than use the traditional many-to-many table:

class Beer
  include DataMapper::Resource

  property :id, Serial
  property :name, String
  property :containers, Integer # use bit arithmetic to store multiple values

  validates_presence_of :name, :containers

end

class Container
  include DataMapper::Resource

  property :id, Serial # increment in powers of two?
  property :name, String
  property :volume, Integer

  validates_presence_of :name, :volume

end

Containers:

ID  Name    Volume  Unit
1   Growler 64      oz
2   Cowler  32      oz
4   Bomber  750     mL
8   Six-fifty  650  mL
16  4 pack  64      oz
32  6 pack  72      oz

Beers:

ID  Name Containers
1   LSD  72
2   Düo  16

Is there an easy way to configure a DataMapper resource to increment serial values in powers of 2? I'm assuming that the association is going to be a challenge.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
craig
  • 25,664
  • 27
  • 119
  • 205
  • 1
    what benefit could this have? – max pleaner Jun 20 '16 at 16:16
  • One fewer table to maintain. Bitwise queries are fast and powerful. That said, I'll probably need a helper function in the view to convert `Containers` to its string representation. – craig Jun 20 '16 at 16:59
  • Everything about this is setting up for failure. Don't do this. Use sequential numbers and a proper relational table. You're going against the grain here in the worst possible way and it will be a constant struggle to keep things on track. Remember, Postgres has an `ARRAY` column and MySQL and Postgres both support `JSON` if you need an arbitrary data structure. – tadman Jun 20 '16 at 17:33

1 Answers1

2

You can't do that with Serial property type, but you can use an Integer and a before :create hook:

class Container
  include DataMapper::Resource

  property :id, Integer, key: true # Use whatever options you like
  property :name, String
  property :volume, Integer

  validates_presence_of :name, :volume

  # Create a new id based on the last element
  before :create do |c|
    last_container = Container.last
    # If integer has N bits, then you can only store N containers in your database (normally, 32 or 64 bits).
    c.id = last_container ? (last_container.id * 2) : 1
  end
end

Anyways, you should be using the relational model, instead of using this hacky-tricks, as someone already commented on your post. It's much more maintainable, easy to read and simple than this kind of solutions.


Oh, by the way, if you need fast access to your database, you should check a look at Graph databases and neo4jrb, an OGM for Neo4j.

Wikiti
  • 1,626
  • 13
  • 21
  • Pretty slick solution. I'll probably go the 'standard' route, as everyone is suggesting. – craig Jun 20 '16 at 21:11