Types are used by DataMapper to map ruby objects into values in the data-store on saving and to translate the values back into ruby objects when a resource is retrieved. The core library supplies several different types, providing mappings for most of the simple ruby objects as direct values in the data-store as well as the Object type which can store any Marshallable ruby object.
They're intended to make the storage of ruby objects as transparent as possible, no matter what the ruby object is, or which data-store is used as the backend.
In DM More there is the dm-types gem, which supplies several more types that map less common ruby classes to data-store values or take care of serializing them to text based formats.
The Enum type uses an Integer create a property which can take one of a number of symbolic values. A use for this might be bug status for an issue tracker or the protocol being used in a packet logging application.
1 class Issue 2 include DataMapper::Resource 3 4 property :status, Enum[ :new, :open, :closed, :invalid ], :default => :new 5 # other properties ... 6 end 7 8 @i = Issue.new 9 @i.status 10 # => :new 11 @i.status = :open 12 # => :open
A Flag is similar to an Enum, though the property that is created can hold multiple symbol values at once. This could be used for recording which colours a product can be ordered in, or what extra features an account has enabled.
1 class Widget 2 include DataMapper::Resource 3 4 property :colours, Flag[ :red, :green, :blue, :heliotrope ] 5 6 # other properties ... 7 end 8 9 @w = Widget.new 10 @w.colours = [ :red, :heliotrope ]
These map objects into simple data-store primitives, then re-initialize as the ruby types
- A ruby Time object stored in the data-store as an Integer -- the number of seconds since the UNIX epoch.
- A ruby URI object, pre-parsed for use of methods such as
#uri, stored as a string in the data-store.
- Stored as a string in the data-store, FilePaths initialize Pathname objects, making it easy to perform various file operations on the file.
- A ruby regex, stored as a string.
- Ruby IPAddr, stored as the string representation.
- Stored in the data-store as string representing the salt, hash and cost of a password using OpenBSD's bcrypt algorithm, it offers an alternative to the more usual pair of hash and salt columns.
These store values in the data-store using text based serialization formats. They work via calling dumping the object to the format on saving and parsing the text to reinitialize them on loading.
Writing Your Own
Writing your own custom type isn't difficult. There are two (or perhaps three)
methods to implement, as well as the selection of an appropriate primitive. All
types are a class which should descend from
DataMapper offers several choices for a data-store primitive.
To assign a primitive to a type, either make the type descend from
DataMapper::Property::(PrimitiveClass) or within the class definition, use
dump(value) method is called when the object is saved
to the data-store. It is responsible for mapping whatever is assigned to the
property on to the primitive type. For example, the EpochTime Type saves an
integer directly to the data-store, or calls
#to_i if a Time object is passed
load(value) method is called when the property is retrieved
from the data-store. It takes the primitive value and initializes a ruby object
from it. For example, the Json type performs
JSON.parse(value) to convert the
json string back into appropriate ruby.
Typecasting is provided by the types
which tries to coerce whatever value the property has into an appropriate type.
A type doesn't have to provide a typecast but it can be useful, for example to
allow the string '2008-09-06' to be converted to a ruby Date without having to
reload the model.
For examples of the types, the best place to look is dm-types on github.