Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Importing from old repository.

  • Loading branch information...
commit e8b4f3bf25a82bc4740e0c04cb20498a59cb3ede 1 parent 648ca80
@sam sam authored
Showing with 17,725 additions and 0 deletions.
  1. +145 −0 CHANGELOG
  2. +124 −0 FAQ
  3. +22 −0 MIT-LICENSE
  4. +742 −0 PERFORMANCE
  5. +12 −0 QUICKLINKS
  6. +151 −0 README
  7. +4 −0 all
  8. +2 −0  bin/.irbrc
  9. +7 −0 bin/dm
  10. +54 −0 environment.rb
  11. +156 −0 example.rb
  12. +92 −0 lib/data_mapper.rb
  13. +43 −0 lib/data_mapper/adapters/abstract_adapter.rb
  14. +479 −0 lib/data_mapper/adapters/data_object_adapter.rb
  15. +71 −0 lib/data_mapper/adapters/mysql_adapter.rb
  16. +257 −0 lib/data_mapper/adapters/postgresql_adapter.rb
  17. +134 −0 lib/data_mapper/adapters/sql/coersion.rb
  18. +545 −0 lib/data_mapper/adapters/sql/commands/load_command.rb
  19. +34 −0 lib/data_mapper/adapters/sql/mappings/associations_set.rb
  20. +279 −0 lib/data_mapper/adapters/sql/mappings/column.rb
  21. +172 −0 lib/data_mapper/adapters/sql/mappings/conditions.rb
  22. +60 −0 lib/data_mapper/adapters/sql/mappings/schema.rb
  23. +459 −0 lib/data_mapper/adapters/sql/mappings/table.rb
  24. +24 −0 lib/data_mapper/adapters/sql/quoting.rb
  25. +158 −0 lib/data_mapper/adapters/sqlite3_adapter.rb
  26. +106 −0 lib/data_mapper/associations.rb
  27. +160 −0 lib/data_mapper/associations/belongs_to_association.rb
  28. +437 −0 lib/data_mapper/associations/has_and_belongs_to_many_association.rb
  29. +283 −0 lib/data_mapper/associations/has_many_association.rb
  30. +143 −0 lib/data_mapper/associations/has_n_association.rb
  31. +47 −0 lib/data_mapper/associations/reference.rb
  32. +73 −0 lib/data_mapper/attributes.rb
  33. +36 −0 lib/data_mapper/auto_migrations.rb
  34. +107 −0 lib/data_mapper/callbacks.rb
  35. +192 −0 lib/data_mapper/cli.rb
  36. +167 −0 lib/data_mapper/container.rb
  37. +112 −0 lib/data_mapper/context.rb
  38. +28 −0 lib/data_mapper/dependency_queue.rb
  39. +145 −0 lib/data_mapper/embedded_value.rb
  40. +47 −0 lib/data_mapper/identity_map.rb
  41. +121 −0 lib/data_mapper/is/tree.rb
  42. +206 −0 lib/data_mapper/logger.rb
  43. +155 −0 lib/data_mapper/migration.rb
  44. +13 −0 lib/data_mapper/model.rb
  45. +873 −0 lib/data_mapper/persistable.rb
  46. +324 −0 lib/data_mapper/property.rb
  47. +164 −0 lib/data_mapper/query.rb
  48. +235 −0 lib/data_mapper/repository.rb
  49. +53 −0 lib/data_mapper/resource.rb
  50. +35 −0 lib/data_mapper/support/blank.rb
  51. +117 −0 lib/data_mapper/support/connection_pool.rb
  52. +35 −0 lib/data_mapper/support/enumerable.rb
  53. +16 −0 lib/data_mapper/support/errors.rb
  54. +265 −0 lib/data_mapper/support/inflector.rb
  55. +54 −0 lib/data_mapper/support/object.rb
  56. +96 −0 lib/data_mapper/support/serialization.rb
  57. +10 −0 lib/data_mapper/support/silence.rb
  58. +72 −0 lib/data_mapper/support/string.rb
  59. +7 −0 lib/data_mapper/support/struct.rb
  60. +82 −0 lib/data_mapper/support/symbol.rb
  61. +68 −0 lib/data_mapper/support/typed_set.rb
  62. +44 −0 lib/data_mapper/types/base.rb
  63. +34 −0 lib/data_mapper/types/string.rb
  64. +12 −0 lib/data_mapper/validatable_extensions/errors.rb
  65. +7 −0 lib/data_mapper/validatable_extensions/macros.rb
  66. +62 −0 lib/data_mapper/validatable_extensions/validatable_instance_methods.rb
  67. +18 −0 lib/data_mapper/validatable_extensions/validation_base.rb
  68. +43 −0 lib/data_mapper/validatable_extensions/validations/formats/email.rb
  69. +7 −0 lib/data_mapper/validatable_extensions/validations/validates_acceptance_of.rb
  70. +7 −0 lib/data_mapper/validatable_extensions/validations/validates_confirmation_of.rb
  71. +7 −0 lib/data_mapper/validatable_extensions/validations/validates_each.rb
  72. +28 −0 lib/data_mapper/validatable_extensions/validations/validates_format_of.rb
  73. +15 −0 lib/data_mapper/validatable_extensions/validations/validates_length_of.rb
  74. +7 −0 lib/data_mapper/validatable_extensions/validations/validates_numericality_of.rb
  75. +7 −0 lib/data_mapper/validatable_extensions/validations/validates_presence_of.rb
  76. +7 −0 lib/data_mapper/validatable_extensions/validations/validates_true_for.rb
  77. +40 −0 lib/data_mapper/validatable_extensions/validations/validates_uniqueness_of.rb
  78. +20 −0 lib/data_mapper/validations.rb
  79. +40 −0 lib/data_mapper/validations/number_validator.rb
  80. +20 −0 lib/data_mapper/validations/string_validator.rb
  81. +13 −0 lib/data_mapper/validations/validator.rb
  82. +2 −0  log/spec.log
  83. +307 −0 performance.rb
  84. +1 −0  plugins/.gitignore
  85. +23 −0 plugins/can_has_sphinx/LICENSE
  86. +4 −0 plugins/can_has_sphinx/README
  87. +1 −0  plugins/can_has_sphinx/REVISION
  88. +22 −0 plugins/can_has_sphinx/Rakefile
  89. +1 −0  plugins/can_has_sphinx/init.rb
  90. +1 −0  plugins/can_has_sphinx/install.rb
  91. +123 −0 plugins/can_has_sphinx/lib/acts_as_sphinx.rb
  92. +460 −0 plugins/can_has_sphinx/lib/sphinx.rb
  93. +47 −0 plugins/can_has_sphinx/scripts/sphinx.sh
  94. +41 −0 plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake
  95. +40 −0 profile_data_mapper.rb
  96. +161 −0 rakefile.rb
  97. +67 −0 spec/acts_as_tree_spec.rb
  98. +31 −0 spec/adapters/data_object_adapter_spec.rb
  99. +98 −0 spec/associations/belongs_to_association_spec.rb
  100. +377 −0 spec/associations/has_and_belongs_to_many_association_spec.rb
  101. +337 −0 spec/associations/has_many_association_spec.rb
  102. +52 −0 spec/attributes_spec.rb
  103. +100 −0 spec/auto_migrations_spec.rb
  104. +186 −0 spec/callbacks_spec.rb
  105. +113 −0 spec/cli_spec.rb
  106. +41 −0 spec/coersion_spec.rb
  107. +114 −0 spec/column_spec.rb
  108. +83 −0 spec/container_spec.rb
  109. +45 −0 spec/count_command_spec.rb
  110. +18 −0 spec/database_spec.rb
  111. +27 −0 spec/dataobjects_spec.rb
  112. +11 −0 spec/delete_command_spec.rb
  113. +29 −0 spec/dependency_spec.rb
  114. +161 −0 spec/embedded_value_spec.rb
  115. +33 −0 spec/fixtures/animals.yaml
  116. +2 −0  spec/fixtures/animals_exhibits.yaml
  117. +5 −0 spec/fixtures/careers.yaml
  118. +1 −0  spec/fixtures/comments.yaml
  119. +90 −0 spec/fixtures/exhibits.yaml
  120. +6 −0 spec/fixtures/fruit.yaml
  121. +37 −0 spec/fixtures/people.yaml
  122. +3 −0  spec/fixtures/posts.yaml
  123. +13 −0 spec/fixtures/projects.yaml
  124. +5 −0 spec/fixtures/sections.yaml
  125. +6 −0 spec/fixtures/serializers.yaml
  126. +6 −0 spec/fixtures/tasks.yaml
  127. +2 −0  spec/fixtures/tasks_tasks.yaml
  128. +1 −0  spec/fixtures/tomatoes.yaml
  129. +1 −0  spec/fixtures/users.yaml
  130. +24 −0 spec/fixtures/zoos.yaml
  131. +149 −0 spec/is_a_tree_spec.rb
  132. +16 −0 spec/legacy_spec.rb
  133. +322 −0 spec/load_command_spec.rb
  134. +26 −0 spec/magic_columns_spec.rb
  135. +267 −0 spec/migration_spec.rb
  136. +20 −0 spec/mock_adapter.rb
  137. +12 −0 spec/models/animal.rb
  138. +8 −0 spec/models/candidate.rb
  139. +7 −0 spec/models/career.rb
  140. +8 −0 spec/models/chain.rb
  141. +6 −0 spec/models/comment.rb
  142. +14 −0 spec/models/exhibit.rb
  143. +7 −0 spec/models/fence.rb
  144. +8 −0 spec/models/fruit.rb
  145. +8 −0 spec/models/job.rb
  146. +30 −0 spec/models/person.rb
  147. +14 −0 spec/models/post.rb
  148. +41 −0 spec/models/project.rb
  149. +5 −0 spec/models/sales_person.rb
  150. +8 −0 spec/models/section.rb
  151. +5 −0 spec/models/serializer.rb
  152. +9 −0 spec/models/task.rb
  153. +27 −0 spec/models/tomato.rb
  154. +13 −0 spec/models/user.rb
  155. +13 −0 spec/models/zoo.rb
  156. +36 −0 spec/natural_key_spec.rb
  157. +38 −0 spec/paranoia_spec.rb
  158. +479 −0 spec/persistable_spec.rb
  159. +96 −0 spec/postgres_spec.rb
  160. +151 −0 spec/property_spec.rb
  161. +77 −0 spec/query_spec.rb
  162. +31 −0 spec/resource_spec.rb
  163. +94 −0 spec/save_command_spec.rb
  164. +5 −0 spec/schema_spec.rb
  165. +19 −0 spec/serialize_spec.rb
  166. +43 −0 spec/single_table_inheritance_spec.rb
  167. +45 −0 spec/spec_helper.rb
  168. +8 −0 spec/support/blank_spec.rb
  169. +41 −0 spec/support/inflector_spec.rb
  170. +9 −0 spec/support/object_spec.rb
  171. +61 −0 spec/support/serialization_spec.rb
  172. +15 −0 spec/support/silence_spec.rb
  173. +7 −0 spec/support/string_spec.rb
  174. +12 −0 spec/support/struct_spec.rb
  175. +66 −0 spec/support/typed_set_spec.rb
  176. +27 −0 spec/symbolic_operators_spec.rb
  177. +79 −0 spec/table_spec.rb
  178. +81 −0 spec/types/string.rb
  179. +55 −0 spec/validates_confirmation_of_spec.rb
  180. +77 −0 spec/validates_format_of_spec.rb
  181. +117 −0 spec/validates_length_of_spec.rb
  182. +92 −0 spec/validates_uniqueness_of_spec.rb
  183. +59 −0 spec/validations/number_validator.rb
  184. +14 −0 spec/validations/string_validator.rb
  185. +141 −0 spec/validations_spec.rb
  186. +53 −0 tasks/fixtures.rb
  187. +9 −0 www/Rakefile
  188. +11 −0 www/content/compare.txt
  189. +51 −0 www/content/contribute.txt
  190. +27 −0 www/content/css/coderay.css
  191. +7 −0 www/content/css/ie_hacks.css
  192. +201 −0 www/content/css/site.css
  193. +65 −0 www/content/docs/associations.txt
  194. +80 −0 www/content/docs/callbacks.txt
  195. +83 −0 www/content/docs/create_and_destroy.txt
  196. +116 −0 www/content/docs/find.txt
  197. +31 −0 www/content/docs/index.txt
  198. +47 −0 www/content/docs/install.txt
  199. +100 −0 www/content/docs/properties.txt
  200. BIN  www/content/files/merb_datamapper.tmbundle.zip
  201. +29 −0 www/content/get.txt
  202. +131 −0 www/content/getting_started.txt
  203. BIN  www/content/images/content_bkg.gif
  204. BIN  www/content/images/download_button.gif
  205. BIN  www/content/images/footer_bkg.gif
  206. BIN  www/content/images/get_button.gif
  207. BIN  www/content/images/header_bkg.gif
  208. BIN  www/content/images/home_bkg.gif
  209. BIN  www/content/images/logo.gif
  210. BIN  www/content/images/new_release_bkg.gif
  211. BIN  www/content/images/page_bkg.gif
  212. +38 −0 www/content/index.txt
  213. +145 −0 www/content/using-git.rhtml
  214. +130 −0 www/content/why.txt
  215. +41 −0 www/layouts/default.rhtml
  216. +12 −0 www/tasks/create.rake
  217. +22 −0 www/tasks/deploy.rake
  218. +26 −0 www/tasks/heel.rake
  219. +27 −0 www/tasks/setup.rb
  220. +18 −0 www/templates/page.erb
