datamapper 0.2.5 → 0.3.0

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 (121) hide show
  1. data/CHANGELOG +5 -1
  2. data/FAQ +96 -0
  3. data/QUICKLINKS +12 -0
  4. data/README +57 -155
  5. data/environment.rb +61 -43
  6. data/example.rb +30 -12
  7. data/lib/data_mapper.rb +6 -1
  8. data/lib/data_mapper/adapters/abstract_adapter.rb +0 -57
  9. data/lib/data_mapper/adapters/data_object_adapter.rb +203 -97
  10. data/lib/data_mapper/adapters/mysql_adapter.rb +4 -0
  11. data/lib/data_mapper/adapters/postgresql_adapter.rb +7 -1
  12. data/lib/data_mapper/adapters/sql/coersion.rb +3 -2
  13. data/lib/data_mapper/adapters/sql/commands/load_command.rb +29 -10
  14. data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +4 -0
  15. data/lib/data_mapper/adapters/sql/mappings/column.rb +13 -9
  16. data/lib/data_mapper/adapters/sql/mappings/conditions.rb +172 -0
  17. data/lib/data_mapper/adapters/sql/mappings/table.rb +43 -17
  18. data/lib/data_mapper/adapters/sqlite3_adapter.rb +9 -2
  19. data/lib/data_mapper/associations.rb +75 -3
  20. data/lib/data_mapper/associations/belongs_to_association.rb +70 -36
  21. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +195 -86
  22. data/lib/data_mapper/associations/has_many_association.rb +168 -61
  23. data/lib/data_mapper/associations/has_n_association.rb +23 -3
  24. data/lib/data_mapper/attributes.rb +73 -0
  25. data/lib/data_mapper/auto_migrations.rb +2 -6
  26. data/lib/data_mapper/base.rb +5 -9
  27. data/lib/data_mapper/database.rb +4 -3
  28. data/lib/data_mapper/embedded_value.rb +66 -30
  29. data/lib/data_mapper/identity_map.rb +1 -3
  30. data/lib/data_mapper/is/tree.rb +121 -0
  31. data/lib/data_mapper/migration.rb +155 -0
  32. data/lib/data_mapper/persistence.rb +532 -218
  33. data/lib/data_mapper/property.rb +306 -0
  34. data/lib/data_mapper/query.rb +164 -0
  35. data/lib/data_mapper/support/blank.rb +2 -2
  36. data/lib/data_mapper/support/connection_pool.rb +5 -6
  37. data/lib/data_mapper/support/enumerable.rb +3 -3
  38. data/lib/data_mapper/support/errors.rb +10 -1
  39. data/lib/data_mapper/support/inflector.rb +174 -238
  40. data/lib/data_mapper/support/object.rb +54 -0
  41. data/lib/data_mapper/support/serialization.rb +19 -1
  42. data/lib/data_mapper/support/string.rb +7 -16
  43. data/lib/data_mapper/support/symbol.rb +3 -15
  44. data/lib/data_mapper/support/typed_set.rb +68 -0
  45. data/lib/data_mapper/types/base.rb +44 -0
  46. data/lib/data_mapper/types/string.rb +34 -0
  47. data/lib/data_mapper/validations/number_validator.rb +40 -0
  48. data/lib/data_mapper/validations/string_validator.rb +20 -0
  49. data/lib/data_mapper/validations/validator.rb +13 -0
  50. data/performance.rb +26 -1
  51. data/profile_data_mapper.rb +1 -1
  52. data/rakefile.rb +42 -2
  53. data/spec/acts_as_tree_spec.rb +11 -3
  54. data/spec/adapters/data_object_adapter_spec.rb +31 -0
  55. data/spec/associations/belongs_to_association_spec.rb +98 -0
  56. data/spec/associations/has_and_belongs_to_many_association_spec.rb +377 -0
  57. data/spec/associations/has_many_association_spec.rb +337 -0
  58. data/spec/attributes_spec.rb +23 -1
  59. data/spec/auto_migrations_spec.rb +86 -29
  60. data/spec/callbacks_spec.rb +107 -0
  61. data/spec/column_spec.rb +5 -2
  62. data/spec/count_command_spec.rb +33 -1
  63. data/spec/database_spec.rb +18 -0
  64. data/spec/dependency_spec.rb +4 -2
  65. data/spec/embedded_value_spec.rb +8 -8
  66. data/spec/fixtures/people.yaml +1 -1
  67. data/spec/fixtures/projects.yaml +10 -1
  68. data/spec/fixtures/tasks.yaml +6 -0
  69. data/spec/fixtures/tasks_tasks.yaml +2 -0
  70. data/spec/fixtures/tomatoes.yaml +1 -0
  71. data/spec/is_a_tree_spec.rb +149 -0
  72. data/spec/load_command_spec.rb +71 -9
  73. data/spec/magic_columns_spec.rb +17 -2
  74. data/spec/migration_spec.rb +267 -0
  75. data/spec/models/animal.rb +1 -1
  76. data/spec/models/candidate.rb +8 -0
  77. data/spec/models/career.rb +1 -1
  78. data/spec/models/chain.rb +8 -0
  79. data/spec/models/comment.rb +1 -1
  80. data/spec/models/exhibit.rb +1 -1
  81. data/spec/models/fence.rb +7 -0
  82. data/spec/models/fruit.rb +2 -2
  83. data/spec/models/job.rb +8 -0
  84. data/spec/models/person.rb +2 -3
  85. data/spec/models/post.rb +1 -1
  86. data/spec/models/project.rb +21 -1
  87. data/spec/models/section.rb +1 -1
  88. data/spec/models/serializer.rb +1 -1
  89. data/spec/models/task.rb +9 -0
  90. data/spec/models/tomato.rb +27 -0
  91. data/spec/models/user.rb +8 -2
  92. data/spec/models/zoo.rb +2 -7
  93. data/spec/paranoia_spec.rb +1 -1
  94. data/spec/{base_spec.rb → persistence_spec.rb} +207 -18
  95. data/spec/postgres_spec.rb +48 -6
  96. data/spec/property_spec.rb +90 -9
  97. data/spec/query_spec.rb +71 -5
  98. data/spec/save_command_spec.rb +11 -0
  99. data/spec/spec_helper.rb +14 -11
  100. data/spec/support/blank_spec.rb +8 -0
  101. data/spec/support/inflector_spec.rb +41 -0
  102. data/spec/support/object_spec.rb +9 -0
  103. data/spec/{serialization_spec.rb → support/serialization_spec.rb} +1 -1
  104. data/spec/support/silence_spec.rb +15 -0
  105. data/spec/{support_spec.rb → support/string_spec.rb} +3 -3
  106. data/spec/support/struct_spec.rb +12 -0
  107. data/spec/support/typed_set_spec.rb +66 -0
  108. data/spec/table_spec.rb +3 -3
  109. data/spec/types/string.rb +81 -0
  110. data/spec/validates_uniqueness_of_spec.rb +17 -0
  111. data/spec/validations/number_validator.rb +59 -0
  112. data/spec/validations/string_validator.rb +14 -0
  113. metadata +59 -17
  114. data/do_performance.rb +0 -153
  115. data/lib/data_mapper/support/active_record_impersonation.rb +0 -103
  116. data/lib/data_mapper/support/weak_hash.rb +0 -46
  117. data/spec/active_record_impersonation_spec.rb +0 -129
  118. data/spec/associations_spec.rb +0 -232
  119. data/spec/conditions_spec.rb +0 -49
  120. data/spec/has_many_association_spec.rb +0 -173
  121. data/spec/models/animals_exhibit.rb +0 -8
