dm-core 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
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