<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Datamapper.org News and Notes</title>
  <subtitle>Ruby Object Relational Mapper</subtitle>
  <id>http://www.datamapper.org</id>
  <generator uri="http://jekyllrb.com/" version="0.5">Jekyll</generator>
  <link href="http://www.datamapper.org/news.rss" rel="self"/>
  <link href="http://www.datamapper.org/"/>
  <updated>2013-02-22T10:29:12-08:00</updated>
  <author>
    <name>Maintained By the Community</name>
    <email>datamapper@googlegroups.com</email>
  </author>

  
  <entry>
    <title>DataMapper 1.2.0 released</title>
    <link href="http://datamapper.org/articles/datamapper-120-released.html"/>
    <updated>2011-10-13T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2011-10-13</id>
    <content type="html">&lt;h1&gt;DataMapper 1.2.0 released&lt;/h1&gt;

&lt;p&gt;I'm pleased to announce that we have released DataMapper 1.2.0.&lt;/p&gt;

&lt;p&gt;This release is focused on bug fixes, performance improvements, internal
refactoring and &lt;em&gt;Rails 3.1 compatibility&lt;/em&gt;. Please give it a try and in case of
any issues please report them on Github.&lt;/p&gt;

&lt;h2&gt;Installation&lt;/h2&gt;

&lt;p&gt;DataMapper can be installed with a one-line command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install data_mapper dm-sqlite-adapter&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The above command assumes you are using SQLite, but if you plan to use MySQL, PostgreSQL or something else replace dm-sqlite-adapter your preferred adapter gem.&lt;/p&gt;

&lt;p&gt;IMPORTANT:&lt;/p&gt;

&lt;p&gt;If you're not using Rails then remember to call &lt;code&gt;DataMapper.finalize&lt;/code&gt; after loading the models!&lt;/p&gt;

&lt;h2&gt;Changes&lt;/h2&gt;