@@ -3,9 +3,7 @@ module DataMapper
3
3
  def auto_migrate!
4
4
  if self::subclasses.empty?
5
5
  table = database.table(self)
6
- table.associations.each do |association|
7
- association.activate!
8
- end
6
+ table.activate_associations!
9
7
 
10
8
  table.create!(true)
11
9
  else
@@ -20,9 +18,7 @@ module DataMapper
20
18
  table.add_column(column.name, column.type, column.options)
21
19
  end
22
20
 
23
- table.associations.each do |association|
24
- association.activate!
25
- end
21
+ table.activate_associations!
26
22
 
27
23
  return table.create!(true)
28
24
  end
@@ -1,21 +1,17 @@
1
1
  require 'data_mapper/persistence'
2
-
3
- begin
4
- require 'ferret'
5
- rescue LoadError
6
- end
2
+ require 'data_mapper/is/tree'
7
3
 
8
4
  module DataMapper
9
5
 
10
6
  class Base
11
- include DataMapper::Persistence
7
+ include DataMapper::Is::Tree
12
8
 
13
9
  def self.inherited(klass)
14
- DataMapper::Persistence::prepare_for_persistence(klass)
10
+ klass.send(:include, DataMapper::Persistence)
15
11
  end
16
12
 
17
- def self.subclasses
18
- []
13
+ def self.auto_migrate!
14
+ DataMapper::Persistence.auto_migrate!
19
15
  end