View
145 CHANGELOG
@@ -0,0 +1,145 @@
+-- 0.1.0
+* Initial Public Release
+
+-- 0.1.1
+* Removed /lib/data_mapper/extensions
+* Moved ActiveRecordImpersonation into DataMapper::Support module
+* Moved CallbackHelper methods into DataMapper::Base class
+* Moved ValidationHelper into DataMapper::Validations module
+* Removed LoadedSet since it's not necessary for it to reference the Database, so it's nothing more than an array now; Replaced with Array
+* Modified data_mapper.rb to load DataMapper::Support::Enumerable
+* Modified example.rb and performance.rb to require 'lib/data_mapper' instead of modifying $LOADPATH
+* Created SqlAdapter base-class
+* Refactored MysqlAdapter to use SqlAdapter superclass
+* Refactored Sqlite3Adapter to use SqlAdapter superclass
+* Moved /lib/data_mapper/queries to /lib/data_mapper/adapters/sql/queries
+* Moved Connection, Result and Reader classes along with Coersion and Quoting modules to DataMapper::Adapters::Sql module
+* Moved DataMapper::Adapters::Sql::Queries to ::Commands
+* Moved Mappings to SqlAdapter
+* Added monolithic DeleteCommand
+* Added monolithic SaveCommand
+* Added TableExistsCommand
+* Moved save/delete logic out of Session
+* Added create-table functionality to SaveCommand
+* Cleaned up Session; #find no longer supported, use #all or #first
+* Moved object materialization into LoadCommand
+* Migrated Sqlite3Adapter::Commands
+* Added Session#query support back in
+* Removed Connection/Reader/Result classes
+* Set DataMapper::Base#key on load to avoid double-hit against Schema
+* Added DataMapper::Support::Struct for increased Session#query performance
+* Added AdvancedHasManyAssociation (preview status)
+* Added benchmarks comparing ActiveRecord::Base::find_by_sql with Session#query
+
+-- 0.2.0
+* AdvancedHasManyAssociation now functional for fetches
+* AdvancedHasManyAssociation renamed to HasNAssociation
+* HasManyAssociation refactored to use HasNAssociation superclass
+* Slight spec tweaks to accomodate the updates
+* HasOneAssociation refactored to use HasNAssociation superclass
+* Added HasAndBelongsToManyAssociation, using HasNAssociation as a basis; Need to add corresponding SQL generation code in AdvancedLoadCommand
+* Added spec for habtm query generation
+* HasNAssociation#foreign_key returns a DataMapper::Adapters::Sql::Mappings::Column instance instead of a raw String now
+* Added table, association, association_table and to_sql methods to HasNAssociation
+* Added associations_spec.rb
+* Added a forced table-recreation to spec_helper.rb so the tests could run with a clean version of the database, including any new columns added to the models
+* Added HasAndBelongsToManyAssociation#to_sql (all current specs pass now!)
+* Minor tweaks to Callbacks
+* Added CallbacksHelper to declare class-method ::callbacks on DataMapper::Base
+* Implemented before_validate and after_validate hooks in ValidationHelper
+* Minor documentation additions in callbacks.rb
+* Added callbacks_spec
+* Moved class-method declarations for built-in callbacks to the callbacks helper instead of DataMapper::Base
+* Renamed :before/after_validate callback to :before/after_validation to match ActiveRecord
+* Callbacks#add now accepts a Symbol which maps a callback to a method call on the targetted instance, also added a spec to verify this behavior
+* Documented callbacks.rb
+* Added DataMapper::Associations::Reference class
+* Documented DataMapper::Associations::Reference class
+* Upgraded BelongsToAssociation to new style
+* Added AssociationsSet to handle simple "last-in" for association bindings
+* Fixed extra spec loading
+* Added *Association#columns
+* Some refactoring in AdvancedLoadCommand regarding :include options
+* Added support for class-less Mappings::Table instances, with just a string name
+* HasAndBelongsToManyAssociation#join_table #left_foreign_key and #right_foreign_key reference actual Table or Column objects now
+* Added :shallow_include option for HABTM joins in AdvancedLoadCommand and corresponding spec
+* Added Commands::AdvancedConditions
+* Added ORDER, LIMIT, OFFSET and WHERE support to AdvancedLoadCommand
+* Renamed spec/has_many.rb to spec/has_many_spec.rb
+* Tweaked the loading of has_many relationships; big performance boost; got rid of an extra query
+* Added EmbeddedValue support, and accompanying spec
+* Fleshed out AdvancedConditions a bit; added conditions_spec.rb
+* Added more AdvancedConditions specs
+* Added Loader to handle multi-instanced rows
+* AdvancedLoadCommand replaced LoadCommand; down to 3 failing specs
+* All specs pass
+* Added :intercept_load finder option and accompanying spec
+* Modified :intercept_load block signature to |instance,columns,row|
+* HasAndBelongsToMany works, all specs pass
+* Fixed a couple bugs with keys; Added DataMapper::Base#key= method
+* Made DataMapper::Base#lazy_load! a little more flexible
+* Removed LoadCommand overwrites from MysqlAdapter
+* Default Database#single_threaded mode is true now
+* Removed MysqlAdapter#initialize, which only served to setup the connections, moved to SqlAdapter
+* Added SqlAdapter#create_connection and SqlAdapter#close_connection abstract methods
+* Added MysqlAdapter#create_connection and MysqlAdapter#close_connection concrete methods
+* Made SqlAdapter#connection a concrete method (instead of abstract), with support for single_threaded operation
+* Database#setup now takes a Hash of options instead of a block-initializer
+* Validation chaining should work for all association types
+* Save chaining should work for has_many associations
+* Added benchmarks for in-session performance to performance.rb
+* Removed block conditions; They're slower and don't offer any real advantages
+* Removed DeleteCommand
+* Removed SaveCommand
+* Removed TableExistsCommand
+* Session renamed to Context
+* Most command implementations moved to methods in SqlAdapter
+* Removed UnitOfWork module, instead moving a slightly refactored implementation into Base
+
+-- 0.2.1
+* Added :float column support
+* Added association proxies: ie: Zoo.first.exhibits.animals
+* Columns stored in SortedSet
+* Swig files are no longer RDOCed
+* Added :date column support
+* BUG: Fixed UTC issues with datetimes
+* Added #to_yaml method
+* Added #to_xml method
+* Added #to_json method
+* BUG: Fixed HasManyAssociation::Set#inspect
+* BUG: Fixed #reload!
+* BUG: Column copy for STI moved into Table#initialize to better handle STI with multiple mapped databases
+* BUG: before_create callbacks moved in the execution flow since they weren't guaranteed to fire before
+* Threading enhancements: Removed single_threaded_mode, #database block form adjusted for thread-safety
+* BUG: Fixed String#blank? when a multi-line string contained a blank line (thanks zapnap!)
+* Performance enhancements: (thanks wycats!)
+
+-- 0.2.2
+* Removed C extension bundles and log files from package
+
+-- 0.2.3
+* Added String#t for translation and overrides for default validation messages
+* Give credit where it's due: zapnap, not pimpmaster, submitted the String#blank? patch. My bad. :-(
+* MAJOR: Resolve issue with non-unique-hash values and #dirty?; now frozen original values are stored instead
+* Added Base#update_attributes
+* MAJOR: Queries are now passed to the database drivers in a parameterized fashion
+* Updated PostgreSQL driver and adapter to current
+
+-- 0.2.4
+* Bug fixes
+* Added paranoia
+
+-- 0.2.5
+* has_one bugfixes
+* Added syntax for setting CHECK-constraints directly in your properties (Postgres)
+* You can now set indexes with :index => true and :index => :unique
+* Support for composite indexes (thanks to Jeffrey Gelens)
+* Add composite scope to validates_uniqueness
+* Added private/protected properties
+* Remove HasOneAssociation, Make HasManyAssociation impersonate has_one relationships
+* Added #get method
+* Persistence module added, inheriting from DataMapper::Base no longer necessary
+
+-- 0.3.0
+* HasManyAssociation::Set now has a nil? method, so we can do stuff like cage.animal.nil?
+
View
124 FAQ
@@ -0,0 +1,124 @@
+:include:QUICKLINKS
+
+= FAQ
+
+=== I don't want to use :id as a primary key, but I don't see
+=== <tt>set_primary_key</tt> anywhere. What do I do?
+
+If you're working with a table that doesn't have a <tt>:id</tt> column, you
+can declare your properties as you usually do, and declare one of them as a
+natural key.
+
+ property :name, :string, :key => true
+
+You should now be able to do <tt>Class['name_string']</tt> as well. Remember:
+this column should be unique, so treat it that way. This is the equivalent to
+using <tt>set_primary_key</tt> in ActiveRecord.
+
+
+=== How do I make a model paranoid?
+
+ property :deleted_at, :datetime
+
+If you've got deleted_at, your model is paranoid auto-magically. All of your
+calls to <tt>##all()</tt>, <tt>##first()</tt>, and <tt>##count()</tt> will be
+scoped with <tt>where deleted_at is null</tt>. Plus, you won't see deleted
+objects in your associations.
+
+=== Does DataMapper support Has Many Through?
+
+Write me!
+
+=== What about Self-Referential Has And Belongs to Many?
+
+Sure does. Here's an example implementation:
+
+ class Task < DataMapper::Base
+ has_and_belongs_to_many :tasks,
+ :join_table => "task_relationships", :left_foreign_key => "parent_id",
+ :right_foreign_key => "child_id"
+ end
+
+You'll notice that instead of <tt>foreign_key</tt> and
+<tt>association_foreign_key</tt>, DataMapper uses the "database-y" terms
+<tt>left_foreign_key</tt>, and <tt>right_foreign_key</tt>.
+
+=== Does DataMapper do Single Table Inheritance?
+
+Oh yes, and particularly well too.
+
+ class Person < Datamapper::Base
+ property :type, :class ## other shared properties here
+ end
+
+ class Salesperson < Person; end
+
+You can claim a column to have the type <tt>:class</tt> and DataMapper will
+automatically drop the class name of the inherited classes into that column of
+the database.
+
+=== What about Class Table Inheritance?
+
+Class Table Inheritance is on the drawing board and everyone's drooling over
+it. So no, not yet, but soon.
+
+=== How do I run my own commands?
+
+You're probably asking for <tt>find_by_sql</tt>, and DataMapper has that in
+it's ActiveRecordImpersonation, but if you want to go straight-up DataMapper,
+you'll want to use <tt>repository.query</tt>
+
+ repository.query("select * from users where clue > 0")
+
+This does not return any Users (har har), but rather Struct's that will quack
+like Users. They'll be read-only as well.
+
+<tt>repository.query</tt> shouldn't be used if you aren't expecting a result set
+back. If you want to just execute something against the database, use
+<tt>repository.execute</tt> instead.
+
+=== Can I batch-process a ton of records at once?
+
+ User.each(:performance_rating => "low") do |u|
+ u.employment_status = "fired"
+ u.save
+ end
+
+With ActiveRecord, doing a <tt>User.find(:all).each{}</tt> would execute the
+find, instantiate an object for EVERY result, THEN apply your transformations
+to each object in turn. Doesn't sound too horrible unless you have a TON of
+records; you WILL grind your system to a screeching and bloody halt.
+
+Datamapper's <tt>#each</tt> works in sets of 500 so the amount of objects
+instantiated at a time won't make your computer think it's a victim in a Saw
+movie. Once it's done executing your block on the first set of 500, it moves
+on to the next.
+
+What's more is <tt>#each</tt> is secretly a finder too. You can pass it an
+options hash and it'll only iterate on 500-item sets matching your query.
+Don't send it <tt>:offset</tt> though, because that's how it pages. You can
+overload the page size by sending it <tt>:limit</tt>
+
+=== Can I get an SQL log of what queries DataMapper is issuing?
+
+Yup, when you issue <tt>Repository.setup</tt>, tack on the <tt>log_stream</tt>
+and <tt>log_level</tt>:
+
+ DataMapper::Repository.setup({
+ :adapter => 'mysql', :host => 'localhost', :username => 'root',
+ :password => 'R00tPaswooooord', :database =>
+ 'myspiffyblog_development', :log_stream => 'log/sql.log', :log_level => 0
+ })
+
+By supplying the <tt>log_stream</tt> you're telling DataMapper what file you
+want to see your sql logs in. <tt>log_level</tt> is the
+Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/] level of output you
+want to see there. 0, in this case, says that you want to see all DEBUG level
+messages (and higher) sent to the logger. For more information on how to work
+with Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/], hit up
+http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/.
+
+Incidentally, if you'd like to send a message into the Datamapper logger, do:
+
+ repository.adapter.logger.info "your message here"
+
View
22 MIT-LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2007 Sam Smoot
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
View
742 PERFORMANCE
@@ -0,0 +1,742 @@
+Most tests are run on a 2.16Ghz Core2Duo iMac.
+Asterisk (*) indicates test run on 2.0Ghz Core2Duo MacBook.
+
+Baseline: Revision 104.
+
+ user system total real
+ActiveRecord:id 0.090000 0.020000 0.110000 ( 0.192854)
+DataMapper:id 0.110000 0.000000 0.110000 ( 0.105890)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.235058)
+DataMapper:conditions 0.230000 0.030000 0.260000 ( 0.376210)
+ActiveRecord:insert 6.090000 0.360000 6.450000 ( 7.080386)
+DataMapper:insert 1.320000 0.160000 1.480000 ( 1.845571)
+ActiveRecord:update 0.520000 0.080000 0.600000 ( 0.849492)
+DataMapper:update 0.240000 0.030000 0.270000 ( 0.394252)
+ActiveRecord:associations:lazy 3.860000 0.410000 4.270000 ( 7.057705)
+ActiveRecord:associations:included 4.140000 0.030000 4.170000 ( 4.757380)
+DataMapper:associations 0.600000 0.030000 0.630000 ( 0.742609)
+
+Revision 106: Merged DataMapper::Session and DataMapper::Loader since the separation of
+responsibilities wasn't all that clear, and the combination results in fewer
+objects being instantiated to execute a finder. No noticeable impact on performance.
+
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.192765)
+DataMapper:id 0.100000 0.000000 0.100000 ( 0.101425)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.233634)
+DataMapper:conditions 0.220000 0.030000 0.250000 ( 0.376636)
+ActiveRecord:insert 6.090000 0.370000 6.460000 ( 7.129772)
+DataMapper:insert 1.310000 0.160000 1.470000 ( 1.847603)
+ActiveRecord:update 0.520000 0.080000 0.600000 ( 0.856744)
+DataMapper:update 0.250000 0.030000 0.280000 ( 0.396352)
+ActiveRecord:associations:lazy 3.830000 0.410000 4.240000 ( 7.007074)
+ActiveRecord:associations:included 4.130000 0.030000 4.160000 ( 4.729850)
+DataMapper:associations 0.590000 0.030000 0.620000 ( 0.737687)
+
+
+WeakHash based IdentityMap:
+ user system total real
+ActiveRecord:id 0.120000 0.020000 0.140000 ( 0.228198)
+DataMapper:id 0.370000 0.030000 0.400000 ( 0.490674)
+ActiveRecord:all 0.180000 0.020000 0.200000 ( 0.339700)
+DataMapper:all 1.680000 0.030000 1.710000 ( 1.858939)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.266388)
+DataMapper:conditions:short 0.390000 0.030000 0.420000 ( 0.555940)
+DataMapper:conditions:long 0.390000 0.030000 0.420000 ( 0.555121)
+ActiveRecord:insert 8.790000 0.390000 9.180000 ( 10.044282)
+DataMapper:insert 2.020000 0.140000 2.160000 ( 2.614329)
+ActiveRecord:update 0.720000 0.090000 0.810000 ( 1.125279)
+DataMapper:update 0.550000 0.040000 0.590000 ( 0.827818)
+ActiveRecord:associations:lazy 5.910000 0.460000 6.370000 ( 9.811961)
+ActiveRecord:associations:included 7.200000 0.040000 7.240000 ( 7.937999)
+DataMapper:associations 13.740000 0.120000 13.860000 ( 14.489632)
+
+
+Hash based IdentityMap:
+sam-wieck-com:~/Desktop/datamapper/trunk sam$ HASH=1 rake perf
+ user system total real
+ActiveRecord:id 0.120000 0.020000 0.140000 ( 0.228911)
+DataMapper:id 0.380000 0.020000 0.400000 ( 0.494686)
+ActiveRecord:all 0.190000 0.020000 0.210000 ( 0.340205)
+DataMapper:all 1.690000 0.040000 1.730000 ( 1.867063)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.267131)
+DataMapper:conditions:short 0.390000 0.020000 0.410000 ( 0.557804)
+DataMapper:conditions:long 0.390000 0.030000 0.420000 ( 0.558492)
+ActiveRecord:insert 8.790000 0.390000 9.180000 ( 10.050892)
+DataMapper:insert 2.040000 0.140000 2.180000 ( 2.632233)
+ActiveRecord:update 0.720000 0.090000 0.810000 ( 1.127465)
+DataMapper:update 0.550000 0.040000 0.590000 ( 0.837932)
+ActiveRecord:associations:lazy 5.910000 0.460000 6.370000 ( 9.826964)
+ActiveRecord:associations:included 7.200000 0.030000 7.230000 ( 7.924813)
+DataMapper:associations 13.750000 0.120000 13.870000 ( 14.492598)
+
+
+DataMapper::Base#key tweak (and logging calls added):
+ user system total real
+ActiveRecord:id 0.120000 0.020000 0.140000 ( 0.228172)
+DataMapper:id 0.370000 0.020000 0.390000 ( 0.486401)
+ActiveRecord:all 0.180000 0.030000 0.210000 ( 0.339840)
+DataMapper:all 1.420000 0.030000 1.450000 ( 1.598266)
+ActiveRecord:conditions 0.120000 0.020000 0.140000 ( 0.267802)
+DataMapper:conditions:short 0.380000 0.030000 0.410000 ( 0.559920)
+DataMapper:conditions:long 0.380000 0.030000 0.410000 ( 0.561586)
+ActiveRecord:insert 8.800000 0.400000 9.200000 ( 10.079014)
+DataMapper:insert 2.020000 0.130000 2.150000 ( 2.618894)
+ActiveRecord:update 0.730000 0.100000 0.830000 ( 1.132801)
+DataMapper:update 0.540000 0.040000 0.580000 ( 0.822116)
+ActiveRecord:associations:lazy 5.910000 0.450000 6.360000 ( 9.815017)
+ActiveRecord:associations:included 7.130000 0.040000 7.170000 ( 7.868133)
+DataMapper:associations 12.550000 0.110000 12.660000 ( 13.287851)
+
+
+DataMapper::Adapters::Sql::Coersion explicit methods and DataMapper::Adapters::Sql::Mappings::Column#type_cast_value dynamic declaration:
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.225506)
+DataMapper:id 0.370000 0.020000 0.390000 ( 0.486096)
+ActiveRecord:all 0.180000 0.030000 0.210000 ( 0.339339)
+DataMapper:all 1.390000 0.030000 1.420000 ( 1.573873)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.264462)
+DataMapper:conditions:short 0.380000 0.030000 0.410000 ( 0.550503)
+DataMapper:conditions:long 0.380000 0.030000 0.410000 ( 0.552697)
+ActiveRecord:insert 8.860000 0.400000 9.260000 ( 10.133664)
+DataMapper:insert 2.010000 0.140000 2.150000 ( 2.617136)
+ActiveRecord:update 0.720000 0.090000 0.810000 ( 1.133349)
+DataMapper:update 0.540000 0.040000 0.580000 ( 0.822566)
+ActiveRecord:associations:lazy 5.900000 0.460000 6.360000 ( 9.792504)
+ActiveRecord:associations:included 7.140000 0.040000 7.180000 ( 7.881259)
+DataMapper:associations 12.660000 0.120000 12.780000 ( 13.409695)
+
+
+DataMapper::Adapters::MysqlAdapter::LoadCommand#fetch_all optimizations:
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.225694)
+DataMapper:id 0.370000 0.020000 0.390000 ( 0.487414)
+ActiveRecord:all 0.180000 0.030000 0.210000 ( 0.340290)
+DataMapper:all 1.270000 0.030000 1.300000 ( 1.443360)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.262927)
+DataMapper:conditions:short 0.390000 0.030000 0.420000 ( 0.550606)
+DataMapper:conditions:long 0.390000 0.030000 0.420000 ( 0.555613)
+ActiveRecord:insert 8.850000 0.400000 9.250000 ( 10.127422)
+DataMapper:insert 2.000000 0.150000 2.150000 ( 2.601586)
+ActiveRecord:update 0.720000 0.090000 0.810000 ( 1.130260)
+DataMapper:update 0.550000 0.040000 0.590000 ( 0.822809)
+ActiveRecord:associations:lazy 5.890000 0.460000 6.350000 ( 9.766891)
+ActiveRecord:associations:included 7.160000 0.040000 7.200000 ( 7.904619)
+DataMapper:associations 10.720000 0.130000 10.850000 ( 11.467452)
+
+
+DataMapper::IdentityMap is Hash based now:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.220881)
+DataMapper:id 0.180000 0.020000 0.200000 ( 0.299763)
+ActiveRecord:all 0.230000 0.020000 0.250000 ( 0.384269)
+DataMapper:all 0.650000 0.020000 0.670000 ( 0.809388)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.256216)
+DataMapper:conditions:short 0.190000 0.020000 0.210000 ( 0.349827)
+DataMapper:conditions:long 0.180000 0.020000 0.200000 ( 0.339805)
+ActiveRecord:insert 5.940000 0.390000 6.330000 ( 7.180603)
+DataMapper:insert 0.930000 0.100000 1.030000 ( 1.482736)
+ActiveRecord:update 0.540000 0.080000 0.620000 ( 0.932296)
+DataMapper:update 0.310000 0.040000 0.350000 ( 0.582662)
+ActiveRecord:associations:lazy 4.300000 0.450000 4.750000 ( 8.165738)
+ActiveRecord:associations:included 4.540000 0.040000 4.580000 ( 5.266950)
+DataMapper:associations 5.190000 0.080000 5.270000 ( 5.854497)
+
+
+DataMapper::Adapters::Sql::Coersion#type_cast_integer modified to use String#to_i instead of Integer():
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.221287)
+DataMapper:id 0.180000 0.020000 0.200000 ( 0.300231)
+ActiveRecord:all 0.220000 0.020000 0.240000 ( 0.380518)
+DataMapper:all 0.640000 0.020000 0.660000 ( 0.796262)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.254120)
+DataMapper:conditions:short 0.180000 0.020000 0.200000 ( 0.345947)
+DataMapper:conditions:long 0.180000 0.020000 0.200000 ( 0.337786)
+ActiveRecord:insert 5.940000 0.390000 6.330000 ( 7.172553)
+DataMapper:insert 0.920000 0.100000 1.020000 ( 1.468706)
+ActiveRecord:update 0.530000 0.080000 0.610000 ( 0.926679)
+DataMapper:update 0.310000 0.040000 0.350000 ( 0.583789)
+ActiveRecord:associations:lazy 4.230000 0.460000 4.690000 ( 8.100321)
+ActiveRecord:associations:included 4.480000 0.030000 4.510000 ( 5.209363)
+DataMapper:associations 5.180000 0.080000 5.260000 ( 5.834756)
+
+
+DataMapper::Adapters::Sql::Commands::Conditions#empty? optimized:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.218253)
+DataMapper:id 0.180000 0.020000 0.200000 ( 0.300902)
+ActiveRecord:all 0.220000 0.020000 0.240000 ( 0.380154)
+DataMapper:all 0.630000 0.020000 0.650000 ( 0.789240)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.258471)
+DataMapper:conditions:short 0.190000 0.020000 0.210000 ( 0.349333)
+DataMapper:conditions:long 0.180000 0.020000 0.200000 ( 0.334961)
+ActiveRecord:insert 5.920000 0.380000 6.300000 ( 7.159693)
+DataMapper:insert 0.920000 0.100000 1.020000 ( 1.465180)
+ActiveRecord:update 0.540000 0.080000 0.620000 ( 0.934276)
+DataMapper:update 0.310000 0.040000 0.350000 ( 0.584914)
+ActiveRecord:associations:lazy 4.240000 0.440000 4.680000 ( 8.138604)
+ActiveRecord:associations:included 4.640000 0.030000 4.670000 ( 5.362673)
+DataMapper:associations 5.180000 0.080000 5.260000 ( 5.835963)
+
+
+String#blank? optimized to use Regexp:
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.218745)
+DataMapper:id 0.190000 0.020000 0.210000 ( 0.302953)
+ActiveRecord:all 0.220000 0.020000 0.240000 ( 0.379534)
+DataMapper:all 0.640000 0.020000 0.660000 ( 0.800096)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.255913)
+DataMapper:conditions:short 0.190000 0.020000 0.210000 ( 0.345159)
+DataMapper:conditions:long 0.170000 0.020000 0.190000 ( 0.332575)
+ActiveRecord:insert 5.920000 0.380000 6.300000 ( 7.154397)
+DataMapper:insert 0.930000 0.100000 1.030000 ( 1.482023)
+ActiveRecord:update 0.530000 0.080000 0.610000 ( 0.932545)
+DataMapper:update 0.300000 0.040000 0.340000 ( 0.585066)
+ActiveRecord:associations:lazy 4.200000 0.450000 4.650000 ( 8.066527)
+ActiveRecord:associations:included 4.650000 0.030000 4.680000 ( 5.368602)
+DataMapper:associations 5.090000 0.080000 5.170000 ( 5.742339)
+
+
+* MysqlAdapter::Commands::LoadCommand#fetch_all (original):
+ user system total real
+ActiveRecord:id 0.120000 0.030000 0.150000 ( 0.258177)
+DataMapper:id 0.210000 0.030000 0.240000 ( 0.356305)
+ActiveRecord:all 0.260000 0.050000 0.310000 ( 0.472395)
+DataMapper:all 0.840000 0.050000 0.890000 ( 1.039711)
+ActiveRecord:conditions 0.120000 0.030000 0.150000 ( 0.299543)
+DataMapper:conditions:short 0.220000 0.030000 0.250000 ( 0.407216)
+DataMapper:conditions:long 0.210000 0.030000 0.240000 ( 0.394301)
+ActiveRecord:insert 6.780000 0.440000 7.220000 ( 8.422043)
+DataMapper:insert 1.000000 0.110000 1.110000 ( 1.641364)
+ActiveRecord:update 0.600000 0.110000 0.710000 ( 1.029808)
+DataMapper:update 0.350000 0.050000 0.400000 ( 0.672673)
+ActiveRecord:associations:lazy 4.820000 0.760000 5.580000 ( 9.459462)
+ActiveRecord:associations:included 4.920000 0.090000 5.010000 ( 5.721876)
+DataMapper:associations 6.720000 0.220000 6.940000 ( 7.578226)
+
+
+* MysqlAdapter::Commands::LoadCommand#fetch_all (optimized):
+ user system total real
+ActiveRecord:id 0.120000 0.030000 0.150000 ( 0.260296)
+DataMapper:id 0.220000 0.030000 0.250000 ( 0.363559)
+ActiveRecord:all 0.260000 0.050000 0.310000 ( 0.474199)
+DataMapper:all 0.700000 0.050000 0.750000 ( 0.898856)
+ActiveRecord:conditions 0.120000 0.030000 0.150000 ( 0.300398)
+DataMapper:conditions:short 0.210000 0.030000 0.240000 ( 0.405056)
+DataMapper:conditions:long 0.210000 0.030000 0.240000 ( 0.392633)
+ActiveRecord:insert 6.750000 0.450000 7.200000 ( 8.427758)
+DataMapper:insert 0.990000 0.110000 1.100000 ( 1.641301)
+ActiveRecord:update 0.590000 0.110000 0.700000 ( 1.033978)
+DataMapper:update 0.350000 0.050000 0.400000 ( 0.676097)
+ActiveRecord:associations:lazy 4.810000 0.770000 5.580000 ( 9.459126)
+ActiveRecord:associations:included 4.950000 0.090000 5.040000 ( 5.758935)
+DataMapper:associations 6.320000 0.220000 6.540000 ( 7.172041)
+
+Repeat on iMac:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.219094)
+DataMapper:id 0.190000 0.020000 0.210000 ( 0.303379)
+ActiveRecord:all 0.220000 0.020000 0.240000 ( 0.380277)
+DataMapper:all 0.630000 0.020000 0.650000 ( 0.796209)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.258002)
+DataMapper:conditions:short 0.180000 0.020000 0.200000 ( 0.348820)
+DataMapper:conditions:long 0.170000 0.020000 0.190000 ( 0.337768)
+ActiveRecord:insert 5.930000 0.390000 6.320000 ( 7.180595)
+DataMapper:insert 0.930000 0.090000 1.020000 ( 1.480698)
+ActiveRecord:update 0.530000 0.090000 0.620000 ( 0.931558)
+DataMapper:update 0.310000 0.040000 0.350000 ( 0.583486)
+ActiveRecord:associations:lazy 4.190000 0.450000 4.640000 ( 8.058710)
+ActiveRecord:associations:included 4.530000 0.030000 4.560000 ( 5.260562)
+DataMapper:associations 5.820000 0.070000 5.890000 ( 6.480988)
+
+Current performance:
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.218224)
+DataMapper:id 0.180000 0.020000 0.200000 ( 0.299119)
+DataMapper:id:in-session 0.060000 0.000000 0.060000 ( 0.058262)
+ActiveRecord:all 0.230000 0.020000 0.250000 ( 0.380154)
+DataMapper:all 0.660000 0.020000 0.680000 ( 0.811355)
+DataMapper:all:in-session 0.540000 0.030000 0.570000 ( 0.700819)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.262222)
+DataMapper:conditions:short 0.200000 0.020000 0.220000 ( 0.356098)
+DataMapper:conditions:short:in-session 0.170000 0.020000 0.190000 ( 0.332662)
+DataMapper:conditions:long 0.200000 0.020000 0.220000 ( 0.355016)
+DataMapper:conditions:long:in-session 0.170000 0.020000 0.190000 ( 0.330220)
+ActiveRecord:insert 5.260000 0.340000 5.600000 ( 6.514014)
+DataMapper:insert 0.960000 0.100000 1.060000 ( 1.528213)
+ActiveRecord:update 0.530000 0.080000 0.610000 ( 0.930696)
+DataMapper:update 0.390000 0.040000 0.430000 ( 0.668540)
+ActiveRecord:associations:lazy 4.170000 0.450000 4.620000 ( 7.936800)
+ActiveRecord:associations:included 4.580000 0.030000 4.610000 ( 5.271687)
+DataMapper:associations 3.360000 0.050000 3.410000 ( 3.766838)
+DataMapper:associations:in-session 0.750000 0.020000 0.770000 ( 0.906840)
+ActiveRecord:find_by_sql 0.220000 0.010000 0.230000 ( 0.373307)
+DataMapper:find_by_sql 0.140000 0.030000 0.170000 ( 0.302143)
+
+Remove block-conditions support:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.221170)
+DataMapper:id 0.190000 0.020000 0.210000 ( 0.302617)
+DataMapper:id:in-session 0.050000 0.000000 0.050000 ( 0.057694)
+ActiveRecord:all 0.220000 0.020000 0.240000 ( 0.377332)
+DataMapper:all 0.650000 0.020000 0.670000 ( 0.811892)
+DataMapper:all:in-session 0.560000 0.020000 0.580000 ( 0.716009)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.263317)
+DataMapper:conditions:short 0.190000 0.020000 0.210000 ( 0.350601)
+DataMapper:conditions:short:in-session 0.170000 0.020000 0.190000 ( 0.331199)
+DataMapper:conditions:long 0.190000 0.020000 0.210000 ( 0.352986)
+DataMapper:conditions:long:in-session 0.170000 0.020000 0.190000 ( 0.331603)
+ActiveRecord:insert 5.240000 0.340000 5.580000 ( 6.472757)
+DataMapper:insert 0.970000 0.100000 1.070000 ( 1.577412)
+ActiveRecord:update 0.550000 0.080000 0.630000 ( 0.942404)
+DataMapper:update 0.400000 0.040000 0.440000 ( 0.667777)
+ActiveRecord:associations:lazy 4.170000 0.450000 4.620000 ( 7.976589)
+ActiveRecord:associations:included 4.650000 0.040000 4.690000 ( 5.385883)
+DataMapper:associations 3.380000 0.040000 3.420000 ( 3.807896)
+DataMapper:associations:in-session 0.750000 0.020000 0.770000 ( 0.903133)
+ActiveRecord:find_by_sql 0.220000 0.020000 0.240000 ( 0.374365)
+DataMapper:find_by_sql 0.140000 0.020000 0.160000 ( 0.300868)
+
+Include TEXT fields in INSERT tests:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.200504)
+DataMapper:id 0.180000 0.020000 0.200000 ( 0.276477)
+DataMapper:id:in-session 0.060000 0.000000 0.060000 ( 0.058879)
+ActiveRecord:all 0.210000 0.020000 0.230000 ( 0.349249)
+DataMapper:all 0.610000 0.020000 0.630000 ( 0.744081)
+DataMapper:all:in-session 0.500000 0.020000 0.520000 ( 0.642338)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.245654)
+DataMapper:conditions:short 0.190000 0.020000 0.210000 ( 0.328919)
+DataMapper:conditions:short:in-session 0.160000 0.030000 0.190000 ( 0.307284)
+DataMapper:conditions:long 0.190000 0.020000 0.210000 ( 0.331199)
+DataMapper:conditions:long:in-session 0.160000 0.020000 0.180000 ( 0.309451)
+ActiveRecord:insert 5.090000 0.330000 5.420000 ( 6.099532)
+DataMapper:insert 0.960000 0.100000 1.060000 ( 1.468360)
+ActiveRecord:update 0.510000 0.080000 0.590000 ( 0.847741)
+DataMapper:update 0.380000 0.040000 0.420000 ( 0.618621)
+ActiveRecord:associations:lazy 4.000000 0.440000 4.440000 ( 7.420747)
+ActiveRecord:associations:included 4.230000 0.030000 4.260000 ( 4.865744)
+DataMapper:associations 3.110000 0.040000 3.150000 ( 3.474378)
+DataMapper:associations:in-session 0.690000 0.020000 0.710000 ( 0.830177)
+ActiveRecord:find_by_sql 0.200000 0.020000 0.220000 ( 0.341861)
+DataMapper:find_by_sql 0.140000 0.020000 0.160000 ( 0.279707)
+
+Add tests for field accessor performance:
+ user system total real
+ActiveRecord:id 0.120000 0.020000 0.140000 ( 0.295290)
+DataMapper:id 0.200000 0.030000 0.230000 ( 0.383191)
+DataMapper:id:in-session 0.060000 0.000000 0.060000 ( 0.060037)
+ActiveRecord:all 0.240000 0.020000 0.260000 ( 0.489402)
+DataMapper:all 0.670000 0.030000 0.700000 ( 0.936084)
+DataMapper:all:in-session 0.570000 0.030000 0.600000 ( 0.820874)
+ActiveRecord:conditions 0.120000 0.020000 0.140000 ( 0.370018)
+DataMapper:conditions:short 0.220000 0.020000 0.240000 ( 0.471751)
+DataMapper:conditions:short:in-session 0.190000 0.020000 0.210000 ( 0.455203)
+DataMapper:conditions:long 0.220000 0.020000 0.240000 ( 0.471703)
+DataMapper:conditions:long:in-session 0.200000 0.030000 0.230000 ( 0.448747)
+ActiveRecord:insert 11.000000 0.540000 11.540000 ( 13.441723)
+DataMapper:insert 1.320000 0.120000 1.440000 ( 2.240316)
+ActiveRecord:update 0.640000 0.100000 0.740000 ( 1.297961)
+DataMapper:update 0.440000 0.050000 0.490000 ( 0.881541)
+ActiveRecord:associations:lazy 4.720000 0.530000 5.250000 ( 10.508575)
+ActiveRecord:associations:included 4.660000 0.050000 4.710000 ( 5.551303)
+DataMapper:associations 3.430000 0.060000 3.490000 ( 4.073533)
+DataMapper:associations:in-session 0.770000 0.030000 0.800000 ( 1.035620)
+ActiveRecord:find_by_sql 0.240000 0.020000 0.260000 ( 0.480992)
+DataMapper:find_by_sql 0.180000 0.030000 0.210000 ( 0.435872)
+ActiveRecord:accessors 0.020000 0.000000 0.020000 ( 0.014591)
+DataMapper:accessors 0.010000 0.000000 0.010000 ( 0.008828)
+
+* Major Command refactoring:
+ user system total real
+ActiveRecord:id 0.130000 0.030000 0.160000 ( 0.266751)
+DataMapper:id 0.300000 0.030000 0.330000 ( 0.446141)
+DataMapper:id:in-session 0.070000 0.000000 0.070000 ( 0.069422)
+ActiveRecord:all 0.280000 0.050000 0.330000 ( 0.487828)
+DataMapper:all 0.860000 0.050000 0.910000 ( 1.073502)
+DataMapper:all:in-session 0.840000 0.050000 0.890000 ( 1.187414)
+ActiveRecord:conditions 0.120000 0.040000 0.160000 ( 0.314645)
+DataMapper:conditions:short 0.310000 0.030000 0.340000 ( 0.499834)
+DataMapper:conditions:short:in-session 0.280000 0.020000 0.300000 ( 0.472508)
+DataMapper:conditions:long 0.300000 0.030000 0.330000 ( 0.500534)
+DataMapper:conditions:long:in-session 0.280000 0.030000 0.310000 ( 0.472286)
+ActiveRecord:insert 12.450000 0.530000 12.980000 ( 13.945422)
+DataMapper:insert 1.640000 0.120000 1.760000 ( 2.341762)
+ActiveRecord:update 0.610000 0.100000 0.710000 ( 1.061672)
+DataMapper:update 0.830000 0.090000 0.920000 ( 1.334947)
+ActiveRecord:associations:lazy 5.030000 0.780000 5.810000 ( 9.969720)
+ActiveRecord:associations:included 5.220000 0.120000 5.340000 ( 6.182199)
+DataMapper:associations 4.230000 0.140000 4.370000 ( 4.837089)
+DataMapper:associations:in-session 0.940000 0.060000 1.000000 ( 1.161469)
+ActiveRecord:find_by_sql 0.270000 0.050000 0.320000 ( 0.487242)
+DataMapper:find_by_sql 0.300000 0.060000 0.360000 ( 0.513722)
+ActiveRecord:accessors 0.010000 0.000000 0.010000 ( 0.015118)
+DataMapper:accessors 0.010000 0.000000 0.010000 ( 0.008976)
+
+* UnitOfWork refactoring:
+ user system total real
+ActiveRecord:id 0.130000 0.030000 0.160000 ( 0.271429)
+DataMapper:id 0.310000 0.030000 0.340000 ( 0.445740)
+DataMapper:id:in-session 0.070000 0.000000 0.070000 ( 0.069947)
+ActiveRecord:all 0.280000 0.050000 0.330000 ( 0.490220)
+DataMapper:all 0.870000 0.050000 0.920000 ( 1.074154)
+DataMapper:all:in-session 0.700000 0.050000 0.750000 ( 0.904959)
+ActiveRecord:conditions 0.120000 0.030000 0.150000 ( 0.313456)
+DataMapper:conditions:short 0.330000 0.030000 0.360000 ( 0.538847)
+DataMapper:conditions:short:in-session 0.280000 0.030000 0.310000 ( 0.478948)
+DataMapper:conditions:long 0.310000 0.030000 0.340000 ( 0.508575)
+DataMapper:conditions:long:in-session 0.280000 0.030000 0.310000 ( 0.493394)
+ActiveRecord:insert 12.580000 0.560000 13.140000 ( 14.652010)
+DataMapper:insert 1.600000 0.110000 1.710000 ( 2.293812)
+ActiveRecord:update 0.600000 0.100000 0.700000 ( 1.051941)
+DataMapper:update 0.830000 0.080000 0.910000 ( 1.323192)
+ActiveRecord:associations:lazy 5.020000 0.770000 5.790000 ( 9.850605)
+ActiveRecord:associations:included 5.260000 0.100000 5.360000 ( 6.100674)
+DataMapper:associations 4.210000 0.140000 4.350000 ( 4.762663)
+DataMapper:associations:in-session 0.930000 0.060000 0.990000 ( 1.146315)
+ActiveRecord:find_by_sql 0.270000 0.050000 0.320000 ( 0.496243)
+DataMapper:find_by_sql 0.300000 0.050000 0.350000 ( 0.518110)
+ActiveRecord:accessors 0.010000 0.000000 0.010000 ( 0.015175)
+DataMapper:accessors 0.010000 0.000000 0.010000 ( 0.009117)
+
+* DataObject::Mysql:
+ user system total real
+DataMapper:id 0.350000 0.040000 0.390000 ( 0.505825)
+DataMapper:id:in-session 0.060000 0.000000 0.060000 ( 0.068158)
+DataMapper:all 1.490000 0.050000 1.540000 ( 1.712837)
+DataMapper:all:in-session 1.290000 0.050000 1.340000 ( 1.498406)
+DataMapper:conditions:short 0.340000 0.030000 0.370000 ( 0.532813)
+DataMapper:conditions:short:in-session 0.310000 0.030000 0.340000 ( 0.503475)
+DataMapper:conditions:long 0.340000 0.030000 0.370000 ( 0.531182)
+DataMapper:conditions:long:in-session 0.310000 0.030000 0.340000 ( 0.502040)
+DataMapper:insert 1.550000 0.110000 1.660000 ( 2.249506)
+DataMapper:update 0.450000 0.040000 0.490000 ( 0.641661)
+DataMapper:associations 5.610000 0.140000 5.750000 ( 6.165153)
+DataMapper:associations:in-session 1.370000 0.050000 1.420000 ( 1.583806)
+DataMapper:find_by_sql 0.770000 0.060000 0.830000 ( 0.990141)
+DataMapper:accessors 0.000000 0.000000 0.000000 ( 0.008986)
+
+* DataObject branch:
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.231399)
+DataMapper:id 0.320000 0.020000 0.340000 ( 0.531620)
+DataMapper:id:in-session 0.050000 0.000000 0.050000 ( 0.060701)
+ActiveRecord:all 0.220000 0.020000 0.240000 ( 0.380837)
+DataMapper:all 1.370000 0.030000 1.400000 ( 1.546245)
+DataMapper:all:in-session 1.150000 0.020000 1.170000 ( 1.318366)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.269084)
+DataMapper:conditions:short 0.300000 0.020000 0.320000 ( 0.474894)
+DataMapper:conditions:short:in-session 0.280000 0.030000 0.310000 ( 0.449529)
+DataMapper:conditions:long 0.310000 0.020000 0.330000 ( 0.471048)
+DataMapper:conditions:long:in-session 0.290000 0.020000 0.310000 ( 0.451029)
+ActiveRecord:insert 10.320000 0.460000 10.780000 ( 12.027767)
+DataMapper:insert 1.600000 0.100000 1.700000 ( 2.188750)
+ActiveRecord:update 0.520000 0.090000 0.610000 ( 0.929980)
+DataMapper:update 0.340000 0.020000 0.360000 ( 0.509320)
+ActiveRecord:associations:lazy 4.470000 0.480000 4.950000 ( 8.550955)
+ActiveRecord:associations:included 4.870000 0.040000 4.910000 ( 5.681657)
+DataMapper:associations 5.250000 0.070000 5.320000 ( 5.822158)
+DataMapper:associations:in-session 1.290000 0.020000 1.310000 ( 1.500369)
+ActiveRecord:find_by_sql 0.240000 0.020000 0.260000 ( 0.411237)
+DataMapper:find_by_sql 12.400000 0.100000 12.500000 ( 12.717913)
+ActiveRecord:accessors 0.020000 0.000000 0.020000 ( 0.014664)
+DataMapper:accessors 0.010000 0.000000 0.010000 ( 0.008668)
+
+* Force AR to type-cast "name" columns:
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.234244)
+DataMapper:id 0.320000 0.020000 0.340000 ( 0.443778)
+DataMapper:id:in-session 0.060000 0.000000 0.060000 ( 0.060680)
+ActiveRecord:all 0.240000 0.020000 0.260000 ( 0.404353)
+DataMapper:all 1.410000 0.030000 1.440000 ( 1.624809)
+DataMapper:all:in-session 1.190000 0.030000 1.220000 ( 1.457031)
+ActiveRecord:conditions 0.120000 0.020000 0.140000 ( 0.307603)
+DataMapper:conditions:short 0.310000 0.020000 0.330000 ( 0.476872)
+DataMapper:conditions:short:in-session 0.290000 0.020000 0.310000 ( 0.445322)
+DataMapper:conditions:long 0.300000 0.020000 0.320000 ( 0.465469)
+DataMapper:conditions:long:in-session 0.280000 0.020000 0.300000 ( 0.443403)
+ActiveRecord:insert 10.330000 0.460000 10.790000 ( 11.786461)
+DataMapper:insert 1.610000 0.100000 1.710000 ( 2.202136)
+ActiveRecord:update 0.520000 0.080000 0.600000 ( 0.928137)
+DataMapper:update 0.350000 0.030000 0.380000 ( 0.518928)
+ActiveRecord:associations:lazy 4.490000 0.480000 4.970000 ( 8.587722)
+ActiveRecord:associations:included 4.830000 0.040000 4.870000 ( 5.618826)
+DataMapper:associations 5.220000 0.050000 5.270000 ( 5.687679)
+DataMapper:associations:in-session 1.310000 0.030000 1.340000 ( 1.494329)
+ActiveRecord:find_by_sql 0.300000 0.020000 0.320000 ( 0.473478)
+DataMapper:find_by_sql 12.410000 0.100000 12.510000 ( 12.712320)
+ActiveRecord:accessors 0.020000 0.000000 0.020000 ( 0.015308)
+DataMapper:accessors 0.010000 0.000000 0.010000 ( 0.008280)
+
+Columns stored in SortedSet:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.202696)
+DataMapper:id 0.310000 0.020000 0.330000 ( 0.412840)
+DataMapper:id:in-session 0.050000 0.000000 0.050000 ( 0.057129)
+ActiveRecord:all 0.230000 0.010000 0.240000 ( 0.363915)
+DataMapper:all 1.300000 0.020000 1.320000 ( 1.454792)
+DataMapper:all:in-session 1.080000 0.020000 1.100000 ( 1.231742)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.248121)
+DataMapper:conditions:short 0.300000 0.020000 0.320000 ( 0.449827)
+DataMapper:conditions:short:in-session 0.280000 0.020000 0.300000 ( 0.424613)
+DataMapper:conditions:long 0.300000 0.020000 0.320000 ( 0.446678)
+DataMapper:conditions:long:in-session 0.280000 0.020000 0.300000 ( 0.423306)
+ActiveRecord:insert 10.950000 0.450000 11.400000 ( 12.196582)
+DataMapper:insert 1.540000 0.100000 1.640000 ( 2.102458)
+ActiveRecord:update 0.510000 0.090000 0.600000 ( 0.855040)
+DataMapper:update 0.340000 0.020000 0.360000 ( 0.486113)
+ActiveRecord:associations:lazy 4.510000 0.490000 5.000000 ( 8.287006)
+ActiveRecord:associations:included 4.570000 0.030000 4.600000 ( 5.325725)
+DataMapper:associations 4.980000 0.050000 5.030000 ( 5.375342)
+DataMapper:associations:in-session 1.270000 0.020000 1.290000 ( 1.425380)
+ActiveRecord:find_by_sql 0.290000 0.020000 0.310000 ( 0.439328)
+DataMapper:find_by_sql 12.030000 0.090000 12.120000 ( 12.352025)
+ActiveRecord:accessors 0.010000 0.000000 0.010000 ( 0.012992)
+DataMapper:accessors 0.010000 0.000000 0.010000 ( 0.007750)
+
+Routine baseline test for 0.2.2:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.200836)
+DataMapper:id 0.300000 0.020000 0.320000 ( 0.402018)
+DataMapper:id:in-session 0.060000 0.000000 0.060000 ( 0.061743)
+ActiveRecord:all 0.330000 0.020000 0.350000 ( 0.483547)
+DataMapper:all 1.130000 0.020000 1.150000 ( 1.297910)
+DataMapper:all:in-session 0.850000 0.020000 0.870000 ( 0.997216)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.249338)
+DataMapper:conditions:short 0.300000 0.030000 0.330000 ( 0.437872)
+DataMapper:conditions:short:in-session 0.270000 0.020000 0.290000 ( 0.415954)
+DataMapper:conditions:long 0.300000 0.020000 0.320000 ( 0.439868)
+DataMapper:conditions:long:in-session 0.280000 0.020000 0.300000 ( 0.420295)
+ActiveRecord:insert 11.070000 0.460000 11.530000 ( 12.424877)
+DataMapper:insert 1.600000 0.100000 1.700000 ( 2.123499)
+ActiveRecord:update 0.510000 0.090000 0.600000 ( 0.879385)
+DataMapper:update 0.330000 0.020000 0.350000 ( 0.508269)
+ActiveRecord:associations:lazy 4.440000 0.490000 4.930000 ( 8.236656)
+ActiveRecord:associations:included 4.710000 0.040000 4.750000 ( 5.486082)
+DataMapper:associations 3.910000 0.040000 3.950000 ( 4.300448)
+DataMapper:associations:in-session 0.930000 0.020000 0.950000 ( 1.072595)
+ActiveRecord:find_by_sql 0.290000 0.020000 0.310000 ( 0.438988)
+DataMapper:find_by_sql 0.320000 0.020000 0.340000 ( 0.483293)
+DataMapper:raw-query 0.130000 0.020000 0.150000 ( 0.288194)
+ActiveRecord:accessors 0.010000 0.000000 0.010000 ( 0.013859)
+DataMapper:accessors 0.000000 0.000000 0.000000 ( 0.007755)
+
+Frozen attributes:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.200084)
+DataMapper:id 0.300000 0.020000 0.320000 ( 0.403073)
+DataMapper:id:in-session 0.060000 0.000000 0.060000 ( 0.061662)
+ActiveRecord:all 0.330000 0.020000 0.350000 ( 0.488180)
+DataMapper:all 1.130000 0.030000 1.160000 ( 1.284038)
+DataMapper:all:in-session 0.870000 0.020000 0.890000 ( 1.018347)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.244069)
+DataMapper:conditions:short 0.290000 0.020000 0.310000 ( 0.438676)
+DataMapper:conditions:short:in-session 0.270000 0.020000 0.290000 ( 0.418105)
+DataMapper:conditions:long 0.300000 0.020000 0.320000 ( 0.442747)
+DataMapper:conditions:long:in-session 0.280000 0.020000 0.300000 ( 0.421202)
+ActiveRecord:insert 10.990000 0.440000 11.430000 ( 12.228132)
+DataMapper:insert 1.600000 0.100000 1.700000 ( 2.109715)
+ActiveRecord:update 0.490000 0.090000 0.580000 ( 0.841281)
+DataMapper:update 0.330000 0.020000 0.350000 ( 0.477265)
+ActiveRecord:associations:lazy 4.450000 0.480000 4.930000 ( 8.245103)
+ActiveRecord:associations:included 4.600000 0.030000 4.630000 ( 5.362895)
+DataMapper:associations 3.870000 0.050000 3.920000 ( 4.271564)
+DataMapper:associations:in-session 0.950000 0.020000 0.970000 ( 1.102860)
+ActiveRecord:find_by_sql 0.290000 0.020000 0.310000 ( 0.442986)
+DataMapper:find_by_sql 0.320000 0.020000 0.340000 ( 0.483927)
+DataMapper:raw-query 0.130000 0.020000 0.150000 ( 0.294662)
+ActiveRecord:accessors 0.020000 0.000000 0.020000 ( 0.015246)
+DataMapper:accessors 0.010000 0.000000 0.010000 ( 0.007762)
+
+Original_values instead of original_hashes:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.199365)
+DataMapper:id 0.300000 0.020000 0.320000 ( 0.411072)
+DataMapper:id:in-session 0.060000 0.000000 0.060000 ( 0.062074)
+ActiveRecord:all 0.320000 0.020000 0.340000 ( 0.479386)
+DataMapper:all 1.160000 0.020000 1.180000 ( 1.320178)
+DataMapper:all:in-session 0.840000 0.020000 0.860000 ( 0.987655)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.241978)
+DataMapper:conditions:short 0.300000 0.020000 0.320000 ( 0.443261)
+DataMapper:conditions:short:in-session 0.270000 0.020000 0.290000 ( 0.415863)
+DataMapper:conditions:long 0.300000 0.020000 0.320000 ( 0.443250)
+DataMapper:conditions:long:in-session 0.270000 0.020000 0.290000 ( 0.420265)
+ActiveRecord:insert 11.000000 0.440000 11.440000 ( 12.263029)
+DataMapper:insert 1.610000 0.100000 1.710000 ( 2.113757)
+ActiveRecord:update 0.500000 0.080000 0.580000 ( 0.856348)
+DataMapper:update 0.330000 0.020000 0.350000 ( 0.472541)
+ActiveRecord:associations:lazy 4.430000 0.480000 4.910000 ( 8.220179)
+ActiveRecord:associations:included 4.690000 0.030000 4.720000 ( 5.461092)
+DataMapper:associations 3.860000 0.040000 3.900000 ( 4.268797)
+DataMapper:associations:in-session 0.920000 0.020000 0.940000 ( 1.078688)
+ActiveRecord:find_by_sql 0.290000 0.020000 0.310000 ( 0.443165)
+DataMapper:find_by_sql 0.310000 0.020000 0.330000 ( 0.480190)
+DataMapper:raw-query 0.130000 0.020000 0.150000 ( 0.293561)
+ActiveRecord:accessors 0.010000 0.000000 0.010000 ( 0.015029)
+DataMapper:accessors 0.000000 0.000000 0.000000 ( 0.007767)
+
+Parameterized Execution:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.204708)
+DataMapper:id 0.290000 0.020000 0.310000 ( 0.400942)
+DataMapper:id:in-session 0.060000 0.000000 0.060000 ( 0.060428)
+ActiveRecord:all 0.330000 0.020000 0.350000 ( 0.485907)
+DataMapper:all 1.120000 0.020000 1.140000 ( 1.276078)
+DataMapper:all:in-session 0.820000 0.020000 0.840000 ( 0.972161)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.248759)
+DataMapper:conditions:short 0.290000 0.020000 0.310000 ( 0.440282)
+DataMapper:conditions:short:in-session 0.220000 0.020000 0.240000 ( 0.360253)
+DataMapper:conditions:long 0.300000 0.020000 0.320000 ( 0.438962)
+DataMapper:conditions:long:in-session 0.220000 0.020000 0.240000 ( 0.362050)
+ActiveRecord:insert 10.950000 0.460000 11.410000 ( 12.220599)
+DataMapper:insert 1.650000 0.100000 1.750000 ( 2.237006)
+ActiveRecord:update 0.500000 0.090000 0.590000 ( 0.849031)
+DataMapper:update 0.320000 0.020000 0.340000 ( 0.473710)
+ActiveRecord:associations:lazy 4.460000 0.490000 4.950000 ( 8.319213)
+ActiveRecord:associations:included 4.670000 0.040000 4.710000 ( 5.413298)
+DataMapper:associations 3.830000 0.040000 3.870000 ( 4.251812)
+DataMapper:associations:in-session 0.910000 0.020000 0.930000 ( 1.058053)
+ActiveRecord:find_by_sql 0.290000 0.020000 0.310000 ( 0.441161)
+DataMapper:find_by_sql 0.330000 0.030000 0.360000 ( 0.494727)
+DataMapper:raw-query 0.140000 0.010000 0.150000 ( 0.300567)
+ActiveRecord:accessors 0.010000 0.000000 0.010000 ( 0.013660)
+DataMapper:accessors 0.000000 0.000000 0.000000 ( 0.007752)
+
+Context#get:
+ user system total real
+ActiveRecord:id 0.100000 0.030000 0.130000 ( 0.223749)
+DataMapper:id 0.250000 0.020000 0.270000 ( 0.364658)
+DataMapper:id:in-session 0.170000 0.020000 0.190000 ( 0.280089)
+ActiveRecord:all 0.270000 0.020000 0.290000 ( 0.441299)
+DataMapper:all 1.440000 0.040000 1.480000 ( 1.625877)
+DataMapper:all:in-session 0.940000 0.030000 0.970000 ( 1.106244)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.246983)
+DataMapper:conditions:short 0.330000 0.020000 0.350000 ( 0.470939)
+DataMapper:conditions:short:in-session 0.310000 0.020000 0.330000 ( 0.475240)
+DataMapper:conditions:long 0.330000 0.020000 0.350000 ( 0.489315)
+DataMapper:conditions:long:in-session 0.290000 0.020000 0.310000 ( 0.431388)
+ActiveRecord:insert 4.260000 0.330000 4.590000 ( 5.959658)
+DataMapper:insert 2.260000 0.100000 2.360000 ( 2.829934)
+ActiveRecord:update 0.490000 0.090000 0.580000 ( 0.838985)
+DataMapper:update 0.420000 0.020000 0.440000 ( 0.569356)
+ActiveRecord:associations:lazy 3.940000 0.410000 4.350000 ( 7.117446)
+ActiveRecord:associations:included 4.550000 0.030000 4.580000 ( 5.322600)
+DataMapper:associations 7.070000 0.060000 7.130000 ( 7.505041)
+DataMapper:associations:in-session 1.020000 0.030000 1.050000 ( 1.180888)
+ActiveRecord:find_by_sql 0.230000 0.020000 0.250000 ( 0.374959)
+DataMapper:find_by_sql 0.450000 0.120000 0.570000 ( 0.963270)
+DataMapper:raw-query 0.130000 0.020000 0.150000 ( 0.285216)
+ActiveRecord:accessors 0.010000 0.000000 0.010000 ( 0.014831)
+DataMapper:accessors 0.030000 0.000000 0.030000 ( 0.030177)
+
+Faster #get (less *splat in the call-stack):
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.218195)
+DataMapper:id 0.250000 0.020000 0.270000 ( 0.345180)
+DataMapper:id:in-session 0.160000 0.020000 0.180000 ( 0.260807)
+ActiveRecord:all 0.270000 0.020000 0.290000 ( 0.418352)
+DataMapper:all 1.400000 0.030000 1.430000 ( 1.548471)
+DataMapper:all:in-session 0.920000 0.020000 0.940000 ( 1.064559)
+ActiveRecord:conditions 0.100000 0.020000 0.120000 ( 0.244208)
+DataMapper:conditions:short 0.330000 0.020000 0.350000 ( 0.469044)
+DataMapper:conditions:short:in-session 0.290000 0.020000 0.310000 ( 0.433122)
+DataMapper:conditions:long 0.330000 0.020000 0.350000 ( 0.466814)
+DataMapper:conditions:long:in-session 0.290000 0.020000 0.310000 ( 0.430728)
+ActiveRecord:insert 4.260000 0.320000 4.580000 ( 5.755669)
+DataMapper:insert 2.270000 0.110000 2.380000 ( 2.795413)
+ActiveRecord:update 0.480000 0.080000 0.560000 ( 0.832237)
+DataMapper:update 0.430000 0.020000 0.450000 ( 0.570414)
+ActiveRecord:associations:lazy 3.870000 0.400000 4.270000 ( 7.031791)
+ActiveRecord:associations:included 4.590000 0.040000 4.630000 ( 5.273726)
+DataMapper:associations 7.030000 0.060000 7.090000 ( 7.429910)
+DataMapper:associations:in-session 1.010000 0.020000 1.030000 ( 1.158633)
+ActiveRecord:find_by_sql 0.230000 0.020000 0.250000 ( 0.375564)
+DataMapper:find_by_sql 0.450000 0.130000 0.580000 ( 0.911728)
+DataMapper:raw-query 0.130000 0.020000 0.150000 ( 0.289264)
+ActiveRecord:accessors 0.020000 0.000000 0.020000 ( 0.015105)
+DataMapper:accessors 0.030000 0.000000 0.030000 ( 0.031271)
+
+Fastest #get (single method-call, limited iterations, fixed identity-map early return):
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.204608)
+DataMapper:id 0.180000 0.020000 0.200000 ( 0.271768)
+DataMapper:id:in-session 0.020000 0.000000 0.020000 ( 0.014118)
+ActiveRecord:all 0.280000 0.020000 0.300000 ( 0.418101)
+DataMapper:all 1.520000 0.020000 1.540000 ( 1.669128)
+DataMapper:all:in-session 1.010000 0.020000 1.030000 ( 1.163907)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.247928)
+DataMapper:conditions:short 0.330000 0.020000 0.350000 ( 0.464634)
+DataMapper:conditions:short:in-session 0.290000 0.020000 0.310000 ( 0.430232)
+DataMapper:conditions:long 0.330000 0.030000 0.360000 ( 0.460992)
+DataMapper:conditions:long:in-session 0.280000 0.020000 0.300000 ( 0.425144)
+ActiveRecord:insert 4.380000 0.330000 4.710000 ( 5.474600)
+DataMapper:insert 2.240000 0.100000 2.340000 ( 2.755951)
+ActiveRecord:update 0.470000 0.080000 0.550000 ( 0.781566)
+DataMapper:update 0.410000 0.020000 0.430000 ( 0.525973)
+ActiveRecord:associations:lazy 3.900000 0.420000 4.320000 ( 7.080422)
+ActiveRecord:associations:included 4.400000 0.030000 4.430000 ( 5.112349)
+DataMapper:associations 6.780000 0.060000 6.840000 ( 7.178618)
+DataMapper:associations:in-session 1.100000 0.020000 1.120000 ( 1.238834)
+ActiveRecord:find_by_sql 0.230000 0.020000 0.250000 ( 0.375993)
+DataMapper:find_by_sql 0.450000 0.130000 0.580000 ( 0.901768)
+DataMapper:raw-query 0.140000 0.020000 0.160000 ( 0.286502)
+ActiveRecord:accessors 0.010000 0.000000 0.010000 ( 0.014866)
+DataMapper:accessors 0.030000 0.000000 0.030000 ( 0.031177)
+
+More benchmarks to test the performance of the underlying drivers:
+ user system total real
+ActiveRecord:id 0.110000 0.020000 0.130000 ( 0.208672)
+ActiveRecord:id:raw_result-set 0.010000 0.020000 0.030000 ( 0.109599)
+DataMapper:id 0.170000 0.020000 0.190000 ( 0.268803)
+DataMapper:id:in-session 0.020000 0.000000 0.020000 ( 0.014197)
+DataMapper:id:raw-result-set 0.050000 0.020000 0.070000 ( 0.136051)
+ActiveRecord:all 0.270000 0.020000 0.290000 ( 0.420558)
+DataMapper:all 1.460000 0.020000 1.480000 ( 1.605453)
+DataMapper:all:in-session 0.990000 0.030000 1.020000 ( 1.131327)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.250190)
+DataMapper:conditions:short 0.320000 0.020000 0.340000 ( 0.462444)
+DataMapper:conditions:short:in-session 0.290000 0.020000 0.310000 ( 0.428014)
+DataMapper:conditions:long 0.320000 0.020000 0.340000 ( 0.459467)
+DataMapper:conditions:long:in-session 0.290000 0.020000 0.310000 ( 0.424365)
+ActiveRecord:insert 4.410000 0.320000 4.730000 ( 5.494924)
+DataMapper:insert 2.250000 0.100000 2.350000 ( 2.783917)
+ActiveRecord:update 0.480000 0.080000 0.560000 ( 0.799163)
+DataMapper:update 0.920000 0.060000 0.980000 ( 1.248217)
+ActiveRecord:associations:lazy 3.940000 0.420000 4.360000 ( 7.184043)
+ActiveRecord:associations:included 4.380000 0.040000 4.420000 ( 5.099299)
+DataMapper:associations 6.770000 0.060000 6.830000 ( 7.173094)
+DataMapper:associations:in-session 1.070000 0.020000 1.090000 ( 1.209617)
+ActiveRecord:find_by_sql 0.230000 0.020000 0.250000 ( 0.376181)
+DataMapper:find_by_sql 0.450000 0.130000 0.580000 ( 0.902970)
+DataMapper:raw-query 0.140000 0.020000 0.160000 ( 0.286420)
+ActiveRecord:accessors 0.010000 0.000000 0.010000 ( 0.015155)
+DataMapper:accessors 0.030000 0.000000 0.030000 ( 0.031162)
+
+Materialize with ::allocate instead of ::new:
+ user system total real
+ActiveRecord:id 0.100000 0.020000 0.120000 ( 0.202005)
+ActiveRecord:id:raw_result-set 0.010000 0.020000 0.030000 ( 0.103574)
+DataMapper:id 0.160000 0.020000 0.180000 ( 0.265041)
+DataMapper:id:in-session 0.010000 0.000000 0.010000 ( 0.013084)
+DataMapper:id:raw-result-set 0.040000 0.020000 0.060000 ( 0.134362)
+ActiveRecord:all 0.260000 0.020000 0.280000 ( 0.402124)
+DataMapper:all 1.300000 0.020000 1.320000 ( 1.444538)
+DataMapper:all:in-session 0.880000 0.020000 0.900000 ( 1.025989)
+ActiveRecord:conditions 0.110000 0.020000 0.130000 ( 0.241918)
+DataMapper:conditions:short 0.320000 0.020000 0.340000 ( 0.452805)
+DataMapper:conditions:short:in-session 0.280000 0.020000 0.300000 ( 0.422840)
+DataMapper:conditions:long 0.310000 0.020000 0.330000 ( 0.450802)
+DataMapper:conditions:long:in-session 0.280000 0.020000 0.300000 ( 0.418631)
+ActiveRecord:insert 4.180000 0.330000 4.510000 ( 5.263403)
+DataMapper:insert 2.220000 0.100000 2.320000 ( 2.807708)
+ActiveRecord:update 0.450000 0.080000 0.530000 ( 0.756596)
+DataMapper:update 0.920000 0.060000 0.980000 ( 1.228032)
+ActiveRecord:associations:lazy 3.790000 0.420000 4.210000 ( 6.955805)
+ActiveRecord:associations:included 4.190000 0.040000 4.230000 ( 4.846686)
+DataMapper:associations 9.380000 0.050000 9.430000 ( 9.775740)
+DataMapper:associations:in-session 1.080000 0.020000 1.100000 ( 1.224072)
+ActiveRecord:find_by_sql 0.210000 0.020000 0.230000 ( 0.359958)
+DataMapper:find_by_sql 2.760000 0.130000 2.890000 ( 3.227678)
+DataMapper:raw-query 0.130000 0.020000 0.150000 ( 0.283691)
+ActiveRecord:accessors 0.020000 0.000000 0.020000 ( 0.013469)
+DataMapper:accessors 0.030000 0.000000 0.030000 ( 0.029187)
View
12 QUICKLINKS
@@ -0,0 +1,12 @@
+= Quick Links
+
+* Finders and CRUD - DataMapper::Persistence::ConvenienceMethods::ClassMethods
+* Properties - DataMapper::Property
+* Validations - Validatable
+* Migrations
+* FAQ[link:/files/FAQ.html]
+* Contact Us
+ * Website - http://www.datamapper.org
+ * Bug Reports - http://wm.lighthouseapp.com/projects/4819-datamapper/overview
+ * IRC Channel - <tt>##datamapper</tt> on irc.freenode.net
+ * Mailing List - http://groups.google.com/group/datamapper/
View
151 README
@@ -0,0 +1,151 @@
+
+:include:QUICKLINKS
+
+= Why DataMapper?
+
+== Open Development
+
+Datamapper sports a very accessible code-base and a welcoming community.
+Outside contributions and feedback are welcome and encouraged, especially
+constructive criticism. Make your voice heard! Submit a
+ticket[http://wm.lighthouseapp.com/projects/4819-datamapper/overview] or
+patch[http://wm.lighthouseapp.com/projects/4819-datamapper/overview], speak up
+on our mailing-list[http://groups.google.com/group/datamapper/], chat with us
+on irc[irc://irc.freenode.net/#datamapper], write a spec, get it reviewed, ask
+for commit rights. It's as easy as that to become a contributor.
+
+== Identity Map
+
+One row in the database should equal one object reference. Pretty simple idea.
+Pretty profound impact. If you run the following code in ActiveRecord you'll
+see all <tt>false</tt> results. Do the same in DataMapper and it's
+<tt>true</tt> all the way down.
+
+
+ @parent = Tree.find(:first, :conditions => ['name = ?', 'bob'])
+
+ @parent.children.each do |child|
+ puts @parent.object_id == child.parent.object_id
+ end
+
+This makes DataMapper faster and allocate less resources to get things done.
+
+== Don't Do What You Don't Have To
+
+ActiveRecord updates every column in a row during a save whether that column
+changed or not. So it performs work it doesn't really need to making it much
+slower, and more likely to eat data during concurrent access if you don't go
+around adding locking support to everything.
+
+DataMapper only does what it needs to. So it plays well with others. You can
+use it in an Integration Database without worrying that your application will
+be a bad actor causing trouble for all of your other processes.
+
+== Eager Loading
+
+Ready for something amazing? The following example executes only two queries.
+
+ zoos = Zoo.all first = zoos.first first.exhibits
+ # Loads the exhibits for all the Zoo objects in the zoos variable.
+
+Pretty impressive huh? The idea is that you aren't going to load a set of
+objects and use only an association in just one of them. This should hold up
+pretty well against a 99% rule. When you don't want it to work like this, just
+load the item you want in it's own set. So the DataMapper thinks ahead. We
+like to call it "performant by default". This feature single-handedly wipes
+out the "N+1 Query Problem". No need to specify an <tt>include</tt> option in
+your finders.
+
+== Laziness Can Be A Virtue
+
+Text columns are expensive in databases. They're generally stored in a
+different place than the rest of your data. So instead of a fast sequential
+read from your hard-drive, your database server has to hop around all over the
+place to get what it needs. Since ActiveRecord returns everything by default,
+adding a text column to a table slows everything down drastically, across the
+board.
+
+Not so with the DataMapper. Text fields are treated like in-row associations
+by default, meaning they only load when you need them. If you want more
+control you can enable or disable this feature for any column (not just
+text-fields) by passing a @lazy@ option to your column mapping with a value of
+<tt>true</tt> or <tt>false</tt>.
+
+
+ class Animal < DataMapper::Base
+ property :name, :string property :notes, :text, :lazy => false
+ end
+
+
+Plus, lazy-loading of text fields happens automatically and intelligently when
+working with associations. The following only issues 2 queries to load up all
+of the notes fields on each animal:
+
+ animals = Animal.all animals.each do |pet|
+ pet.notes
+ end
+
+== Plays Well With Others
+
+In ActiveRecord, all your columns are mapped, whether you want them or not.
+This slows things down. In the DataMapper you define your mappings in your
+model. So instead of an _ALTER TABLE ADD COLUMN_ in your Database, you simply
+add a <tt>property :name, :string</tt> to your model. DRY. No schema.rb. No
+migration files to conflict or die without reverting changes. Your model
+drives the database, not the other way around.
+
+Unless of course you want to map to a legacy database. Raise your hand if you
+like seeing a method called <tt>col2Name</tt> on your model just because
+that's what it's called in an old database you can't afford to change right
+now? In DataMapper you control the mappings:
+
+
+ class Fruit < DataMapper::Base
+ set_table_name 'frt' property :name, :string, :column => 'col2'
+ end
+
+
+== All Ruby, All The Time
+
+It's great that ActiveRecord allows you to write SQL when you need to, but
+should we have to so often?
+
+DataMapper supports issuing your own SQL, but it also provides more helpers
+and a unique hash-based condition syntax to cover more of the use-cases where
+issuing your own SQL would have been the only way to go. For example, any
+finder option that's non-standard is considered a condition. So you can write
+<tt>Zoo.all(:name => 'Dallas')</tt> and DataMapper will look for zoos with the
+name of 'Dallas'.
+
+It's just a little thing, but it's so much nicer than writing
+<tt>Zoo.find(:all, :conditions => ['name = ?', 'Dallas'])</tt>. What if you
+need other comparisons though? Try these:
+
+
+ Zoo.first(:name => 'Galveston')
+
+ # 'gt' means greater-than. We also do 'lt'. Person.all(:age.gt => 30)
+
+ # 'gte' means greather-than-or-equal-to. We also do 'lte'.
+ Person.all(:age.gte => 30)
+
+ Person.all(:name.not => 'bob')
+
+ # If the value of a pair is an Array, we do an IN-clause for you.
+ Person.all(:name.like => 'S%', :id => [1, 2, 3, 4, 5])
+
+ # An alias for Zoo.find(11) Zoo[11]
+
+ # Does a NOT IN () clause for you. Person.all(:name.not =>
+ ['bob','rick','steve'])
+
+
+See? Fewer SQL fragments dirtying your Ruby code. And that's just a few of the
+nice syntax tweaks DataMapper delivers out of the box...
+
+== Better Is Great, But Familiar Is Nice
+
+The DataMapper also supports a lot of old-fashioned ActiveRecord syntax. We
+want to make it easy for you to get started, so aside from mapping your
+columns and changing the base-class your models inherit from, much of AR
+syntax for finders are supported as well, making your transition easy.
View
4 all
@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+ADAPTER=sqlite3 rake
+ADAPTER=mysql rake
+ADAPTER=postgresql rake
View
2  bin/.irbrc
@@ -0,0 +1,2 @@
+IRB.conf[:PROMPT] = {:DM => { :PROMPT_I=>"%03n:%i dm> ", :PROMPT_N=>"%03n:%i dm> ", :PROMPT_S=>"%03n:%i%l dm", :PROMPT_C=>"%03n:%i dm*", :RETURN=>"%s\n" }}
+IRB.conf[:PROMPT_MODE] = :DM
View
7 bin/dm
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+require "rubygems"
+require "data_mapper"
+require "data_mapper/cli"
+require "optparse"
+
+DataMapper::CLI.start
View
54 environment.rb
@@ -0,0 +1,54 @@
+unless defined?(INITIAL_CLASSES)
+ # Require the DataMapper, and a Mock Adapter.
+ require File.dirname(__FILE__) + "/lib/data_mapper"
+ require File.dirname(__FILE__) + "/spec/mock_adapter"
+
+ adapter = ENV["ADAPTER"] || "sqlite3"
+
+ repository_uri = URI.parse case ENV["ADAPTER"]
+ when 'mysql' then "mysql://localhost/data_mapper_1"
+ when 'postgres' then "postgres://localhost/data_mapper_1"
+ else "sqlite3:///#{Dir.pwd}/data_mapper_1.db"
+ end
+
+ # Prepare the log path, and remove the existing spec.log
+ require "fileutils"
+ #
+ # if ENV["LOG_NAME"]
+ # log_path = nil
+ #
+ # if ENV["LOG_NAME"] != "STDOUT"
+ # FileUtils::mkdir_p(File.dirname(__FILE__) + "/log")
+ # log_path = File.dirname(__FILE__) + "/log/#{ENV["LOG_NAME"]}.log"
+ # FileUtils::rm log_path if File.exists?(log_path)
+ # else
+ # log_path = "STDOUT"
+ # end
+ #
+ # configuration_options.merge!(:log_stream => log_path, :log_level => DataMapper::Logger::Levels[:debug])
+ # end
+
+ load_models = lambda do
+ Dir[File.dirname(__FILE__) + "/spec/models/*.rb"].sort.each { |path| load path }
+ end
+
+ # secondary_configuration_options = configuration_options.dup
+ # secondary_configuration_options.merge!(:database => (adapter == "sqlite3" ? "data_mapper_2.db" : "data_mapper_2"))
+
+ # DataMapper.setup(repository_uri)
+
+ # DataMapper::Repository.setup(configuration_options)
+ # DataMapper::Repository.setup(:secondary, secondary_configuration_options)
+ # DataMapper::Repository.setup(:mock, :adapter => MockAdapter)
+
+ # [:default, :secondary, :mock].each { |name| repository(name) { load_models.call } }
+
+ # Reset the test database.
+ # unless ENV['AUTO_MIGRATE'] == 'false'
+ # [:default, :secondary].each { |name| repository(name) { DataMapper::Persistable.auto_migrate! } }
+ # end
+
+ # Save the initial database layout so we can put everything back together
+ # after auto migrations testing
+ # INITIAL_CLASSES = Array.new(DataMapper::Persistable.subclasses.to_a)
+end
View
156 example.rb
@@ -0,0 +1,156 @@
+#!/usr/bin/env ruby
+
+ENV['LOG_NAME'] ||= 'example'
+require 'environment'
+
+# Define a fixtures helper method to load up our test data.
+def fixtures(name)
+ entry = YAML::load_file(File.dirname(__FILE__) + "/spec/fixtures/#{name}.yaml")
+ klass = begin
+ Kernel::const_get(Inflector.classify(Inflector.singularize(name)))
+ rescue
+ nil
+ end
+
+ unless klass.nil?
+ repository.logger.debug { "AUTOMIGRATE: #{klass}" }
+ klass.auto_migrate!
+
+ (entry.kind_of?(Array) ? entry : [entry]).each do |hash|
+ if hash['type']
+ Object::const_get(hash['type'])::create(hash)
+ else
+ klass::create(hash)
+ end
+ end
+ else
+ table = repository.table(name.to_s)
+ table.create! true
+ table.activate_associations!
+
+ #pp repository.schema
+
+ (entry.kind_of?(Array) ? entry : [entry]).each do |hash|
+ table.insert(hash)
+ end
+ end
+end
+
+
+# Pre-fill the database so non-destructive tests don't need to reload fixtures.
+Dir[File.dirname(__FILE__) + "/spec/fixtures/*.yaml"].each do |path|
+ fixtures(File::basename(path).sub(/\.yaml$/, ''))
+end
+
+require 'irb'
+
+# database { IRB::start }
+IRB::start
+
+if false
+
+# Simple example to setup a database:
+DataMapper::Repository.setup({
+ :adapter => 'mysql',
+ :database => 'data_mapper_1',
+ :username => 'root'
+})
+
+class Animal #:nodoc:
+ include DataMapper::Persistence
+
+ set_table_name 'animals' # Just as an example. Same inflector as Rails,
+ # so this really isn't necessary.
+
+ property :name, :string
+ property :notes, :string, :lazy => true
+
+ has_and_belongs_to_many :exhibits
+end
+
+class Exhibit #:nodoc:
+ include DataMapper::Persistence
+
+ property :name, :string
+ belongs_to :zoo
+end
+
+class Zoo #:nodoc:
+ include DataMapper::Persistence
+
+ property :name, :string
+ has_many :exhibits
+end
+
+class Person #:nodoc:
+ include DataMapper::Persistence
+
+ property :name, :string
+ property :age, :integer
+ property :occupation, :string
+ property :notes, :text, :lazy => true
+
+ # Generates Person::Address class:
+ embed :address do
+ property :street, :string
+ property :city, :string
+ property :state, :string, :size => 2
+ property :postal_code, :string
+ end
+end
+
+# Compatible with ActiveRecord finder syntax:
+Zoo.find(1)
+Zoo.find(:first, :conditions => ['name = ?', 'Galveston'])
+Zoo.find(:all)
+
+# These are options as well:
+Zoo[1]
+Zoo.first(:name => 'Galveston')
+Zoo.all
+
+# Or even this as an alias to ::first:
+Zoo[:name => 'Galveston']
+
+# EmbeddedValues are just nice sugar to partition
+# denormalized data.
+Person.first.address.city
+
+# Remove all data in a table...
+Person.truncate!
+
+# Create a new object...
+Person::create(:name => 'Sam', :age => 30, :occupation => 'Software Monkey')
+
+# Saving only updates the values that have changed,
+# and is skipped entirely if the object is not dirty.
+dumbo = Animal.first(:name => 'Elephant')
+dumbo.notes = 'He can fly!'
+dumbo.save # returns true
+dumbo.save # The object is no longer dirty, so returns false
+
+# DataMapper associations are loaded as sets.
+# Here's the code:
+Zoo.all.each { |zoo| zoo.exhibits.entries }
+# The important bit to understand about the above is that
+# every Zoo that was loaded by Zoo.all has a reference to
+# every other Zoo it was loaded with through Zoo#loaded_set.
+# This is then used to load all other instances in the set
+# when the association of one instance is accessed. So while
+# it looks like we'd run into the dreaded 1+N query problem
+# with the above, we actually avoid it entirely. The above
+# code will only execute two queries. The first to find all
+# zoos, the second to load all exhibits with zoo_id's that
+# are a part of the set of loaded zoos.
+
+
+# Objects within the same session are uniqued, so this is both
+# faster, and fulfills obvious expectations.
+repository do
+ Zoo.first == Zoo.first
+end
+
+# DataMapper find_by_sql equivilent
+repository.query("SELECT * FROM zoos")
+
+end
View
92 lib/data_mapper.rb
@@ -0,0 +1,92 @@
+# This file begins the loading sequence.
+#
+# Quick Overview:
+# * Requires set, fastthread, support libs, and base
+# * Sets the applications root and environment for compatibility with rails or merb
+# * Checks for the database.yml and loads it if it exists
+# * Sets up the database using the config from the yaml file or from the environment
+# *
+
+# This line just let's us require anything in the +lib+ sub-folder
+# without specifying a full path.
+unless defined?(DM_PLUGINS_ROOT)
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
+
+ DM_PLUGINS_ROOT = (File.dirname(__FILE__) + '/../plugins')
+end
+
+# Require the basics...
+require 'uri'
+require 'date'
+require 'time'
+require 'rubygems'
+require 'yaml'
+require 'set'
+require 'fastthread'
+require 'validatable'
+require 'data_mapper/support/object'
+require 'data_mapper/support/blank'
+require 'data_mapper/support/enumerable'
+require 'data_mapper/support/symbol'
+require 'data_mapper/support/string'
+require 'data_mapper/support/silence'
+require 'data_mapper/support/inflector'
+require 'data_mapper/support/errors'
+require 'data_mapper/support/typed_set'
+require 'data_mapper/logger'
+require 'data_mapper/repository'
+require 'data_mapper/persistable'
+require 'data_mapper/container'
+require 'data_mapper/resource'
+require 'data_mapper/types/string'
+require 'data_mapper/model'
+
+
+begin
+ # This block of code is for compatibility with Ruby On Rails' or Merb's database.yml
+ # file, allowing you to simply require the data_mapper.rb in your
+ # Rails application's environment.rb to configure the DataMapper.
+ unless defined?(DM_APP_ROOT)
+ application_root, application_environment = *if defined?(RAILS_ROOT)
+ [RAILS_ROOT, RAILS_ENV]
+ end
+
+ DM_APP_ROOT = application_root || Dir::pwd
+
+ if application_root && File.exists?(application_root + '/config/database.yml')
+
+ database_configurations = YAML::load_file(application_root + '/config/database.yml')
+ current_database_config = database_configurations[application_environment] || database_configurations[application_environment.to_sym]
+
+ config = lambda { |key| current_database_config[key.to_s] || current_database_config[key] }
+
+ default_database_config = {
+ :adapter => config[:adapter],
+ :host => config[:host],
+ :database => config[:database],
+ :username => config[:username],
+ :password => config[:password],
+ :socket => config[:socket]
+ }
+
+ DataMapper::Repository.setup(default_database_config)
+
+ elsif application_root && FileTest.directory?(application_root + '/config')
+
+ %w(development testing production).map do |environment|
+ <<-EOS.margin
+ #{environment}:
+ adapter: mysql
+ username: root
+ password:
+ host: localhost
+ database: #{File.dirname(DM_APP_ROOT).split('/').last}_#{environment}
+ EOS
+ end
+
+ #File::open(application_root + '/config/database.yml')
+ end
+ end
+rescue Exception
+ warn "Could not connect to database specified by database.yml."
+end
View
43 lib/data_mapper/adapters/abstract_adapter.rb
@@ -0,0 +1,43 @@
+module DataMapper
+ module Adapters
+
+ class AbstractAdapter
+
+ # Instantiate an Adapter by passing it a DataMapper::Repository
+ # object for configuration.
+ def initialize(configuration)
+ @configuration = configuration
+ end
+
+ def index_path
+ @configuration.index_path
+ end
+
+ def name
+ @configuration.name
+ end
+
+ def delete(instance_or_klass, options = nil)
+ raise NotImplementedError.new
+ end
+
+ def save(database_context, instance)
+ raise NotImplementedError.new
+ end
+
+ def load(database_context, klass, options)
+ raise NotImplementedError.new
+ end
+
+ def get(database_context, klass, *keys)
+ raise NotImplementedError.new
+ end
+
+ def logger
+ @logger || @logger = @configuration.logger
+ end
+
+ end # class AbstractAdapter
+
+ end # module Adapters
+end # module DataMapper
View
479 lib/data_mapper/adapters/data_object_adapter.rb
@@ -0,0 +1,479 @@
+require 'data_mapper/adapters/abstract_adapter'
+require 'data_mapper/adapters/sql/commands/load_command'
+require 'data_mapper/adapters/sql/coersion'
+require 'data_mapper/adapters/sql/quoting'
+require 'data_mapper/adapters/sql/mappings/schema'
+require 'data_mapper/support/connection_pool'
+require 'data_mapper/query'
+
+module DataMapper
+
+ # An Adapter is really a Factory for three types of object,
+ # so they can be selectively sub-classed where needed.
+ #
+ # The first type is a Query. The Query is an object describing
+ # the database-specific operations we wish to perform, in an
+ # abstract manner. For example: While most if not all databases
+ # support a mechanism for limiting the size of results returned,
+ # some use a "LIMIT" keyword, while others use a "TOP" keyword.
+ # We can set a SelectStatement#limit field then, and allow
+ # the adapter to override the underlying SQL generated.
+ # Refer to DataMapper::Queries.
+ #
+ # The final type provided is a DataMapper::Transaction.
+ # Transactions are duck-typed Connections that span multiple queries.
+ #
+ # Note: It is assumed that the Adapter implements it's own
+ # ConnectionPool if any since some libraries implement their own at
+ # a low-level, and it wouldn't make sense to pay a performance
+ # cost twice by implementing a secondary pool in the DataMapper itself.
+ # If the library being adapted does not provide such functionality,
+ # DataMapper::Support::ConnectionPool can be used.
+ module Adapters
+
+ # You must inherit from the DoAdapter, and implement the
+ # required methods to adapt a database library for use with the DataMapper.
+ #
+ # NOTE: By inheriting from DoAdapter, you get a copy of all the
+ # standard sub-modules (Quoting, Coersion and Queries) in your own Adapter.
+ # You can extend and overwrite these copies without affecting the originals.
+ class DataObjectAdapter < AbstractAdapter
+
+ $LOAD_PATH << (DM_PLUGINS_ROOT + '/dataobjects')
+
+ FIND_OPTIONS = [
+ :select, :offset, :limit, :class, :include, :shallow_include, :reload, :conditions, :order, :intercept_load
+ ]
+
+ TABLE_QUOTING_CHARACTER = '`'.freeze
+ COLUMN_QUOTING_CHARACTER = '`'.freeze
+
+ SYNTAX = {
+ :now => 'NOW()'.freeze
+ }
+
+ def initialize(configuration)
+ super
+ @connection_pool = Support::ConnectionPool.new { create_connection }
+ end
+
+ def activated?
+ @activated
+ end
+
+ def activate!
+ @activated = true
+ schema.activate!
+ end
+
+ def create_connection
+ raise NotImplementedError.new
+ end
+
+ def batch_insertable?
+ true
+ end
+
+ # Yields an available connection. Flushes the connection-pool and reconnects
+ # if the connection returns an error.
+ def connection
+ begin
+ # Yield the appropriate connection
+ @connection_pool.hold { |active_connection| yield(active_connection) }
+ rescue => execution_error
+ # Log error on failure
+ logger.error { execution_error }
+
+ # Close all open connections, assuming that if one
+ # had an error, it's likely due to a lost connection,
+ # in which case all connections are likely broken.
+ flush_connections!
+
+ raise execution_error
+ end
+ end
+
+ # Close any open connections.
+ def flush_connections!
+ begin
+ @connection_pool.available_connections.each do |active_connection|
+ active_connection.close
+ end
+ rescue => close_connection_error
+ # An error on closing the connection is almost expected
+ # if the socket is broken.
+ logger.warn { close_connection_error }
+ end
+
+ # Reopen fresh connections.
+ @connection_pool.available_connections.clear
+ end
+
+ def transaction(&block)
+ raise NotImplementedError.new
+ end
+
+ def query(*args)
+ db = create_connection
+
+ command = db.create_command(args.shift)
+
+ reader = command.execute_reader(*args)
+ fields = reader.fields.map { |field| Inflector.underscore(field).to_sym }
+ results = []
+
+ if fields.size > 1
+ struct = Struct.new(*fields)
+
+ reader.each do
+ results << struct.new(*reader.current_row)
+ end
+ else
+ reader.each do
+ results << reader.item(0)
+ end
+ end
+
+ return results
+ rescue => e
+ logger.error { e }
+ raise e
+ ensure
+ reader.close if reader
+ db.close
+ end
+
+ def execute(*args)
+ db = create_connection
+ command = db.create_command(args.shift)
+ return command.execute_non_query(*args)
+ rescue => e
+ logger.error { e }
+ raise e
+ ensure
+ db.close
+ end
+
+ def handle_error(error)
+ raise error
+ end
+
+ def schema
+ @schema || ( @schema = self.class::Mappings::Schema.new(self, @configuration.database) )
+ end
+
+ def column_exists_for_table?(table_name, column_name)
+ connection do |db|
+ table = self.table(table_name)
+ command = db.create_command(table.to_column_exists_sql)
+ command.execute_reader(table.name, column_name, table.schema.name) do |reader|
+ reader.any? { reader.item(1) == column_name.to_s }
+ end
+ end
+ end
+
+ def delete(database_context, instance)
+ table = self.table(instance)
+
+ if instance.is_a?(Class)
+ table.delete_all!
+ else
+ callback(instance, :before_destroy)
+
+ table.associations.each do |association|
+ instance.send(association.name).deactivate unless association.is_a?(::DataMapper::Associations::BelongsToAssociation)
+ end
+
+ if table.paranoid?
+ instance.instance_variable_set(table.paranoid_column.instance_variable_name, Time::now)
+ instance.save
+ else
+ if connection do |db|
+ command = db.create_command("DELETE FROM #{table.to_sql} WHERE #{table.key.to_sql} = ?")
+ command.execute_non_query(instance.key).to_i > 0
+ end # connection do...end # if continued below:
+ instance.instance_variable_set(:@new_record, true)
+ instance.database_context = database_context
+ instance.original_values.clear
+ database_context.identity_map.delete(instance)
+ callback(instance, :after_destroy)
+ end
+ end
+ end
+ end
+
+ def save(database_context, instance, validate = true, cleared = Set.new)
+ case instance
+ when Class then
+ table(instance).create!
+ table(instance).activate_associations!
+ when Mappings::Table then instance.create!
+ when DataMapper::Persistable then
+ event = instance.new_record? ? :create : :update
+
+ return false if (validate && !instance.validate_recursively(event, Set.new)) || cleared.include?(instance)
+ cleared << instance
+
+ callback(instance, :before_save)
+
+ return true unless instance.new_record? || instance.dirty?
+
+ result = send(event, database_context, instance)
+
+ instance.database_context = database_context
+ instance.attributes.each_pair do |name, value|
+ instance.original_values[name] = value
+ end
+
+ instance.loaded_associations.each do |association|
+ association.save_without_validation(database_context, cleared) if association.dirty?
+ end
+
+ callback(instance, :after_save)
+ result
+ end
+ rescue => error
+ logger.error(error)
+ raise error
+ end
+
+ def save_without_validation(database_context, instance, cleared = Set.new)
+ save(database_context, instance, false, cleared)
+ end
+
+ def update(database_context, instance)
+ callback(instance, :before_update)
+
+ instance = update_magic_properties(database_context, instance)
+
+ table = self.table(instance)
+ attributes = instance.dirty_attributes
+ parameters = []
+
+ unless attributes.empty?
+ sql = "UPDATE " << table.to_sql << " SET "
+
+ sql << attributes.map do |key, value|
+ parameters << value
+ "#{table[key].to_sql} = ?"
+ end.join(', ')
+
+ sql << " WHERE #{table.key.to_sql} = ?"
+ parameters << instance.key
+
+ result = connection do |db|
+ db.create_command(sql).execute_non_query(*parameters)
+ end
+
+ # BUG: do_mysql returns inaccurate affected row counts for UPDATE statements.
+ if true || result.to_i > 0
+ callback(instance, :after_update)
+ return true
+ else
+ return false
+ end
+ else
+ true
+ end
+ end
+
+ def empty_insert_sql
+ "DEFAULT VALUES"
+ end
+
+ def create(database_context, instance)
+ callback(instance, :before_create)
+
+ instance = update_magic_properties(database_context, instance)
+
+ table = self.table(instance)
+ attributes = instance.dirty_attributes
+
+ if table.multi_class?
+ instance.instance_variable_set(
+ table[:type].instance_variable_name,
+ attributes[:type] = instance.class.name
+ )
+ end
+
+ keys = []
+ values = []
+ attributes.each_pair do |key, value|
+ raise ArgumentError.new("#{value.inspect} is not a valid value for #{key.inspect}") if value.is_a?(Array)
+
+ keys << table[key].to_sql
+ values << value
+ end
+
+ sql = if keys.size > 0
+ "INSERT INTO #{table.to_sql} (#{keys.join(', ')}) VALUES ?"
+ else
+ "INSERT INTO #{table.to_sql} #{self.empty_insert_sql}"
+ end
+
+ result = connection do |db|
+ db.create_command(sql).execute_non_query(values)
+ end
+
+ if result.to_i > 0
+ instance.instance_variable_set(:@new_record, false)
+ instance.key = result.last_insert_row if table.key.serial? && !attributes.include?(table.key.name)
+ database_context.identity_map.set(instance)
+ callback(instance, :after_create)
+ return true
+ else
+ return false
+ end
+ end
+
+ MAGIC_PROPERTIES = {
+ :updated_at => lambda { self.updated_at = Time::now },
+ :updated_on => lambda { self.updated_on = Date::today },
+ :created_at => lambda { self.created_at ||= Time::now },
+ :created_on => lambda { self.created_on ||= Date::today }
+ }
+
+ def update_magic_properties(database_context, instance)
+ instance.class.properties.find_all { |property| MAGIC_PROPERTIES.has_key?(property.name) }.each do |property|
+ instance.instance_eval(&MAGIC_PROPERTIES[property.name])
+ end
+ instance
+ end
+
+ def load(database_context, klass, options)
+ self.class::Commands::LoadCommand.new(self, database_context, klass, options).call
+ end
+
+ def get(database_context, klass, keys)
+ table = self.table(klass)
+ instance_id = table.key.type_cast_value(keys.first)
+ instance = database_context.identity_map.get(klass, instance_id)
+
+ return instance if instance
+
+ column_indexes = {}
+ select_columns = []
+
+ table.columns.each_with_index do |column, i|
+ column_indexes[column] = i
+ select_columns << column.to_sql
+ end
+
+ sql = "SELECT #{select_columns.join(', ')} FROM #{table.to_sql} WHERE #{table.keys.map { |key| "#{key.to_sql} = ?" }.join(' AND ')}"
+
+ connection do |db|
+ reader = nil
+ begin
+ reader = db.create_command(sql).execute_reader(*keys)
+
+ if reader.has_rows?
+
+ instance_type = klass
+
+ if table.multi_class? && table.type_column
+ value = reader.item(column_indexes[table.type_column])
+ instance_type = table.type_column.type_cast_value(value) unless value.blank?
+ end
+
+ if instance.nil?
+ instance = instance_type.allocate()
+ instance.instance_variable_set(:@__key, instance_id)
+ instance.instance_variable_set(:@new_record, false)
+ database_context.identity_map.set(instance)
+ elsif instance.new_record?
+ instance.instance_variable_set(:@__key, instance_id)
+ instance.instance_variable_set(:@new_record, false)
+ database_context.identity_map.set(instance)
+ end
+
+ instance.database_context = database_context
+
+ instance_type.callbacks.execute(:before_materialize, instance)
+
+ originals = instance.original_values
+
+ column_indexes.each_pair do |column, i|
+ value = column.type_cast_value(reader.item(i))
+ instance.instance_variable_set(column.instance_variable_name, value)
+
+ case value
+ when String, Date, Time then originals[column.name] = value.dup
+ else originals[column.name] = value
+ end
+ end
+
+ instance.loaded_set = [instance]
+
+ instance_type.callbacks.execute(:after_materialize, instance)
+ end # if reader.has_rows?
+ ensure
+ reader.close if reader && reader.open?
+ end
+ end # connection
+
+ return instance
+ end
+
+ def table(instance)
+ case instance
+ when DataMapper::Adapters::Sql::Mappings::Table then instance
+ when DataMapper::Persistable then schema[instance.class]
+ when Class, String then schema[instance]
+ else raise "Don't know how to map #{instance.inspect} to a table."
+ end
+ end
+
+ def callback(instance, callback_name)
+ instance.class.callbacks.execute(callback_name, instance)
+ end
+
+ # This callback copies and sub-classes modules and classes
+ # in the DoAdapter to the inherited class so you don't
+ # have to copy and paste large blocks of code from the
+ # DoAdapter.
+ #
+ # Basically, when inheriting from the DoAdapter, you
+ # aren't just inheriting a single class, you're inheriting
+ # a whole graph of Types. For convenience.
+ def self.inherited(base)
+
+ commands = base.const_set('Commands', Module.new)
+
+ Sql::Commands.constants.each do |name|
+ commands.const_set(name, Class.new(Sql::Commands.const_get(name)))
+ end
+
+ mappings = base.const_set('Mappings', Module.new)
+
+ Sql::Mappings.constants.each do |name|
+ mappings.const_set(name, Class.new(Sql::Mappings.const_get(name)))
+ end
+
+ base.const_set('TYPES', TYPES.dup)
+ base.const_set('FIND_OPTIONS', FIND_OPTIONS.dup)
+ base.const_set('SYNTAX', SYNTAX.dup)
+
+ super
+ end
+
+ TYPES = {
+ :integer => 'int'.freeze,
+ :string => 'varchar'.freeze,
+ :text => 'text'.freeze,
+ :class => 'varchar'.freeze,
+ :decimal => 'decimal'.freeze,
+ :float => 'float'.freeze,
+ :datetime => 'datetime'.freeze,
+ :date => 'date'.freeze,
+ :boolean => 'boolean'.freeze,
+ :object => 'text'.freeze
+ }
+
+ include Sql
+ include Quoting
+ include Coersion
+
+ end # class DoAdapter
+
+ end # module Adapters
+end # module DataMapper
View
71 lib/data_mapper/adapters/mysql_adapter.rb
@@ -0,0 +1,71 @@
+require 'data_mapper/adapters/data_object_adapter'
+begin
+ require 'do_mysql'
+rescue LoadError
+ STDERR.puts <<-EOS
+You must install the DataObjects::Mysql driver.
+ gem install do_mysql
+EOS
+ exit
+end
+
+module DataMapper
+ module Adapters
+
+ class MysqlAdapter < DataObjectAdapter
+
+ TRUE_ALIASES << "T".freeze << "\004\bT".freeze
+ FALSE_ALIASES << "F".freeze << "\004\bF".freeze
+
+ def empty_insert_sql
+ "() VALUES ()"
+ end
+
+ def create_connection
+
+ connection_string = ""
+ builder = lambda { |k,v| connection_string << "#{k}=#{@configuration.send(v)} " unless @configuration.send(v).blank? }
+
+ builder['host', :host]
+ builder['user', :username]
+ builder['password', :password]
+ builder['dbname', :database]
+ builder['socket', :socket]
+ builder['port', :port]
+
+ logger.debug { connection_string.strip }
+
+ conn = DataObject::Mysql::Connection.new(connection_string.strip)
+ conn.logger = self.logger
+ conn.open
+ cmd = conn.create_command("SET NAMES UTF8")
+ cmd.execute_non_query
+ return conn
+ end
+
+ def database_column_name
+ "TABLE_SCHEMA"
+ end
+
+ module Mappings
+
+ def to_create_table_sql
+ @to_create_table_sql || @to_create_table_sql = begin
+ "CREATE TABLE #{to_sql} (#{columns.map { |c| c.to_long_form }.join(', ')}) Type=MyISAM CHARACTER SET utf8"
+ end
+ end
+
+ class Schema
+
+ def database_tables
+ get_database_tables(@adapter.schema.name)
+ end
+
+ end
+
+
+ end # module Mappings
+ end # class MysqlAdapter
+
+ end # module Adapters
+end # module DataMapper
View
257 lib/data_mapper/adapters/postgresql_adapter.rb
@@ -0,0 +1,257 @@
+require "data_mapper/adapters/data_object_adapter"
+begin
+ require "do_postgres"
+rescue LoadError
+ STDERR.puts <<-EOS
+You must install the DataObjects::Postgres driver.
+ gem install do_postgres
+EOS
+ exit
+end
+
+module DataMapper
+ module Adapters
+
+ class PostgresqlAdapter < DataObjectAdapter
+
+ def schema_search_path
+ @schema_search_path || @schema_search_path = begin
+ if @configuration.schema_search_path
+ @configuration.schema_search_path.split(',').map do |part|
+ part.blank? ? nil : part.strip.ensure_wrapped_with("'")
+ end.compact
+ else
+ []
+ end
+ end
+ end
+
+ def create_connection
+ connection_string = ""
+ builder = lambda do |k,v|
+ connection_string << "#{k}=#{@configuration.send(v)} " unless
+ @configuration.send(v).blank?
+ end
+ builder["host", :host]
+ builder["user", :username]
+ builder["password", :password]
+ builder["dbname", :database]
+ builder["socket", :socket]
+ builder["port", :port]
+ conn = DataObject::Postgres::Connection.new(connection_string.strip)
+ conn.logger = self.logger
+ conn.open
+
+ unless schema_search_path.empty?
+ execute("SET search_path TO #{schema_search_path}")
+ end
+
+ return conn
+ end
+
+ def database_column_name
+ "TABLE_CATALOG"
+ end
+
+ TABLE_QUOTING_CHARACTER = '"'.freeze
+ COLUMN_QUOTING_CHARACTER = '"'.freeze
+
+ TYPES.merge!({
+ :integer => "integer".freeze,
+ :datetime => "timestamp with time zone".freeze
+ })
+
+ module Mappings
+ class Table
+ def sequence_sql
+ @sequence_sql ||= quote_table("_id_seq").freeze
+ end
+
+ def to_create_table_sql
+ schema_name = name.index('.') ? name.split('.').first : nil
+ schema_list = @adapter.query('SELECT nspname FROM pg_namespace').join(',')
+
+ sql = if schema_name and !schema_list.include?(schema_name)
+ "CREATE SCHEMA #{@adapter.quote_table_name(schema_name)}; "
+ else
+ ''
+ end
+
+ sql << "CREATE TABLE " << to_sql
+
+ sql << " (" << columns.map do |column|
+ column.to_long_form
+ end.join(', ') << ")"
+
+ return sql
+ end
+
+ # The logic of this comes from AR; it was modified for smarter typecasting
+ def unquote_default(default)
+ # Boolean types
+ return true if default =~ /true/i
+ return false if default =~ /false/i
+
+ # Char/String/Bytea type values
+ return $1 if default =~ /^'(.*)'::(bpchar|text|character varying|bytea)$/
+
+ # Numeric values
+ return value.to_f if default =~ /^-?[0-9]+(\.[0-9]*)/
+ return value.to_i if default =~ /^-?[0-9]+/
+
+ # Fixed dates / times
+ return Date.parse($1) if default =~ /^'(.+)'::date/
+ return DateTime.parse($1) if default =~ /^'(.+)'::timestamp/
+
+ # Anything else is blank, some user type, or some function
+ # and we can't know the value of that, so return nil.
+ return nil
+ end