&lt;p&gt;dm-core:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;STI queries no longer include the top-level class name&lt;/li&gt;
&lt;li&gt;UnderscoredAndPluralizedWithoutLeadingModule naming convention was added&lt;/li&gt;
&lt;li&gt;belongs_to supports :unique option&lt;/li&gt;
&lt;li&gt;Validation of property names was improved&lt;/li&gt;
&lt;li&gt;Resource[] and Resource[]= no longer fail when property name is not known&lt;/li&gt;
&lt;li&gt;Redundant usage of chainable was removed resulting in a better performance&lt;/li&gt;
&lt;li&gt;Boolean property typecasting was refactored&lt;/li&gt;
&lt;li&gt;Various issues with setting default Property options were fixed&lt;/li&gt;
&lt;li&gt;Resource#attributes= no longer use public_method_defined? - this is a security fix preventing possible DDOS attacks&lt;/li&gt;
&lt;li&gt;Problems with auto-migrations in multiple repositories were fixed&lt;/li&gt;
&lt;li&gt;Encoding problems with Binary property are fixed&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;dm-adjust:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for InMemoryAdapter&lt;/li&gt;
&lt;li&gt;Add COALESCE to default NULL columns to 0&lt;/li&gt;
&lt;li&gt;Fixed a bug with loading dm-adjust after the dm-do-adapter&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;dm-constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total rewrite&lt;/li&gt;
&lt;li&gt;Fixed for Oracle&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;dm-do-adapter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Warning from DO is gone now&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;dm-migrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;alter table is fixed for postgres&lt;/li&gt;
&lt;li&gt;Property options (such as :length) are now correctly used in migrations&lt;/li&gt;
&lt;li&gt;Support to specify table options when creating a table was added (for things like db engines in mysql etc.)&lt;/li&gt;
&lt;li&gt;Fix bug related to migrating custom types derived from builtin types&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;dm-rails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for Rails 3.1.0&lt;/li&gt;
&lt;li&gt;Storage create/drop tasks are by default noops in case an adapter doesn't support it&lt;/li&gt;
&lt;li&gt;Support for field_naming_convention option&lt;/li&gt;
&lt;li&gt;Support for resource_naming_convention option&lt;/li&gt;
&lt;li&gt;You can now set a custom repository scope for the repository in the IdentityMap middleware&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;dm-serializer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Should&lt;/em&gt; work with psych&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;dm-types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for Resource#dirty? upon indirect property mutation was added (this is huge, more info here: https://github.com/datamapper/dm-types/commit/3d96b1cd2b270a3843877a5...)&lt;/li&gt;
&lt;li&gt;Issues with Paranoid properties and STI were fixed&lt;/li&gt;
&lt;li&gt;JSON property uses multi_json now&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;dm-validations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;h1&gt;valid? is always called even if a resource is not dirty&lt;/h1&gt;&lt;/li&gt;
&lt;li&gt;Issues with JRuby and unicode were fixed&lt;/li&gt;
&lt;li&gt;Massive internal clean-up towards future rewrite that will make validations even more awesome&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;dm-oracle-adapter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many bug fixes&lt;/li&gt;
&lt;li&gt;Important: on MRI it requires ruby-oci8 gem (it's not specified in the gemspec, you need to add it to your gemfiles)&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>DataMapper 1.1.0 released</title>
    <link href="http://datamapper.org/articles/datamapper-110-released.html"/>
    <updated>2011-03-17T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2011-03-17</id>
    <content type="html">&lt;h1&gt;DataMapper 1.1.0 released&lt;/h1&gt;

&lt;p&gt;I'm pleased to announce that we have released DataMapper 1.1.&lt;/p&gt;

&lt;p&gt;This has been one of the most enjoyable releases in recent memory. The community rallied together and compared to the previous release we had at least 3-4x more people submitting patches and working together to get this release ready.&lt;/p&gt;

&lt;p&gt;DataMapper 1.1 brings several minor API changes, warranting the minor version bump, and closes 52 tickets in Lighthouse. There have been many performance improvements, some closing bottlenecks that result in as much as a 20x speedup from the 1.0.2 behaviour.&lt;/p&gt;

&lt;p&gt;As part of the bug fixing process we've refactored some of the objects we use internally to group relationships and dependencies and removed methods and classes that were deprecated in 1.0.&lt;/p&gt;

&lt;h2&gt;Installation&lt;/h2&gt;

&lt;p&gt;DataMapper can be installed with a one-line command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install datamapper dm-sqlite-adapter --no-ri --no-rdoc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The above command assumes you are using SQLite, but if you plan to use MySQL, PostgreSQL or something else replace dm-sqlite-adapter your preferred adapter gem.&lt;/p&gt;

&lt;h2&gt;Changes&lt;/h2&gt;

&lt;p&gt;Here's a &lt;a href=&quot;http://datamapper.lighthouseapp.com/projects/20609/milestones/83769&quot;&gt;full list of the tickets we've resolved for 1.1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ActiveSupport / Extlib dependency is removed. If your code relies on one of these libs then just add a dependency on your own.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DataMapper::Type&lt;/code&gt; is gone now in favour of &lt;code&gt;DataMapper::Property&lt;/code&gt;. The Type API was deprecated in 1.0 but if you still have some Types floating around read how to upgrade them &lt;a href=&quot;http://groups.google.com/group/datamapper/browse_thread/thread/5d3d212c3614db36/ae7be012e06488f6&quot;&gt;in this thread&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;RelationshipSet&lt;/code&gt; and &lt;code&gt;PropertySet&lt;/code&gt; are now &lt;a href=&quot;https://github.com/datamapper/dm-core/commit/e97e9af2021660dc422a035468456ddeadd499fc&quot;&gt;subclasses of a new SubjectSet class&lt;/a&gt;. Please be aware that previously &lt;code&gt;RelationshipSet&lt;/code&gt; and &lt;code&gt;PropertySet&lt;/code&gt; inherited from &lt;code&gt;Hash&lt;/code&gt; and &lt;code&gt;Array&lt;/code&gt;, respectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The property class finder is now improved and it is possible to declare properties that aren't defined in &lt;code&gt;DataMapper::Property&lt;/code&gt; namespace without providing the full const path. For instance you can have &lt;code&gt;YourApp::Properties::FooBar&lt;/code&gt; and you can declare it as &lt;code&gt;property :foo_bar, FooBar&lt;/code&gt;. There's a convention that if your property class has the same name as one of the other properties from &lt;code&gt;DataMapper::Property&lt;/code&gt; namespace then you have to provide the full const path, otherwise your property won't be found.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Removed deprecated methods:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;DataMapper::Collection#add (replaced by #&amp;lt;&amp;lt;)
DataMapper::Collection#build (replaced by #new)
DataMapper::IdentityMap#get (replaced by #[])
DataMapper::IdentityMap#set (replaced by #[]=)
DataMapper::PropertySet#has_property? (replaced by #named?)
DataMapper::PropertySet#slice (replaced by #values_at)
DataMapper::PropertySet#add (replaced by #&amp;lt;&amp;lt;)
DataMapper::Query::Conditions::Comparison#property (replaced by #subject)
DataMapper::Query::Direction#property (replaced by #subject)
DataMapper::Query::Direction#direction (replaced by #operator)
DataMapper::Property#unique (replaced by #unique?)
DataMapper::Property#nullable? (replaced by #allow_nil?)
DataMapper::Property#value (replaced by #dump)
DataMapper::Resource#new_record? (replaced by #new?)
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;How to report issues&lt;/h2&gt;

&lt;p&gt;Please report any issues you find in IRC, on the mailing list, or in the bug tracker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;irc://irc.freenode.net/%23datamapper&quot;&gt;IRC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://groups.google.com/group/datamapper&quot;&gt;Mailing List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://datamapper.lighthouseapp.com/projects/20609-datamapper&quot;&gt;Bug Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>DataMapper 1.0.2 released</title>
    <link href="http://datamapper.org/articles/datamapper-102-released.html"/>
    <updated>2010-09-07T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2010-09-07</id>
    <content type="html">&lt;h1&gt;DataMapper 1.0.2 released&lt;/h1&gt;

&lt;p&gt;I'm pleased to announce that we released DataMapper 1.0.2 this afternoon.&lt;/p&gt;

&lt;p&gt;This fixes a few small bugs discovered since the 1.0.0 release.&lt;/p&gt;

&lt;p&gt;Earlier today I shipped 1.0.1, but there were some bugs discovered in the docs that caused rdoc and YARD to output some really nasty looking warnings. Rather than just telling people to ignore them, I decided to work-around the problems as much as I could. Even still, I'm going to recommend that you use --no-ri --no-rdoc to install the gems because some of the errors are inside YARD and rdoc themselves, and the authors need time to fix the bugs that I can't work around.&lt;/p&gt;

&lt;h2&gt;Installation&lt;/h2&gt;

&lt;p&gt;Install dm-core:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install dm-core --no-ri --no-rdoc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The next thing you want to do is decide which adapter you want to use. For example if you want to use sqlite, do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install dm-sqlite-adapter --no-ri --no-rdoc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It's likely you'll want to use migrations (for classic or auto-migrations), and transactions when using sqlite, so to install them do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install dm-migrations dm-transactions --no-ri --no-rdoc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There is also a metagem which combines several gems into a single package:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install data_mapper --no-ri --no-rdoc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This pulls a nice base stack for DM development. The gems included are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dm-core&lt;/li&gt;
&lt;li&gt;dm-aggregates&lt;/li&gt;
&lt;li&gt;dm-constraints&lt;/li&gt;
&lt;li&gt;dm-migrations&lt;/li&gt;
&lt;li&gt;dm-transactions&lt;/li&gt;
&lt;li&gt;dm-serializer&lt;/li&gt;
&lt;li&gt;dm-timestamps&lt;/li&gt;
&lt;li&gt;dm-validations&lt;/li&gt;
&lt;li&gt;dm-types&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;So putting this all together you can do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install data_mapper dm-sqlite-adapter --no-ri --no-rdoc&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;Changes&lt;/h2&gt;

&lt;p&gt;Here's a list of the tickets we've resolved since 1.0.0:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://datamapper.lighthouseapp.com/projects/20609/milestones/75769&quot;&gt;http://datamapper.lighthouseapp.com/projects/20609/milestones/75769&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;How to report issues&lt;/h2&gt;

&lt;p&gt;Please report any issues you find in IRC, on the mailing list, or in the bug tracker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;irc://irc.freenode.net/%23datamapper&quot;&gt;IRC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://groups.google.com/group/datamapper&quot;&gt;Mailing List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://datamapper.lighthouseapp.com/projects/20609-datamapper&quot;&gt;Bug Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>DataMapper 1.0 released</title>
    <link href="http://datamapper.org/articles/datamapper-100-released.html"/>
    <updated>2010-06-12T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2010-06-12</id>
    <content type="html">&lt;h1&gt;DataMapper 1.0 released&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/datamapper/dm-core/tree/v1.0.0&quot;&gt;DataMapper 1.0 (Vermouth)&lt;/a&gt; was released earlier this week, coinciding with &lt;a href=&quot;http://twitter.com/dbussink&quot;&gt;Dirkjan Bussink&lt;/a&gt;'s &lt;a href=&quot;http://en.oreilly.com/rails2010/public/schedule/detail/14198&quot;&gt;presentation at Railsconf 2010&lt;/a&gt; (&lt;a href=&quot;http://www.slideshare.net/dbussink/datamapper-railsconf2010&quot;&gt;his slides are posted&lt;/a&gt; as well).&lt;/p&gt;

&lt;p&gt;The transition from the 0.10.x series to 1.0 does involve several changes regarding how users will interact with DataMapper.  Unfortunately we have no had time to update all of our documentation on the site, so please bear with us while we get everything in order.  Read on for further details regarding these changes, and users are always welcome in #datamapper on irc.freenode.net and we strive to any answer questions promptly.&lt;/p&gt;

&lt;p&gt;Thank you to everyone in the community, especially this mailing list and the IRC channel. There's no way we could've reached this milestone
without your encouragement and assistance. It's extremely rewarding to see DM hit 1.0, but at the same time it also sets a baseline for future development to build on. In some ways we're only just getting started, the future we have planned for DM is even more ambitious.&lt;/p&gt;

&lt;h2&gt;Before you install&lt;/h2&gt;

&lt;p&gt;The installation process for DM 1.0 is pretty similar to what it was previously in 0.10.x and 0.9.x with a few exceptions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using auto-migration and auto-upgrading require dm-migrations rather than just dm-core. The reason for this is that dm-migrations
should share a lot of code with auto-migrations, but they don’t, and in an attempt to DRY things up we’ve centralized all the code in one
package and will begin refactoring the code over the coming months.&lt;/li&gt;
&lt;li&gt;Transactions require the use of the dm-transactions gem.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is no longer necessary to gem install data_objects or any do_*
gem directly. Each DO based adapter has been extracted into their own
gems, and installing them will setup the dependencies on dm-core and
the appropriate DO gem(s). The new adapters are:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;dm-sqlite-adapter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;dm-postgres-adaper&lt;/li&gt;
&lt;li&gt;dm-mysql-adapter&lt;/li&gt;
&lt;li&gt;dm-oracle-adapter&lt;/li&gt;
&lt;li&gt;dm-sqlserver-adapter&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;Installation&lt;/h2&gt;

&lt;p&gt;Install dm-core:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install dm-core&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The next thing you want to do is decide which adapter you want to use. For example if you want to use sqlite, do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install dm-sqlite-adapter&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This should pull in data_objects and do_sqlite3 automatically, so no need to specify either of those explicitly anymore.
It’s likely you’ll want to use migrations (for classic or auto-migrations), and transactions when using sqlite, so to install them
do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install dm-migrations dm-transactions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There is also a metagem which combines several gems into a single package:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install data_mapper&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This pulls a nice base stack for DM development. The gems included are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dm-core&lt;/li&gt;
&lt;li&gt;dm-aggregates&lt;/li&gt;
&lt;li&gt;dm-constraints&lt;/li&gt;
&lt;li&gt;dm-migrations&lt;/li&gt;
&lt;li&gt;dm-transactions&lt;/li&gt;
&lt;li&gt;dm-serializer&lt;/li&gt;
&lt;li&gt;dm-timestamps&lt;/li&gt;
&lt;li&gt;dm-validations&lt;/li&gt;
&lt;li&gt;dm-types&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;So putting this all together you can do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ gem install data_mapper dm-sqlite-adapter&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;Changes&lt;/h2&gt;

&lt;p&gt;A lot of tickets have been addressed during the release candidate cycle and you can refer to the earlier RC notes for change details (&lt;a href=&quot;http://datamapper.org/articles/datamapper-100_rc2_released.html&quot;&gt;RC2&lt;/a&gt;, &lt;a href=&quot;http://datamapper.org/articles/datamapper-100_rc3_released.html&quot;&gt;RC3&lt;/a&gt;).
You should also refer to the list of 61 tickets we've resolved for the 1.0 milestone:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://datamapper.lighthouseapp.com/projects/20609/milestones/62234-0103&quot;&gt;http://datamapper.lighthouseapp.com/projects/20609/milestones/62234-0103&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;How to report issues&lt;/h2&gt;

&lt;p&gt;Please report any issues you find in IRC, on the mailing list, or inthe tracker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;irc://irc.freenode.net/%23datamapper&quot;&gt;IRC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://groups.google.com/group/datamapper&quot;&gt;Mailing List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://datamapper.lighthouseapp.com/projects/20609-datamapper&quot;&gt;Bug Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>DataMapper 1.0.0 rc3 released</title>
    <link href="http://datamapper.org/articles/datamapper-100_rc3_released.html"/>
    <updated>2010-05-27T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2010-05-27</id>
    <content type="html">&lt;h1&gt;DataMapper 1.0.0 rc3 released&lt;/h1&gt;

&lt;p&gt;Today I released DataMapper 1.0.0 rc3. It includes several bugs fixes
for issues found in rc2, as well as a few other tickets in the queue.&lt;/p&gt;

&lt;h2&gt;How do I install rc3?&lt;/h2&gt;

&lt;p&gt;Since the installation process is pretty similar to rc2, I'm going to
give you the abbreviated version. &lt;a href=&quot;http://bit.ly/dC7U1p&quot;&gt;Click here&lt;/a&gt; if
you would like to see the release notes.&lt;/p&gt;

&lt;p&gt;1) Install dm-core:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install dm-core --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;2) Install an adapter:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install dm-sqlite-adapter --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;3a) Install supporting gems:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install dm-migrations dm-transactions --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;3b) OR install a metagem with several well tested supporting gems:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install data_mapper --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This pulls a nice base stack for DM development. The gems included are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dm-core&lt;/li&gt;
&lt;li&gt;dm-aggregates&lt;/li&gt;
&lt;li&gt;dm-constraints&lt;/li&gt;
&lt;li&gt;dm-migrations&lt;/li&gt;
&lt;li&gt;dm-transactions&lt;/li&gt;
&lt;li&gt;dm-serializer&lt;/li&gt;
&lt;li&gt;dm-timestamps&lt;/li&gt;
&lt;li&gt;dm-validations&lt;/li&gt;
&lt;li&gt;dm-types&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Or use this one-liner to install everything in one go:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install data_mapper dm-sqlite-adapter --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;What's changed?&lt;/h2&gt;