20
16
  end
21
17
  end
@@ -102,7 +102,7 @@ module DataMapper
102
102
  #
103
103
  # This is what gives us thread safety, boys and girls
104
104
  def self.context
105
- Thread::current[:context] || Thread::current[:context] = []
105
+ Thread::current[:database_contexts] || Thread::current[:database_contexts] = []
106
106
  end
107
107
 
108
108
  # Setup creates a database and sets all of your properties for that database.
@@ -158,13 +158,14 @@ module DataMapper
158
158
  # Creates a new database object with the name you specify, and a default set of options.
159
159
  #
160
160
  # The default options are as follows:
161
- # { :host => 'localhost', :database => nil, :username => 'root', :password => '', :adapter = nil }
161
+ # { :host => 'localhost', :database => nil, :port => nil, :username => 'root', :password => '', :adapter = nil }
162
162
  def initialize(name)
163
163
  @name = name
164
164
 
165
165
  @adapter = nil
166
166
  @host = 'localhost'
167
167
  @database = nil
168
+ @port = nil
168
169
  @schema_search_path = nil
169
170
  @username = 'root'
170
171
  @password = ''
@@ -176,7 +177,7 @@ module DataMapper
176
177
 
177
178
  attr_reader :name, :adapter, :log_stream
178
179
 
179
- attr_accessor :host, :database, :schema_search_path, :username, :password, :log_level, :index_path, :socket
180
+ attr_accessor :host, :database, :port, :schema_search_path, :username, :password, :log_level, :index_path, :socket
180
181
 
181
182
  def log_stream=(val)
182
183
  @log_stream = (val.is_a?(String) && val =~ /STDOUT/ ? STDOUT : val)
@@ -1,73 +1,109 @@
1
1
  module DataMapper
2
2
 
3
+ # == EmbeddedValue
4
+ # As an alternative to an extraneous has_one association, EmbeddedValue offers a means
5
+ # to serialize component objects to a table without having to define an entirely new model.
6
+ #
7
+ # Example:
8
+ #
9
+ # class Person < DataMapper::Base
10
+ #
11
+ # property :name, :string
12
+ # property :occupation, :string
13
+ #
14
+ # embed :address, :prefix => true do
15
+ # property :street, :string
16
+ # property :city, :string
17
+ # property :state, :string, :size => 2
18
+ # property :zip_code, :string, :size => 10
19
+ #
20
+ # def city_state_zip_code
21
+ # "#{city}, #{state} #{zip_code}"
22
+ # end
23
+ #
24
+ # end
25
+ # end
26
+ #
27
+ # Columns for the Address model will appear in the Person table. Passing
28
+ # <tt>:prefix => true</tt> will prefix the column name with the parent table's name.
29
+ # The default behavior is to use the columns as they are defined. Using the above
30
+ # example, the database table structure will become:
31
+ #
32
+ # Column Datatype, Options
33
+ # ===============================================================
34
+ # name :string
35
+ # occupation :string
36
+ # address_street :string
37
+ # address_city :string
38
+ # address_state :string, :size => 2
39
+ # address_zip_code :string, :size => 10
40
+ #
41
+ # EmbeddedValue's become instance methods off of an instance of the parent
42
+ # class and return a sub-class of the parent class.
43
+ #
44
+ # bob = Person.first(:name => 'Bob')
45
+ # bob.address # => #<Person::Address:0x1a492b8>
46
+ # bob.address.city # => "Pittsburgh"
47
+ # bob.address.city_state_zip_code # => "Pitsburgh, PA 90210"
48
+
3
49
  class EmbeddedValue
4
50
  EMBEDDED_PROPERTIES = []
5
51
 
6
52
  def initialize(instance)
7
53
  @instance = instance
8
54
  @container_prefix = ''
