sam-dm-core 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. data/.autotest +26 -0
  2. data/CONTRIBUTING +51 -0
  3. data/FAQ +92 -0
  4. data/History.txt +145 -0
  5. data/MIT-LICENSE +22 -0
  6. data/Manifest.txt +125 -0
  7. data/QUICKLINKS +12 -0
  8. data/README.txt +143 -0
  9. data/Rakefile +30 -0
  10. data/SPECS +63 -0
  11. data/TODO +1 -0
  12. data/lib/dm-core.rb +224 -0
  13. data/lib/dm-core/adapters.rb +4 -0
  14. data/lib/dm-core/adapters/abstract_adapter.rb +202 -0
  15. data/lib/dm-core/adapters/data_objects_adapter.rb +707 -0
  16. data/lib/dm-core/adapters/mysql_adapter.rb +136 -0
  17. data/lib/dm-core/adapters/postgres_adapter.rb +188 -0
  18. data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
  19. data/lib/dm-core/associations.rb +199 -0
  20. data/lib/dm-core/associations/many_to_many.rb +147 -0
  21. data/lib/dm-core/associations/many_to_one.rb +107 -0
  22. data/lib/dm-core/associations/one_to_many.rb +309 -0
  23. data/lib/dm-core/associations/one_to_one.rb +61 -0
  24. data/lib/dm-core/associations/relationship.rb +218 -0
  25. data/lib/dm-core/associations/relationship_chain.rb +81 -0
  26. data/lib/dm-core/auto_migrations.rb +113 -0
  27. data/lib/dm-core/collection.rb +638 -0
  28. data/lib/dm-core/dependency_queue.rb +31 -0
  29. data/lib/dm-core/hook.rb +11 -0
  30. data/lib/dm-core/identity_map.rb +45 -0
  31. data/lib/dm-core/is.rb +16 -0
  32. data/lib/dm-core/logger.rb +232 -0
  33. data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
  34. data/lib/dm-core/migrator.rb +29 -0
  35. data/lib/dm-core/model.rb +471 -0
  36. data/lib/dm-core/naming_conventions.rb +84 -0
  37. data/lib/dm-core/property.rb +673 -0
  38. data/lib/dm-core/property_set.rb +162 -0
  39. data/lib/dm-core/query.rb +625 -0
  40. data/lib/dm-core/repository.rb +159 -0
  41. data/lib/dm-core/resource.rb +637 -0
  42. data/lib/dm-core/scope.rb +58 -0
  43. data/lib/dm-core/support.rb +7 -0
  44. data/lib/dm-core/support/array.rb +13 -0
  45. data/lib/dm-core/support/assertions.rb +8 -0
  46. data/lib/dm-core/support/errors.rb +23 -0
  47. data/lib/dm-core/support/kernel.rb +7 -0
  48. data/lib/dm-core/support/symbol.rb +41 -0
  49. data/lib/dm-core/transaction.rb +267 -0
  50. data/lib/dm-core/type.rb +160 -0
  51. data/lib/dm-core/type_map.rb +80 -0
  52. data/lib/dm-core/types.rb +19 -0
  53. data/lib/dm-core/types/boolean.rb +7 -0
  54. data/lib/dm-core/types/discriminator.rb +34 -0
  55. data/lib/dm-core/types/object.rb +24 -0
  56. data/lib/dm-core/types/paranoid_boolean.rb +34 -0
  57. data/lib/dm-core/types/paranoid_datetime.rb +33 -0
  58. data/lib/dm-core/types/serial.rb +9 -0
  59. data/lib/dm-core/types/text.rb +10 -0
  60. data/lib/dm-core/version.rb +3 -0
  61. data/script/all +5 -0
  62. data/script/performance.rb +203 -0
  63. data/script/profile.rb +87 -0
  64. data/spec/integration/association_spec.rb +1371 -0
  65. data/spec/integration/association_through_spec.rb +203 -0
  66. data/spec/integration/associations/many_to_many_spec.rb +449 -0
  67. data/spec/integration/associations/many_to_one_spec.rb +163 -0
  68. data/spec/integration/associations/one_to_many_spec.rb +151 -0
  69. data/spec/integration/auto_migrations_spec.rb +398 -0
  70. data/spec/integration/collection_spec.rb +1069 -0
  71. data/spec/integration/data_objects_adapter_spec.rb +32 -0
  72. data/spec/integration/dependency_queue_spec.rb +58 -0
  73. data/spec/integration/model_spec.rb +127 -0
  74. data/spec/integration/mysql_adapter_spec.rb +85 -0
  75. data/spec/integration/postgres_adapter_spec.rb +731 -0
  76. data/spec/integration/property_spec.rb +233 -0
  77. data/spec/integration/query_spec.rb +506 -0
  78. data/spec/integration/repository_spec.rb +57 -0
  79. data/spec/integration/resource_spec.rb +475 -0
  80. data/spec/integration/sqlite3_adapter_spec.rb +352 -0
  81. data/spec/integration/sti_spec.rb +208 -0
  82. data/spec/integration/strategic_eager_loading_spec.rb +138 -0
  83. data/spec/integration/transaction_spec.rb +75 -0
  84. data/spec/integration/type_spec.rb +271 -0
  85. data/spec/lib/logging_helper.rb +18 -0
  86. data/spec/lib/mock_adapter.rb +27 -0
  87. data/spec/lib/model_loader.rb +91 -0
  88. data/spec/lib/publicize_methods.rb +28 -0
  89. data/spec/models/vehicles.rb +34 -0
  90. data/spec/models/zoo.rb +47 -0
  91. data/spec/spec.opts +3 -0
  92. data/spec/spec_helper.rb +86 -0
  93. data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
  94. data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
  95. data/spec/unit/adapters/data_objects_adapter_spec.rb +628 -0
  96. data/spec/unit/adapters/postgres_adapter_spec.rb +133 -0
  97. data/spec/unit/associations/many_to_many_spec.rb +17 -0
  98. data/spec/unit/associations/many_to_one_spec.rb +152 -0
  99. data/spec/unit/associations/one_to_many_spec.rb +393 -0
  100. data/spec/unit/associations/one_to_one_spec.rb +7 -0
  101. data/spec/unit/associations/relationship_spec.rb +71 -0
  102. data/spec/unit/associations_spec.rb +242 -0
  103. data/spec/unit/auto_migrations_spec.rb +111 -0
  104. data/spec/unit/collection_spec.rb +182 -0
  105. data/spec/unit/data_mapper_spec.rb +35 -0
  106. data/spec/unit/identity_map_spec.rb +126 -0
  107. data/spec/unit/is_spec.rb +80 -0
  108. data/spec/unit/migrator_spec.rb +33 -0
  109. data/spec/unit/model_spec.rb +339 -0
  110. data/spec/unit/naming_conventions_spec.rb +36 -0
  111. data/spec/unit/property_set_spec.rb +83 -0
  112. data/spec/unit/property_spec.rb +753 -0
  113. data/spec/unit/query_spec.rb +530 -0
  114. data/spec/unit/repository_spec.rb +93 -0
  115. data/spec/unit/resource_spec.rb +626 -0
  116. data/spec/unit/scope_spec.rb +142 -0
  117. data/spec/unit/transaction_spec.rb +493 -0
  118. data/spec/unit/type_map_spec.rb +114 -0
  119. data/spec/unit/type_spec.rb +119 -0
  120. data/tasks/ci.rb +68 -0
  121. data/tasks/dm.rb +63 -0
  122. data/tasks/doc.rb +20 -0
  123. data/tasks/gemspec.rb +23 -0
  124. data/tasks/hoe.rb +46 -0
  125. data/tasks/install.rb +20 -0
  126. metadata +216 -0
