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
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6037f75d98e75ad634497e1000fdf8cac67cd388a366dc01d73e7a4f00897f15
|
|
4
|
+
data.tar.gz: 8c6d0fe5f0146d296e85a3e074cf28394e803104c93253e1f200c04274da3ba5
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d5bf204ce162b8dae4e8780202f5031c2c7a48bf2f3f3eaa18552e2a346c9096a6c046a2e6c5232eb3f3f175314e332fa95d51c11a29711f848135d7f7701dd9
|
|
7
|
+
data.tar.gz: 2eed48961ec313876ecc72aa512d53f7cdca5ab0792fe93309c01d359d8dbe72489f02ce91e5250769580b1f00a8cae25f449219b77a5b8d8c207332605fc551
|
checksums.yaml.gz.sig
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
����&����sȻc�9�&�gDX��n��%���i��,�,����.|���>E�Cs��*���&36h'���J����S5��|4j
|
data.tar.gz.sig
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
���Q.���e��Đ�xzEm��E�aQ��M'�5"�-`�����;w���C��?�[b��R�Z���m��v��`�2 �2�.�I��4�ң�~h�B:��;EL�C�=�P�:j�������T��j}�ɵuz�{�`p�dO��?�����Y�X�&!YQ
|
|
2
|
+
����v�a��Lk��y:\D�e�'� O���لR
|
|
3
|
+
�n99*�ԃ�ĽU�k�q�m��]5���W�u���ZzT.�g�S�t��J=���Y��?��a�{��Н(���O�M6�-{�;).�=�"�'ϳ�/c+�L����T�z�Ȋ�٘���U?��K�� ݶ����q+�K7�VX,7C���?HM��a`K&Wv�D�
|
data/.document
ADDED
data/.editorconfig
ADDED
data/.rdoc_options
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
--- !ruby/object:RDoc::Options
|
|
2
|
+
encoding: UTF-8
|
|
3
|
+
static_path: []
|
|
4
|
+
rdoc_include:
|
|
5
|
+
- .
|
|
6
|
+
charset: UTF-8
|
|
7
|
+
exclude:
|
|
8
|
+
hyperlink_all: false
|
|
9
|
+
line_numbers: false
|
|
10
|
+
main_page: README.md
|
|
11
|
+
markup: markdown
|
|
12
|
+
show_hash: false
|
|
13
|
+
tab_width: 8
|
|
14
|
+
title: sequel-plugins-inline_schema Documentation
|
|
15
|
+
visibility: :protected
|
|
16
|
+
webcvs:
|
data/.simplecov
ADDED
data/ChangeLog
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
2018-07-10 Michael Granger <ged@FaerieMUD.org>
|
|
2
|
+
|
|
3
|
+
* .hgtags:
|
|
4
|
+
Added tag v0.0.1 for changeset 5f6554f4bd40
|
|
5
|
+
[8fe6f86ec7c7] [tip]
|
|
6
|
+
|
|
7
|
+
* .hgsigs:
|
|
8
|
+
Added signature for changeset f94a7b19d4de
|
|
9
|
+
[5f6554f4bd40] [v0.0.1]
|
|
10
|
+
|
|
11
|
+
* .hgignore, History.md, README.md, Rakefile, sequel-
|
|
12
|
+
inline_schema.gemspec:
|
|
13
|
+
Prep for first release.
|
|
14
|
+
[f94a7b19d4de]
|
|
15
|
+
|
|
16
|
+
2017-09-28 Michael Granger <ged@FaerieMUD.org>
|
|
17
|
+
|
|
18
|
+
* lib/sequel/plugins/inline_migrations.rb,
|
|
19
|
+
lib/sequel/plugins/inline_schema.rb:
|
|
20
|
+
Fix documentation formatting, add some more details about migrations
|
|
21
|
+
[f7de01d27012] [github/master]
|
|
22
|
+
|
|
23
|
+
2017-09-27 Michael Granger <ged@FaerieMUD.org>
|
|
24
|
+
|
|
25
|
+
* README.md:
|
|
26
|
+
Fix README links.
|
|
27
|
+
[81085384e8eb]
|
|
28
|
+
|
|
29
|
+
* lib/sequel/plugins/inline_schema.rb,
|
|
30
|
+
spec/sequel/plugins/inline_schema_spec.rb:
|
|
31
|
+
More documentation updates, add drop_table hooks.
|
|
32
|
+
[dc2231fc945a]
|
|
33
|
+
|
|
34
|
+
* .hgignore, README.md, lib/sequel/plugins/inline_migrations.rb,
|
|
35
|
+
lib/sequel/plugins/inline_schema.rb:
|
|
36
|
+
Documentation fixes/additions.
|
|
37
|
+
[4783fffe2ab9]
|
|
38
|
+
|
|
39
|
+
* .document, .editorconfig, .gems, .hgignore, .pryrc, .rdoc_options,
|
|
40
|
+
.ruby-gemset, .ruby-version, .simplecov, Gemfile, History.md,
|
|
41
|
+
LICENSE.txt, Manifest.txt, README.md, Rakefile, certs/ged.pem,
|
|
42
|
+
lib/sequel/inline_schema.rb,
|
|
43
|
+
lib/sequel/plugins/inline_migrations.rb,
|
|
44
|
+
lib/sequel/plugins/inline_schema.rb, sequel-inline_schema.gemspec,
|
|
45
|
+
spec/sequel/plugins/inline_migrations_spec.rb,
|
|
46
|
+
spec/sequel/plugins/inline_schema_spec.rb, spec/spec_helper.rb:
|
|
47
|
+
Initial implementation
|
|
48
|
+
[fe2f291518ce]
|
data/History.md
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
This plugin uses code from the Sequel project under the MIT License:
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2007-2008 Sharon Rosner
|
|
4
|
+
Copyright (c) 2008-2017 Jeremy Evans
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to
|
|
8
|
+
deal in the Software without restriction, including without limitation the
|
|
9
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
10
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
19
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
20
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
21
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
The rest is licensed under the same terms, but:
|
|
24
|
+
|
|
25
|
+
Copyright (c) 2017, Michael Granger
|
|
26
|
+
|
data/Manifest.txt
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
.document
|
|
2
|
+
.editorconfig
|
|
3
|
+
.rdoc_options
|
|
4
|
+
.simplecov
|
|
5
|
+
ChangeLog
|
|
6
|
+
History.md
|
|
7
|
+
LICENSE.txt
|
|
8
|
+
Manifest.txt
|
|
9
|
+
README.md
|
|
10
|
+
Rakefile
|
|
11
|
+
lib/sequel/inline_schema.rb
|
|
12
|
+
lib/sequel/plugins/inline_migrations.rb
|
|
13
|
+
lib/sequel/plugins/inline_schema.rb
|
|
14
|
+
spec/sequel/plugins/inline_migrations_spec.rb
|
|
15
|
+
spec/sequel/plugins/inline_schema_spec.rb
|
|
16
|
+
spec/spec_helper.rb
|
data/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# sequel-inline_schema
|
|
2
|
+
|
|
3
|
+
home
|
|
4
|
+
: http://bitbucket.org/ged/sequel-inlineschema
|
|
5
|
+
|
|
6
|
+
github
|
|
7
|
+
: https://github.com/ged/sequel-inlineschema
|
|
8
|
+
|
|
9
|
+
docs
|
|
10
|
+
: http://deveiate.org/code/sequel-inline_schema
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## Description
|
|
14
|
+
|
|
15
|
+
This is a set of plugins for Sequel for declaring a model's table schema and
|
|
16
|
+
any migrations in the class itself (similar to the legacy `schema` plugin).
|
|
17
|
+
|
|
18
|
+
It has only really been tested with PostgreSQL, but patches that make it more generic are welcomed.
|
|
19
|
+
|
|
20
|
+
The two plugins are:
|
|
21
|
+
|
|
22
|
+
* Sequel::Plugins::InlineSchema
|
|
23
|
+
* Sequel::Plugins::InlineMigrations
|
|
24
|
+
|
|
25
|
+
Examples and usage documentation are included there.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## Prerequisites
|
|
29
|
+
|
|
30
|
+
* Ruby >= 2.4
|
|
31
|
+
* Sequel >= 5.0
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
$ gem install sequel-inline_schema
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## Contributing
|
|
40
|
+
|
|
41
|
+
You can check out the current development source with Mercurial via its
|
|
42
|
+
[project page][bitbucket]. Or if you prefer Git, via [its Github
|
|
43
|
+
mirror][github].
|
|
44
|
+
|
|
45
|
+
After checking out the source, run:
|
|
46
|
+
|
|
47
|
+
$ rake newb
|
|
48
|
+
|
|
49
|
+
This task will install any missing dependencies, run the tests/specs,
|
|
50
|
+
and generate the API documentation.
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
|
|
55
|
+
This plugin uses code from the Sequel project under the MIT License:
|
|
56
|
+
|
|
57
|
+
Copyright (c) 2007-2008 Sharon Rosner
|
|
58
|
+
Copyright (c) 2008-2017 Jeremy Evans
|
|
59
|
+
|
|
60
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
61
|
+
of this software and associated documentation files (the "Software"), to
|
|
62
|
+
deal in the Software without restriction, including without limitation the
|
|
63
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
64
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
|
65
|
+
furnished to do so, subject to the following conditions:
|
|
66
|
+
|
|
67
|
+
The above copyright notice and this permission notice shall be included in
|
|
68
|
+
all copies or substantial portions of the Software.
|
|
69
|
+
|
|
70
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
71
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
72
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
73
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
74
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
75
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
76
|
+
|
|
77
|
+
The rest is licensed under the same terms, but:
|
|
78
|
+
|
|
79
|
+
Copyright (c) 2017-2018, Michael Granger
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
[bitbucket]: http://bitbucket.org/ged/sequel-inlineschema
|
|
84
|
+
[github]: https://github.com/ged/sequel-inlineschema
|
|
85
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'hoe'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
abort "This Rakefile requires hoe (gem install hoe)"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
GEMSPEC = 'sequel-inline_schema.gemspec'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Hoe.plugin :mercurial
|
|
13
|
+
Hoe.plugin :signing
|
|
14
|
+
Hoe.plugin :deveiate
|
|
15
|
+
|
|
16
|
+
Hoe.plugins.delete :rubyforge
|
|
17
|
+
|
|
18
|
+
hoespec = Hoe.spec 'sequel-inline_schema' do |spec|
|
|
19
|
+
|
|
20
|
+
spec.readme_file = 'README.md'
|
|
21
|
+
spec.history_file = 'History.md'
|
|
22
|
+
spec.urls = {
|
|
23
|
+
home: 'http://bitbucket.org/ged/sequel-inline_schema',
|
|
24
|
+
code: 'http://bitbucket.org/ged/sequel-inline_schema',
|
|
25
|
+
docs: 'http://deveiate.org/code/sequel-inline_schema',
|
|
26
|
+
github: 'http://github.com/ged/sequel-inline_schema',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
spec.extra_rdoc_files = FileList[ '*.rdoc', '*.md' ]
|
|
30
|
+
spec.license 'BSD-3-Clause'
|
|
31
|
+
|
|
32
|
+
spec.developer 'Michael Granger', 'ged@FaerieMUD.org'
|
|
33
|
+
|
|
34
|
+
spec.dependency 'sequel', '~> 5.0'
|
|
35
|
+
|
|
36
|
+
spec.dependency 'hoe-deveiate', '~> 0.9', :developer
|
|
37
|
+
spec.dependency 'simplecov', '~> 0.13', :developer
|
|
38
|
+
spec.dependency 'rdoc-generator-fivefish', '~> 0.3', :developer
|
|
39
|
+
|
|
40
|
+
spec.require_ruby_version( '>=2.4.0' )
|
|
41
|
+
spec.hg_sign_tags = true if spec.respond_to?( :hg_sign_tags= )
|
|
42
|
+
spec.check_history_on_release = true if spec.respond_to?( :check_history_on_release= )
|
|
43
|
+
|
|
44
|
+
spec.rdoc_locations << "deveiate:/usr/local/www/public/code/#{remote_rdoc_dir}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
ENV['VERSION'] ||= hoespec.spec.version.to_s
|
|
49
|
+
|
|
50
|
+
# Run the tests before checking in
|
|
51
|
+
task 'hg:precheckin' => [ :check_history, :check_manifest, :gemspec, :spec ]
|
|
52
|
+
|
|
53
|
+
task :test => :spec
|
|
54
|
+
|
|
55
|
+
# Rebuild the ChangeLog immediately before release
|
|
56
|
+
task :prerelease => 'ChangeLog'
|
|
57
|
+
CLOBBER.include( 'ChangeLog' )
|
|
58
|
+
|
|
59
|
+
desc "Build a coverage report"
|
|
60
|
+
task :coverage do
|
|
61
|
+
ENV["COVERAGE"] = 'yes'
|
|
62
|
+
Rake::Task[:spec].invoke
|
|
63
|
+
end
|
|
64
|
+
CLOBBER.include( 'coverage' )
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Use the fivefish formatter for docs generated from development checkout
|
|
68
|
+
if File.directory?( '.hg' )
|
|
69
|
+
require 'rdoc/task'
|
|
70
|
+
|
|
71
|
+
Rake::Task[ 'docs' ].clear
|
|
72
|
+
RDoc::Task.new( 'docs' ) do |rdoc|
|
|
73
|
+
|
|
74
|
+
rdoc.markup = 'markdown'
|
|
75
|
+
rdoc.main = "README.md"
|
|
76
|
+
rdoc.rdoc_files.include( "*.md", "ChangeLog", "lib/**/*.rb" )
|
|
77
|
+
|
|
78
|
+
rdoc.generator = :fivefish
|
|
79
|
+
rdoc.title = 'sequel-inline_schema'
|
|
80
|
+
rdoc.rdoc_dir = 'doc'
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
task :gemspec => GEMSPEC
|
|
85
|
+
file GEMSPEC => [ __FILE__, 'Manifest.txt' ]
|
|
86
|
+
task GEMSPEC do |task|
|
|
87
|
+
spec = $hoespec.spec
|
|
88
|
+
spec.files.delete( '.gemtest' )
|
|
89
|
+
spec.signing_key = nil
|
|
90
|
+
spec.cert_chain = ['certs/ged.pem']
|
|
91
|
+
spec.version = "#{spec.version.bump}.0.pre#{Time.now.strftime("%Y%m%d%H%M%S")}"
|
|
92
|
+
File.open( task.name, 'w' ) do |fh|
|
|
93
|
+
fh.write( spec.to_ruby )
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
CLOBBER.include( GEMSPEC.to_s )
|
|
97
|
+
|
|
98
|
+
task :default => :gemspec
|
|
99
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- ruby -*-
|
|
2
|
+
#encoding: utf-8
|
|
3
|
+
|
|
4
|
+
require 'sequel'
|
|
5
|
+
require 'sequel/plugins/inline_schema'
|
|
6
|
+
|
|
7
|
+
module Sequel::InlineSchema
|
|
8
|
+
|
|
9
|
+
# Package version
|
|
10
|
+
VERSION = '0.0.1'
|
|
11
|
+
|
|
12
|
+
# Version control revision
|
|
13
|
+
REVISION = %q$Revision: fe2f291518ce $
|
|
14
|
+
|
|
15
|
+
end # Sequel::InlineSchema
|
|
16
|
+
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'sequel'
|
|
4
|
+
require 'sequel/model'
|
|
5
|
+
|
|
6
|
+
Sequel.extension( :migration )
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# A plugin for Sequel::Model that allows migrations for the model to be defined
|
|
10
|
+
# directly in the class declaration. It uses the `inline_schema` plugin
|
|
11
|
+
# internally, and will add it for you if necessary.
|
|
12
|
+
#
|
|
13
|
+
# ## Example
|
|
14
|
+
#
|
|
15
|
+
# Define a base (abstract) model class:
|
|
16
|
+
#
|
|
17
|
+
# ```
|
|
18
|
+
# # lib/acme/model.rb
|
|
19
|
+
# module Acme
|
|
20
|
+
# Model = Class.new( Sequel::Model )
|
|
21
|
+
# Model.def_Model( Acme )
|
|
22
|
+
#
|
|
23
|
+
# class Model
|
|
24
|
+
# plugin :inline_schema
|
|
25
|
+
# plugin :inline_migrations
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
# ```
|
|
29
|
+
#
|
|
30
|
+
# Defining a model class with two migrations:
|
|
31
|
+
#
|
|
32
|
+
# ```
|
|
33
|
+
# # lib/acme/vendor.rb
|
|
34
|
+
# require 'acme/model'
|
|
35
|
+
#
|
|
36
|
+
# class Acme::Vendor < Acme::Model( :vendor )
|
|
37
|
+
#
|
|
38
|
+
# # The schema should always be kept up-to-date. I.e., it should be
|
|
39
|
+
# # modified along with each migration to reflect the state of the table
|
|
40
|
+
# # after the migration is applied.
|
|
41
|
+
# set_schema do
|
|
42
|
+
# primary_key :id
|
|
43
|
+
# String :name
|
|
44
|
+
# String :contact
|
|
45
|
+
# timestamp :created_at, :null => false
|
|
46
|
+
# timestamp :updated_at
|
|
47
|
+
#
|
|
48
|
+
# add_index :name
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# # Similar to Sequel's TimeStampMigrator, inline migrations have a symbolic
|
|
52
|
+
# # name, which is how they're tracked in the migrations table, and how
|
|
53
|
+
# # they're ordered when they're applied. The second argument is a human-readable
|
|
54
|
+
# # description that can be used for automated change control descriptions or
|
|
55
|
+
# # other tooling.
|
|
56
|
+
# migration( '20110228_1115_add_timestamps', "Add timestamp fields" ) do
|
|
57
|
+
# change do
|
|
58
|
+
# alter_table do
|
|
59
|
+
# add_column :created_at, :timestamp, :null => false
|
|
60
|
+
# add_column :updated_at, :timestamp
|
|
61
|
+
# end
|
|
62
|
+
# update( :created_at => :now[] )
|
|
63
|
+
# end
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# migration( '20110303_1751_index_name', "Add an index to the name field" ) do
|
|
67
|
+
# change do
|
|
68
|
+
# alter_table do
|
|
69
|
+
# add_index :name
|
|
70
|
+
# end
|
|
71
|
+
# end
|
|
72
|
+
# end
|
|
73
|
+
#
|
|
74
|
+
# end
|
|
75
|
+
# ```
|
|
76
|
+
#
|
|
77
|
+
# Apply pending migrations.
|
|
78
|
+
#
|
|
79
|
+
# ```
|
|
80
|
+
# # bin/migrate
|
|
81
|
+
#
|
|
82
|
+
# require 'acme/model'
|
|
83
|
+
# require 'acme/vendor'
|
|
84
|
+
# # ...
|
|
85
|
+
#
|
|
86
|
+
# puts "Creating new tables, applying any pending migrations..."
|
|
87
|
+
# Acme::Model.migrate
|
|
88
|
+
# ```
|
|
89
|
+
#
|
|
90
|
+
# ## Notable Model Methods
|
|
91
|
+
#
|
|
92
|
+
# See Sequel::Plugins::InlineSchema::ClassMethods for documentation for the methods the
|
|
93
|
+
# plugin adds to your model class/es.
|
|
94
|
+
#
|
|
95
|
+
# * `migration` -- define a migration
|
|
96
|
+
# * `migrate` -- create any missing tables for the receiving model and any subclasses,
|
|
97
|
+
# then run any unapplied migrations.
|
|
98
|
+
#
|
|
99
|
+
# Inline migrations also have model hook methods:
|
|
100
|
+
#
|
|
101
|
+
# * `before_migration`
|
|
102
|
+
# * `after_migration`
|
|
103
|
+
#
|
|
104
|
+
# There's also a method that will return a configured Sequel::Plugins::InlineMigrations::Migrator
|
|
105
|
+
# in case you want to inspect what will happen when you call #migrate:
|
|
106
|
+
#
|
|
107
|
+
# * `migrator`
|
|
108
|
+
#
|
|
109
|
+
module Sequel::Plugins::InlineMigrations
|
|
110
|
+
|
|
111
|
+
### Sequel plugin API -- Called the first time the plugin is loaded for
|
|
112
|
+
### this model (unless it was already loaded by an ancestor class),
|
|
113
|
+
### before including/extending any modules, with the arguments and block
|
|
114
|
+
### provided to the call to Model.plugin.
|
|
115
|
+
def self::apply( model, *args ) # :nodoc:
|
|
116
|
+
@plugins ||= []
|
|
117
|
+
model.plugin( :subclasses ) # track subclasses
|
|
118
|
+
model.plugin( :inline_schema )
|
|
119
|
+
model.instance_variable_set( :@migrations, {} )
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
### A mixin that gets applied to inline migrations to add introspection attributes
|
|
124
|
+
### and accessors.
|
|
125
|
+
module MigrationIntrospection
|
|
126
|
+
|
|
127
|
+
### Extension callback -- adds 'name', 'model_class', and 'description' instance
|
|
128
|
+
### variables.
|
|
129
|
+
def self::extend_object( obj )
|
|
130
|
+
super
|
|
131
|
+
obj.instance_variable_set( :@description, nil )
|
|
132
|
+
obj.instance_variable_set( :@model_class, nil )
|
|
133
|
+
obj.instance_variable_set( :@name, nil )
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
attr_accessor :name, :model_class, :description
|
|
137
|
+
|
|
138
|
+
end # module MigrationIntrospection
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Methods to extend Model classes with.
|
|
142
|
+
#
|
|
143
|
+
# :markup: RDoc
|
|
144
|
+
module ClassMethods
|
|
145
|
+
|
|
146
|
+
# A Regexp for matching valid migration names
|
|
147
|
+
MIGRATION_NAME_PATTERN = /\A\d{8}_\d{4}_\w+\z/
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# The Hash of Sequel::SimpleMigration objects for this model, keyed by name
|
|
151
|
+
attr_reader :migrations
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
### Add a migration with the specified +name+ and optional +description+. See the
|
|
155
|
+
### docs for Sequel::Migration for usage, and Sequel::MigrationDSL for the allowed
|
|
156
|
+
### syntax in the +block+. The name of the migration should be in the form:
|
|
157
|
+
### <year><month><day>_<hour><minute>_<underbarred_desc>
|
|
158
|
+
def migration( name, description=nil, &block )
|
|
159
|
+
raise ScriptError, "invalid migration name %p" % [ name ] unless
|
|
160
|
+
MIGRATION_NAME_PATTERN.match( name )
|
|
161
|
+
|
|
162
|
+
@migrations ||= {}
|
|
163
|
+
migration_obj = Sequel::MigrationDSL.create( &block )
|
|
164
|
+
migration_obj.extend( MigrationIntrospection )
|
|
165
|
+
migration_obj.name = name
|
|
166
|
+
migration_obj.model_class = self
|
|
167
|
+
migration_obj.description = description
|
|
168
|
+
|
|
169
|
+
@migrations[ name ] = migration_obj
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
### Table-migration hook; called once before missing tables are installed and pending
|
|
174
|
+
### migrations are run.
|
|
175
|
+
def before_migration
|
|
176
|
+
return true
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
### Table-migration hook; called once after missing tables are installed and
|
|
181
|
+
### pending migrations are run.
|
|
182
|
+
def after_migration
|
|
183
|
+
return true
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
### After table creation hook to register any existing migrations as being
|
|
188
|
+
### already applied, as the schema declared by set_schema should be the *latest*
|
|
189
|
+
### schema, and already incorporate the changes described by the migrations.
|
|
190
|
+
def after_create_table
|
|
191
|
+
super
|
|
192
|
+
self.register_existing_migrations
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
### Register any migrations on the receiver as having already been run (as when creating
|
|
197
|
+
### the table initially).
|
|
198
|
+
def register_existing_migrations
|
|
199
|
+
# Register existing migrations as already being applied
|
|
200
|
+
if self.migrations && !self.migrations.empty?
|
|
201
|
+
migrator = self.migrator
|
|
202
|
+
|
|
203
|
+
self.migrations.each_value do |migration|
|
|
204
|
+
migration_data = {
|
|
205
|
+
name: migration.name,
|
|
206
|
+
model_class: migration.model_class.name
|
|
207
|
+
}
|
|
208
|
+
next unless migrator.dataset.filter( migration_data ).empty?
|
|
209
|
+
self.db.log_info " fast-forwarding migration #{migration.name}..."
|
|
210
|
+
migrator.dataset.insert( migration_data )
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
### Create any new tables and run any pending migrations. If the optional +target+ is
|
|
216
|
+
### supplied, the migrations up to (and including) that one will be applied. If
|
|
217
|
+
### it has already been applied, any from the currently-applied one to it
|
|
218
|
+
### (inclusive) will be reversed. A target of +nil+ is equivalent to the last one
|
|
219
|
+
def migrate( target=nil )
|
|
220
|
+
migrator = self.migrator( target )
|
|
221
|
+
classes_to_install = self.uninstalled_tables
|
|
222
|
+
self.db.log_info "Classes with tables that need to be installed: %p" % [ classes_to_install ]
|
|
223
|
+
|
|
224
|
+
self.db.transaction do
|
|
225
|
+
self.before_migration
|
|
226
|
+
self.db.log_info "Creating tables that don't yet exist..."
|
|
227
|
+
classes_to_install.each( &:create_table )
|
|
228
|
+
|
|
229
|
+
self.db.log_info "Running any pending migrations..."
|
|
230
|
+
migrator.run
|
|
231
|
+
self.after_migration
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
### Return a configured inline migrator set with the given +target+ migration.
|
|
237
|
+
def migrator( target=nil )
|
|
238
|
+
self.db.log_info "Creating the migrator..."
|
|
239
|
+
Sequel::Plugins::InlineMigrations::Migrator.new( self, nil, target: target )
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
end # module ClassMethods
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
# Subclass of Sequel::Migrator that provides the logic for extracting and running
|
|
247
|
+
# migrations from the model classes themselves.
|
|
248
|
+
class Migrator < Sequel::Migrator
|
|
249
|
+
|
|
250
|
+
# Default options for .run and #initialize.
|
|
251
|
+
DEFAULT_OPTS = {
|
|
252
|
+
:table => :schema_migrations,
|
|
253
|
+
:column => :name,
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
### Migrates the supplied +db+ (a Sequel::Database) using the migrations declared in the
|
|
258
|
+
### given +baseclass+. The +baseclass+ is the class to gather migrations from; it and all
|
|
259
|
+
### of its concrete descendents will be considered.
|
|
260
|
+
###
|
|
261
|
+
### The +options+ this method understands:
|
|
262
|
+
###
|
|
263
|
+
### column
|
|
264
|
+
### : The column in the table that stores the migration version. Defaults to
|
|
265
|
+
### `:version`.
|
|
266
|
+
###
|
|
267
|
+
### current
|
|
268
|
+
### : The current version of the database. If not given, it is retrieved from the
|
|
269
|
+
### database using the `:table` and `:column` options.
|
|
270
|
+
###
|
|
271
|
+
### table
|
|
272
|
+
### : The name of the migrations table. Defaults to `:schema_migrations`.
|
|
273
|
+
###
|
|
274
|
+
### target
|
|
275
|
+
### : The target version to migrate to. If not given, migrates to the
|
|
276
|
+
### maximum version.
|
|
277
|
+
###
|
|
278
|
+
### Examples
|
|
279
|
+
###
|
|
280
|
+
### ```
|
|
281
|
+
### # Assuming Acme::Model is a Sequel::Model subclass, and Acme::Vendor is a subclass
|
|
282
|
+
### # of that...
|
|
283
|
+
### Sequel::InlineMigrations::Migrator.run( Acme::Model )
|
|
284
|
+
### Sequel::InlineMigrations::Migrator.run( Acme::Model, :target => 15, :current => 10 )
|
|
285
|
+
### Sequel::InlineMigrations::Migrator.run( Acme::Vendor, :column => :app2_version)
|
|
286
|
+
### Sequel::InlineMigrations::Migrator.run( Acme::Vendor, :column => :app2_version,
|
|
287
|
+
### :table => :schema_info2 )
|
|
288
|
+
### ```
|
|
289
|
+
def self::run( baseclass, db=nil, opts={} )
|
|
290
|
+
if db.is_a?( Hash )
|
|
291
|
+
opts = db
|
|
292
|
+
db = nil
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
new( baseclass, db, opts ).run
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
### Create a new Migrator that will organize migrations defined for
|
|
300
|
+
### +baseclass+ or any of its subclasses for the specified +db+.
|
|
301
|
+
### See Sequel::Plugins::InlineMigrations::Migrator.run for argument details.
|
|
302
|
+
def initialize( baseclass, db=nil, opts={} )
|
|
303
|
+
if db.is_a?( Hash )
|
|
304
|
+
opts = db
|
|
305
|
+
db = nil
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
db ||= baseclass.db
|
|
309
|
+
|
|
310
|
+
opts = DEFAULT_OPTS.merge( opts )
|
|
311
|
+
schema, table = db.send( :schema_and_table, opts[:table] )
|
|
312
|
+
|
|
313
|
+
@db = db
|
|
314
|
+
@baseclass = baseclass
|
|
315
|
+
@table = opts[ :table ]
|
|
316
|
+
@column = opts[ :column ]
|
|
317
|
+
@target = opts[ :target ]
|
|
318
|
+
@dataset = make_schema_dataset( @db, @table, @column )
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
######
|
|
323
|
+
public
|
|
324
|
+
######
|
|
325
|
+
|
|
326
|
+
# The database to which the migrator will apply its migrations; a Sequel::Database.
|
|
327
|
+
attr_reader :db
|
|
328
|
+
|
|
329
|
+
# The Class at the top of the hierarchy from which migrations will be fetched
|
|
330
|
+
attr_reader :baseclass
|
|
331
|
+
|
|
332
|
+
# The name of the migration table as a Sequel::SQL::QualifiedIdentifier.
|
|
333
|
+
attr_reader :table
|
|
334
|
+
|
|
335
|
+
# The name of the column which will contain the names of applied migrations as a Symbol.
|
|
336
|
+
attr_reader :column
|
|
337
|
+
|
|
338
|
+
# The migration table dataset (a Sequel::Dataset).
|
|
339
|
+
attr_reader :dataset
|
|
340
|
+
|
|
341
|
+
# The name of the target migration to play up or down to as a String.
|
|
342
|
+
attr_reader :target
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
### Apply all migrations to the database
|
|
346
|
+
def run
|
|
347
|
+
applied, pending = self.get_partitioned_migrations
|
|
348
|
+
|
|
349
|
+
# If no target was specified, and there are no pending
|
|
350
|
+
# migrations, return early.
|
|
351
|
+
return if pending.empty? && self.target.nil?
|
|
352
|
+
|
|
353
|
+
# If no target was specified, the last one is the target
|
|
354
|
+
target = self.target || pending.last.name
|
|
355
|
+
migrations = nil
|
|
356
|
+
direction = nil
|
|
357
|
+
|
|
358
|
+
if target == '0'
|
|
359
|
+
direction = :down
|
|
360
|
+
migrations = applied.reverse
|
|
361
|
+
|
|
362
|
+
elsif tgtidx = pending.find_index {|m| m.name == target }
|
|
363
|
+
migrations = pending[ 0..tgtidx ]
|
|
364
|
+
direction = :up
|
|
365
|
+
|
|
366
|
+
elsif tgtidx = applied.find_index {|m| m.name == target }
|
|
367
|
+
migrations = applied[ tgtidx..-1 ].reverse
|
|
368
|
+
direction = :down
|
|
369
|
+
|
|
370
|
+
else
|
|
371
|
+
raise Sequel::Error, "couldn't find migration %p"
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Run the selected migrations
|
|
375
|
+
self.db.log_info "Migrating %d steps %s..." % [ migrations.length, direction ]
|
|
376
|
+
migrations.each do |migration|
|
|
377
|
+
start = Time.now
|
|
378
|
+
self.db.log_info "Begin: %s, direction: %s" %
|
|
379
|
+
[ migration.description, direction ]
|
|
380
|
+
|
|
381
|
+
self.db.transaction do
|
|
382
|
+
migration.apply( self.db, direction )
|
|
383
|
+
|
|
384
|
+
mclass = migration.model_class.name
|
|
385
|
+
if direction == :up
|
|
386
|
+
self.dataset.insert( self.column => migration.name, :model_class => mclass )
|
|
387
|
+
else
|
|
388
|
+
self.dataset.filter( self.column => migration.name, :model_class => mclass ).delete
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
self.db.log_info " finished: %s, direction: %s (%0.6fs)" %
|
|
393
|
+
[ migration.description, direction, Time.now - start ]
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
### Fetch an Array of all model classes which are descended from the migrating subclass,
|
|
399
|
+
### inclusive.
|
|
400
|
+
def all_migrating_model_classes
|
|
401
|
+
return [ self.baseclass ] + self.baseclass.descendents
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
### Returns any migration objects found in the migrating subclass or any of its
|
|
406
|
+
### descendents as an Array of Sequel::SimpleMigration objects, sorted by the migration
|
|
407
|
+
### name and the name of its migrating class.
|
|
408
|
+
def all_migrations
|
|
409
|
+
migrations = self.all_migrating_model_classes.
|
|
410
|
+
collect( &:migrations ).
|
|
411
|
+
compact.
|
|
412
|
+
inject {|all, hash| all.merge(hash) }
|
|
413
|
+
|
|
414
|
+
return migrations.values.sort_by {|m| [m.name, m.model_class.name] }
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
### Returns two Arrays of migrations, the first one containing those which have already
|
|
419
|
+
### been applied, and the second containing migrations which are pending. Migrations that
|
|
420
|
+
### have been marked as applied but are (no longer) defined by a model class will be
|
|
421
|
+
### ignored.
|
|
422
|
+
def get_partitioned_migrations
|
|
423
|
+
|
|
424
|
+
# Get the list of applied migrations for the subclass and its descendents.
|
|
425
|
+
migrating_class_names = self.all_migrating_model_classes.map( &:name ).compact
|
|
426
|
+
applied_map = self.dataset.
|
|
427
|
+
filter( :model_class => migrating_class_names ).
|
|
428
|
+
select_hash( column, :model_class )
|
|
429
|
+
|
|
430
|
+
# Split up the migrations by whether or not it exists in the map of applied migrations.
|
|
431
|
+
# Each one is removed from the map, so it can be checked for consistency
|
|
432
|
+
part_migrations = self.all_migrations.partition do |migration|
|
|
433
|
+
applied_map.delete( migration.name )
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
# If there are any "applied" migrations left, it's likely been deleted since it was
|
|
437
|
+
# applied, so just ignore it.
|
|
438
|
+
unless applied_map.empty?
|
|
439
|
+
applied_map.each do |migration, classname|
|
|
440
|
+
db.log_info "No %s migration defined in %s; ignoring it." %
|
|
441
|
+
[ migration, classname ]
|
|
442
|
+
end
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
return part_migrations
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
#######
|
|
450
|
+
private
|
|
451
|
+
#######
|
|
452
|
+
|
|
453
|
+
### Returns the dataset for the schema_migrations table. If no such table
|
|
454
|
+
### exists, it is automatically created.
|
|
455
|
+
def make_schema_dataset( db, table, column )
|
|
456
|
+
ds = db.from( table )
|
|
457
|
+
db.log_info "Schema dataset is: %p" % [ ds ]
|
|
458
|
+
|
|
459
|
+
if !db.table_exists?( table ) || ds.columns.empty?
|
|
460
|
+
db.log_info "No migrations table: Installing one."
|
|
461
|
+
db.create_table( table ) do
|
|
462
|
+
String column, :primary_key => true
|
|
463
|
+
String :model_class, :null => false
|
|
464
|
+
end
|
|
465
|
+
elsif !ds.columns.include?( column )
|
|
466
|
+
raise Sequel::Error, "Migrator table %p does not contain column %p (%p)" %
|
|
467
|
+
[ table, column, ds.columns ]
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
return ds
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
end # class Migrator
|
|
474
|
+
|
|
475
|
+
end # Sequel::Plugins::InlineMigrations
|