&lt;p&gt;To see more information about the tickets we've closed since 0.10.2
check out the &lt;a href=&quot;http://bit.ly/b4yVl3&quot;&gt;current milestone status&lt;/a&gt; on Lighthouse.&lt;/p&gt;

&lt;h2&gt;How to report issues&lt;/h2&gt;

&lt;p&gt;Please report any issues you find in IRC, on the mailing list, or in
the tracker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;irc://irc.freenode.net/%23datamapper&quot;&gt;IRC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://groups.google.com/group/datamapper&quot;&gt;Mailing List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://datamapper.lighthouseapp.com/projects/20609-datamapper&quot;&gt;Bug Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>DataMapper 1.0.0 rc2 released</title>
    <link href="http://datamapper.org/articles/datamapper-100_rc2_released.html"/>
    <updated>2010-05-20T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2010-05-20</id>
    <content type="html">&lt;h1&gt;DataMapper 1.0.0 rc2 released&lt;/h1&gt;

&lt;p&gt;I just wanted to give you the heads up that we've just released
DataMapper 1.0.0 rc2.&lt;/p&gt;

&lt;p&gt;With RailsConf coming up, and the launch of DM 1.0, we are starting
the RC process now to make sure the installation process is solid and
that the API is stable beforehand.&lt;/p&gt;