9
-
10
- # force lazy load on access to any lazy-loaded embed property
11
- @instance.lazy_load!(*self.class::EMBEDDED_PROPERTIES) # if @container_lazy
12
55
  end
13
56
 
14
57
  def self.inherited(base)
15
58
  base.const_set('EMBEDDED_PROPERTIES', [])
16
59
  end
17
60
 
18
- # add an embedded property
61
+ # add an embedded property. For more information about how to define properties, visit Property.
19
62
  def self.property(name, type, options = {})
20
63
  # set lazy option on the mapping if defined in the embed block
21
64
  options[:lazy] ||= @container_lazy
22
-
23
- visibility_options = [:public, :protected, :private]
24
- reader_visibility = options[:reader] || options[:accessor] || @container_reader_visibility
25
- writer_visibility = options[:writer] || options[:accessor] || @container_writer_visibility
26
- writer_visibility = :protected if options[:protected]
27
- writer_visibility = :private if options[:private]
28
-
29
- raise(ArgumentError.new, "property visibility must be :public, :protected, or :private") unless visibility_options.include?(reader_visibility) && visibility_options.include?(writer_visibility)
30
-
31
- mapping = database.schema[containing_class].add_column("#{@container_prefix}#{name}", type, options)
32
-
33
- self::EMBEDDED_PROPERTIES << "#{@container_prefix}#{name}"
34
- define_property_getter(name, mapping, reader_visibility)
35
- define_property_setter(name, mapping, writer_visibility)
65
+
66
+ options[:reader] ||= options[:accessor] || @container_reader_visibility
67
+ options[:writer] ||= options[:accessor] || @container_writer_visibility
68
+
69
+ property_name = @container_prefix ? @container_prefix + name.to_s : name
70
+
71
+ property = containing_class.property(property_name, type, options)
72
+ define_property_getter(name, property)
73
+ define_property_setter(name, property)
36
74
  end
37
75
 
38
76
  # define embedded property getters
39
- def self.define_property_getter(name, mapping, visibility = :public)
40
- # add convenience method on non-embedded base for #update_attributes
41
- self.containing_class.property_getter(mapping, visibility)
77
+ def self.define_property_getter(name, property) # :nodoc:
42
78
 
43
79
  # add the method on the embedded class
44
80
  class_eval <<-EOS
45
- #{visibility.to_s}
81
+ #{property.reader_visibility.to_s}
46
82
  def #{name}
