dm-core 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. data/CHANGELOG +144 -0
  2. data/FAQ +74 -0
  3. data/MIT-LICENSE +22 -0
  4. data/QUICKLINKS +12 -0
  5. data/README +143 -0
  6. data/lib/dm-core.rb +213 -0
  7. data/lib/dm-core/adapters.rb +4 -0
  8. data/lib/dm-core/adapters/abstract_adapter.rb +202 -0
  9. data/lib/dm-core/adapters/data_objects_adapter.rb +701 -0
  10. data/lib/dm-core/adapters/mysql_adapter.rb +132 -0
  11. data/lib/dm-core/adapters/postgres_adapter.rb +179 -0
  12. data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
  13. data/lib/dm-core/associations.rb +172 -0
  14. data/lib/dm-core/associations/many_to_many.rb +138 -0
  15. data/lib/dm-core/associations/many_to_one.rb +101 -0
  16. data/lib/dm-core/associations/one_to_many.rb +275 -0
  17. data/lib/dm-core/associations/one_to_one.rb +61 -0
  18. data/lib/dm-core/associations/relationship.rb +116 -0
  19. data/lib/dm-core/associations/relationship_chain.rb +74 -0
  20. data/lib/dm-core/auto_migrations.rb +64 -0
  21. data/lib/dm-core/collection.rb +604 -0
  22. data/lib/dm-core/hook.rb +11 -0
  23. data/lib/dm-core/identity_map.rb +45 -0
  24. data/lib/dm-core/is.rb +16 -0
  25. data/lib/dm-core/logger.rb +233 -0
  26. data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
  27. data/lib/dm-core/migrator.rb +29 -0
  28. data/lib/dm-core/model.rb +399 -0
  29. data/lib/dm-core/naming_conventions.rb +52 -0
  30. data/lib/dm-core/property.rb +611 -0
  31. data/lib/dm-core/property_set.rb +158 -0
  32. data/lib/dm-core/query.rb +590 -0
  33. data/lib/dm-core/repository.rb +159 -0
  34. data/lib/dm-core/resource.rb +618 -0
  35. data/lib/dm-core/scope.rb +35 -0
  36. data/lib/dm-core/support.rb +7 -0
  37. data/lib/dm-core/support/array.rb +13 -0
  38. data/lib/dm-core/support/assertions.rb +8 -0
  39. data/lib/dm-core/support/errors.rb +23 -0
  40. data/lib/dm-core/support/kernel.rb +7 -0
  41. data/lib/dm-core/support/symbol.rb +41 -0
  42. data/lib/dm-core/transaction.rb +267 -0
  43. data/lib/dm-core/type.rb +160 -0
  44. data/lib/dm-core/type_map.rb +80 -0
  45. data/lib/dm-core/types.rb +19 -0
  46. data/lib/dm-core/types/boolean.rb +7 -0
  47. data/lib/dm-core/types/discriminator.rb +32 -0
  48. data/lib/dm-core/types/object.rb +20 -0
  49. data/lib/dm-core/types/paranoid_boolean.rb +23 -0
  50. data/lib/dm-core/types/paranoid_datetime.rb +22 -0
  51. data/lib/dm-core/types/serial.rb +9 -0
  52. data/lib/dm-core/types/text.rb +10 -0
  53. data/spec/integration/association_spec.rb +1215 -0
  54. data/spec/integration/association_through_spec.rb +150 -0
  55. data/spec/integration/associations/many_to_many_spec.rb +171 -0
  56. data/spec/integration/associations/many_to_one_spec.rb +123 -0
  57. data/spec/integration/associations/one_to_many_spec.rb +66 -0
  58. data/spec/integration/auto_migrations_spec.rb +398 -0
  59. data/spec/integration/collection_spec.rb +1015 -0
  60. data/spec/integration/data_objects_adapter_spec.rb +32 -0
  61. data/spec/integration/model_spec.rb +68 -0
  62. data/spec/integration/mysql_adapter_spec.rb +85 -0
  63. data/spec/integration/postgres_adapter_spec.rb +732 -0
  64. data/spec/integration/property_spec.rb +224 -0
  65. data/spec/integration/query_spec.rb +376 -0
  66. data/spec/integration/repository_spec.rb +57 -0
  67. data/spec/integration/resource_spec.rb +324 -0
  68. data/spec/integration/sqlite3_adapter_spec.rb +352 -0
  69. data/spec/integration/sti_spec.rb +185 -0
  70. data/spec/integration/transaction_spec.rb +75 -0
  71. data/spec/integration/type_spec.rb +149 -0
  72. data/spec/lib/mock_adapter.rb +27 -0
  73. data/spec/spec_helper.rb +112 -0
  74. data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
  75. data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
  76. data/spec/unit/adapters/data_objects_adapter_spec.rb +627 -0
  77. data/spec/unit/adapters/postgres_adapter_spec.rb +125 -0
  78. data/spec/unit/associations/many_to_many_spec.rb +14 -0
  79. data/spec/unit/associations/many_to_one_spec.rb +138 -0
  80. data/spec/unit/associations/one_to_many_spec.rb +385 -0
  81. data/spec/unit/associations/one_to_one_spec.rb +7 -0
  82. data/spec/unit/associations/relationship_spec.rb +67 -0
  83. data/spec/unit/associations_spec.rb +205 -0
  84. data/spec/unit/auto_migrations_spec.rb +110 -0
  85. data/spec/unit/collection_spec.rb +174 -0
  86. data/spec/unit/data_mapper_spec.rb +21 -0
  87. data/spec/unit/identity_map_spec.rb +126 -0
  88. data/spec/unit/is_spec.rb +80 -0
  89. data/spec/unit/migrator_spec.rb +33 -0
  90. data/spec/unit/model_spec.rb +339 -0
  91. data/spec/unit/naming_conventions_spec.rb +28 -0
  92. data/spec/unit/property_set_spec.rb +96 -0
  93. data/spec/unit/property_spec.rb +447 -0
  94. data/spec/unit/query_spec.rb +485 -0
  95. data/spec/unit/repository_spec.rb +93 -0
  96. data/spec/unit/resource_spec.rb +557 -0
  97. data/spec/unit/scope_spec.rb +131 -0
  98. data/spec/unit/transaction_spec.rb +493 -0
  99. data/spec/unit/type_map_spec.rb +114 -0
  100. data/spec/unit/type_spec.rb +119 -0
  101. metadata +187 -0
