datamapper-dm-core 0.9.11 → 0.10.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 (192) hide show
  1. data/.autotest +17 -14
  2. data/.gitignore +3 -1
  3. data/FAQ +6 -5
  4. data/History.txt +5 -39
  5. data/Manifest.txt +67 -76
  6. data/QUICKLINKS +1 -1
  7. data/README.txt +21 -15
  8. data/Rakefile +16 -15
  9. data/SPECS +2 -29
  10. data/TODO +1 -1
  11. data/dm-core.gemspec +11 -15
  12. data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
  13. data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
  14. data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
  15. data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
  16. data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
  17. data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
  18. data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
  19. data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
  20. data/lib/dm-core/adapters.rb +135 -16
  21. data/lib/dm-core/associations/many_to_many.rb +372 -90
  22. data/lib/dm-core/associations/many_to_one.rb +220 -73
  23. data/lib/dm-core/associations/one_to_many.rb +319 -255
  24. data/lib/dm-core/associations/one_to_one.rb +66 -53
  25. data/lib/dm-core/associations/relationship.rb +560 -158
  26. data/lib/dm-core/collection.rb +1104 -381
  27. data/lib/dm-core/core_ext/kernel.rb +12 -0
  28. data/lib/dm-core/core_ext/symbol.rb +10 -0
  29. data/lib/dm-core/identity_map.rb +4 -34
  30. data/lib/dm-core/migrations.rb +1283 -0
  31. data/lib/dm-core/model/descendant_set.rb +81 -0
  32. data/lib/dm-core/model/hook.rb +45 -0
  33. data/lib/dm-core/model/is.rb +32 -0
  34. data/lib/dm-core/model/property.rb +248 -0
  35. data/lib/dm-core/model/relationship.rb +335 -0
  36. data/lib/dm-core/model/scope.rb +90 -0
  37. data/lib/dm-core/model.rb +570 -369
  38. data/lib/dm-core/property.rb +753 -280
  39. data/lib/dm-core/property_set.rb +141 -98
  40. data/lib/dm-core/query/conditions/comparison.rb +814 -0
  41. data/lib/dm-core/query/conditions/operation.rb +247 -0
  42. data/lib/dm-core/query/direction.rb +43 -0
  43. data/lib/dm-core/query/operator.rb +42 -0
  44. data/lib/dm-core/query/path.rb +102 -0
  45. data/lib/dm-core/query/sort.rb +45 -0
  46. data/lib/dm-core/query.rb +974 -492
  47. data/lib/dm-core/repository.rb +147 -107
  48. data/lib/dm-core/resource.rb +644 -429
  49. data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
  50. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
  51. data/lib/dm-core/support/chainable.rb +20 -0
  52. data/lib/dm-core/support/deprecate.rb +12 -0
  53. data/lib/dm-core/support/equalizer.rb +23 -0
  54. data/lib/dm-core/support/logger.rb +13 -0
  55. data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
  56. data/lib/dm-core/transaction.rb +333 -92
  57. data/lib/dm-core/type.rb +98 -60
  58. data/lib/dm-core/types/boolean.rb +1 -1
  59. data/lib/dm-core/types/discriminator.rb +34 -20
  60. data/lib/dm-core/types/object.rb +7 -4
  61. data/lib/dm-core/types/paranoid_boolean.rb +11 -9
  62. data/lib/dm-core/types/paranoid_datetime.rb +11 -9
  63. data/lib/dm-core/types/serial.rb +3 -3
  64. data/lib/dm-core/types/text.rb +3 -4
  65. data/lib/dm-core/version.rb +1 -1
  66. data/lib/dm-core.rb +106 -110
  67. data/script/performance.rb +102 -109
  68. data/script/profile.rb +169 -38
  69. data/spec/lib/adapter_helpers.rb +105 -0
  70. data/spec/lib/collection_helpers.rb +18 -0
  71. data/spec/lib/counter_adapter.rb +34 -0
  72. data/spec/lib/pending_helpers.rb +27 -0
  73. data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
  74. data/spec/public/associations/many_to_many_spec.rb +193 -0
  75. data/spec/public/associations/many_to_one_spec.rb +73 -0
  76. data/spec/public/associations/one_to_many_spec.rb +77 -0
  77. data/spec/public/associations/one_to_one_spec.rb +156 -0
  78. data/spec/public/collection_spec.rb +65 -0
  79. data/spec/public/model/relationship_spec.rb +924 -0
  80. data/spec/public/model_spec.rb +159 -0
  81. data/spec/public/property_spec.rb +829 -0
  82. data/spec/public/resource_spec.rb +71 -0
  83. data/spec/public/sel_spec.rb +44 -0
  84. data/spec/public/setup_spec.rb +145 -0
  85. data/spec/public/shared/association_collection_shared_spec.rb +317 -0
  86. data/spec/public/shared/collection_shared_spec.rb +1723 -0
  87. data/spec/public/shared/finder_shared_spec.rb +1619 -0
  88. data/spec/public/shared/resource_shared_spec.rb +924 -0
  89. data/spec/public/shared/sel_shared_spec.rb +112 -0
  90. data/spec/public/transaction_spec.rb +129 -0
  91. data/spec/public/types/discriminator_spec.rb +130 -0
  92. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  93. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  94. data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
  95. data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
  96. data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
  97. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
  98. data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
  99. data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
  100. data/spec/semipublic/associations/relationship_spec.rb +194 -0
  101. data/spec/semipublic/associations_spec.rb +177 -0
  102. data/spec/semipublic/collection_spec.rb +142 -0
  103. data/spec/semipublic/property_spec.rb +61 -0
  104. data/spec/semipublic/query/conditions_spec.rb +528 -0
  105. data/spec/semipublic/query/path_spec.rb +443 -0
  106. data/spec/semipublic/query_spec.rb +2626 -0
  107. data/spec/semipublic/resource_spec.rb +47 -0
  108. data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
  109. data/spec/spec.opts +3 -1
  110. data/spec/spec_helper.rb +80 -57
  111. data/tasks/ci.rb +19 -31
  112. data/tasks/dm.rb +43 -48
  113. data/tasks/doc.rb +8 -11
  114. data/tasks/gemspec.rb +5 -5
  115. data/tasks/hoe.rb +15 -16
  116. data/tasks/install.rb +8 -10
  117. metadata +72 -93
  118. data/lib/dm-core/associations/relationship_chain.rb +0 -81
  119. data/lib/dm-core/associations.rb +0 -207
  120. data/lib/dm-core/auto_migrations.rb +0 -105
  121. data/lib/dm-core/dependency_queue.rb +0 -32
  122. data/lib/dm-core/hook.rb +0 -11
  123. data/lib/dm-core/is.rb +0 -16
  124. data/lib/dm-core/logger.rb +0 -232
  125. data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
  126. data/lib/dm-core/migrator.rb +0 -29
  127. data/lib/dm-core/scope.rb +0 -58
  128. data/lib/dm-core/support/array.rb +0 -13
  129. data/lib/dm-core/support/assertions.rb +0 -8
  130. data/lib/dm-core/support/errors.rb +0 -23
  131. data/lib/dm-core/support/kernel.rb +0 -11
  132. data/lib/dm-core/support/symbol.rb +0 -41
  133. data/lib/dm-core/support.rb +0 -7
  134. data/lib/dm-core/type_map.rb +0 -80
  135. data/lib/dm-core/types.rb +0 -19
  136. data/script/all +0 -4
  137. data/spec/integration/association_spec.rb +0 -1382
  138. data/spec/integration/association_through_spec.rb +0 -203
  139. data/spec/integration/associations/many_to_many_spec.rb +0 -449
  140. data/spec/integration/associations/many_to_one_spec.rb +0 -163
  141. data/spec/integration/associations/one_to_many_spec.rb +0 -188
  142. data/spec/integration/auto_migrations_spec.rb +0 -413
  143. data/spec/integration/collection_spec.rb +0 -1073
  144. data/spec/integration/data_objects_adapter_spec.rb +0 -32
  145. data/spec/integration/dependency_queue_spec.rb +0 -46
  146. data/spec/integration/model_spec.rb +0 -197
  147. data/spec/integration/mysql_adapter_spec.rb +0 -85
  148. data/spec/integration/postgres_adapter_spec.rb +0 -731
  149. data/spec/integration/property_spec.rb +0 -253
  150. data/spec/integration/query_spec.rb +0 -514
  151. data/spec/integration/repository_spec.rb +0 -61
  152. data/spec/integration/resource_spec.rb +0 -513
  153. data/spec/integration/sqlite3_adapter_spec.rb +0 -352
  154. data/spec/integration/sti_spec.rb +0 -273
  155. data/spec/integration/strategic_eager_loading_spec.rb +0 -156
  156. data/spec/integration/transaction_spec.rb +0 -75
  157. data/spec/integration/type_spec.rb +0 -275
  158. data/spec/lib/logging_helper.rb +0 -18
  159. data/spec/lib/mock_adapter.rb +0 -27
  160. data/spec/lib/model_loader.rb +0 -100
  161. data/spec/lib/publicize_methods.rb +0 -28
  162. data/spec/models/content.rb +0 -16
  163. data/spec/models/vehicles.rb +0 -34
  164. data/spec/models/zoo.rb +0 -48
  165. data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
  166. data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
  167. data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
  168. data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
  169. data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
  170. data/spec/unit/associations/many_to_many_spec.rb +0 -32
  171. data/spec/unit/associations/many_to_one_spec.rb +0 -159
  172. data/spec/unit/associations/one_to_many_spec.rb +0 -393
  173. data/spec/unit/associations/one_to_one_spec.rb +0 -7
  174. data/spec/unit/associations/relationship_spec.rb +0 -71
  175. data/spec/unit/associations_spec.rb +0 -242
  176. data/spec/unit/auto_migrations_spec.rb +0 -111
  177. data/spec/unit/collection_spec.rb +0 -182
  178. data/spec/unit/data_mapper_spec.rb +0 -35
  179. data/spec/unit/identity_map_spec.rb +0 -126
  180. data/spec/unit/is_spec.rb +0 -80
  181. data/spec/unit/migrator_spec.rb +0 -33
  182. data/spec/unit/model_spec.rb +0 -321
  183. data/spec/unit/naming_conventions_spec.rb +0 -36
  184. data/spec/unit/property_set_spec.rb +0 -90
  185. data/spec/unit/property_spec.rb +0 -753
  186. data/spec/unit/query_spec.rb +0 -571
  187. data/spec/unit/repository_spec.rb +0 -93
  188. data/spec/unit/resource_spec.rb +0 -649
  189. data/spec/unit/scope_spec.rb +0 -142
  190. data/spec/unit/transaction_spec.rb +0 -493
  191. data/spec/unit/type_map_spec.rb +0 -114
  192. data/spec/unit/type_spec.rb +0 -119