@@ -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
+
@@ -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,30 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+ require 'rubygems'
4
+ require 'rake'
5
+ require 'rake/rdoctask'
6
+ require 'spec/rake/spectask'
7
+
8
+ require 'lib/dm-core/version'
9
+
10
+ ROOT = Pathname(__FILE__).dirname.expand_path
11
+
12
+ AUTHOR = "Sam Smoot"
13
+ EMAIL = "ssmoot@gmail.com"
14
+ GEM_NAME = "dm-core"
15
+ GEM_VERSION = DataMapper::VERSION
16
+ GEM_DEPENDENCIES = ["data_objects", ">=0.9.5"], ["extlib", ">=0.9.5"],
17
+ ["rspec", ">=1.1.3"], ["addressable", ">=1.0.4"]
18
+
19
+
20
+ PROJECT_NAME = "datamapper"
21
+ PROJECT_DESCRIPTION = "Faster, Better, Simpler."
22
+ PROJECT_SUMMARY = "An Object/Relational Mapper for Ruby"
23
+ PROJECT_URL = "http://datamapper.org"
24
+
25
+ require ROOT + 'tasks/hoe'
26
+ require ROOT + 'tasks/gemspec'
27
+ require ROOT + 'tasks/install'
28
+ require ROOT + 'tasks/dm'
29
+ require ROOT + 'tasks/doc'
30
+ require ROOT + 'tasks/ci'
data/SPECS ADDED
@@ -0,0 +1,63 @@
1
+ Reading Specs
2
+ =============
3
+
4
+ Blah blah blah...
5
+
6
+ Writing Specs
7
+ =============
8
+
9
+ Here are some general dos and don'ts
10
+
11
+ = DO:
12
+
13
+ * Write more specs for error conditions than clean conditions.
14
+ * Write specs with readability in mind. Somebody knew to DataMapper should be
15
+ able to read specs to learn how something works.
16
+ * Use existing models that are part of a metaphor.
17
+ * Nest describe blocks (2 or 3 levels deep is probably fine).
18
+ * Limit a describe block to 10 - 15 examples.
19
+ * Group specs by method being tested. (See the 'Ordering Specs' section)
20
+ * Use custom matchers.
21
+
22
+ = DON'T:
23
+
24
+ * Spec more than one unit of functionality in an example. An example should be
25
+ as short as possible (while still remaining readable).
26
+ * Spec implementation. Refactoring code should not break specs.
27
+ * Declare models in the spec file.
28
+
29
+ And a final do: Do go against the guidelines if your best judgement tells you
30
+ to. These are just guidelines and are obviously not fast rules.
31
+
32
+ Models
33
+ ======
34
+
35
+ Models are declared in separate files as opposed to individual spec files for
36
+ two reasons. The first is to improve readability. By creating as few models
37
+ as possible and sharing these models throughout the specs, a reader can
38
+ become familiar with the models being used quicker. Models also follow a
39
+ few simple metaphors, such as a zoo, a blog implementation, etc... Following
40
+ metaphors makes it easier for a reader to guess what is going on with respect
41
+ to the models.
42
+
43
+ The second reason is to allow the spec environment to be as pristine as
44
+ possible going into an example. Models being loaded from the model directory
45
+ are tracked and reloaded before each example. Any changes that might be made
46
+ to the model are reset at the end.
47
+
48
+ Mocks and Stubs
49
+ ===============
50
+
51
+ Obviously, mocks and stubs are a powerful feature when it comes to BDD;
52
+ however, remember that you are writing specs for behavior and NOT
53
+ implementation.
54
+
55
+ Ordering Specs
56
+ ==============
57
+
58
+ Specs aren't much use if nobody can find where anything is, so keeping specs
59
+ well organized is critical. Currently, we are trying out the following
60
+ structure:
61
+
62
+ * List guidelines here...
63
+
data/TODO ADDED
@@ -0,0 +1 @@
1
+ See: http://github.com/sam/dm-core/wikis
@@ -0,0 +1,224 @@
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.5'
24
+ require 'extlib'
25
+ require "extlib/inflection"
26
+
27
+ begin
28
+ require 'fastthread'
29
+ rescue LoadError
30
+ # fastthread not installed
31
+ end
32
+
33
+ dir = Pathname(__FILE__).dirname.expand_path / 'dm-core'
34
+
35
+ require dir / 'support'
36
+ require dir / 'resource'
37
+ require dir / 'model'
38
+
39
+ require dir / 'dependency_queue'
40
+ require dir / 'type'
41
+ require dir / 'type_map'
42
+ require dir / 'types'
43
+ require dir / 'hook'
44
+ require dir / 'associations'
45
+ require dir / 'auto_migrations'
46
+ require dir / 'identity_map'
47
+ require dir / 'logger'
48
+ require dir / 'migrator'
49
+ require dir / 'naming_conventions'
50
+ require dir / 'property_set'
51
+ require dir / 'query'
52
+ require dir / 'transaction'
53
+ require dir / 'repository'
54
+ require dir / 'scope'
55
+ require dir / 'property'
56
+ require dir / 'adapters'
57
+ require dir / 'collection'
58
+ require dir / 'is'
59
+
60
+ # == Setup and Configuration
61
+ # DataMapper uses URIs or a connection hash to connect to your data-store.
62
+ # URI connections takes the form of:
63
+ # DataMapper.setup(:default, 'protocol://username:password@localhost:port/path/to/repo')
64
+ #
65
+ # Breaking this down, the first argument is the name you wish to give this
66
+ # connection. If you do not specify one, it will be assigned :default. If you
67
+ # would like to connect to more than one data-store, simply issue this command
68
+ # again, but with a different name specified.
69
+ #
70
+ # In order to issue ORM commands without specifying the repository context, you
71
+ # must define the :default database. Otherwise, you'll need to wrap your ORM
72
+ # calls in <tt>repository(:name) { }</tt>.
73
+ #
74
+ # Second, the URI breaks down into the access protocol, the username, the
75
+ # server, the password, and whatever path information is needed to properly
76
+ # address the data-store on the server.
77
+ #
78
+ # Here's some examples
79
+ # DataMapper.setup(:default, "sqlite3://path/to/your/project/db/development.db")
80
+ # DataMapper.setup(:default, "mysql://localhost/dm_core_test")
81
+ # # no auth-info
82
+ # DataMapper.setup(:default, "postgres://root:supahsekret@127.0.0.1/dm_core_test")
83
+ # # with auth-info
84
+ #
85
+ #
86
+ # Alternatively, you can supply a hash as the second parameter, which would
87
+ # take the form:
88
+ #
89
+ # DataMapper.setup(:default, {
90
+ # :adapter => 'adapter_name_here',
91
+ # :database => "path/to/repo",
92
+ # :username => 'username',
93
+ # :password => 'password',
94
+ # :host => 'hostname'
95
+ # })
96
+ #
97
+ # === Logging
98
+ # To turn on error logging to STDOUT, issue:
99
+ #
100
+ # DataMapper::Logger.new(STDOUT, 0)
101
+ #
102
+ # You can pass a file location ("/path/to/log/file.log") in place of STDOUT.
103
+ # see DataMapper::Logger for more information.
104
+ #
105
+ module DataMapper
106
+ extend Assertions
107
+
108
+ def self.root
109
+ @root ||= Pathname(__FILE__).dirname.parent.expand_path
110
+ end
111
+
112
+ ##
113
+ # Setups up a connection to a data-store
114
+ #
115
+ # @param Symbol name a name for the context, defaults to :default
116
+ # @param [Hash{Symbol => String}, Addressable::URI, String] uri_or_options
117
+ # connection information
118
+ #
119
+ # @return Repository the resulting setup repository
120
+ #
121
+ # @raise ArgumentError "+name+ must be a Symbol, but was..." indicates that
122
+ # an invalid argument was passed for name[Symbol]
123
+ # @raise [ArgumentError] "+uri_or_options+ must be a Hash, URI or String,
124
+ # but was..." indicates that connection information could not be gleaned
125
+ # from the given uri_or_options<Hash, Addressable::URI, String>
126
+ #
127
+ # -
128
+ # @api public
129
+ def self.setup(name, uri_or_options)
130
+ assert_kind_of 'name', name, Symbol
131
+ assert_kind_of 'uri_or_options', uri_or_options, Addressable::URI, Hash, String
132
+
133
+ case uri_or_options
134
+ when Hash
135
+ adapter_name = uri_or_options[:adapter].to_s
136
+ when String, Addressable::URI
137
+ uri_or_options = Addressable::URI.parse(uri_or_options) if uri_or_options.kind_of?(String)
138
+ adapter_name = uri_or_options.scheme
139
+ end
140
+
141
+ class_name = Extlib::Inflection.classify(adapter_name) + 'Adapter'
142
+
143
+ unless Adapters::const_defined?(class_name)
144
+ lib_name = "#{Extlib::Inflection.underscore(adapter_name)}_adapter"
145
+ begin
146
+ require root / 'lib' / 'dm-core' / 'adapters' / lib_name
147
+ rescue LoadError => e
148
+ begin
149
+ require lib_name
150
+ rescue Exception
151
+ # library not found, raise the original error
152
+ raise e
153
+ end
154
+ end
155
+ end
156
+
157
+ Repository.adapters[name] = Adapters::const_get(class_name).new(name, uri_or_options)
158
+ end
159
+
160
+ ##
161
+ # Block Syntax
162
+ # Pushes the named repository onto the context-stack,
163
+ # yields a new session, and pops the context-stack.
164
+ #
165
+ # Non-Block Syntax
166
+ # Returns the current session, or if there is none,
167
+ # a new Session.
168
+ #
169
+ # @param [Symbol] args the name of a repository to act within or return, :default is default
170
+ # @yield [Proc] (optional) block to execute within the context of the named repository
171
+ # @demo spec/integration/repository_spec.rb
172
+ def self.repository(*args, &block) # :yields: current_context
173
+ if args.size > 1
174
+ raise ArgumentError, "Can only pass in one optional argument, but passed in #{args.size} arguments", caller
175
+ end
176
+
177
+ if args.any? && !args.first.kind_of?(Symbol)
178
+ raise ArgumentError, "First optional argument must be a Symbol, but was #{args.first.inspect}", caller
179
+ end
180
+
181
+ name = args.first
182
+
183
+ current_repository = if name
184
+ Repository.context.detect { |r| r.name == name } || Repository.new(name)
185
+ else
186
+ Repository.context.last || Repository.new(Repository.default_name)
187
+ end
188
+
189
+ return current_repository unless block_given?
190
+
191
+ current_repository.scope(&block)
192
+ end
193
+
194
+ # A logger should always be present. Lets be consistent with DO
195
+ Logger.new(nil, :off)
196
+
197
+ ##
198
+ # destructively migrates the repository upwards to match model definitions
199
+ #
200
+ # @param [Symbol] name repository to act on, :default is the default
201
+ def self.migrate!(name = Repository.default_name)
202
+ repository(name).migrate!
203
+ end
204
+
205
+ ##
206
+ # drops and recreates the repository upwards to match model definitions
207
+ #
208
+ # @param [Symbol] name repository to act on, :default is the default
209
+ def self.auto_migrate!(repository_name = nil)
210
+ AutoMigrator.auto_migrate(repository_name)
211
+ end
212
+
213
+ def self.auto_upgrade!(repository_name = nil)
214
+ AutoMigrator.auto_upgrade(repository_name)
215
+ end
216
+
217
+ def self.prepare(*args, &blk)
218
+ yield repository(*args)
219
+ end
220
+
221
+ def self.dependency_queue
222
+ @dependency_queue ||= DependencyQueue.new
223
+ end
224
+ end