&lt;h2&gt;Installation Changes&lt;/h2&gt;

&lt;p&gt;The installation process for DM 1.0 is pretty similar to what it was
previously in 0.10.x and 0.9.x with a few exceptions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Using auto-migration and auto-upgrading require dm-migrations
rather than just dm-core. The reason for this is that dm-migrations
&lt;em&gt;should&lt;/em&gt; share alot of code with auto-migrations, but they don't, and
in an attempt to DRY things up we've centralized all the code in one
package and will begin refactoring the code over the coming months.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transactions require the use of the dm-transactions gem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is no longer necessary to gem install data_objects or any do_*
gem directly. Each DO based adapter has been extracted into their own
gems, and installing them will setup the dependencies on dm-core and
the appropriate DO gem(s). The new adapters are:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;dm-sqlite-adapter&lt;/li&gt;
&lt;li&gt;dm-postgres-adaper&lt;/li&gt;
&lt;li&gt;dm-mysql-adapter&lt;/li&gt;
&lt;li&gt;dm-oracle-adapter&lt;/li&gt;
&lt;li&gt;dm-sqlserver-adapter&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;How do I install the RC?&lt;/h2&gt;

&lt;p&gt;The first step is to make sure you've installed extlib 0.9.15:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install extlib -v0.9.15
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note that this will go away in the next RC. I forgot to add extlib
0.9.15 as a dependency for rc2, which is why it's required explicitly
at the moment.&lt;/p&gt;

&lt;p&gt;Since this is a prerelease gem you have to install dm-core with the --
pre option, eg:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install dm-core --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If you don't specify --pre, rubygems will download the last stable
version of DM, which is 0.10.2.&lt;/p&gt;

&lt;p&gt;The next thing you want to do is decide which adapter you want to use.
For example if you want to use sqlite, do:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install dm-sqlite-adapter --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This should pull in data_objects and do_sqlite3 automatically, so no
need to specify either of those explicitly anymore.&lt;/p&gt;

&lt;p&gt;It's likely you'll want to use migrations (for classic or auto-
migrations), and transactions when using sqlite, so to install them
do:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install dm-migrations dm-transactions --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;There is also a metagem which combines several gems into a single
package:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install data_mapper --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This pulls a nice base stack for DM development. The gems included
are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/datamapper/dm-core&quot;&gt;dm-core&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/datamapper/dm-aggregates&quot;&gt;dm-aggregates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/datamapper/dm-constraints&quot;&gt;dm-constraints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/datamapper/dm-migrations&quot;&gt;dm-migrations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/datamapper/dm-transactions&quot;&gt;dm-transactions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/datamapper/dm-serializer&quot;&gt;dm-serializer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/datamapper/dm-timestamps&quot;&gt;dm-timestamps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/datamapper/dm-validations&quot;&gt;dm-validations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/datamapper/dm-types&quot;&gt;dm-types&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;So putting this all together you can do:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install extlib -v0.9.15
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install data_mapper dm-sqlite-adapter --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Again, the extlib installation step will not be necessary in the next
RC.&lt;/p&gt;

&lt;h2&gt;What are the changes?&lt;/h2&gt;

&lt;p&gt;There are alot of internal refactorings, some bug fixes, but for the
most part 1.0.0 should be quite similar to 0.10.2. We decided to
launch 1.0 because DM has been in a relatively stable state for the
last 6 months, and there aren't any really major API changes left.
Anything that's planned are more additions rather than changes to
existing functionality, so we decided it was better to freeze the
current API at 1.0 and release for RailsConf.&lt;/p&gt;

&lt;p&gt;There are some simplifications in the Property/Type API you should be
aware of. Some custom types you have may require slight modifications
to work with 1.0.0 rc2. Piotr Solnica will be posting some information
about how to do the modification, but for now look at the Property
subclasses in dm-types as well as inside dm-core to get an idea of how
it works.&lt;/p&gt;

&lt;p&gt;As mentioned, the other large change is how auto-migrations have been
moved to dm-migrations, as well as transactions to dm-transactions.
The main reason we moved those from the core is that only a small
fraction of DM adapters support migrations and transactions, and it
didn't seem right for the core layer to know anything about those
concerns. I felt that having them in a separate package allows us to
eliminate some duplcation (in the case of migrations), and ensure
transactions gets more attention than if it was part of core.&lt;/p&gt;

&lt;h2&gt;Where was rc1?&lt;/h2&gt;

&lt;p&gt;You might be asking yourself &quot;where was rc1?&quot;. Well... I decided to do
a soft launch of the first rc and just announce it to people in the
&lt;a href=&quot;irc://irc.freenode.net/%23datamapper&quot;&gt;#datamapper&lt;/a&gt; IRC channel on freenode. It's been a few months since we
did any kind of release, and with the new gem organization I wasn't
sure if we'd have all the kinks worked out. There was one small issue
actually, so we bumped to rc2 and released the same day. We also added
the latest DO as a dependency, which has a number of improvements/bug
fixes, so I think this was a good thing overall.&lt;/p&gt;

&lt;h2&gt;How to report issues&lt;/h2&gt;

&lt;p&gt;Please report any issues you find in IRC, on the mailing list, or in
the tracker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;irc://irc.freenode.net/%23datamapper&quot;&gt;IRC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://groups.google.com/group/datamapper&quot;&gt;Mailing List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://datamapper.lighthouseapp.com/projects/20609-datamapper&quot;&gt;Bug Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>DataMapper 0.10.2 is Released</title>
    <link href="http://datamapper.org/articles/datamapper_0102_released.html"/>
    <updated>2009-12-11T00:00:00-08:00</updated>
    <id>tag:datamapper.org,2009-12-11</id>
    <content type="html">&lt;h1&gt;DataMapper 0.10.2 is Released&lt;/h1&gt;

&lt;p&gt;This release adds new Set operations, fixes multiple bugs, and even more of the public API is specced.&lt;/p&gt;

&lt;p&gt;Read the &lt;a href=&quot;http://bit.ly/5l5ftv&quot;&gt;Release Announcement&lt;/a&gt; for more info&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>DataMapper at RubyEnRails Amsterdam 2009</title>
    <link href="http://datamapper.org/articles/datamapper-at-rer-2009.html"/>
    <updated>2009-12-07T00:00:00-08:00</updated>
    <id>tag:datamapper.org,2009-12-07</id>
    <content type="html">&lt;h1&gt;DataMapper at RubyEnRails Amsterdam 2009&lt;/h1&gt;