@@ -1,413 +0,0 @@
1
- require 'pathname'
2
- require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
- require 'ostruct'
4
-
5
- TODAY = Date.today
6
- NOW = DateTime.now
7
-
8
- TIME_STRING_1 = '2007-04-21 04:14:12'
9
- TIME_STRING_2 = '2007-04-21 04:14:12.1'
10
- TIME_STRING_3 = '2007-04-21 04:14:12.01'
11
- TIME_STRING_4 = '2007-04-21 04:14:12.123456'
12
-
13
- TIME_1 = Time.parse(TIME_STRING_1)
14
- TIME_2 = Time.parse(TIME_STRING_2)
15
- TIME_3 = Time.parse(TIME_STRING_3)
16
- TIME_4 = Time.parse(TIME_STRING_4)
17
-
18
- class EveryType
19
- include DataMapper::Resource
20
-
21
- property :serial, Serial
22
- property :fixnum, Integer, :nullable => false, :default => 1
23
- property :string, String, :nullable => false, :default => 'default'
24
- property :empty, String, :nullable => false, :default => ''
25
- property :date, Date, :nullable => false, :default => TODAY, :index => :date_date_time, :unique_index => :date_float
26
- property :true_class, TrueClass, :nullable => false, :default => true
27
- property :false_class, TrueClass, :nullable => false, :default => false
28
- property :text, DM::Text, :nullable => false, :default => 'text'
29
- # property :class, Class, :nullable => false, :default => Class # FIXME: Class types cause infinite recursions in Resource
30
- property :big_decimal, BigDecimal, :nullable => false, :default => BigDecimal('1.1'), :precision => 2, :scale => 1
31
- property :float, Float, :nullable => false, :default => 1.1, :precision => 2, :scale => 1, :unique_index => :date_float
32
- property :date_time, DateTime, :nullable => false, :default => NOW, :index => [:date_date_time, true]
33
- property :time_1, Time, :nullable => false, :default => TIME_1, :unique_index => true
34
- property :time_2, Time, :nullable => false, :default => TIME_2
35
- property :time_3, Time, :nullable => false, :default => TIME_3
36
- property :time_4, Time, :nullable => false, :default => TIME_4
37
- property :object, Object, :nullable => true # FIXME: cannot supply a default for Object
38
- property :discriminator, DM::Discriminator
39
- end
40
-
41
- module Publications
42
- class StoryCollection
43
- end
44
-
45
- class ShortStoryCollection < StoryCollection
46
- include DataMapper::Resource
47
- property :serial, Serial
48
- property :date, Date, :nullable => false, :default => TODAY, :index => :date_date_time
49
- end
50
- end
51
-
52
- if HAS_SQLITE3
53
- describe DataMapper::AutoMigrations, '.auto_migrate! with sqlite3' do
54
- before :all do
55
- @adapter = repository(:sqlite3).adapter
56
-
57
- DataMapper::Resource.descendants.clear
58
-
59
- @property_class = Struct.new(:name, :type, :nullable, :default, :serial)
60
- end
61
-
62
- after :all do
63
- DataMapper::Resource.descendants.clear
64
- end
65
-
66
- describe 'with sqlite3' do
67
- before :all do
68
- EveryType.auto_migrate!(:sqlite3).should be_true
69
-
70
- @table_set = @adapter.query('PRAGMA table_info(?)', 'every_types').inject({}) do |ts,column|
71
- default = if 'NULL' == column.dflt_value || column.dflt_value.nil?
72
- nil
73
- else
74
- /^(['"]?)(.*)\1$/.match(column.dflt_value)[2]
75
- end
76
-
77
- property = @property_class.new(
78
- column.name,
79
- column.type.upcase,
80
- column.notnull == 0,
81
- default,
82
- column.pk == 1 # in SQLite3 the serial key is also primary
83
- )
84
-
85
- ts.update(property.name => property)
86
- end
87
-
88
- @index_list = @adapter.query('PRAGMA index_list(?)', 'every_types')
89
-
90
- # bypass DM to create the record using only the column default values
91
- @adapter.execute('INSERT INTO "every_types" ("serial", "discriminator") VALUES (?, ?)', 1, EveryType)
92
-
93
- @book = repository(:sqlite3) { EveryType.first }
94
- end
95
-
96
- types = {
97
- :serial => [ Integer, 'INTEGER', false, nil, 1, true ],
98
- :fixnum => [ Integer, 'INTEGER', false, '1', 1, false ],
99
- :string => [ String, 'VARCHAR(50)', false, 'default', 'default', false ],
100
- :empty => [ String, 'VARCHAR(50)', false, '', '' , false ],
101
- :date => [ Date, 'DATE', false, TODAY.strftime('%Y-%m-%d'), TODAY, false ],
102
- :true_class => [ TrueClass, 'BOOLEAN', false, 't', true, false ],
103
- :false_class => [ TrueClass, 'BOOLEAN', false, 'f', false, false ],
104
- :text => [ DM::Text, 'TEXT', false, 'text', 'text', false ],
105
- # :class => [ Class, 'VARCHAR(50)', false, 'Class', 'Class', false ],
106
- :big_decimal => [ BigDecimal, 'DECIMAL(2,1)', false, '1.1', BigDecimal('1.1'), false ],
107
- :float => [ Float, 'FLOAT(2,1)', false, '1.1', 1.1, false ],
108
- :date_time => [ DateTime, 'DATETIME', false, NOW.strftime('%Y-%m-%d %H:%M:%S'), NOW, false ],
109
- :time_1 => [ Time, 'TIMESTAMP', false, TIME_STRING_1, TIME_1, false ],
110
- #SQLite pads out the microseconds to the full 6 digits no matter what the value is - we simply pad up the zeros needed
111
- :time_2 => [ Time, 'TIMESTAMP', false, TIME_STRING_2.dup << '00000', TIME_2, false ],
112
- :time_3 => [ Time, 'TIMESTAMP', false, TIME_STRING_3.dup << '0000', TIME_3, false ],
113
- :time_4 => [ Time, 'TIMESTAMP', false, TIME_STRING_4, TIME_4, false ],
114
- :object => [ Object, 'TEXT', true, nil, nil, false ],
115
- :discriminator => [ DM::Discriminator, 'VARCHAR(50)', false, nil, EveryType, false ],
116
- }
117
-
118
- types.each do |name,(klass,type,nullable,default,key)|
119
- describe "a #{klass} property" do
120
- it "should be created as a #{type}" do
121
- @table_set[name.to_s].type.should == type
122
- end
123
-
124
- it "should #{!nullable && 'not'} be nullable".squeeze(' ') do
125
- @table_set[name.to_s].nullable.should == nullable
126
- end
127
-
128
- it "should have a default value #{default.inspect}" do
129
- @table_set[name.to_s].default.should == default
130
- end
131
-
132
- expected_value = types[name][4]
133
- it 'should properly typecast value' do
134
- if DateTime == klass
135
- @book.send(name).to_s.should == expected_value.to_s
136
- else
137
- @book.send(name).should == expected_value
138
- end
139
- end
140
- end
141
- end
142
-
143
- it 'should have 4 indexes: 2 non-unique index, 2 unique index' do
144
- @index_list.size.should == 4
145
-
146
- expected_indices = {
147
- "unique_index_every_types_date_float" => 1,
148
- "unique_index_every_types_time_1" => 1,
149
- "index_every_types_date_date_time" => 0,
150
- "index_every_types_date_time" => 0
151
- }
152
-
153
- @index_list.each do |index|
154
- expected_indices.should have_key(index.name)
155
- expected_indices[index.name].should == index.unique
156
- end
157
- end
158
-
159
- it 'should handle a model which inherits from a regular object' do
160
- lambda { Publications::ShortStoryCollection.auto_migrate!(:sqlite3) }.should_not raise_error
161
- end
162
-
163
- it 'should escape a namespaced model' do
164
- Publications::ShortStoryCollection.auto_migrate!(:sqlite3).should be_true
165
- @adapter.query('SELECT "name" FROM "sqlite_master" WHERE type = ?', 'table').should include('publications_short_story_collections')
166
- end
167
- end
168
- end
169
- end
170
-
171
- if HAS_MYSQL
172
- describe DataMapper::AutoMigrations, '.auto_migrate! with mysql' do
173
- before :all do
174
- @adapter = repository(:mysql).adapter
175
-
176
- DataMapper::Resource.descendants.clear
177
-
178
- @property_class = Struct.new(:name, :type, :nullable, :default, :serial)
179
- end
180
-
181
- after :all do
182
- DataMapper::Resource.descendants.clear
183
- end
184
-
185
- describe 'with mysql' do#
186
- before :all do
187
- EveryType.auto_migrate!(:mysql).should be_true
188
-
189
- @table_set = @adapter.query('DESCRIBE `every_types`').inject({}) do |ts,column|
190
- property = @property_class.new(
191
- column.field,
192
- column.type.upcase,
193
- column.null == 'YES',
194
- column.type.upcase == 'TEXT' ? nil : column.default,
195
- column.extra.split.include?('auto_increment')
196
- )
197
-
198
- ts.update(property.name => property)
199
- end
200
-
201
- @index_list = @adapter.query('SHOW INDEX FROM `every_types`')
202
-
203
- # bypass DM to create the record using only the column default values
204
- @adapter.execute('INSERT INTO `every_types` (`serial`, `text`, `discriminator`) VALUES (?, ?, ?)', 1, 'text', EveryType)
205
-
206
- @book = repository(:mysql) { EveryType.first }
207
- end
208
-
209
- types = {
210
- :serial => [ Integer, 'INT(11)', false, nil, 1, true ],
211
- :fixnum => [ Integer, 'INT(11)', false, '1', 1, false ],
212
- :string => [ String, 'VARCHAR(50)', false, 'default', 'default', false ],
213
- :empty => [ String, 'VARCHAR(50)', false, '', '', false ],
214
- :date => [ Date, 'DATE', false, TODAY.strftime('%Y-%m-%d'), TODAY, false ],
215
- :true_class => [ TrueClass, 'TINYINT(1)', false, '1', true, false ],
216
- :false_class => [ TrueClass, 'TINYINT(1)', false, '0', false, false ],
217
- :text => [ DM::Text, 'TEXT', false, nil, 'text', false ],
218
- # :class => [ Class, 'VARCHAR(50)', false, 'Class', 'Class', false ],
219
- :big_decimal => [ BigDecimal, 'DECIMAL(2,1)', false, '1.1', BigDecimal('1.1'), false ],
220
- :float => [ Float, 'FLOAT(2,1)', false, '1.1', 1.1, false ],
221
- :date_time => [ DateTime, 'DATETIME', false, NOW.strftime('%Y-%m-%d %H:%M:%S'), NOW, false ],
222
- :time_1 => [ Time, 'TIMESTAMP', false, TIME_1.strftime('%Y-%m-%d %H:%M:%S'), TIME_1, false ],
223
- :time_2 => [ Time, 'TIMESTAMP', false, TIME_2.strftime('%Y-%m-%d %H:%M:%S'), TIME_2, false ],
224
- :time_3 => [ Time, 'TIMESTAMP', false, TIME_3.strftime('%Y-%m-%d %H:%M:%S'), TIME_3 , false ],
225
- :time_4 => [ Time, 'TIMESTAMP', false, TIME_4.strftime('%Y-%m-%d %H:%M:%S'), TIME_4 , false ],
226
- :object => [ Object, 'TEXT', true, nil, nil, false ],
227
- :discriminator => [ DM::Discriminator, 'VARCHAR(50)', false, nil, EveryType, false ],
228
- }
229
-
230
- types.each do |name,(klass,type,nullable,default,key)|
231
- describe "a #{klass} property" do
232
- it "should be created as a #{type}" do
233
- @table_set[name.to_s].type.should == type
234
- end
235
-
236
- it "should #{!nullable && 'not'} be nullable".squeeze(' ') do
237
- @table_set[name.to_s].nullable.should == nullable
238
- end
239
-
240
- it "should have a default value #{default.inspect}" do
241
- @table_set[name.to_s].default.should == default
242
- end
243
-
244
- expected_value = types[name][4]
245
- it 'should properly typecast value' do
246
- if DateTime == klass || Time == klass # mysql doesn't support microsecond
247
- @book.send(name).to_s.should == expected_value.to_s
248
- else
249
- @book.send(name).should == expected_value
250
- end
251
- end
252
- end
253
- end
254
-
255
- it 'should have 4 indexes: 2 non-unique index, 2 unique index' do
256
- pending do
257
- # TODO
258
- @index_list[0].Key_name.should == 'unique_index_every_types_date_float'
259
- @index_list[0].Non_unique.should == 0
260
- @index_list[1].Key_name.should == 'unique_index_every_types_time_1'
261
- @index_list[1].Non_unique.should == 0
262
- @index_list[2].Key_name.should == 'index_every_types_date_date_time'
263
- @index_list[2].Non_unique.should == 1
264
- @index_list[3].Key_name.should == 'index_every_types_date_time'
265
- @index_list[3].Non_unique.should == 1
266
- end
267
- end
268
-
269
- it 'should handle a model which inherits from a regular object' do
270
- lambda { Publications::ShortStoryCollection.auto_migrate!(:mysql) }.should_not raise_error
271
- end
272
-
273
- it 'should escape a namespaced model' do
274
- Publications::ShortStoryCollection.auto_migrate!(:mysql).should be_true
275
- @adapter.query('SHOW TABLES').should include('publications_short_story_collections')
276
- end
277
- end
278
- end
279
- end
280
-
281
- if HAS_POSTGRES
282
- describe DataMapper::AutoMigrations, '.auto_migrate! with postgres' do
283
- before :all do
284
- @adapter = repository(:postgres).adapter
285
-
286
- DataMapper::Resource.descendants.clear
287
-
288
- @property_class = Struct.new(:name, :type, :nullable, :default, :serial)
289
- end
290
-
291
- after :all do
292
- DataMapper::Resource.descendants.clear
293
- end
294
-
295
- describe 'with postgres' do
296
- before :all do
297
- EveryType.auto_migrate!(:postgres).should be_true
298
-
299
- query = <<-EOS
300
- SELECT
301
- -- Field
302
- "pg_attribute"."attname" AS "Field",
303
- -- Type
304
- CASE "pg_type"."typname"
305
- WHEN 'varchar' THEN 'varchar'
306
- ELSE "pg_type"."typname"
307
- END AS "Type",
308
- -- Null
309
- CASE WHEN "pg_attribute"."attnotnull" THEN ''
310
- ELSE 'YES'
311
- END AS "Null",
312
- -- Default
313
- "pg_attrdef"."adsrc" AS "Default"
314
- FROM "pg_class"
315
- INNER JOIN "pg_attribute"
316
- ON ("pg_class"."oid" = "pg_attribute"."attrelid")
317
- INNER JOIN pg_type
318
- ON ("pg_attribute"."atttypid" = "pg_type"."oid")
319
- LEFT JOIN "pg_attrdef"
320
- ON ("pg_class"."oid" = "pg_attrdef"."adrelid" AND "pg_attribute"."attnum" = "pg_attrdef"."adnum")
321
- WHERE "pg_class"."relname" = ? AND "pg_attribute"."attnum" >= ? AND NOT "pg_attribute"."attisdropped"
322
- ORDER BY "pg_attribute"."attnum"
323
- EOS
324
-
325
- @table_set = @adapter.query(query, 'every_types', 1).inject({}) do |ts,column|
326
- default = column.default
327
- serial = false
328
-
329
- if column.default == "nextval('every_types_serial_seq'::regclass)"
330
- default = nil
331
- serial = true
332
- end
333
-
334
- property = @property_class.new(
335
- column.field,
336
- column.type.upcase,
337
- column.null == 'YES',
338
- default,
339
- serial
340
- )
341
-
342
- ts.update(property.name => property)
343
- end
344
-
345
- # bypass DM to create the record using only the column default values
346
- @adapter.execute('INSERT INTO "every_types" ("serial", "discriminator") VALUES (?, ?)', 1, EveryType)
347
-
348
- @book = repository(:postgres) { EveryType.first }
349
- end
350
-
351
- types = {
352
- :serial => [ Integer, 'INT4', false, nil, 1, true ],
353
- :fixnum => [ Integer, 'INT4', false, '1', 1, false ],
354
- :string => [ String, 'VARCHAR', false, "'default'::character varying", 'default', false ],
355
- :empty => [ String, 'VARCHAR', false, "''::character varying", '', false ],
356
- :date => [ Date, 'DATE', false, "'#{TODAY.strftime('%Y-%m-%d')}'::date", TODAY, false ],
357
- :true_class => [ TrueClass, 'BOOL', false, 'true', true, false ],
358
- :false_class => [ TrueClass, 'BOOL', false, 'false', false, false ],
359
- :text => [ DM::Text, 'TEXT', false, "'text'::text", 'text', false ],
360
- # :class => [ Class, 'VARCHAR(50)', false, 'Class', 'Class', false ],
361
- :big_decimal => [ BigDecimal, 'NUMERIC', false, '1.1', BigDecimal('1.1'), false ],
362
- :float => [ Float, 'FLOAT8', false, '1.1', 1.1, false ],
363
- :date_time => [ DateTime, 'TIMESTAMP', false, "'#{NOW.strftime('%Y-%m-%d %H:%M:%S')}'::timestamp without time zone", NOW, false ],
364
- :time_1 => [ Time, 'TIMESTAMP', false, "'" << TIME_STRING_1.dup << "'::timestamp without time zone", TIME_1, false ],
365
- #The weird zero here is simply because postgresql seems to want to store .10 instead of .1 for this one
366
- #affects anything with an exact tenth of a second (i.e. .1, .2, .3, ...)
367
- :time_2 => [ Time, 'TIMESTAMP', false, "'" << TIME_STRING_2.dup << "0'::timestamp without time zone", TIME_2, false ],
368
- :time_3 => [ Time, 'TIMESTAMP', false, "'" << TIME_STRING_3.dup << "'::timestamp without time zone", TIME_3, false ],
369
- :time_4 => [ Time, 'TIMESTAMP', false, "'" << TIME_STRING_4.dup << "'::timestamp without time zone", TIME_4, false ],
370
- :object => [ Object, 'TEXT', true, nil, nil, false ],
371
- :discriminator => [ DM::Discriminator, 'VARCHAR', false, nil, EveryType, false ],
372
- }
373
-
374
- types.each do |name,(klass,type,nullable,default,key)|
375
- describe "a #{Extlib::Inflection.classify(name.to_s)} property" do
376
- it "should be created as a #{type}" do
377
- @table_set[name.to_s].type.should == type
378
- end
379
-
380
- it "should #{!nullable && 'not'} be nullable".squeeze(' ') do
381
- @table_set[name.to_s].nullable.should == nullable
382
- end
383
-
384
- it "should have a default value #{default.inspect}" do
385
- @table_set[name.to_s].default.should == default
386
- end
387
-
388
- expected_value = types[name][4]
389
- it 'should properly typecast value' do
390
- if DateTime == klass
391
- @book.send(name).to_s.should == expected_value.to_s
392
- else
393
- @book.send(name).should == expected_value
394
- end
395
- end
396
- end
397
- end
398
-
399
- it 'should have 4 indexes: 2 non-unique index, 2 unique index' do
400
- pending 'TODO'
401
- end
402
-
403
- it 'should handle a model which inherits from a regular object' do
404
- lambda { Publications::ShortStoryCollection.auto_migrate!(:postgres) }.should_not raise_error
405
- end
406
-
407
- it 'should escape a namespaced model' do
408
- Publications::ShortStoryCollection.auto_migrate!(:postgres).should be_true
409
- @adapter.query('SELECT "tablename" FROM "pg_tables" WHERE "tablename" NOT LIKE ?', 'pg_%').should include('publications_short_story_collections')
410
- end
411
- end
412
- end
413
- end