sbf-dm-migrations 1.3.0.beta

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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +38 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +468 -0
  5. data/.travis.yml +52 -0
  6. data/Gemfile +61 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +39 -0
  9. data/Rakefile +4 -0
  10. data/db/migrations/1_create_people_table.rb +12 -0
  11. data/db/migrations/2_add_dob_to_people.rb +13 -0
  12. data/db/migrations/config.rb +4 -0
  13. data/dm-migrations.gemspec +20 -0
  14. data/examples/Rakefile +149 -0
  15. data/examples/sample_migration.rb +58 -0
  16. data/examples/sample_migration_spec.rb +46 -0
  17. data/lib/dm-migrations/adapters/dm-do-adapter.rb +304 -0
  18. data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +306 -0
  19. data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +339 -0
  20. data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +152 -0
  21. data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +88 -0
  22. data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +184 -0
  23. data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +21 -0
  24. data/lib/dm-migrations/auto_migration.rb +227 -0
  25. data/lib/dm-migrations/exceptions/duplicate_migration.rb +6 -0
  26. data/lib/dm-migrations/migration.rb +323 -0
  27. data/lib/dm-migrations/migration_runner.rb +76 -0
  28. data/lib/dm-migrations/sql/column.rb +5 -0
  29. data/lib/dm-migrations/sql/mysql.rb +84 -0
  30. data/lib/dm-migrations/sql/oracle.rb +9 -0
  31. data/lib/dm-migrations/sql/postgres.rb +89 -0
  32. data/lib/dm-migrations/sql/sqlite.rb +59 -0
  33. data/lib/dm-migrations/sql/sqlserver.rb +9 -0
  34. data/lib/dm-migrations/sql/table.rb +15 -0
  35. data/lib/dm-migrations/sql/table_creator.rb +105 -0
  36. data/lib/dm-migrations/sql/table_modifier.rb +57 -0
  37. data/lib/dm-migrations/sql.rb +7 -0
  38. data/lib/dm-migrations/version.rb +5 -0
  39. data/lib/dm-migrations.rb +3 -0
  40. data/lib/spec/example/migration_example_group.rb +69 -0
  41. data/lib/spec/matchers/migration_matchers.rb +96 -0
  42. data/spec/integration/auto_migration_spec.rb +590 -0
  43. data/spec/integration/auto_upgrade_spec.rb +41 -0
  44. data/spec/integration/migration_runner_spec.rb +84 -0
  45. data/spec/integration/migration_spec.rb +156 -0
  46. data/spec/integration/sql_spec.rb +290 -0
  47. data/spec/isolated/require_after_setup_spec.rb +24 -0
  48. data/spec/isolated/require_before_setup_spec.rb +24 -0
  49. data/spec/isolated/require_spec.rb +23 -0
  50. data/spec/spec_helper.rb +16 -0
  51. data/spec/unit/migration_spec.rb +501 -0
  52. data/spec/unit/sql/column_spec.rb +14 -0
  53. data/spec/unit/sql/postgres_spec.rb +90 -0
  54. data/spec/unit/sql/sqlite_extensions_spec.rb +103 -0
  55. data/spec/unit/sql/table_creator_spec.rb +91 -0
  56. data/spec/unit/sql/table_modifier_spec.rb +47 -0
  57. data/spec/unit/sql/table_spec.rb +26 -0
  58. data/spec/unit/sql_spec.rb +7 -0
  59. data/tasks/spec.rake +21 -0
  60. data/tasks/yard.rake +9 -0
  61. data/tasks/yardstick.rake +19 -0
  62. metadata +120 -0