&lt;object width=&quot;400&quot; height=&quot;225&quot;&gt;&lt;param name=&quot;allowfullscreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot; /&gt;&lt;param name=&quot;movie&quot; value=&quot;http://vimeo.com/moogaloop.swf?clip_id=7643064&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1&quot; /&gt;&lt;embed src=&quot;http://vimeo.com/moogaloop.swf?clip_id=7643064&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; allowscriptaccess=&quot;always&quot; width=&quot;400&quot; height=&quot;225&quot;&gt;&lt;/embed&gt;&lt;/object&gt;


&lt;p&gt;&lt;a href=&quot;http://vimeo.com/7643064&quot;&gt;ReR09 - DirkjanBussink&lt;/a&gt; from &lt;a href=&quot;http://vimeo.com/user2623183&quot;&gt;Interbureau Holder&lt;/a&gt; on &lt;a href=&quot;http://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;At this year's &lt;a href=&quot;http://2009.rubyenrails.nl/&quot;&gt;RubyEnRails 2009&lt;/a&gt;, Dirkjan Bussink
presented the current 0.10.x series of DataMapper and gave a preview of what
lies ahead for the 1.0 release.&lt;/p&gt;

&lt;div style=&quot;width:425px;text-align:left&quot; id=&quot;__ss_2390430&quot;&gt;&lt;a style=&quot;font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;&quot; href=&quot;http://www.slideshare.net/dbussink/datamapper-2390430&quot; title=&quot;DataMapper&quot;&gt;DataMapper&lt;/a&gt;&lt;object style=&quot;margin:0px&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=datamapper-091031084329-phpapp02&amp;stripped_title=datamapper-2390430&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;&lt;embed src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=datamapper-091031084329-phpapp02&amp;stripped_title=datamapper-2390430&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style=&quot;font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;&quot;&gt;View more &lt;a style=&quot;text-decoration:underline;&quot; href=&quot;http://www.slideshare.net/&quot;&gt;documents&lt;/a&gt; from &lt;a style=&quot;text-decoration:underline;&quot; href=&quot;http://www.slideshare.net/dbussink&quot;&gt;Dirkjan Bussink&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;

</content>
  </entry>
  
  <entry>
    <title>DataMapper 0.10 is Released</title>
    <link href="http://datamapper.org/articles/datamapper_010_released.html"/>
    <updated>2009-09-15T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2009-09-15</id>
    <content type="html">&lt;h1&gt;DataMapper 0.10 is Released&lt;/h1&gt;

&lt;p&gt;DataMapper 0.10 is ready for release. We've worked on it for the past 11 months,
pushed 1250 commits, written 3000+ specs, and fixed 140 tickets in the process.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>DataMapper Presented at RailsConf 2008</title>
    <link href="http://datamapper.org/articles/datamapper_presented_at_railsconf08.html"/>
    <updated>2008-06-10T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2008-06-10</id>
    <content type="html">&lt;h1&gt;DataMapper Presented at RailsConf 2008&lt;/h1&gt;

&lt;p&gt;Yehuda Katz (wycats) gave an updated version of his &quot;DataMapper - The
Persistence Framework&quot; presentation at Rails Conf 2008. Though video isn't
available for the talk, he was nice enough to share his slides.&lt;/p&gt;

&lt;div style=&quot;width:425px;text-align:left; margin:0 auto;&quot; id=&quot;__ss_445593&quot;&gt;&lt;object style=&quot;margin:0px&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slideshare.net/swf/ssplayer2.swf?doc=datamapper-1212540345128334-9&quot;/&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;&lt;embed src=&quot;http://static.slideshare.net/swf/ssplayer2.swf?doc=datamapper-1212540345128334-9&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style=&quot;font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/?src=embed&quot;&gt;&lt;img src=&quot;http://static.slideshare.net/swf/logo_embd.png&quot; style=&quot;border:0px none;margin-bottom:-5px&quot; alt=&quot;SlideShare&quot;/&gt;&lt;/a&gt; | &lt;a href=&quot;http://www.slideshare.net/wycats/datamapper?src=embed&quot; title=&quot;View DataMapper on SlideShare&quot;&gt;View&lt;/a&gt; | &lt;a href=&quot;http://www.slideshare.net/upload?src=embed&quot;&gt;Upload your own&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;


&lt;p&gt;They're available for download and review direct from SlideShare at
&lt;a href=&quot;http://www.slideshare.net/wycats/datamapper/&quot;&gt;http://www.slideshare.net/wycats/datamapper/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Adam French (afrench) was in attendance and participated in the 'Birds Of A
Feather' discussion panel on &lt;a href=&quot;http://en.oreilly.com/rails2008/public/schedule/detail/4426&quot;&gt;Rails Alternatives and You&lt;/a&gt; led by &lt;a href=&quot;http://www.metabates.com/&quot;&gt;Mark Bates&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>DataMapper 0.9 is Released</title>
    <link href="http://datamapper.org/articles/datamapper_090_released.html"/>
    <updated>2008-05-27T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2008-05-27</id>
    <content type="html">&lt;h1&gt;DataMapper 0.9 is Released&lt;/h1&gt;

&lt;p&gt;DataMapper 0.9 is ready for the world. It brings with it a massive overhaul of
the internals of DataMapper, a shift in terminology, a dramatic bump in speed,
improved code-base organization, and support for more than just database
data-stores.&lt;/p&gt;

&lt;p&gt;To install it:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo gem install addressable english rspec
sudo gem install data_objects do_mysql do_postgres do_sqlite3
sudo gem install dm-core
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This is NOT a backwards compatible release. Code written for DataMapper 0.3 will
not function with DataMapper 0.9.* due to syntactical changes and library
improvements.&lt;/p&gt;

&lt;p&gt;REPEAT: This is NOT a backwards compatible release.&lt;/p&gt;