@@ -0,0 +1,144 @@
1
+ -- 0.1.0
2
+ * Initial Public Release
3
+
4
+ -- 0.1.1
5
+ * Removed /lib/data_mapper/extensions
6
+ * Moved ActiveRecordImpersonation into DataMapper::Support module
7
+ * Moved CallbackHelper methods into DataMapper::Base class
8
+ * Moved ValidationHelper into DataMapper::Validations module
9
+ * 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
10
+ * Modified data_mapper.rb to load DataMapper::Support::Enumerable
11
+ * Modified example.rb and performance.rb to require 'lib/data_mapper' instead of modifying $LOADPATH
12
+ * Created SqlAdapter base-class
13
+ * Refactored MysqlAdapter to use SqlAdapter superclass
14
+ * Refactored Sqlite3Adapter to use SqlAdapter superclass
15
+ * Moved /lib/data_mapper/queries to /lib/data_mapper/adapters/sql/queries
16
+ * Moved Connection, Result and Reader classes along with Coersion and Quoting modules to DataMapper::Adapters::Sql module
17
+ * Moved DataMapper::Adapters::Sql::Queries to ::Commands
18
+ * Moved Mappings to SqlAdapter
19
+ * Added monolithic DeleteCommand
20
+ * Added monolithic SaveCommand
21
+ * Added TableExistsCommand
22
+ * Moved save/delete logic out of Session
23
+ * Added create-table functionality to SaveCommand
24
+ * Cleaned up Session; #find no longer supported, use #all or #first
25
+ * Moved object materialization into LoadCommand
26
+ * Migrated Sqlite3Adapter::Commands
27
+ * Added Session#query support back in
28
+ * Removed Connection/Reader/Result classes
29
+ * Set DataMapper::Base#key on load to avoid double-hit against Schema
30
+ * Added DataMapper::Support::Struct for increased Session#query performance
31
+ * Added AdvancedHasManyAssociation (preview status)
32
+ * Added benchmarks comparing ActiveRecord::Base::find_by_sql with Session#query
33
+
34
+ -- 0.2.0
35
+ * AdvancedHasManyAssociation now functional for fetches
36
+ * AdvancedHasManyAssociation renamed to HasNAssociation
37
+ * HasManyAssociation refactored to use HasNAssociation superclass
38
+ * Slight spec tweaks to accomodate the updates
39
+ * HasOneAssociation refactored to use HasNAssociation superclass
40
+ * Added HasAndBelongsToManyAssociation, using HasNAssociation as a basis; Need to add corresponding SQL generation code in AdvancedLoadCommand
41
+ * Added spec for habtm query generation
42
+ * HasNAssociation#foreign_key returns a DataMapper::Adapters::Sql::Mappings::Column instance instead of a raw String now
43
+ * Added table, association, association_table and to_sql methods to HasNAssociation
44
+ * Added associations_spec.rb
45
+ * 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
46
+ * Added HasAndBelongsToManyAssociation#to_sql (all current specs pass now!)
47
+ * Minor tweaks to Callbacks
48
+ * Added CallbacksHelper to declare class-method ::callbacks on DataMapper::Base
49
+ * Implemented before_validate and after_validate hooks in ValidationHelper
50
+ * Minor documentation additions in callbacks.rb
51
+ * Added callbacks_spec
52
+ * Moved class-method declarations for built-in callbacks to the callbacks helper instead of DataMapper::Base
53
+ * Renamed :before/after_validate callback to :before/after_validation to match ActiveRecord
54
+ * 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
55
+ * Documented callbacks.rb
56
+ * Added DataMapper::Associations::Reference class
57
+ * Documented DataMapper::Associations::Reference class
58
+ * Upgraded BelongsToAssociation to new style
59
+ * Added AssociationsSet to handle simple "last-in" for association bindings
60
+ * Fixed extra spec loading
61
+ * Added *Association#columns
62
+ * Some refactoring in AdvancedLoadCommand regarding :include options
63
+ * Added support for class-less Mappings::Table instances, with just a string name
64
+ * HasAndBelongsToManyAssociation#join_table #left_foreign_key and #right_foreign_key reference actual Table or Column objects now
65
+ * Added :shallow_include option for HABTM joins in AdvancedLoadCommand and corresponding spec
66
+ * Added Commands::AdvancedConditions
67
+ * Added ORDER, LIMIT, OFFSET and WHERE support to AdvancedLoadCommand
68
+ * Renamed spec/has_many.rb to spec/has_many_spec.rb
69
+ * Tweaked the loading of has_many relationships; big performance boost; got rid of an extra query
70
+ * Added EmbeddedValue support, and accompanying spec
71
+ * Fleshed out AdvancedConditions a bit; added conditions_spec.rb
72
+ * Added more AdvancedConditions specs
73
+ * Added Loader to handle multi-instanced rows
74
+ * AdvancedLoadCommand replaced LoadCommand; down to 3 failing specs
75
+ * All specs pass
76
+ * Added :intercept_load finder option and accompanying spec
77
+ * Modified :intercept_load block signature to |instance,columns,row|
78
+ * HasAndBelongsToMany works, all specs pass
79
+ * Fixed a couple bugs with keys; Added DataMapper::Base#key= method
80
+ * Made DataMapper::Base#lazy_load! a little more flexible
81
+ * Removed LoadCommand overwrites from MysqlAdapter
82
+ * Default Database#single_threaded mode is true now
83
+ * Removed MysqlAdapter#initialize, which only served to setup the connections, moved to SqlAdapter
84
+ * Added SqlAdapter#create_connection and SqlAdapter#close_connection abstract methods
85
+ * Added MysqlAdapter#create_connection and MysqlAdapter#close_connection concrete methods
86
+ * Made SqlAdapter#connection a concrete method (instead of abstract), with support for single_threaded operation
87
+ * Database#setup now takes a Hash of options instead of a block-initializer
88
+ * Validation chaining should work for all association types
89
+ * Save chaining should work for has_many associations
90
+ * Added benchmarks for in-session performance to performance.rb
91
+ * Removed block conditions; They're slower and don't offer any real advantages
92
+ * Removed DeleteCommand
93
+ * Removed SaveCommand
94
+ * Removed TableExistsCommand
95
+ * Session renamed to Context
96
+ * Most command implementations moved to methods in SqlAdapter
97
+ * Removed UnitOfWork module, instead moving a slightly refactored implementation into Base
98
+
99
+ -- 0.2.1
100
+ * Added :float column support
101
+ * Added association proxies: ie: Zoo.first.exhibits.animals
102
+ * Columns stored in SortedSet
103
+ * Swig files are no longer RDOCed
104
+ * Added :date column support
105
+ * BUG: Fixed UTC issues with datetimes
106
+ * Added #to_yaml method
107
+ * Added #to_xml method
108
+ * Added #to_json method
109
+ * BUG: Fixed HasManyAssociation::Set#inspect
110
+ * BUG: Fixed #reload!
111
+ * BUG: Column copy for STI moved into Table#initialize to better handle STI with multiple mapped databases
112
+ * BUG: before_create callbacks moved in the execution flow since they weren't guaranteed to fire before
113
+ * Threading enhancements: Removed single_threaded_mode, #database block form adjusted for thread-safety
114
+ * BUG: Fixed String#blank? when a multi-line string contained a blank line (thanks zapnap!)
115
+ * Performance enhancements: (thanks wycats!)
116
+
117
+ -- 0.2.2
118
+ * Removed C extension bundles and log files from package
119
+
120
+ -- 0.2.3
121
+ * Added String#t for translation and overrides for default validation messages
122
+ * Give credit where it's due: zapnap, not pimpmaster, submitted the String#blank? patch. My bad. :-(
123
+ * MAJOR: Resolve issue with non-unique-hash values and #dirty?; now frozen original values are stored instead
124
+ * Added Base#update_attributes
125
+ * MAJOR: Queries are now passed to the database drivers in a parameterized fashion
126
+ * Updated PostgreSQL driver and adapter to current
127
+
128
+ -- 0.2.4
129
+ * Bug fixes
130
+ * Added paranoia
131
+
132
+ -- 0.2.5
133
+ * has_one bugfixes
134
+ * Added syntax for setting CHECK-constraints directly in your properties (Postgres)
135
+ * You can now set indexes with :index => true and :index => :unique
136
+ * Support for composite indexes (thanks to Jeffrey Gelens)
137
+ * Add composite scope to validates_uniqueness
138
+ * Added private/protected properties
139
+ * Remove HasOneAssociation, Make HasManyAssociation impersonate has_one relationships
140
+ * Added #get method
141
+ * Persistence module added, inheriting from DataMapper::Base no longer necessary
142
+
143
+ -- 0.3.0
144
+ * HasManyAssociation::Set now has a nil? method, so we can do stuff like cage.animal.nil?
data/FAQ ADDED
@@ -0,0 +1,74 @@
1
+ :include:QUICKLINKS
2
+
3
+ = FAQ
4
+
5
+ === So where's my :id column?
6
+
7
+ DataMapper will NOT create an auto-incrementing <tt>:id</tt> key for you
8
+ automatically, so you'll need to either explicitly create one with
9
+
10
+ property :id, Serial
11
+
12
+ You can choose to use a natural key by doing
13
+
14
+ property :slug, String, :key => true
15
+
16
+ Remember, DataMapper supports multiple keys ("composite keys"), so if your
17
+ model has two or more keys, no big deal
18
+
19
+ property :store_id, Integer, :key => true
20
+ property :invoice_id, Integer, :key => true
21
+
22
+ === How do I make a model paranoid?
23
+
24
+ Create a property and make it a ParanoidDateTime or ParanoidBoolean type.
25
+
26
+ property :deleted_at, ParanoidDateTime
27
+ property :deleted, ParanoidBoolean
28
+
29
+ All of your calls to <tt>##all()</tt>, <tt>##first()</tt> will be scoped
30
+ with <tt>:deleted_at => nil</tt> or <tt>:deleted => false</tt>. Plus,
31
+ you won't see deleted objects in your associations.
32
+
33
+ === Does DataMapper do Single Table Inheritance?
34
+
35
+ This is what the Discriminator data-type is for:
36
+
37
+ class Person
38
+ include DataMapper::Resource
39
+ property :id, Serial
40
+ property :type, Discriminator ## other shared properties here
41
+ end
42
+
43
+ class Salesperson < Person; end
44
+
45
+ You can claim a column to have the type <tt>Discriminator</tt> and DataMapper will
46
+ automatically drop the class name of the inherited classes into that field of
47
+ the data-store.
48
+
49
+ === How do I run my own commands?
50
+
51
+ repository.adapter.query("select * from users where clue > 0")
52
+ repository(:integration).adapter.query("select * from users where clue > 0")
53
+
54
+ This does not return any Users (har har), but rather Struct's that will quack
55
+ like Users. They'll be read-only as well.
56
+
57
+ <tt>repository.adapter.query</tt> shouldn't be used if you aren't expecting a result set
58
+ back. If you want to just execute something against the database, use
59
+ <tt>repository.adapter.execute</tt> instead.
60
+
61
+
62
+ === Can I get an query log of what DataMapper is issuing?
63
+
64
+ Yup, to set this up, do:
65
+
66
+ DataMapper::Logger.new(STDOUT, 0)
67
+
68
+ Incidentally, if you'd like to send a message into the DataMapper logger, do:
69
+
70
+ DataMapper.logger.debug { "something" }
71
+ DataMapper.logger.info { "something" }
72
+ DataMapper.logger.warn { "something" }
73
+ DataMapper.logger.error { "something" }
74
+ DataMapper.logger.fatal { "something" }
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2007 Sam Smoot
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,12 @@
1
+ = Quick Links
2
+
3
+ * Setup and Configuration - DataMapper
4
+ * Finders and CRUD -
5
+ * Properties - DataMapper::Property
6
+ * FAQ[link:/files/FAQ.html]
7
+ * Contact Us
8
+ * Website - http://www.datamapper.org
9
+ * Bug Reports - http://wm.lighthouseapp.com/projects/4819-datamapper/overview
10
+ * IRC Channel - <tt>##datamapper</tt> on irc.freenode.net
11
+ * Mailing List - http://groups.google.com/group/datamapper/
12
+
data/README ADDED
@@ -0,0 +1,143 @@
1
+
2
+ :include:QUICKLINKS
3
+
4
+ = Why DataMapper?
5
+
6
+ == Open Development
7
+
8
+ DataMapper sports a very accessible code-base and a welcoming community.
9
+ Outside contributions and feedback are welcome and encouraged, especially
10
+ constructive criticism. Make your voice heard! Submit a
11
+ ticket[http://wm.lighthouseapp.com/projects/4819-datamapper/overview] or
12
+ patch[http://wm.lighthouseapp.com/projects/4819-datamapper/overview], speak up
13
+ on our mailing-list[http://groups.google.com/group/datamapper/], chat with us
14
+ on irc[irc://irc.freenode.net/#datamapper], write a spec, get it reviewed, ask
15
+ for commit rights. It's as easy as that to become a contributor.
16
+
17
+ == Identity Map
18
+
19
+ One row in the data-store should equal one object reference. Pretty simple idea.
20
+ Pretty profound impact. If you run the following code in ActiveRecord you'll
21
+ see all <tt>false</tt> results. Do the same in DataMapper and it's
22
+ <tt>true</tt> all the way down.
23
+
24
+ @parent = Tree.find(:first, :conditions => ['name = ?', 'bob'])
25
+
26
+ @parent.children.each do |child|
27
+ puts @parent.object_id == child.parent.object_id
28
+ end
29
+
30
+ This makes DataMapper faster and allocate less resources to get things done.
31
+
32
+ == Dirty Tracking
33
+
34
+ When you save a model back to your data-store, DataMapper will only write
35
+ the fields that actually changed. So it plays well with others. You can
36
+ use it in an Integration data-store without worrying that your application will
37
+ be a bad actor causing trouble for all of your other processes.
38
+
39
+ You can also configure which strategy you'd like to use to track dirtiness.
40
+
41
+ == Eager Loading
42
+
43
+ Ready for something amazing? The following example executes only two queries.
44
+
45
+ zoos = Zoo.all
46
+ first = zoos.first
47
+ first.exhibits # Loads the exhibits for all the Zoo objects in the zoos variable.
48
+
49
+ Pretty impressive huh? The idea is that you aren't going to load a set of
50
+ objects and use only an association in just one of them. This should hold up
51
+ pretty well against a 99% rule. When you don't want it to work like this, just
52
+ load the item you want in it's own set. So the DataMapper thinks ahead. We
53
+ like to call it "performant by default". This feature single-handedly wipes
54
+ out the "N+1 Query Problem". No need to specify an <tt>include</tt> option in
55
+ your finders.
56
+
57
+ == Laziness Can Be A Virtue
58
+
59
+ Text fields are expensive in data-stores. They're generally stored in a
60
+ different place than the rest of your data. So instead of a fast sequential
61
+ read from your hard-drive, your data-store server has to hop around all over the
62
+ place to get what it needs. Since ActiveRecord returns everything by default,
63
+ adding a text field to a table slows everything down drastically, across the
64
+ board.
65
+
66
+ Not so with the DataMapper. Text fields are treated like in-row associations
67
+ by default, meaning they only load when you need them. If you want more
68
+ control you can enable or disable this feature for any field (not just
69
+ text-fields) by passing a @lazy@ option to your field mapping with a value of
70
+ <tt>true</tt> or <tt>false</tt>.
71
+
72
+ class Animal
73
+ include DataMapper::Resource
74
+ property :name, String
75
+ property :notes, Text, :lazy => false
76
+ end
77
+
78
+ Plus, lazy-loading of text fields happens automatically and intelligently when
79
+ working with associations. The following only issues 2 queries to load up all
80
+ of the notes fields on each animal:
81
+
82
+ animals = Animal.all
83
+ animals.each do |pet|
84
+ pet.notes
85
+ end
86
+
87
+ == Plays Well With Others
88
+
89
+ In ActiveRecord, all your fields are mapped, whether you want them or not.
90
+ This slows things down. In the DataMapper you define your mappings in your
91
+ model. So instead of an _ALTER TABLE ADD field_ in your data-store, you simply
92
+ add a <tt>property :name, :string</tt> to your model. DRY. No schema.rb. No
93
+ migration files to conflict or die without reverting changes. Your model
94
+ drives the data-store, not the other way around.
95
+
96
+ Unless of course you want to map to a legacy data-store. Raise your hand if you
97
+ like seeing a method called <tt>col2Name</tt> on your model just because
98
+ that's what it's called in an old data-store you can't afford to change right
99
+ now? In DataMapper you control the mappings:
100
+
101
+ class Fruit
102
+ include DataMapper::Resource
103
+ storage_names[:repo] = 'frt'
104
+ property :name, String, :field => 'col2Name'
105
+ end
106
+
107
+ == All Ruby, All The Time
108
+
109
+ It's great that ActiveRecord allows you to write SQL when you need to, but
110
+ should we have to so often?
111
+
112
+ DataMapper supports issuing your own query, but it also provides more helpers
113
+ and a unique hash-based condition syntax to cover more of the use-cases where
114
+ issuing your own SQL would have been the only way to go. For example, any
115
+ finder option that's non-standard is considered a condition. So you can write
116
+ <tt>Zoo.all(:name => 'Dallas')</tt> and DataMapper will look for zoos with the
117
+ name of 'Dallas'.
118
+
119
+ It's just a little thing, but it's so much nicer than writing
120
+ <tt>Zoo.find(:all, :conditions => ['name = ?', 'Dallas'])</tt>. What if you
121
+ need other comparisons though? Try these:
122
+
123
+ Zoo.first(:name => 'Galveston')
124
+
125
+ # 'gt' means greater-than. We also do 'lt'.
126
+ Person.all(:age.gt => 30)
127
+
128
+ # 'gte' means greather-than-or-equal-to. We also do 'lte'.
129
+ Person.all(:age.gte => 30)
130
+
131
+ Person.all(:name.not => 'bob')
132
+
133
+ # If the value of a pair is an Array, we do an IN-clause for you.
134
+ Person.all(:name.like => 'S%', :id => [1, 2, 3, 4, 5])
135
+
136
+ # An alias for Zoo.find(11)
137
+ Zoo[11]
138
+
139
+ # Does a NOT IN () clause for you.
140
+ Person.all(:name.not => ['bob','rick','steve'])
141
+
142
+ See? Fewer SQL fragments dirtying your Ruby code. And that's just a few of the
143
+ nice syntax tweaks DataMapper delivers out of the box...
@@ -0,0 +1,213 @@
1
+ # This file begins the loading sequence.
2
+ #
3
+ # Quick Overview:
4
+ # * Requires fastthread, support libs, and base.
5
+ # * Sets the application root and environment for compatibility with frameworks
6
+ # such as Rails or Merb.
7
+ # * Checks for the database.yml and loads it if it exists.
8
+ # * Sets up the database using the config from the Yaml file or from the
9
+ # environment.
10
+ #
11
+
12
+ require 'date'
13
+ require 'pathname'
14
+ require 'set'
15
+ require 'time'
16
+ require 'yaml'
17
+
18
+ require 'rubygems'
19
+
20
+ gem 'addressable', '>=1.0.4'
21
+ require 'addressable/uri'
22
+
23
+ gem 'extlib', '=0.9.2'
24
+ require 'extlib'
25
+
26
+ begin
27
+ require 'fastthread'
28
+ rescue LoadError
29
+ # fastthread not installed
30
+ end
31
+
32
+ dir = Pathname(__FILE__).dirname.expand_path / 'dm-core'
33
+
34
+ require dir / 'support'
35
+ require dir / 'resource'
36
+ require dir / 'model'
37
+
38
+ require dir / 'type'
39
+ require dir / 'type_map'
40
+ require dir / 'types'
41
+ require dir / 'hook'
42
+ require dir / 'associations'
43
+ require dir / 'auto_migrations'
44
+ require dir / 'identity_map'
45
+ require dir / 'logger'
46
+ require dir / 'migrator'
47
+ require dir / 'naming_conventions'
48
+ require dir / 'property_set'
49
+ require dir / 'query'
50
+ require dir / 'transaction'
51
+ require dir / 'repository'
52
+ require dir / 'scope'
53
+ require dir / 'property'
54
+ require dir / 'adapters'
55
+ require dir / 'collection'
56
+ require dir / 'is'
57
+
58
+ # == Setup and Configuration
59
+ # DataMapper uses URIs or a connection hash to connect to your data-store.
60
+ # URI connections takes the form of:
61
+ # DataMapper.setup(:default, 'protocol://username:password@localhost:port/path/to/repo')
62
+ #
63
+ # Breaking this down, the first argument is the name you wish to give this
64
+ # connection. If you do not specify one, it will be assigned :default. If you
65
+ # would like to connect to more than one data-store, simply issue this command
66
+ # again, but with a different name specified.
67
+ #
68
+ # In order to issue ORM commands without specifying the repository context, you
69
+ # must define the :default database. Otherwise, you'll need to wrap your ORM
70
+ # calls in <tt>repository(:name) { }</tt>.
71
+ #
72
+ # Second, the URI breaks down into the access protocol, the username, the
73
+ # server, the password, and whatever path information is needed to properly
74
+ # address the data-store on the server.
75
+ #
76
+ # Here's some examples
77
+ # DataMapper.setup(:default, "sqlite3://path/to/your/project/db/development.db")
78
+ # DataMapper.setup(:default, "mysql://localhost/dm_core_test")
79
+ # # no auth-info
80
+ # DataMapper.setup(:default, "postgres://root:supahsekret@127.0.0.1/dm_core_test")
81
+ # # with auth-info
82
+ #
83
+ #
84
+ # Alternatively, you can supply a hash as the second parameter, which would
85
+ # take the form:
86
+ #
87
+ # DataMapper.setup(:default, {
88
+ # :adapter => 'adapter_name_here',
89
+ # :database => "path/to/repo",
90
+ # :username => 'username',
91
+ # :password => 'password',
92
+ # :host => 'hostname'
93
+ # })
94
+ #
95
+ # === Logging
96
+ # To turn on error logging to STDOUT, issue:
97
+ #
98
+ # DataMapper::Logger.new(STDOUT, 0)
99
+ #
100
+ # You can pass a file location ("/path/to/log/file.log") in place of STDOUT.
101
+ # see DataMapper::Logger for more information.
102
+ #
103
+ module DataMapper
104
+ extend Assertions
105
+
106
+ def self.root
107
+ @root ||= Pathname(__FILE__).dirname.parent.expand_path
108
+ end
109
+
110
+ ##
111
+ # Setups up a connection to a data-store
112
+ #
113
+ # @param Symbol name a name for the context, defaults to :default
114
+ # @param [Hash{Symbol => String}, Addressable::URI, String] uri_or_options
115
+ # connection information
116
+ #
117
+ # @return Repository the resulting setup repository
118
+ #
119
+ # @raise ArgumentError "+name+ must be a Symbol, but was..." indicates that
120
+ # an invalid argument was passed for name[Symbol]
121
+ # @raise [ArgumentError] "+uri_or_options+ must be a Hash, URI or String,
122
+ # but was..." indicates that connection information could not be gleaned
123
+ # from the given uri_or_options<Hash, Addressable::URI, String>
124
+ #
125
+ # -
126
+ # @api public
127
+ def self.setup(name, uri_or_options)
128
+ assert_kind_of 'name', name, Symbol
129
+ assert_kind_of 'uri_or_options', uri_or_options, Addressable::URI, Hash, String
130
+
131
+ case uri_or_options
132
+ when Hash
133
+ adapter_name = uri_or_options[:adapter].to_s
134
+ when String, Addressable::URI
135
+ uri_or_options = Addressable::URI.parse(uri_or_options) if uri_or_options.kind_of?(String)
136
+ adapter_name = uri_or_options.scheme
137
+ end
138
+
139
+ class_name = Extlib::Inflection.classify(adapter_name) + 'Adapter'
140
+
141
+ unless Adapters::const_defined?(class_name)
142
+ lib_name = "#{Extlib::Inflection.underscore(adapter_name)}_adapter"
143
+ begin
144
+ require root / 'lib' / 'dm-core' / 'adapters' / lib_name
145
+ rescue LoadError
146
+ require lib_name
147
+ end
148
+ end
149
+
150
+ Repository.adapters[name] = Adapters::const_get(class_name).new(name, uri_or_options)
151
+ end
152
+
153
+ ##
154
+ # Block Syntax
155
+ # Pushes the named repository onto the context-stack,
156
+ # yields a new session, and pops the context-stack.
157
+ #
158
+ # Non-Block Syntax
159
+ # Returns the current session, or if there is none,
160
+ # a new Session.
161
+ #
162
+ # @param [Symbol] args the name of a repository to act within or return, :default is default
163
+ # @yield [Proc] (optional) block to execute within the context of the named repository
164
+ # @demo spec/integration/repository_spec.rb
165
+ def self.repository(*args, &block) # :yields: current_context
166
+ if args.size > 1
167
+ raise ArgumentError, "Can only pass in one optional argument, but passed in #{args.size} arguments", caller
168
+ end
169
+
170
+ if args.any? && !args.first.kind_of?(Symbol)
171
+ raise ArgumentError, "First optional argument must be a Symbol, but was #{args.first.inspect}", caller
172
+ end
173
+
174
+ name = args.first
175
+
176
+ current_repository = if name
177
+ Repository.context.detect { |r| r.name == name } || Repository.new(name)
178
+ else
179
+ Repository.context.last || Repository.new(Repository.default_name)
180
+ end
181
+
182
+ return current_repository unless block_given?
183
+
184
+ current_repository.scope(&block)
185
+ end
186
+
187
+ # A logger should always be present. Lets be consistent with DO
188
+ Logger.new(nil, :off)
189
+
190
+ ##
191
+ # destructively migrates the repository upwards to match model definitions
192
+ #
193
+ # @param [Symbol] name repository to act on, :default is the default
194
+ def self.migrate!(name = Repository.default_name)
195
+ repository(name).migrate!
196
+ end
197
+
198
+ ##
199
+ # drops and recreates the repository upwards to match model definitions
200
+ #
201
+ # @param [Symbol] name repository to act on, :default is the default
202
+ def self.auto_migrate!(name = Repository.default_name)
203
+ repository(name).auto_migrate!
204
+ end
205
+
206
+ def self.auto_upgrade!(name = Repository.default_name)
207
+ repository(name).auto_upgrade!
208
+ end
209
+
210
+ def self.prepare(*args, &blk)
211
+ yield repository(*args)
212
+ end
213
+ end