@@ -0,0 +1,501 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe 'Migration' do
4
+
5
+ describe 'repository_execute' do
6
+ before(:each) do
7
+ class DefaultKlass
8
+ include DataMapper::Resource
9
+ property :required_property, String, key: true
10
+ end
11
+
12
+ class ContextKlass
13
+ include DataMapper::Resource
14
+ property :required_property, String, key: true
15
+ def self.repository_name
16
+ :not_default_repository
17
+ end
18
+ end
19
+ end
20
+
21
+ it 'sends the method to all models by default' do
22
+ DataMapper.finalize
23
+ expect(DefaultKlass).to receive(:auto_migrate!).with(:default)
24
+ expect(ContextKlass).to receive(:auto_migrate!).with(:not_default_repository)
25
+ DataMapper.auto_migrate!
26
+ end
27
+
28
+ it 'sends the method to only repository models if a repository_name is given' do
29
+ DataMapper.finalize
30
+ expect(DefaultKlass).not_to receive(:auto_migrate!)
31
+ expect(ContextKlass).to receive(:auto_migrate!).with(:not_default_repository)
32
+ DataMapper.auto_migrate!(:not_default_repository)
33
+ end
34
+ end
35
+
36
+ supported_by :postgres, :mysql, :sqlite do
37
+ before do
38
+ @adapter = double('adapter', :class => DataMapper::Spec.adapter.class)
39
+ @repo = double('DataMapper.repository', :adapter => @adapter)
40
+ DataMapper.stub!(:repository).and_return(@repo)
41
+ @m = DataMapper::Migration.new(1, :do_nothing, {}) {}
42
+ @m.stub!(:write) # silence any output
43
+ end
44
+
45
+ [:position, :name, :database, :adapter].each do |meth|
46
+ it "responds to ##{meth}" do
47
+ expect(@m).to respond_to(meth)
48
+ end
49
+ end
50
+
51
+ describe 'initialization' do
52
+ it 'sets @position from the given position' do
53
+ expect(@m.instance_variable_get(:@position)).to eq 1
54
+ end
55
+
56
+ it 'sets @name from the given name' do
57
+ expect(@m.instance_variable_get(:@name)).to eq :do_nothing
58
+ end
59
+
60
+ it 'sets @options from the options hash' do
61
+ expect(@m.instance_variable_get(:@options)).to eq({})
62
+ end
63
+
64
+ it 'sets @repository from the default repository if no :repository option is given' do
65
+ m = DataMapper::Migration.new(1, :do_nothing, {}) {}
66
+
67
+ expect(m.instance_variable_get(:@repository)).to eq :default
68
+ end
69
+
70
+ it 'sets @repository to the specified :repository option' do
71
+ m = DataMapper::Migration.new(1, :do_nothing, :repository => :foobar) {}
72
+
73
+ expect(m.instance_variable_get(:@repository)).to eq :foobar
74
+ end
75
+
76
+ it 'sets @verbose from the options hash' do
77
+ m = DataMapper::Migration.new(1, :do_nothing, :verbose => false) {}
78
+ expect(m.instance_variable_get(:@verbose)).to be(false)
79
+ end
80
+
81
+ it 'sets @verbose to true by default' do
82
+ expect(@m.instance_variable_get(:@verbose)).to be(true)
83
+ end
84
+
85
+ it 'sets the @up_action to nil' do
86
+ expect(@m.instance_variable_get(:@up_action)).to be_nil
87
+ end
88
+
89
+ it 'sets the @down_action to nil' do
90
+ expect(@m.instance_variable_get(:@down_action)).to be_nil
91
+ end
92
+
93
+ it 'evaluates the given block'
94
+
95
+ end
96
+
97
+ it 'sets the @up_action when #up is called with a block' do
98
+ action = lambda {}
99
+ @m.up(&action)
100
+ expect(@m.instance_variable_get(:@up_action)).to eq action
101
+ end
102
+
103
+ it 'sets the @up_action when #up is called with a block' do
104
+ action = lambda {}
105
+ @m.down(&action)
106
+ expect(@m.instance_variable_get(:@down_action)).to eq action
107
+ end
108
+
109
+ describe 'adapter' do
110
+ before(:each) do
111
+ @m.instance_variable_set(:@adapter, nil)
112
+ end
113
+
114
+ it 'determines the class of the adapter to be extended' do
115
+ expect(@adapter).to receive(:class).and_return(DataMapper::Spec.adapter.class)
116
+
117
+ @m.adapter
118
+ end
119
+
120
+ it 'extends the adapter with the right module' do
121
+ expect(@adapter).to receive(:extend).with(SQL.const_get(DataMapper::Spec.adapter_name.capitalize))
122
+
123
+ @m.adapter
124
+ end
125
+
126
+ it 'raises "Unsupported adapter" on an unknown adapter' do
127
+ expect(@adapter).to receive(:class).any_number_of_times.and_return("InvalidAdapter")
128
+
129
+ expect { @m.adapter }.to raise_error
130
+ end
131
+ end
132
+
133
+ describe 'perform_up' do
134
+ before do
135
+ @up_action = mock('proc', :call => true)
136
+ @m.instance_variable_set(:@up_action, @up_action)
137
+ @m.stub!(:needs_up?).and_return(true)
138
+ @m.stub!(:update_migration_info)
139
+ end
140
+
141
+ it 'calls the action assigned to @up_action and return the result' do
142
+ expect(@up_action).to receive(:call).and_return(:result)
143
+ expect(@m.perform_up).to eq :result
144
+ end
145
+
146
+ it 'outputs a status message with the position and name of the migration' do
147
+ expect(@m).to receive(:write).with(/Performing Up Migration #1: do_nothing/)
148
+ @m.perform_up
149
+ end
150
+
151
+ it 'does not run if it doesnt need to be' do
152
+ expect(@m).to receive(:needs_up?).and_return(false)
153
+ expect(@up_action).not_to receive(:call)
154
+ @m.perform_up
155
+ end
156
+
157
+ it 'updates the migration info table' do
158
+ expect(@m).to receive(:update_migration_info).with(:up)
159
+ @m.perform_up
160
+ end
161
+
162
+ it 'does not update the migration info table if the migration does not need run' do
163
+ expect(@m).to receive(:needs_up?).and_return(false)
164
+ expect(@m).not_to receive(:update_migration_info)
165
+ @m.perform_up
166
+ end
167
+
168
+ end
169
+
170
+ describe 'perform_down' do
171
+ before do
172
+ @down_action = mock('proc', :call => true)
173
+ @m.instance_variable_set(:@down_action, @down_action)
174
+ @m.stub!(:needs_down?).and_return(true)
175
+ @m.stub!(:update_migration_info)
176
+ end
177
+
178
+ it 'calls the action assigned to @down_action and return the result' do
179
+ expect(@down_action).to receive(:call).and_return(:result)
180
+ expect(@m.perform_down).to eq :result
181
+ end
182
+
183
+ it 'outputs a status message with the position and name of the migration' do
184
+ expect(@m).to receive(:write).with(/Performing Down Migration #1: do_nothing/)
185
+ @m.perform_down
186
+ end
187
+
188
+ it 'does not run if it doesnt need to be' do
189
+ expect(@m).to receive(:needs_down?).and_return(false)
190
+ expect(@down_action).not_to receive(:call)
191
+ @m.perform_down
192
+ end
193
+
194
+ it 'updates the migration info table' do
195
+ expect(@m).to receive(:update_migration_info).with(:down)
196
+ @m.perform_down
197
+ end
198
+
199
+ it 'does not update the migration info table if the migration does not need run' do
200
+ expect(@m).to receive(:needs_down?).and_return(false)
201
+ expect(@m).not_to receive(:update_migration_info)
202
+ @m.perform_down
203
+ end
204
+
205
+ end
206
+
207
+ describe 'methods used in the action blocks' do
208
+
209
+ describe '#execute' do
210
+ before do
211
+ @adapter.stub!(:execute)
212
+ end
213
+
214
+ it 'sends the SQL it its executing to the adapter execute method' do
215
+ expect(@adapter).to receive(:execute).with('SELECT SOME SQL')
216
+ @m.execute('SELECT SOME SQL')
217
+ end
218
+
219
+ it 'outputs the SQL it is executing' do
220
+ expect(@m).to receive(:write).with(/SELECT SOME SQL/)
221
+ @m.execute('SELECT SOME SQL')
222
+ end
223
+ end
224
+
225
+ describe '#execute' do
226
+ before do
227
+ @adapter.stub!(:select)
228
+ end
229
+
230
+ it 'sends the SQL it its executing to the adapter execute method' do
231
+ expect(@adapter).to receive(:select).with('SELECT SOME SQL')
232
+ @m.select('SELECT SOME SQL')
233
+ end
234
+
235
+ it 'outputs the SQL it is executing' do
236
+ expect(@m).to receive(:write).with(/SELECT SOME SQL/)
237
+ @m.select('SELECT SOME SQL')
238
+ end
239
+ end
240
+
241
+ describe 'helpers' do
242
+ before do
243
+ @m.stub!(:execute) # don't actually run anything
244
+ end
245
+
246
+ describe '#create_table' do
247
+ before do
248
+ @tc = mock('TableCreator', :to_sql => 'CREATE TABLE')
249
+ SQL::TableCreator.stub!(:new).and_return(@tc)
250
+ end
251
+
252
+ it 'creates a new TableCreator object' do
253
+ expect(SQL::TableCreator).to receive(:new).with(@adapter, :users, {}).and_return(@tc)
254
+ @m.create_table(:users) { }
255
+ end
256
+
257
+ it 'converts the TableCreator object to an sql statement' do
258
+ expect(@tc).to receive(:to_sql).and_return('CREATE TABLE')
259
+ @m.create_table(:users) { }
260
+ end
261
+
262
+ it 'executes the create table sql' do
263
+ expect(@m).to receive(:execute).with('CREATE TABLE')
264
+ @m.create_table(:users) { }
265
+ end
266
+
267
+ end
268
+
269
+ describe '#drop_table' do
270
+ it 'quotes the table name' do
271
+ expect(@adapter).to receive(:quote_name).with('users')
272
+ @m.drop_table :users
273
+ end
274
+
275
+ it 'executes the DROP TABLE sql for the table' do
276
+ @adapter.stub!(:quote_name).and_return("'users'")
277
+ expect(@m).to receive(:execute).with(%{DROP TABLE 'users'})
278
+ @m.drop_table :users
279
+ end
280
+
281
+ end
282
+
283
+ describe '#modify_table' do
284
+ before do
285
+ @tm = mock('TableModifier', :statements => [])
286
+ SQL::TableModifier.stub!(:new).and_return(@tm)
287
+ end
288
+
289
+ it 'creates a new TableModifier object' do
290
+ expect(SQL::TableModifier).to receive(:new).with(@adapter, :users, {}).and_return(@tm)
291
+ @m.modify_table(:users){ }
292
+ end
293
+
294
+ it 'gets the statements from the TableModifier object' do
295
+ expect(@tm).to receive(:statements).and_return([])
296
+ @m.modify_table(:users){ }
297
+ end
298
+
299
+ it 'iterates over the statements and execute each one' do
300
+ expect(@tm).to receive(:statements).and_return(['SELECT 1', 'SELECT 2'])
301
+ expect(@m).to receive(:execute).with('SELECT 1')
302
+ expect(@m).to receive(:execute).with('SELECT 2')
303
+ @m.modify_table(:users){ }
304
+ end
305
+
306
+ end
307
+
308
+ describe 'sorting' do
309
+ it 'orders things by position' do
310
+ m1 = DataMapper::Migration.new(1, :do_nothing){}
311
+ m2 = DataMapper::Migration.new(2, :do_nothing_else){}
312
+
313
+ expect(m1 <=> m2).to eq -1
314
+ end
315
+
316
+ it 'orders things by name when they have the same position' do
317
+ m1 = DataMapper::Migration.new(1, :do_nothing_a){}
318
+ m2 = DataMapper::Migration.new(1, :do_nothing_b){}
319
+
320
+ expect(m1 <=> m2).to eq -1
321
+ end
322
+
323
+ end
324
+
325
+ describe 'formatting output' do
326
+ describe '#say' do
327
+ it 'outputs the message' do
328
+ expect(@m).to receive(:write).with(/Paul/)
329
+ @m.say("Paul")
330
+ end
331
+
332
+ it 'indents the message with 4 spaces by default' do
333
+ expect(@m).to receive(:write).with(/^\s{4}/)
334
+ @m.say("Paul")
335
+ end
336
+
337
+ it 'indents the message with a given number of spaces' do
338
+ expect(@m).to receive(:write).with(/^\s{3}/)
339
+ @m.say("Paul", 3)
340
+ end
341
+ end
342
+
343
+ describe '#say_with_time' do
344
+ before do
345
+ @m.stub!(:say)
346
+ end
347
+
348
+ it 'says the message with an indent of 2' do
349
+ expect(@m).to receive(:say).with("Paul", 2)
350
+ @m.say_with_time("Paul"){}
351
+ end
352
+
353
+ it 'outputs the time it took' do
354
+ expect(@m).to receive(:say).with(/\d+/, 2)
355
+ @m.say_with_time("Paul"){}
356
+ end
357
+ end
358
+
359
+ describe '#write' do
360
+ before do
361
+ # need a new migration object, because the main one had #write stubbed to silence output
362
+ @m = DataMapper::Migration.new(1, :do_nothing) {}
363
+ end
364
+
365
+ it 'puts the message' do
366
+ expect(@m).to receive(:puts).with("Paul")
367
+ @m.write("Paul")
368
+ end
369
+
370
+ it 'does not puts the message if @verbose is false' do
371
+ @m.instance_variable_set(:@verbose, false)
372
+ expect(@m).not_to receive(:puts)
373
+ @m.write("Paul")
374
+ end
375
+
376
+ end
377
+
378
+ end
379
+
380
+ describe 'working with the migration_info table' do
381
+ before do
382
+ @adapter.stub!(:storage_exists?).and_return(true)
383
+ # --- Please remove stubs ---
384
+ @adapter.stub!(:quote_name).and_return { |name| "'#{name}'" }
385
+ end
386
+
387
+ describe '#update_migration_info' do
388
+ it 'adds a record of the migration' do
389
+ expect(@m).to receive(:execute).with(
390
+ %Q{INSERT INTO 'migration_info' ('migration_name') VALUES ('do_nothing')}
391
+ )
392
+ @m.update_migration_info(:up)
393
+ end
394
+
395
+ it 'removes the record of the migration' do
396
+ expect(@m).to receive(:execute).with(
397
+ %Q{DELETE FROM 'migration_info' WHERE 'migration_name' = 'do_nothing'}
398
+ )
399
+ @m.update_migration_info(:down)
400
+ end
401
+
402
+ it 'tries to create the migration_info table' do
403
+ expect(@m).to receive(:create_migration_info_table_if_needed)
404
+ @m.update_migration_info(:up)
405
+ end
406
+ end
407
+
408
+ describe '#create_migration_info_table_if_needed' do
409
+ it 'creates the migration info table' do
410
+ expect(@m).to receive(:migration_info_table_exists?).and_return(false)
411
+ expect(@m).to receive(:execute).with(
412
+ %Q{CREATE TABLE 'migration_info' ('migration_name' VARCHAR(255) UNIQUE)}
413
+ )
414
+ @m.create_migration_info_table_if_needed
415
+ end
416
+
417
+ it 'does not try to create the migration info table if it already exists' do
418
+ expect(@m).to receive(:migration_info_table_exists?).and_return(true)
419
+ expect(@m).not_to receive(:execute)
420
+ @m.create_migration_info_table_if_needed
421
+ end
422
+ end
423
+
424
+ it 'quotes the name of the migration for use in sql' do
425
+ expect(@m.quoted_name).to eq %{'do_nothing'}
426
+ end
427
+
428
+ it 'queries the adapter to see if the migration_info table exists' do
429
+ expect(@adapter).to receive(:storage_exists?).with('migration_info').and_return(true)
430
+ expect(@m.migration_info_table_exists?).to eq true
431
+ end
432
+
433
+ describe '#migration_record' do
434
+ it 'queries for the migration' do
435
+ expect(@adapter).to receive(:select).with(
436
+ %Q{SELECT 'migration_name' FROM 'migration_info' WHERE 'migration_name' = 'do_nothing'}
437
+ )
438
+ @m.migration_record
439
+ end
440
+
441
+ it 'does not try to query if the table does not exist' do
442
+ @m.stub!(:migration_info_table_exists?).and_return(false)
443
+ expect(@adapter).not_to receive(:select)
444
+ @m.migration_record
445
+ end
446
+
447
+ end
448
+
449
+ describe '#needs_up?' do
450
+ it 'is true if there is no record' do
451
+ expect(@m).to receive(:migration_record).and_return([])
452
+ expect(@m.needs_up?).to eq true
453
+ end
454
+
455
+ it 'is false if the record exists' do
456
+ expect(@m).to receive(:migration_record).and_return([:not_empty])
457
+ expect(@m.needs_up?).to eq false
458
+ end
459
+
460
+ it 'is true if there is no migration_info table' do
461
+ expect(@m).to receive(:migration_info_table_exists?).and_return(false)
462
+ expect(@m.needs_up?).to eq true
463
+ end
464
+
465
+ end
466
+
467
+ describe '#needs_down?' do
468
+ it 'is false if there is no record' do
469
+ expect(@m).to receive(:migration_record).and_return([])
470
+ expect(@m.needs_down?).to eq false
471
+ end
472
+
473
+ it 'is true if the record exists' do
474
+ expect(@m).to receive(:migration_record).and_return([:not_empty])
475
+ expect(@m.needs_down?).to eq true
476
+ end
477
+
478
+ it 'is false if there is no migration_info table' do
479
+ expect(@m).to receive(:migration_info_table_exists?).and_return(false)
480
+ expect(@m.needs_down?).to eq false
481
+ end
482
+
483
+ end
484
+
485
+ it 'has the adapter quote the migration_info table' do
486
+ expect(@adapter).to receive(:quote_name).with('migration_info').and_return("'migration_info'")
487
+ expect(@m.migration_info_table).to eq "'migration_info'"
488
+ end
489
+
490
+ it 'has a quoted migration_name_column' do
491
+ expect(@adapter).to receive(:quote_name).with('migration_name').and_return("'migration_name'")
492
+ expect(@m.migration_name_column).to eq "'migration_name'"
493
+ end
494
+
495
+ end
496
+
497
+ end
498
+
499
+ end
500
+ end
501
+ end
@@ -0,0 +1,14 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe SQL::Column do
4
+ before do
5
+ @column = SQL::Column.new
6
+ end
7
+
8
+ %w{name type not_null default_value primary_key unique}.each do |meth|
9
+ it "has a ##{meth} attribute" do
10
+ expect(@column).to respond_to(meth.intern)
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,90 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ # a dummy class to include the module into
4
+ class PostgresExtension
5
+ include SQL::Postgres
6
+ end
7
+
8
+ describe "Postgres Extensions" do
9
+ before do
10
+ @pe = PostgresExtension.new
11
+ end
12
+
13
+ it 'supports schema-level transactions' do
14
+ expect(@pe.supports_schema_transactions?).to be(true)
15
+ end
16
+
17
+ it 'supports the serial column attribute' do
18
+ expect(@pe.supports_serial?).to be(true)
19
+ end
20
+
21
+ it 'creates a table object from the name' do
22
+ table = instance_double('Postgres Table')
23
+ expect(SQL::Postgres::Table).to receive(:new).with(@pe, 'users').and_return(table)
24
+
25
+ expect(@pe.table('users')).to eq table
26
+ end
27
+
28
+ describe 'recreating the database'
29
+
30
+ describe 'Table' do
31
+ before do
32
+ @cs1 = instance_double('Column Struct')
33
+ @cs2 = instance_double('Column Struct')
34
+ @adapter = instance_double('adapter', select: [])
35
+ allow(@adapter).to receive(:query_table).with('users').and_return([@cs1, @cs2])
36
+
37
+ @col1 = instance_double('Postgres Column')
38
+ @col2 = instance_double('Postgres Column')
39
+ end
40
+
41
+ it 'initializes columns by querying the table' do
42
+ expect(SQL::Postgres::Column).to receive(:new).with(@cs1).and_return(@col1)
43
+ expect(SQL::Postgres::Column).to receive(:new).with(@cs2).and_return(@col2)
44
+ expect(@adapter).to receive(:query_table).with('users').and_return([@cs1,@cs2])
45
+ SQL::Postgres::Table.new(@adapter, 'users')
46
+ end
47
+
48
+ it 'creates Postgres Column objects from the returned column structs' do
49
+ expect(SQL::Postgres::Column).to receive(:new).with(@cs1).and_return(@col1)
50
+ expect(SQL::Postgres::Column).to receive(:new).with(@cs2).and_return(@col2)
51
+ SQL::Postgres::Table.new(@adapter, 'users')
52
+ end
53
+
54
+ it 'sets the @columns to the looked-up columns' do
55
+ expect(SQL::Postgres::Column).to receive(:new).with(@cs1).and_return(@col1)
56
+ expect(SQL::Postgres::Column).to receive(:new).with(@cs2).and_return(@col2)
57
+ t = SQL::Postgres::Table.new(@adapter, 'users')
58
+ expect(t.columns).to eq [@col1, @col2]
59
+ end
60
+
61
+ describe '#query_column_constraints'
62
+ end
63
+
64
+ describe 'Column' do
65
+ before do
66
+ @cs = instance_double('Struct',
67
+ column_name: 'id',
68
+ data_type: 'integer',
69
+ column_default: 123,
70
+ is_nullable: 'NO')
71
+ @c = SQL::Postgres::Column.new(@cs)
72
+ end
73
+
74
+ it 'sets the name from the column_name value' do
75
+ expect(@c.name).to eq 'id'
76
+ end
77
+
78
+ it 'sets the type from the data_type value' do
79
+ expect(@c.type).to eq 'integer'
80
+ end
81
+
82
+ it 'sets the default_value from the column_default value' do
83
+ expect(@c.default_value).to eq 123
84
+ end
85
+
86
+ it 'sets not_null based on the is_nullable value' do
87
+ expect(@c.not_null).to eq true
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,103 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ # a dummy class to include the module into
4
+ class SqliteExtension
5
+ include SQL::Sqlite
6
+ end
7
+
8
+ describe "SQLite3 Extensions" do
9
+ before do
10
+ @se = SqliteExtension.new
11
+ end
12
+
13
+ it 'supports schema-level transactions' do
14
+ expect(@se.supports_schema_transactions?).to be(true)
15
+ end
16
+
17
+ it 'supports the serial column attribute' do
18
+ expect(@se.supports_serial?).to be(true)
19
+ end
20
+
21
+ it 'creates a table object from the name' do
22
+ table = instance_double('SQLite3 Table')
23
+ expect(SQL::Sqlite::Table).to receive(:new).with(@se, 'users').and_return(table)
24
+
25
+ expect(@se.table('users')).to eq table
26
+ end
27
+
28
+ describe 'recreating the database' do
29
+ before do
30
+ uri = instance_double('URI', path: '/foo/bar.db')
31
+ @se.instance_variable_set('@uri', uri)
32
+ end
33
+
34
+ it "rm's the db file" do
35
+ expect(FileUtils).to receive(:rm_f).with('/foo/bar.db')
36
+ @se.recreate_database
37
+ end
38
+ end
39
+
40
+ describe 'Table' do
41
+ before do
42
+ @cs1 = double('Column Struct')
43
+ @cs2 = double('Column Struct')
44
+ @adapter = double('adapter')
45
+ allow(@adapter).to receive(:table_info).with('users').and_return([@cs1, @cs2])
46
+
47
+ @col1 = double('SQLite3 Column')
48
+ @col2 = double('SQLite3 Column')
49
+ end
50
+
51
+ it 'initializes columns by querying the table' do
52
+ expect(SQL::Sqlite::Column).to receive(:new).with(@cs1).and_return(@col1)
53
+ expect(SQL::Sqlite::Column).to receive(:new).with(@cs2).and_return(@col2)
54
+ expect(@adapter).to receive(:table_info).with('users').and_return([@cs1,@cs2])
55
+ SQL::Sqlite::Table.new(@adapter, 'users')
56
+ end
57
+
58
+ it 'creates SQLite3 Column objects from the returned column structs' do
59
+ expect(SQL::Sqlite::Column).to receive(:new).with(@cs1).and_return(@col1)
60
+ expect(SQL::Sqlite::Column).to receive(:new).with(@cs2).and_return(@col2)
61
+ SQL::Sqlite::Table.new(@adapter, 'users')
62
+ end
63
+
64
+ it 'sets the @columns to the looked-up columns' do
65
+ expect(SQL::Sqlite::Column).to receive(:new).with(@cs1).and_return(@col1)
66
+ expect(SQL::Sqlite::Column).to receive(:new).with(@cs2).and_return(@col2)
67
+ t = SQL::Sqlite::Table.new(@adapter, 'users')
68
+ expect(t.columns).to eq [ @col1, @col2 ]
69
+ end
70
+ end
71
+
72
+ describe 'Column' do
73
+ before do
74
+ @cs = instance_double('Struct',
75
+ name: 'id',
76
+ type: 'integer',
77
+ dflt_value: 123,
78
+ pk: true,
79
+ notnull: 0)
80
+ @c = SQL::Sqlite::Column.new(@cs)
81
+ end
82
+
83
+ it 'sets the name from the name value' do
84
+ expect(@c.name).to eq 'id'
85
+ end
86
+
87
+ it 'sets the type from the type value' do
88
+ expect(@c.type).to eq 'integer'
89
+ end
90
+
91
+ it 'sets the default_value from the dflt_value value' do
92
+ expect(@c.default_value).to eq 123
93
+ end
94
+
95
+ it 'sets the primary_key from the pk value' do
96
+ expect(@c.primary_key).to eq true
97
+ end
98
+
99
+ it 'sets not_null based on the notnull value' do
100
+ expect(@c.not_null).to eq true
101
+ end
102
+ end
103
+ end