&lt;table class=&quot;changeSummary&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
  &lt;thead&gt;
    &lt;th&gt;&amp;nbsp;&lt;/th&gt;
    &lt;th&gt;DataMapper 0.3&lt;/th&gt;
    &lt;th&gt;DataMapper 0.9&lt;/th&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;Creating a class&lt;/th&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:Base&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:Resource&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;Keys&lt;/th&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Key was not mandatory&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Automatically added +id+ if missing&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Natural Key&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Composite Key&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# keys are now mandatory&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;no&quot;&gt;Serial&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Natural Key&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Composite Key&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;Properties&lt;/th&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:string&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;ss&quot;&gt;:text&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posted_on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:datetime&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:active&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;ss&quot;&gt;:boolean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;no&quot;&gt;Text&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posted_on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DateTime&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:active&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Boolean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;Associations&lt;/th&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:comments&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:blog&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;has_and_belongs_to_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:categories&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;has_one&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:author&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:comments&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:blog&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:categories&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Resource&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:author&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;Finders&lt;/th&gt;
      &lt;td&gt;
        
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;created_at DESC&amp;#39;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;active = ?&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;SELECT 1&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;UPDATE posts...&amp;#39;&lt;/span&gt;
        
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
      &lt;td&gt;
        
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:created_at&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;active = ?&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;SELECT 1&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;UPDATE posts...&amp;#39;&lt;/span&gt;
        
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;Validations&lt;/th&gt;
      &lt;td&gt;
        
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;validates_presence_of&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;validates_numericality_of&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rating&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;validates_format_of&lt;/span&gt;       &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;ss&quot;&gt;:with&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:email_address&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;validates_length_of&lt;/span&gt;       &lt;span class=&quot;ss&quot;&gt;:summary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:within&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;validates_uniqueness_of&lt;/span&gt;   &lt;span class=&quot;ss&quot;&gt;:slug&lt;/span&gt;
        
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
      &lt;td&gt;
        
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;validates_present&lt;/span&gt;   &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;validates_is_number&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rating&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;validates_format&lt;/span&gt;    &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:email_address&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;validates_length&lt;/span&gt;    &lt;span class=&quot;ss&quot;&gt;:summary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;validates_is_unique&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:slug&lt;/span&gt;
        
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;Callbacks&lt;/th&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;before_save&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:categorize&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;before_create&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# do stuff with post&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# return false to abort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
      &lt;td&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:categorize&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:create&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# do stuff with self&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# throw :halt to abort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

</content>
  </entry>
  
  <entry>
    <title>DataMapper Presented at MWRC 2008</title>
    <link href="http://datamapper.org/articles/datamapper_talk_atmwrc08.html"/>
    <updated>2008-04-10T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2008-04-10</id>
    <content type="html">&lt;h1&gt;DataMapper Presented at MWRC 2008&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://mwrc2008.confreaks.com/04katz.html&quot; style=&quot;border:10px; color:#FFF; text-decoration:none;&quot;&gt;
&lt;img src=&quot;/images/wykatz_at_mwrc2008.png&quot; title=&quot;Yehuda Katz' presentation entitled 'Faster, Better ORM With DataMapper&quot;/&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this year's &lt;a href=&quot;http://mtnwestrubyconf.org/2008/&quot;&gt;Mountain West Ruby Conference 2008&lt;/a&gt;,
DataMapper's own Yehuda Katz gave a presentation entitled &quot;Faster, Better ORM
With DataMapper.&quot;&lt;/p&gt;

&lt;p&gt;The video of the talk is available for viewing and downloading at
&lt;a href=&quot;http://mwrc2008.confreaks.com/04katz.html&quot;&gt;http://mwrc2008.confreaks.com/04katz.html&lt;/a&gt; and is brought to you by the
good people at &lt;a href=&quot;http://confreaks.net/&quot;&gt;confreaks.com&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Spotlight on... Laziness</title>
    <link href="http://datamapper.org/articles/spotlight_on_laziness.html"/>
    <updated>2008-04-03T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2008-04-03</id>
    <content type="html">&lt;h1&gt;Spotlight on... Laziness&lt;/h1&gt;

&lt;p&gt;Laziness. It means &quot;an unwillingness to work or use energy&quot; and typically
indicates that the dishes don't get washed after lunch, the bath tub doesn't get
cleaned, and the trash sits around an extra few days and stinks up the place.&lt;/p&gt;

&lt;p&gt;But that very same definition in software takes on a whole new meaning: To avoid
doing work you don't have to do for as long as you can avoid it; sometimes never
doing it at all. It's a good thing. It means that expensive and slow tasks can
be put off until the very last cycle possible and thus only incur their cost
when it really is worth it. Maybe you never execute the code at all.&lt;/p&gt;

&lt;p&gt;You could put off running a specific subroutine because it's slow, or because it
locks a file that might be needed elsewhere, or because instantiating the
resulting object eats up RAM. Either way, deferring execution of a block of code
until the very last possible moment can be the difference between a snappy
application that rarely slows down and a slow application that rarely speeds up.&lt;/p&gt;

&lt;p&gt;But laziness isn't without its hidden costs. If you put off everything to the
very last moment, you forfeit the opportunity to do more than one thing at a
time, and likely create more work for yourself, rather than less.&lt;/p&gt;

&lt;p&gt;So where's the balance?&lt;/p&gt;

&lt;p&gt;Ultimately, it depends on your application. The tools you use should offer you
the flexibility you need to design your application optimally. Every system,
after all, is unique and breaks the mold of systems before it.&lt;/p&gt;

&lt;p&gt;This brings us to DataMapper.&lt;/p&gt;

&lt;h2&gt;Lazy-loading attributes&lt;/h2&gt;

&lt;p&gt;You likely already know that DataMapper supports lazy properties.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:Resource&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Serial&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;# auto_incrementing primary key&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:lazy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# intentionally lazy&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;no&quot;&gt;Text&lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;# lazy by default&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In this case, we're intentionally marking this Post's &lt;code&gt;:title&lt;/code&gt; property as lazy,
as well as letting the &lt;code&gt;:body&lt;/code&gt; be lazy by default. If we go and inspect our
query log for the retrieval of a post with the ID of 1, we see&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;DataMapper didn't request the two lazy columns. But when we call &lt;code&gt;.title&lt;/code&gt; off of
our post, we suddenly see&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This is the very definition of a lazy-loaded property; The lazy column didn't
get requested from our data store until we actually needed it, and no sooner.&lt;/p&gt;

&lt;p&gt;But this is just for one individual instance of a post. How does this behave
when we have a collection of posts and iteratively call the &lt;code&gt;.title&lt;/code&gt; method?&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;DataMapper loaded up the title for all of the posts in our collection in one
query. It didn't issue the lazy-load retrieval from above over and over for each
individual post, nor did it chicken out and issue the lazy-load retrieval for
ALL of the posts in the data store.&lt;/p&gt;

&lt;p&gt;When you retrieve a set of results using DataMapper's &lt;code&gt;.all&lt;/code&gt;, each instance it
returns knows about the others in the result set, which makes it brutally simple
to issue just one lazy-load retrieval of &lt;code&gt;:title&lt;/code&gt;, and thus solving the n+1
query problem without having to do anything special in the initial retrieval.&lt;/p&gt;

&lt;h2&gt;Contextual Lazy-loading&lt;/h2&gt;

&lt;p&gt;With a recent commit by &lt;a href=&quot;http://web.archive.org/web/20080706235220/http://www.guyvdb.info/ruby/lazy-loading-properties-in-datamapper/&quot;&gt;Guy van den Berg&lt;/a&gt;,
DataMapper just got a whole lot more flexible.&lt;/p&gt;