47
- @instance.instance_variable_get(#{mapping.instance_variable_name.inspect})
83
+ #{"@instance.lazy_load!("+ property.name.inspect + ")" if property.lazy?}
84
+ @instance.instance_variable_get(#{property.instance_variable_name.inspect})
48
85
  end
49
86
  EOS
50
87
 
51
88
  # add a shortcut boolean? method if applicable (ex: activated?)
52
- if mapping.type == :boolean
53
- class_eval("alias #{name}? #{name}")
89
+ if property.type == :boolean
90
+ class_eval("alias #{property.name}? #{property.name}")
54
91
  end
55
92
  end
56
93
 
57
94
  # define embedded property setters
58
- def self.define_property_setter(name, mapping, visibility = :public)
59
- # add convenience method on non-embedded base for #update_attributes
60
- self.containing_class.property_setter(mapping, visibility)
95
+ def self.define_property_setter(name, property) # :nodoc:
61
96
 
62
97
  # add the method on the embedded class
63
98
  class_eval <<-EOS
64
- #{visibility.to_s}
99
+ #{property.writer_visibility.to_s}
65
100
  def #{name.to_s.sub(/\?$/, '')}=(value)
66
- @instance.instance_variable_set(#{mapping.instance_variable_name.inspect}, value)
101
+ @instance.instance_variable_set(#{property.instance_variable_name.inspect}, value)
67
102
  end
68
103
  EOS
69
104
  end
70
105
 
106
+ # returns the class in which the EmbeddedValue is declared
71
107
  def self.containing_class
72
108
  @containing_class || @containing_class = begin
73
109
  tree = name.split('::')
@@ -1,5 +1,3 @@
1
- require 'data_mapper/support/weak_hash'
2
-
3
1
  module DataMapper
4
2
 
5
3
  # Tracks objects to help ensure that each object gets loaded only once.
@@ -39,7 +37,7 @@ module DataMapper
39
37
 
40
38
  private
41
39
  def mapped_class(klass)
42
- if ! klass.superclass.respond_to?(:persistent?)
40
+ unless klass.superclass.respond_to?(:persistent?)
43
41
  klass
44
42
  else
45
43
  mapped_class(klass.superclass)
@@ -0,0 +1,121 @@
1
+ module DataMapper
2
+ module Is
3
+ module Tree
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ # An extension to DataMapper to easily allow the creation of tree structures from your DataMapper Models.
9
+ # This requires a foreign key property for your model, which by default would be called :parent_id.
10
+ #
11
+ # Example:
12
+ #
13
+ # class Category < DataMapper::Base
14
+ # property :parent_id, :integer
15
+ # property :name, :string
16
+ #
17
+ # is_a_tree :order => "name"
18
+ # end
19
+ #
20
+ # root
21
+ # +- child
22
+ # +- grandchild1
23
+ # +- grandchild2
24
+ #
25
+ # root = Category.create("name" => "root")
26
+ # child = root.children.create("name" => "child")
27
+ # grandchild1 = child1.children.create("name" => "grandchild1")
28
+ # grandchild2 = child2.children.create("name" => "grandchild2")
29
+ #
30
+ # root.parent # => nil
31
+ # child.parent # => root
32
+ # root.children # => [child]
33
+ # root.children.first.children.first # => grandchild1
34
+ # Category.first_root # => root
35
+ # Category.roots # => [root]
36
+ #
37
+ # The following instance methods are added:
38
+ # * <tt>children</tt> - Returns all nodes with the current node as their parent, in the order specified by
39
+ # <tt>:order</tt> (<tt>[grandchild1, grandchild2]</tt> when called on <tt>child</tt>)
40
+ # * <tt>parent</tt> - Returns the node referenced by the foreign key (<tt>:parent_id</tt> by
41
+ # default) (<tt>root</tt> when called on <tt>child</tt>)
42
+ # * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node
43
+ # (<tt>[grandchild2]</tt> when called on <tt>grandchild1</tt>)
44
+ # * <tt>generation</tt> - Returns all the children of the parent, including the current node (<tt>
45
+ # [grandchild1, grandchild2]</tt> when called on <tt>grandchild1</tt>)
46
+ # * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[root, child1]</tt>
47
+ # when called on <tt>grandchild2</tt>)
48
+ # * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>grandchild2</tt>)
49
+ #
50
+ # Author:: Timothy Bennett (http://lanaer.com)
51
+ module ClassMethods
52
+ # Configuration options are:
53
+ #
54
+ # * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
55
+ # * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
56
+ # * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
57
+ def is_a_tree(options = {})
58
+ configuration = { :foreign_key => "parent_id" }
59
+ configuration.update(options) if options.is_a?(Hash)
60
+
61
+ belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
62
+ has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order]
63
+
64
+ include DataMapper::Is::Tree::InstanceMethods
65
+
66
+ class_eval <<-CLASS
67
+ def self.roots
68
+ self.all :#{configuration[:foreign_key]} => nil, :order => #{configuration[:order].inspect}
69
+ end
70
+
71
+ def self.first_root
72
+ self.first :#{configuration[:foreign_key]} => nil, :order => #{configuration[:order].inspect}
73
+ end
74
+ CLASS
75
+
76
+ class << self
77
+ alias_method :root, :first_root # for people used to the ActiveRecord acts_as_tree
78
+ end
79
+ end
80
+
81
+ alias_method :can_has_tree, :is_a_tree # just for fun ;)
82
+ end
83
+
84
+ module InstanceMethods
85
+ # Returns list of ancestors, starting with the root.
86
+ #
87
+ # grandchild1.ancestors # => [root, child]
88
+ def ancestors
89
+ node, nodes = self, []
90
+ nodes << node = node.parent while node.parent
91
+ nodes.reverse
92
+ end
93
+
94
+ # Returns the root node of the current node’s tree.
95
+ #
96
+ # grandchild1.root # => root
97
+ def root
98
+ node = self
99
+ node = node.parent while node.parent
100
+ node
101
+ end
102
+
103
+ # Returns all siblings of the current node.
104
+ #
105
+ # grandchild1.siblings # => [grandchild2]
106
+ def siblings
107
+ generation - [self]
108
+ end
109
+
110
+ # Returns all children of the current node’s parent.
111
+ #
112
+ # grandchild1.generation # => [grandchild1, grandchild2]
113
+ def generation
114
+ parent ? parent.children : self.class.roots
115
+ end
116
+
117
+ alias_method :self_and_siblings, :generation # for those used to the ActiveRecord acts_as_tree
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,155 @@
1
+ module DataMapper
2
+ class Migration
3
+ class Table
4
+
5
+ MAPPINGS = DataMapper::Adapters::Sql::Mappings unless defined?(MAPPINGS)
6
+
7
+ attr_accessor :name
8
+
9
+ def initialize(table = nil, options = {})
10
+ @name, @options = table, options
11
+ @columns = []
12
+ end
13
+
14
+ def self.create(table)
15
+ table.create!
16
+ end
17
+
18
+ def self.drop(table_name)
19
+ database.table(klass(table_name)).drop!
20
+ end
21
+
22
+ def self.add_column(table, column, type, options = {})
23
+ column = table.add_column column, type, options
24
+ column.create!
25
+ end
26
+
27
+ def self.remove_column(table, column)
28
+ column = table[column]
29
+ column.drop!
30
+ end
31
+
32
+ def add(column, type, options = {})
33
+ column_data = [column, type, options]
34
+ exists? ? self.class.add_column(table, *column_data) : table.add_column(*column_data)
35
+ end
36
+
37
+ def remove(column)
38
+ self.class.remove_column table, column
39
+ end
40
+
41
+ def rename(old_column, new_column)
42
+ column = table[old_column]
43
+ column.rename!(new_column)
44
+ end
45
+
46
+ def alter(column, type, options = {})
47
+ column = table[column]
48
+ column.type = type
49
+ column.options = options
50
+ column.parse_options!
51
+ column.alter!
52
+ end
53
+
54
+ def exists?
55
+ database.table_exists?(klass)
56
+ end
57
+
58
+ def after_create!
59
+ unless exists?
60
+ table.add_column(:id, :integer, { :key => true }) unless @options[:id] == false
61
+ self.class.create(table)
62
+ end
63
+ end
64
+
65
+ # Rails Style
66
+
67
+ def column(name, type, options = {})
68
+ add(name, type, options)
69
+ end
70
+
71
+ # klass!
72
+
73
+ def table
74
+ @table ||= database.table(klass)
75
+ end
76
+
77
+ def klass
78
+ @klass ||= self.class.klass(self.name)
79
+ end
80
+
81
+ def self.klass(table)
82
+ table_name = table.to_s
83
+ class_name = Inflector::classify(table_name)
84
+ klass = Inflector::constantize(class_name)
85
+ rescue NameError
86
+ module_eval <<-classdef
87
+ class ::#{class_name} < DataMapper::Base
88
+ end
89
+ classdef
90
+ klass = eval("#{class_name}")
91
+ ensure
92
+ klass
93
+ end
94
+
95
+ end
96
+
97
+ class << self
98
+
99
+ def up; end
100
+
101
+ def down; end
102
+
103
+ def migrate(direction = :up)
104
+ send(direction)
105
+ end
106
+
107
+ def table(table = nil, options = {}, &block)
108
+ if table && block
109
+ table = DataMapper::Migration::Table.new(table, options)
110
+ table.instance_eval &block
111
+ table.after_create!
112
+ else
113
+ return DataMapper::Migration::Table
114
+ end
115
+ end
116
+
117
+ # Rails Style
118
+
119
+ def create_table(table_name, options = {}, &block)
120
+ new_table = table.new(table_name, options)
121
+ yield new_table
122
+ new_table.after_create!
123
+ end
124
+
125
+ def drop_table(table_name)
126
+ table.drop(table_name)
127
+ end
128
+
129
+ def add_column(table_name, column, type, options = {})
130
+ table table_name do
131
+ add column, type, options
132
+ end
133
+ end
134
+
135
+ def rename_column(table_name, old_column_name, new_column_name)
136
+ table table_name do
137
+ rename old_column_name, new_column_name
138
+ end
139
+ end
140
+
141
+ def change_column(table_name, column_name, type, options = {})
142
+ table table_name do
143
+ alter column_name, type, options
144
+ end
145
+ end
146
+
147
+ def remove_column(table_name, column)
148
+ table table_name do
149
+ remove column
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ end