sequel-seed 0.1.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 69f6d93c61eea344cdf8319b68f627bc9abf8b97
4
+ data.tar.gz: 7e3042d71cc4c888924bc7603085dd8606e00a2f
5
+ SHA512:
6
+ metadata.gz: b41ae81873403d6688ac393b75859767eac89acbeade98f67724e307c1bf18cf6d51643164581c5baafe07f6b0d4e3b18f76f09b41f6ab22a0256ca3294a92bc
7
+ data.tar.gz: 243e5ae79b93013e95925b20fc98019b78680be3217a4dfa85f3071c37474bb67f515b9ad9c81df5c13f8045fb456bfd47401d17fffa6607b32619832a4f5df3
data/CHANGELOG ADDED
@@ -0,0 +1 @@
1
+ ## Changelog
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Ewerton Assis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # Sequel::Seed
2
+
3
+ > A Sequel extension to make seeds/fixtures manageable like migrations
4
+
5
+ ## Usage
6
+
7
+ Load the extension
8
+
9
+ ```rb
10
+ require 'sequel'
11
+ require 'sequel/extensions/seed'
12
+
13
+ Sequel.extension :seed
14
+ ```
15
+
16
+ Create a seed file (eg. `/path/to/seeds/20150928071637_currencies`)
17
+
18
+ ```rb
19
+ Sequel.seed(:development, :test, :production) do
20
+ def run
21
+ [
22
+ ['USD', 'United States dollar'],
23
+ ['BRL', 'Brazilian real']
24
+ ].each do |abbr, name|
25
+ Currency.create abbr: abbr, name: name
26
+ end
27
+ end
28
+ end
29
+ ```
30
+
31
+ Set the environment
32
+
33
+ ```rb
34
+ Sequel::Seed.environment = :development
35
+ ```
36
+
37
+ Apply the seeds/fixtures
38
+
39
+ ```rb
40
+ DB = Sequel.connect(...)
41
+ Sequel::Seeder.apply(DB, "/path/to/seeds")
42
+ ```
43
+
44
+ ## Limitations
45
+
46
+ Only timestamped seeds files
47
+
48
+ ## License
49
+
50
+ [MIT License](http://earaujoassis.mit-license.org/) © Ewerton Assis
@@ -0,0 +1,202 @@
1
+ # Extension based upon Sequel::Migration and Sequel::Migrator
2
+ #
3
+ # Adds the Sequel::Seed and Sequel::Seeder classes, which allow
4
+ # the user to easily group entity changes and seed the database
5
+ # to a newer version only (migrations are directional, up or down;
6
+ # seeds are always applied).
7
+ #
8
+ # To load the extension:
9
+ #
10
+ # Sequel.extension :seed
11
+
12
+ module Sequel
13
+ class Seed
14
+ class << self
15
+ attr_accessor :environment
16
+ end
17
+
18
+ def self.apply
19
+ new.run
20
+ end
21
+
22
+ def self.descendants
23
+ @descendants ||= []
24
+ end
25
+
26
+ def self.inherited(base)
27
+ descendants << base
28
+ end
29
+
30
+ def run
31
+ end
32
+ end
33
+
34
+ def self.seed *env_labels, &block
35
+ return if env_labels.length > 0 && !env_labels.include?(Seed.environment)
36
+
37
+ seed = Class.new(Seed)
38
+ seed.class_eval(&block) if block_given?
39
+ Seed.inherited(seed) unless Seed.descendants.include? seed
40
+ seed
41
+ end
42
+
43
+ class Seeder
44
+ SEED_FILE_PATTERN = /\A(\d+)_.+\.rb\z/i.freeze
45
+ SEED_SPLITTER = '_'.freeze
46
+ MINIMUM_TIMESTAMP = 20000101
47
+
48
+ class Error < Sequel::Error
49
+ end
50
+
51
+ class NotCurrentError < Error
52
+ end
53
+
54
+ def self.apply(db, directory, opts = {})
55
+ seeder_class(directory).new(db, directory, opts).run
56
+ end
57
+
58
+ def self.seeder_class(directory)
59
+ if self.equal?(Seeder)
60
+ Dir.new(directory).each do |file|
61
+ next unless SEED_FILE_PATTERN.match(file)
62
+ return TimestampSeeder if file.split(SEED_SPLITTER, 2).first.to_i > MINIMUM_TIMESTAMP
63
+ end
64
+ raise(Error, 'seeder not available for files')
65
+ else
66
+ self
67
+ end
68
+ end
69
+
70
+ attr_reader :column
71
+
72
+ attr_reader :db
73
+
74
+ attr_reader :directory
75
+
76
+ attr_reader :ds
77
+
78
+ attr_reader :files
79
+
80
+ attr_reader :table
81
+
82
+ def initialize(db, directory, opts = {})
83
+ raise(Error, "Must supply a valid seed path") unless File.directory?(directory)
84
+ @db = db
85
+ @directory = directory
86
+ @allow_missing_seed_files = opts[:allow_missing_seed_files]
87
+ @files = get_seed_files
88
+ schema, table = @db.send(:schema_and_table, opts[:table] || self.class.const_get(:DEFAULT_SCHEMA_TABLE))
89
+ @table = schema ? Sequel::SQL::QualifiedIdentifier.new(schema, table) : table
90
+ @column = opts[:column] || self.class.const_get(:DEFAULT_SCHEMA_COLUMN)
91
+ @ds = schema_dataset
92
+ @use_transactions = opts[:use_transactions]
93
+ end
94
+
95
+ private
96
+
97
+ def checked_transaction(seed, &block)
98
+ use_trans = if @use_transactions.nil?
99
+ @db.supports_transactional_ddl?
100
+ else
101
+ @use_transactions
102
+ end
103
+
104
+ if use_trans
105
+ db.transaction(&block)
106
+ else
107
+ yield
108
+ end
109
+ end
110
+
111
+ def remove_seed_classes
112
+ Seed.descendants.each do |c|
113
+ Object.send(:remove_const, c.to_s) rescue nil
114
+ end
115
+ Seed.descendants.clear
116
+ end
117
+
118
+ def seed_version_from_file(filename)
119
+ filename.split(SEED_SPLITTER, 2).first.to_i
120
+ end
121
+ end
122
+
123
+ class TimestampSeeder < Seeder
124
+ DEFAULT_SCHEMA_COLUMN = :filename
125
+ DEFAULT_SCHEMA_TABLE = :schema_seeds
126
+
127
+ Error = Seeder::Error
128
+
129
+ attr_reader :applied_seeds
130
+
131
+ attr_reader :seed_tuples
132
+
133
+ def initialize(db, directory, opts = {})
134
+ super
135
+ @applied_seeds = get_applied_seeds
136
+ @seed_tuples = get_seed_tuples
137
+ end
138
+
139
+ def run
140
+ seed_tuples.each do |s, f|
141
+ t = Time.now
142
+ db.log_info("Begin applying seed #{f}")
143
+ checked_transaction(s) do
144
+ s.apply
145
+ fi = f.downcase
146
+ ds.insert(column => fi)
147
+ end
148
+ db.log_info("Finished applying seed #{f}, took #{sprintf('%0.6f', Time.now - t)} seconds")
149
+ end
150
+ nil
151
+ end
152
+
153
+ private
154
+
155
+ def get_applied_seeds
156
+ am = ds.select_order_map(column)
157
+ missing_seed_files = am - files.map{|f| File.basename(f).downcase}
158
+ if missing_seed_files.length > 0 && !@allow_missing_seed_files
159
+ raise(Error, "Applied seed files not in file system: #{missing_seed_files.join(', ')}")
160
+ end
161
+ am
162
+ end
163
+
164
+ def get_seed_files
165
+ files = []
166
+ Dir.new(directory).each do |file|
167
+ next unless SEED_FILE_PATTERN.match(file)
168
+ files << File.join(directory, file)
169
+ end
170
+ files.sort_by{|f| SEED_FILE_PATTERN.match(File.basename(f))[1].to_i}
171
+ end
172
+
173
+ def get_seed_tuples
174
+ remove_seed_classes
175
+ seeds = []
176
+ ms = Seed.descendants
177
+ files.each do |path|
178
+ f = File.basename(path)
179
+ fi = f.downcase
180
+ if !applied_seeds.include?(fi)
181
+ load(path)
182
+ el = [ms.last, f]
183
+ if ms.last.present? && !seeds.include?(el)
184
+ seeds << [ms.last, f]
185
+ end
186
+ end
187
+ end
188
+ seeds
189
+ end
190
+
191
+ def schema_dataset
192
+ c = column
193
+ ds = db.from(table)
194
+ if !db.table_exists?(table)
195
+ db.create_table(table){String c, :primary_key => true}
196
+ elsif !ds.columns.include?(c)
197
+ raise(Error, "Seeder table #{table} does not contain column #{c}")
198
+ end
199
+ ds
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ Sequel::Seed.environment = :test
4
+
5
+ describe Sequel.seed do
6
+ it 'should create a Seed descendant according to the current environment' do
7
+ seed = Sequel.seed(:test) do
8
+ end
9
+ expect(Sequel::Seed.descendants).to include seed
10
+ end
11
+
12
+ it 'should ignore a Seed not applicable to the current environment' do
13
+ seed = Sequel.seed(:development) do
14
+ end
15
+ expect(Sequel::Seed.descendants).not_to include seed
16
+ end
17
+
18
+ it 'should create a Seed applicable to every environment' do
19
+ seed = Sequel.seed do
20
+ end
21
+ expect(Sequel::Seed.descendants).to include seed
22
+ end
23
+ end
24
+
25
+ describe Sequel::Seeder do
26
+ let(:DB) {Sequel.sqlite}
27
+
28
+ context 'when there\'s no Seed created' do
29
+ it 'should not make any change to the database' do
30
+ expect {Sequel::Seeder.apply(DB, '/')}.not_to raise_error
31
+ expect(SpecModel.dataset.all.length).to be 0
32
+ end
33
+ end
34
+
35
+ context 'when there\'s a Seed created' do
36
+ it 'should change the database accordingly only once' do
37
+ Sequel.seed do
38
+ def run
39
+ SpecModel.create name: 'some name'
40
+ end
41
+ end
42
+
43
+ expect(Sequel::Seed.descendants.length).to be 1
44
+ expect {Sequel::Seeder.apply(DB, '/')}.not_to raise_error
45
+ expect(Sequel::Seed.descendants.length).to be 0
46
+ expect(SpecModel.dataset.all.length).to be 1
47
+ expect(SpecModel.dataset.first.name).to eq 'some name'
48
+ end
49
+ end
50
+
51
+ context 'when the specified Seed is not applicable to the current environment' do
52
+ let(:seed) {
53
+ Sequel.seed(:hithere) do
54
+ def run
55
+ SpecModel.create name: 'some name'
56
+ end
57
+ end
58
+ }
59
+
60
+ it 'should not make any change to the database' do
61
+ seed
62
+ expect(Sequel::Seed.descendants.length).to be 0
63
+ expect {Sequel::Seeder.apply(DB, '/')}.not_to raise_error
64
+ expect(SpecModel.dataset.all.length).to be 0
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,55 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup(:default, :development)
3
+
4
+ require 'sequel'
5
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/sequel/extensions/seed.rb')
6
+
7
+ RSpec.configure do |config|
8
+ Sequel.extension :seed
9
+
10
+ class Sequel::Seeder
11
+ def self.seeder_class(directory)
12
+ if self.equal?(Sequel::Seeder)
13
+ return Sequel::TimestampSeeder
14
+ else
15
+ self
16
+ end
17
+ end
18
+ end
19
+
20
+ class Sequel::TimestampSeeder
21
+ def run
22
+ seed_tuples.each {|s| s.apply}
23
+ Sequel::Seed.descendants.clear
24
+ end
25
+
26
+ private
27
+
28
+ def get_applied_seeds
29
+ []
30
+ end
31
+
32
+ def get_seed_files
33
+ []
34
+ end
35
+
36
+ def get_seed_tuples
37
+ Sequel::Seed.descendants
38
+ end
39
+ end
40
+
41
+ DB = Sequel.sqlite
42
+
43
+ DB.create_table(:spec_models) do
44
+ primary_key :id, :auto_increment => true
45
+ String :name
46
+ end
47
+
48
+ config.before(:each) do
49
+ SpecModel.dataset.delete
50
+ Sequel::Seed.descendants.clear
51
+ end
52
+ end
53
+
54
+ class SpecModel < Sequel::Model
55
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sequel-seed
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Ewerton Assis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sequel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ description: A Sequel extension to make seeds/fixtures manageable like migrations
28
+ email: hello@dearaujoassis.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - CHANGELOG
34
+ - LICENSE
35
+ - README.md
36
+ - lib/sequel/extensions/seed.rb
37
+ - spec/extensions/seed_spec.rb
38
+ - spec/spec_helper.rb
39
+ homepage: https://github.com/earaujoassis/sequel-seed
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 1.9.1
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.4.8
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: A Sequel extension to make seeds/fixtures manageable like migrations
63
+ test_files: []