&lt;p&gt;Most applications have only a few main views of a resource: a brief summary view
used in listing results, a complete representation that might appear on a show
page and a comprehensive view for when someone is editing something and needs
access to metadata. Wouldn't it be nice to lump all of the lazy-load retrieval
queries into one query which loads up multiple lazy properties, rather than
query after query for each lazy property as you call them?&lt;/p&gt;

&lt;p&gt;DataMapper now does this!&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:Resource&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Serial&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:lazy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:summary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:brief&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;no&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;ss&quot;&gt;:lazy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:summary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So now, when you load an attribute with the &lt;code&gt;:summary&lt;/code&gt; context, DataMapper will
load up all of the other lazy-loaded properties marked &lt;code&gt;:summary&lt;/code&gt; in one query
to the data store.&lt;/p&gt;

&lt;p&gt;In your query log, you'll see:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;c1&quot;&gt;-- initial load&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- lazy-loading of multiple properties in a given context in one query&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If you use this wisely, it would mean that DataMapper will never load more than
it needs nor will it ever fire off more than the absolutely necessary amount of
queries to get the job done.&lt;/p&gt;

&lt;p&gt;It's lazy ;-)&lt;/p&gt;

&lt;h2&gt;Strategic Eager Loading&lt;/h2&gt;

&lt;p&gt;Well, not for everything.&lt;/p&gt;

&lt;p&gt;Returning for a little bit to our &quot;loaded set&quot; discussion from above, every item
you pull out of the data store is aware of any other item that got pulled along
with it. This is a very powerful feature which lets DataMapper defeat n+1 query
problems when dealing with associations as well as lazy-loading of properties.&lt;/p&gt;

&lt;p&gt;For example, this is a severe &quot;no no&quot; in ActiveRecord:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;  &lt;span class=&quot;no&quot;&gt;Zoo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zoo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;zoo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;animals&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This is a very bad idea because the ORM must query the &quot;animals&quot; table over and
over again to load the association for each iteration. It's far better to use
&lt;code&gt;Zoo.find(:all, :include =&amp;gt; [ :animals ]).each {}&lt;/code&gt; because a JOIN occurs and
everything is retrieved in 1 query.&lt;/p&gt;

&lt;p&gt;But the same issue doesn't exist in DataMapper. Each instance is aware of the
other instances it was retrieved with. The same iterator example from above only
fires off 2 queries as you're iterating and calling the association inside the
&lt;code&gt;each&lt;/code&gt;. If you forget to &lt;code&gt;:include =&amp;gt; [ :association ]&lt;/code&gt; in the initial query,
DataMapper only ever fires off one more query to get what it needs.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://yehudakatz.com/&quot;&gt;Yehuda Katz&lt;/a&gt; has aptly named this 'Strategic Eager Loading'.&lt;/p&gt;

&lt;h2&gt;Getting Around to It&lt;/h2&gt;

&lt;p&gt;A conclusion for our talk about laziness will be written whenever I get around
to it.&lt;/p&gt;

&lt;p&gt;For now, just remember that DataMapper embraces lazy-loading, yet isn't overly
zealous when the lazy properties are finally retrieved. It also fills
associations strategically, and assumes you're going to iterate over the set of
results. You don't have to catch yourself when you write an iterator because
DataMapper loads associations for all of your items in the set, rather than on a
one-by-one basis.&lt;/p&gt;

&lt;p&gt;And, most importantly, you can avoid doing work you don't have to do for as long
as you can avoid it.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Spotlight on... Composite Keys</title>
    <link href="http://datamapper.org/articles/spotlight_on_cpk.html"/>
    <updated>2008-03-29T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2008-03-29</id>
    <content type="html">&lt;h1&gt;Spotlight on... Composite Keys&lt;/h1&gt;

&lt;p&gt;For those of us who have taken a course on database design in college or
university, you may have run across a concept called 'Composite Primary Keys'
(or sometimes 'Compound Keys' or 'Concatenated Keys', and abbreviated CPKs).
It's usually right before you tackle JOINs and right after you fight with the
&quot;surrogate key&quot; or &quot;primary key&quot; concept.&lt;/p&gt;

&lt;p&gt;Boiling CPKs down, they're just a way of identifying a row by multiple keys
rather than one. So instead of an auto_incrementing &quot;serial&quot; primary key (as in
&lt;code&gt;id&lt;/code&gt;), you'd have a combination of &lt;code&gt;some_column&lt;/code&gt; and &lt;code&gt;some_other_column&lt;/code&gt; that
would uniquely identify a row.&lt;/p&gt;

&lt;p&gt;CPKs aren't as prevalent in the Rails world as Serial Keys (such as the
auto-incrementing &lt;code&gt;:id&lt;/code&gt; column), but if you're going to support legacy,
integration or reporting databases or just de-normalized schemas for performance
reasons, they can be invaluable. So sure, Surrogate Keys are a great
convenience, but sometimes they just aren't an option.&lt;/p&gt;

&lt;p&gt;Let's briefly take a look at how a few ruby ORMs support Composite Primary Keys
and then we'll talk about DataMapper's support for CPKs.&lt;/p&gt;

&lt;h2&gt;ActiveRecord&lt;/h2&gt;

&lt;p&gt;In short, ActiveRecord doesn't support CPKs without the help of an external
library. &lt;a href=&quot;http://drnicwilliams.com/about/&quot;&gt;Dr. Nic Williams&lt;/a&gt;
&lt;a href=&quot;http://compositekeys.rubyforge.org/&quot;&gt;Composite Keys&lt;/a&gt; is an effort to overcome
this limitation.&lt;/p&gt;

&lt;h2&gt;Sequel&lt;/h2&gt;

