sequel-inline_schema 0.0.1
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +3 -0
- data/.document +5 -0
- data/.editorconfig +14 -0
- data/.rdoc_options +16 -0
- data/.simplecov +9 -0
- data/ChangeLog +48 -0
- data/History.md +4 -0
- data/LICENSE.txt +26 -0
- data/Manifest.txt +16 -0
- data/README.md +85 -0
- data/Rakefile +99 -0
- data/lib/sequel/inline_schema.rb +16 -0
- data/lib/sequel/plugins/inline_migrations.rb +475 -0
- data/lib/sequel/plugins/inline_schema.rb +281 -0
- data/spec/sequel/plugins/inline_migrations_spec.rb +283 -0
- data/spec/sequel/plugins/inline_schema_spec.rb +401 -0
- data/spec/spec_helper.rb +24 -0
- metadata +217 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# -*- ruby -*-
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
# frozen-string-literal: true
|
|
4
|
+
|
|
5
|
+
require 'tsort'
|
|
6
|
+
require 'sequel'
|
|
7
|
+
|
|
8
|
+
# A replacement for Sequel's old built in schema plugin. It allows you to define
|
|
9
|
+
# your schema directly in the model using Model.set_schema (which takes a block
|
|
10
|
+
# similar to Database#create_table), and use Model.create_table to create a
|
|
11
|
+
# table using the schema information.
|
|
12
|
+
#
|
|
13
|
+
# ## Usage
|
|
14
|
+
#
|
|
15
|
+
# There are several ways to use this plugin.
|
|
16
|
+
#
|
|
17
|
+
# Add the schema methods to all model subclasses:
|
|
18
|
+
#
|
|
19
|
+
# Sequel::Model.plugin :inline_schema
|
|
20
|
+
#
|
|
21
|
+
# Add the schema methods to a particular class:
|
|
22
|
+
#
|
|
23
|
+
# Album.plugin :inline_schema
|
|
24
|
+
# Album.set_schema { ... }
|
|
25
|
+
# Album.create_table?
|
|
26
|
+
#
|
|
27
|
+
# Add the schema methods to an abstract base class:
|
|
28
|
+
#
|
|
29
|
+
# # lib/acme/model.rb
|
|
30
|
+
# require 'sequel'
|
|
31
|
+
# require 'acme'
|
|
32
|
+
#
|
|
33
|
+
# module ACME
|
|
34
|
+
# Model = Class.new( Sequel::Model )
|
|
35
|
+
# Model.def_Model( ACME )
|
|
36
|
+
#
|
|
37
|
+
# class Model
|
|
38
|
+
# plugin :inline_schema
|
|
39
|
+
# end
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# # lib/acme/product.rb
|
|
43
|
+
# require 'acme/model'
|
|
44
|
+
#
|
|
45
|
+
# class ACME::Product < ACME::Model( :products )
|
|
46
|
+
#
|
|
47
|
+
# set_schema do
|
|
48
|
+
# primary_key :id
|
|
49
|
+
# String :sku, null: false
|
|
50
|
+
# String :name, null: false
|
|
51
|
+
# ...
|
|
52
|
+
# end
|
|
53
|
+
#
|
|
54
|
+
# end
|
|
55
|
+
#
|
|
56
|
+
# ## Notable Model Methods
|
|
57
|
+
#
|
|
58
|
+
# See Sequel::Plugins::InlineSchema::ClassMethods for documentation for the methods the
|
|
59
|
+
# plugin adds to your model class/es.
|
|
60
|
+
#
|
|
61
|
+
# Of particular note:
|
|
62
|
+
#
|
|
63
|
+
# A model class with an inline schema has several methods for creating/dropping its
|
|
64
|
+
# associated table:
|
|
65
|
+
#
|
|
66
|
+
# * create_table
|
|
67
|
+
# * create_table!
|
|
68
|
+
# * create_table?
|
|
69
|
+
# * table_exists?
|
|
70
|
+
# * drop_table
|
|
71
|
+
# * drop_table?
|
|
72
|
+
#
|
|
73
|
+
# If you use it with an abstract base class, you can ask the base class which of
|
|
74
|
+
# its subclasses need their tables created:
|
|
75
|
+
#
|
|
76
|
+
# * uninstalled_tables
|
|
77
|
+
#
|
|
78
|
+
# It can also define hooks for creating and dropping the table:
|
|
79
|
+
#
|
|
80
|
+
# * before_create_table
|
|
81
|
+
# * after_create_table
|
|
82
|
+
# * before_drop_table
|
|
83
|
+
# * after_drop_table
|
|
84
|
+
#
|
|
85
|
+
# As with other Sequel
|
|
86
|
+
# [model hooks](http://sequel.jeremyevans.net/rdoc/files/doc/model_hooks_rdoc.html),
|
|
87
|
+
# you can prevent the action from the `before_*` hooks by calling `cancel_action`.
|
|
88
|
+
module Sequel::Plugins::InlineSchema
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
### Sequel plugin API -- called the first time the plugin is loaded for this
|
|
92
|
+
### +model+.
|
|
93
|
+
def self::apply( model, *args ) # :nodoc:
|
|
94
|
+
model.plugin( :subclasses ) # track subclasses
|
|
95
|
+
model.extend( TSort )
|
|
96
|
+
model.require_valid_table = false
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# Sequel plugin API -- add these methods to model classes which load the plugin.
|
|
101
|
+
module ClassMethods
|
|
102
|
+
|
|
103
|
+
### Creates table, using the column information from set_schema.
|
|
104
|
+
def create_table( *args, &block )
|
|
105
|
+
self.set_schema( *args, &block ) if block
|
|
106
|
+
self.before_create_table
|
|
107
|
+
self.db.create_table( self.table_name, generator: self.schema )
|
|
108
|
+
@db_schema = get_db_schema( true )
|
|
109
|
+
self.after_create_table
|
|
110
|
+
return self.columns
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
### Drops the table if it exists and then runs create_table. Should probably
|
|
115
|
+
### not be used except in testing.
|
|
116
|
+
def create_table!( *args, &block )
|
|
117
|
+
self.drop_table?
|
|
118
|
+
return self.create_table( *args, &block )
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
### Creates the table unless the table already exists
|
|
123
|
+
def create_table?( *args, &block )
|
|
124
|
+
self.create_table( *args, &block ) unless self.table_exists?
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
### Called before the table is created.
|
|
129
|
+
def before_create_table
|
|
130
|
+
# No-op
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
### Called after the table is created.
|
|
135
|
+
def after_create_table
|
|
136
|
+
# No-op
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
### Drops table. If the table doesn't exist, this will probably raise an error.
|
|
141
|
+
def drop_table
|
|
142
|
+
self.before_drop_table
|
|
143
|
+
self.db.drop_table( self.table_name )
|
|
144
|
+
self.after_drop_table
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
### Drops table if it already exists, do nothing if it doesn't exist.
|
|
149
|
+
def drop_table?
|
|
150
|
+
self.db.drop_table?( self.table_name )
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
### Called before the table is dropped.
|
|
155
|
+
def before_drop_table
|
|
156
|
+
# No-op
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
### Called after the table is dropped.
|
|
161
|
+
def after_drop_table
|
|
162
|
+
# No-op
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
### Returns the table schema created with set_schema.
|
|
167
|
+
def schema
|
|
168
|
+
if !@schema && @schema_block
|
|
169
|
+
self.set_dataset( self.db[@schema_name] ) if @schema_name
|
|
170
|
+
@schema = self.db.create_table_generator( &@schema_block )
|
|
171
|
+
self.set_primary_key( @schema.primary_key_name ) if @schema.primary_key_name
|
|
172
|
+
end
|
|
173
|
+
return @schema || ( superclass.schema unless superclass == Sequel::Model )
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
### Defines a table schema (see Schema::CreateTableGenerator for more information).
|
|
178
|
+
###
|
|
179
|
+
### This will also set the dataset if you provide a +name+, as well as setting
|
|
180
|
+
### the primary key if you define one in the passed block.
|
|
181
|
+
###
|
|
182
|
+
### Since this plugin allows you to declare the schema inline with the model
|
|
183
|
+
### class that acts as its interface, the table will not always exist when the
|
|
184
|
+
### class loads, so calling #set_schema will call require_valid_table to `false`
|
|
185
|
+
### for you. You can disable this by passing `require_table: true`.
|
|
186
|
+
def set_schema( name=nil, require_table: false, &block )
|
|
187
|
+
self.require_valid_table = require_table
|
|
188
|
+
@schema = nil
|
|
189
|
+
@schema_name = name
|
|
190
|
+
@schema_block = block
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
### Returns true if table exists, false otherwise.
|
|
195
|
+
def table_exists?
|
|
196
|
+
return self.db.table_exists?( self.table_name )
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
### Table-creation hook; called on a model class before its table is created.
|
|
201
|
+
def before_create_table
|
|
202
|
+
return true
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
### Table-creation hook; called on a model class after its table is created.
|
|
207
|
+
def after_create_table
|
|
208
|
+
return true
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
### Return an Array of model table names that don't yet exist, in the order they
|
|
213
|
+
### need to be created to satisfy foreign key constraints.
|
|
214
|
+
def uninstalled_tables
|
|
215
|
+
self.db.log_info " searching for unbacked model classes..."
|
|
216
|
+
|
|
217
|
+
self.tsort.find_all do |modelclass|
|
|
218
|
+
next unless modelclass.name && modelclass.name != ''
|
|
219
|
+
!modelclass.table_exists?
|
|
220
|
+
end.uniq( &:table_name )
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
#########
|
|
225
|
+
protected
|
|
226
|
+
#########
|
|
227
|
+
|
|
228
|
+
### Raise an appropriate Sequel::HookFailure exception for the specified +type+.
|
|
229
|
+
def raise_hook_failure( type=nil )
|
|
230
|
+
msg = case type
|
|
231
|
+
when String
|
|
232
|
+
type
|
|
233
|
+
when Symbol
|
|
234
|
+
"the #{type} hook failed"
|
|
235
|
+
else
|
|
236
|
+
"a hook failed"
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
raise Sequel::HookFailed.new( msg, self )
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
### Cancel the currently-running before_* hook. If a +msg+ is given, use it when
|
|
244
|
+
### constructing the HookFailed exception.
|
|
245
|
+
def cancel_action( msg=nil )
|
|
246
|
+
self.raise_hook_failure( msg )
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
### TSort API -- yield each model class.
|
|
251
|
+
def tsort_each_node( &block )
|
|
252
|
+
self.descendents.select( &:name ).each( &block )
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
### TSort API -- yield each of the given +model_class+'s dependent model
|
|
257
|
+
### classes.
|
|
258
|
+
def tsort_each_child( model_class ) # :yields: model_class
|
|
259
|
+
# Include (non-anonymous) parents other than Model
|
|
260
|
+
model_class.ancestors[1..-1].
|
|
261
|
+
select {|cl| cl < self }.
|
|
262
|
+
select( &:name ).
|
|
263
|
+
each do |parentclass|
|
|
264
|
+
yield( parentclass )
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Include associated classes for which this model class's table has a
|
|
268
|
+
# foreign key
|
|
269
|
+
model_class.association_reflections.each do |name, config|
|
|
270
|
+
next if config[:polymorphic]
|
|
271
|
+
|
|
272
|
+
associated_class = config.associated_class
|
|
273
|
+
|
|
274
|
+
yield( associated_class ) if config[:type] == :many_to_one
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
end # module ClassMethods
|
|
280
|
+
|
|
281
|
+
end # module Sequel::Plugin::Schema
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
|
2
|
+
|
|
3
|
+
require_relative '../../spec_helper'
|
|
4
|
+
|
|
5
|
+
require 'sequel'
|
|
6
|
+
require 'sequel/model'
|
|
7
|
+
require 'sequel/inline_schema'
|
|
8
|
+
require 'sequel/plugins/inline_migrations'
|
|
9
|
+
|
|
10
|
+
describe Sequel::Plugins::InlineMigrations do
|
|
11
|
+
|
|
12
|
+
let( :db ) { Sequel.connect('mock://postgres', logger: Loggability[Sequel::InlineSchema]) }
|
|
13
|
+
|
|
14
|
+
let( :model_class ) do
|
|
15
|
+
cls = Class.new( Sequel::Model ) do
|
|
16
|
+
def self::name; "Thing"; end
|
|
17
|
+
end
|
|
18
|
+
cls.dataset = db[:things]
|
|
19
|
+
cls.plugin( :inline_migrations )
|
|
20
|
+
cls
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
it "also adds the 'subclasses' and 'inline_schema' plugins to including models" do
|
|
25
|
+
expect( model_class ).to respond_to( :create_table )
|
|
26
|
+
expect( model_class ).to respond_to( :descendents )
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
it "allows a migration to be defined for the class" do
|
|
31
|
+
model_class.migration( '20110308_1335_simple', "A very simple migration." ) do
|
|
32
|
+
change do
|
|
33
|
+
alter_table(:things) do
|
|
34
|
+
add_column :age, :number
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
migrations = model_class.migrations
|
|
40
|
+
|
|
41
|
+
expect( migrations.size ).to eq( 1 )
|
|
42
|
+
expect( migrations ).to have_key( '20110308_1335_simple' )
|
|
43
|
+
expect( migrations['20110308_1335_simple'] ).to be_a( Sequel::SimpleMigration )
|
|
44
|
+
expect( migrations['20110308_1335_simple'].name ).to eq( '20110308_1335_simple' )
|
|
45
|
+
expect( migrations['20110308_1335_simple'].model_class ).to eq( model_class )
|
|
46
|
+
expect( migrations['20110308_1335_simple'].description ).to eq( 'A very simple migration.' )
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
it "adds existing migrations to the migrations table on table creation" do
|
|
51
|
+
model_class.migration( '20110404_1817_index_name', "Add an index to the name field" ) do
|
|
52
|
+
change do
|
|
53
|
+
alter_table(:things) do
|
|
54
|
+
add_index :name
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
model_class.db.columns = [ :name, :model_class ]
|
|
60
|
+
model_class.db.fetch = nil
|
|
61
|
+
|
|
62
|
+
model_class.create_table
|
|
63
|
+
|
|
64
|
+
expect( model_class.db.sqls.last ).to eq(
|
|
65
|
+
%Q{INSERT INTO "schema_migrations" ("name", "model_class") } +
|
|
66
|
+
%Q{VALUES ('20110404_1817_index_name', 'Thing') RETURNING "id"}
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
it "ignores migrations which have been removed" do
|
|
72
|
+
db.fetch = {
|
|
73
|
+
name: '20140603_1139_add_unique_email_constraint',
|
|
74
|
+
model_class: model_class.name
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
migrator = model_class.migrator
|
|
78
|
+
migrations = migrator.get_partitioned_migrations
|
|
79
|
+
|
|
80
|
+
expect( migrations ).to be_an( Array )
|
|
81
|
+
expect( migrations.size ).to eq( 2 )
|
|
82
|
+
expect( migrations ).to all( be_empty )
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
it "can migrate up" do
|
|
87
|
+
model_class.migration( '20110308_1335_simple', "A very simple migration." ) do
|
|
88
|
+
change do
|
|
89
|
+
alter_table(:things) do
|
|
90
|
+
add_column :age, :number
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
model_class.migrate
|
|
96
|
+
|
|
97
|
+
expect( db.sqls ).to include(
|
|
98
|
+
%Q{ALTER TABLE "things" ADD COLUMN "age" number}
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
it "doesn't try to apply already-applied migrations" do
|
|
104
|
+
model_class.migration( '20110308_1335_simple', "A very simple migration." ) do
|
|
105
|
+
change do
|
|
106
|
+
alter_table(:things) do
|
|
107
|
+
add_column :age, :number
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
model_class.migration( '20110711_1623_another_simple', "A later simple migration." ) do
|
|
112
|
+
change do
|
|
113
|
+
alter_table(:things) do
|
|
114
|
+
add_column :strength, :number
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
db.fetch = Proc.new do |query|
|
|
120
|
+
case query
|
|
121
|
+
when /SELECT .* FROM "schema_migrations"/
|
|
122
|
+
[{name: '20110308_1335_simple', model_class: 'Things'}]
|
|
123
|
+
else
|
|
124
|
+
[]
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
model_class.migrate
|
|
128
|
+
|
|
129
|
+
statements = db.sqls
|
|
130
|
+
expect( statements ).to_not include(
|
|
131
|
+
%Q{ALTER TABLE "things" ADD COLUMN "age" number}
|
|
132
|
+
)
|
|
133
|
+
expect( statements ).to include(
|
|
134
|
+
%Q{ALTER TABLE "things" ADD COLUMN "strength" number}
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
it "can migrate up to a particular migration" do
|
|
140
|
+
model_class.migration( '20110308_1335_simple', "A very simple migration." ) do
|
|
141
|
+
change do
|
|
142
|
+
alter_table(:things) do
|
|
143
|
+
add_column :age, :number
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
model_class.migration( '20110711_1623_another_simple', "A later simple migration." ) do
|
|
148
|
+
change do
|
|
149
|
+
alter_table(:things) do
|
|
150
|
+
add_column :strength, :number
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
model_class.migrate( '20110308_1335_simple' )
|
|
156
|
+
|
|
157
|
+
statements = db.sqls
|
|
158
|
+
expect( statements ).to include(
|
|
159
|
+
%Q{ALTER TABLE "things" ADD COLUMN "age" number}
|
|
160
|
+
)
|
|
161
|
+
expect( statements ).to_not include(
|
|
162
|
+
%Q{ALTER TABLE "things" ADD COLUMN "strength" number}
|
|
163
|
+
)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
it "can reverse migrate down to a particular migration" do
|
|
168
|
+
model_class.migration( '20110308_1335_simple', "A very simple migration." ) do
|
|
169
|
+
change do
|
|
170
|
+
alter_table(:things) do
|
|
171
|
+
add_column :age, :number
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
model_class.migration( '20110711_1623_another_simple', "A later simple migration." ) do
|
|
176
|
+
change do
|
|
177
|
+
alter_table(:things) do
|
|
178
|
+
add_column :strength, :number
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
db.fetch = Proc.new do |query|
|
|
184
|
+
case query
|
|
185
|
+
when /SELECT .* FROM "schema_migrations"/
|
|
186
|
+
[{name: '20110308_1335_simple', model_class: 'Things'}]
|
|
187
|
+
else
|
|
188
|
+
[]
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
model_class.migrate( '20110308_1335_simple' )
|
|
192
|
+
|
|
193
|
+
statements = db.sqls
|
|
194
|
+
expect( statements ).to include(
|
|
195
|
+
%Q{ALTER TABLE "things" DROP COLUMN "age"}
|
|
196
|
+
)
|
|
197
|
+
expect( statements ).to_not include(
|
|
198
|
+
%Q{ALTER TABLE "things" DROP COLUMN "strength"}
|
|
199
|
+
)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
describe "hooks" do
|
|
204
|
+
|
|
205
|
+
let( :model_class ) do
|
|
206
|
+
class_obj = super()
|
|
207
|
+
class_obj.migration( '20110308_1335_simple', "A very simple migration." ) do
|
|
208
|
+
change do
|
|
209
|
+
alter_table(:things) do
|
|
210
|
+
add_column :age, :number
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
class_obj.singleton_class.send( :attr_accessor, :called )
|
|
215
|
+
class_obj.called = {}
|
|
216
|
+
class_obj
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
it "calls a hook before applying pending migrations" do
|
|
221
|
+
def model_class.before_migration
|
|
222
|
+
self.called[ :before_migration ] = true
|
|
223
|
+
super
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
model_class.migrate
|
|
227
|
+
|
|
228
|
+
expect( model_class.called ).to include( :before_migration )
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
it "allows cancellation of migration from the before_migration hook" do
|
|
233
|
+
def model_class.before_migration
|
|
234
|
+
self.called[ :before_migration ] = true
|
|
235
|
+
cancel_action
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
expect {
|
|
239
|
+
model_class.migrate
|
|
240
|
+
}.to raise_error( Sequel::HookFailed, /hook failed/i )
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
it "allows cancellation of migration with a message from the before_migration hook" do
|
|
245
|
+
def model_class.before_migration
|
|
246
|
+
self.called[ :before_migration ] = true
|
|
247
|
+
cancel_action( "Wait, don't migrate yet!" )
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
expect {
|
|
251
|
+
model_class.migrate
|
|
252
|
+
}.to raise_error( Sequel::HookFailed, "Wait, don't migrate yet!" )
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
it "allows cancellation of migration with a Symbol from the before_migration hook" do
|
|
257
|
+
def model_class.before_migration
|
|
258
|
+
self.called[ :before_migration ] = true
|
|
259
|
+
cancel_action( :before_migration )
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
expect {
|
|
263
|
+
model_class.migrate
|
|
264
|
+
}.to raise_error( Sequel::HookFailed, /before_migration/ )
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
it "calls a hook after migration" do
|
|
269
|
+
def model_class.after_migration
|
|
270
|
+
self.called[ :after_migration ] = true
|
|
271
|
+
super
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
model_class.migrate
|
|
275
|
+
|
|
276
|
+
expect( model_class.called ).to include( :after_migration )
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# vim: set nosta noet ts=4 sw=4:
|