&lt;p&gt;Unlike ActiveRecord, Sequel supports CPKs natively:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;Sequel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:Model&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set_primary_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ruby&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;hello world&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [ &amp;#39;ruby&amp;#39;, &amp;#39;hello world&amp;#39; ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;p(attribution). example compiled from &lt;a href=&quot;http://github.com/jeremyevans/sequel&quot;&gt;http://github.com/jeremyevans/sequel&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;DataMapper&lt;/h2&gt;

&lt;p&gt;The latest DataMapper was designed from the ground up to support CPKs:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Pig&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:Resource&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;pig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Pig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Porky&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;pig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [ 1, &amp;#39;Wilbur&amp;#39; ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We declared our keys by adding the &lt;code&gt;:key =&amp;gt; true&lt;/code&gt; to the appropriate properties.
The order is important as it will determine the order keys are addressed
throughout the system.&lt;/p&gt;

&lt;p&gt;Next, we mixed and matched the keys' types. &lt;code&gt;:id&lt;/code&gt; is a Integer, but &lt;code&gt;:slug&lt;/code&gt; is a
String. DataMapper didn't flinch when we defined a key column as a String
because it supports &lt;a href=&quot;http://en.wikipedia.org/wiki/Natural_key&quot;&gt;Natural Keys&lt;/a&gt; as
well.&lt;/p&gt;

&lt;p&gt;Lastly, when retrieving rows via &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;[]&lt;/code&gt; with a CPK, we supplied the keys
in the order they were defined within our model. For example, we defined &lt;code&gt;:id&lt;/code&gt;
first, then &lt;code&gt;:slug&lt;/code&gt; second; later, we retrieved Porky by specifying his &lt;code&gt;:id&lt;/code&gt;
and &lt;code&gt;:slug&lt;/code&gt; in the same order. Additionally, when we asked Wilbur for his keys,
he handed us an array in the order the keys were defined.&lt;/p&gt;

&lt;p&gt;We didn't need to mix in an external library to get support for CPKs, nor did we
need to call a &lt;code&gt;set_primary_key&lt;/code&gt; method and then supply more than one key to it.
DataMapper supports Composite Primary Keys intuitively and without compromise!&lt;/p&gt;

&lt;p&gt;In later &quot;Spotlight On...&quot; articles, we'll examine and demonstrate other
DataMapper features or persistence concepts as well as compare similar features
with other ORMs or libraries.&lt;/p&gt;

&lt;p&gt;*[CPK]: Composite Primary Keys&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Great Refactoring</title>
    <link href="http://datamapper.org/articles/the_great_refactoring.html"/>
    <updated>2008-03-22T00:00:00-07:00</updated>
    <id>tag:datamapper.org,2008-03-22</id>
    <content type="html">&lt;h1&gt;The Great Refactoring&lt;/h1&gt;

&lt;p&gt;&quot;Tip&quot; DataMapper (hosted on &lt;a href=&quot;http://github.com/datamapper/dm-core&quot;&gt;github&lt;/a&gt;) is
going through a dramatic re-factor. Here's a quick summary of the anticipated
NEW public API.&lt;/p&gt;

&lt;h2&gt;Not Just for Databases Anymore&lt;/h2&gt;

&lt;p&gt;DataMapper's class terminology will change and 'de-couple' itself from
database-specific terminology. Gone are &quot;database&quot;, &quot;table&quot;, &quot;column&quot; and
&quot;join&quot;. Say hello to &quot;Repository&quot;, &quot;Resource&quot;, &quot;Property&quot;, and &quot;Link&quot;.&lt;/p&gt;

&lt;p&gt;&quot;Why would you want to do that?&quot;, you ask. Ultimately it's because DataMapper
will soon support different types of persistence layers, not just databases.
It'll talk to all sorts of things like web services (REST and such), XML files,
YAML files, non-relational databases, even custom file-types or services of your
own design. Just implement an Adapter that conforms to a certain API and
DataMapper could support any type of data store. No need for a completely
separate library or anything.&lt;/p&gt;

&lt;p&gt;As an added benefit, DataMapper become more &quot;RESTful&quot;. &lt;a href=&quot;http://tomayko.com/writings/rest-to-my-wife&quot;&gt;Ryan Tomayko&lt;/a&gt;
has a very good explanation
of REST that all should read entitled &lt;a href=&quot;http://tomayko.com/writings/rest-to-my-wife&quot;&gt;How I Explained REST to My Wife&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Model Definitions Are a Little Different&lt;/h2&gt;

&lt;p&gt;Since we're changing up the terminology, model definitions are going to change
up a little bit. Here's what a Planet model would look like using the new API:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Planet&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:Resource&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;resource_names&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:legacy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;dying_planets&amp;#39;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;Integer&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;ss&quot;&gt;:private&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;A couple of things are going on here. First, DataMapper::Base and
DataMapper::Persistence are gone and replaced with &lt;a href=&quot;http://rubydoc.info/github/datamapper/dm-core/master/DataMapper/Resource&quot;&gt;DataMapper::Resource&lt;/a&gt;.
Next &lt;code&gt;set_table_name&lt;/code&gt; has been replaced with
&lt;code&gt;resource_names&lt;/code&gt; hash where you specify which arena play occurs in. After that
we have a couple of Property definitions that look a little different.&lt;/p&gt;

&lt;p&gt;First off, Properties will no longer take &lt;code&gt;:symbols&lt;/code&gt; for their types and instead
take real constants like String, Integer, DateTime. Also on the docket are the
ability to define your own custom types.&lt;/p&gt;

&lt;p&gt;Think about that for a minute. If developers are able to define their own custom
types with their own materialization and serialization methods, DataMapper will
be able to support all kinds of wild data-types like GIS information, network
information, marshaled objects, JSON...pretty much anything a developer might
need, or want.&lt;/p&gt;

&lt;h2&gt;A Command-Line Interface&lt;/h2&gt;

&lt;p&gt;Taking a lesson from web frameworks, DataMapper will sport an interactive
command-line so that you can browse your resources without the need to load up
the entire environment of your application. Here's an example session:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;dm mysql://root@localhost/great_musicians  &lt;span class=&quot;c&quot;&gt;# connecting to a repository&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;An IRB session boots up...&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the_king&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;elvis&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the_king&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alive?&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; maybe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This is very similar to &lt;code&gt;script/console&lt;/code&gt; in Rails or &lt;code&gt;merb -i&lt;/code&gt; in Merb, only it
won't load up the entire environment of your application, just your DataMapper
resources and their associations, methods, and such. If you prefer &quot;fat models&quot;,
this will constitute the core of your application.&lt;/p&gt;

&lt;h2&gt;How This All Comes Together&lt;/h2&gt;

&lt;p&gt;This is the coolest new feature of DataMapper: we're skipping all the way from
0.3.0 to 0.9! Get excited, contact the press, fire up the blogosphere! Its a
huge jump and we're honestly concerned that people may not be able to handle it.&lt;/p&gt;

&lt;p&gt;Alright, so it's not &lt;em&gt;that&lt;/em&gt; big of a deal, but we're confident that all of this
will get DataMapper so close to going 1.0 that we'll be able to taste it. To get
there, DataMapper's more advanced features like single table inheritance,
paranoia, and chained associations will be re-implemented to use all this new
stuff, and then we're sure 0.9 will need a touch up or two.&lt;/p&gt;

&lt;p&gt;So close....so very very close...&lt;/p&gt;

&lt;p&gt;Stay tuned in to the &lt;a href=&quot;http://groups.google.com/group/datamapper&quot;&gt;mailing list&lt;/a&gt;,
check up on the &lt;a href=&quot;http://datamapper.org/&quot;&gt;wiki&lt;/a&gt;, chat it up in
&lt;a href=&quot;irc://irc.freenode.net/%23datamapper&quot;&gt;#datamapper&lt;/a&gt; and watch
&lt;a href=&quot;http://github.com/datamapper/dm-core/commits/master&quot;&gt;github commit messages&lt;/a&gt; for updates.&lt;/p&gt;
</content>
  </entry>
  

</feed>
