tern 0.7.0 → 0.7.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.
- data/.rspec +1 -0
- data/README.markdown +8 -0
- data/lib/tern.rb +33 -18
- data/lib/tern/app.rb +1 -1
- data/spec/projects/alteration_with_error/alterations/001_create_people.sql +8 -0
- data/spec/projects/alteration_with_error/alterations/002_create_animals.sql +8 -0
- data/spec/projects/alteration_with_error/alterations/003_create_plants.sql +10 -0
- data/spec/projects/alteration_with_error/config.yml +15 -0
- data/spec/projects/alteration_with_error/definitions/sequence.yml +18 -0
- data/spec/projects/alteration_with_error/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/definition_with_error/alterations/001_create_people.sql.example +16 -0
- data/spec/projects/definition_with_error/config.yml +15 -0
- data/spec/projects/definition_with_error/definitions/sequence.yml +19 -0
- data/spec/projects/definition_with_error/definitions/ultimate_answer.sql +9 -0
- data/spec/tern_spec.rb +14 -0
- data/tern.gemspec +1 -1
- metadata +14 -3
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/README.markdown
CHANGED
@@ -211,6 +211,14 @@ This will result in:
|
|
211
211
|
|
212
212
|
DROP FUNCTION rendered_function();
|
213
213
|
|
214
|
+
Version History
|
215
|
+
===============
|
216
|
+
|
217
|
+
* **0.7.1**
|
218
|
+
* Print friendly error message when database error occurs instead of stack trace.
|
219
|
+
* **0.7.0**
|
220
|
+
* Added ERB processing to SQL files
|
221
|
+
|
214
222
|
License
|
215
223
|
=======
|
216
224
|
|
data/lib/tern.rb
CHANGED
@@ -2,6 +2,9 @@ require 'sequel'
|
|
2
2
|
require 'yaml'
|
3
3
|
require 'erb'
|
4
4
|
|
5
|
+
class TernError < StandardError
|
6
|
+
end
|
7
|
+
|
5
8
|
class Parser
|
6
9
|
def render_text(text)
|
7
10
|
ERB.new(text).result(binding)
|
@@ -14,12 +17,25 @@ class Parser
|
|
14
17
|
end
|
15
18
|
|
16
19
|
class Change
|
20
|
+
class DatabaseError < TernError
|
21
|
+
end
|
22
|
+
|
17
23
|
SPLIT_MARKER = '---- CREATE above / DROP below ----'
|
18
24
|
|
19
25
|
def self.parse(string)
|
20
26
|
create_sql, drop_sql = Parser.new.render_text(string).split(SPLIT_MARKER)
|
21
27
|
[create_sql, drop_sql]
|
22
28
|
end
|
29
|
+
|
30
|
+
def run(sql, context)
|
31
|
+
DB.run sql
|
32
|
+
rescue Sequel::DatabaseError
|
33
|
+
raise DatabaseError, "Error in #{context}\n#{$!.to_s}"
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :create_sql
|
37
|
+
attr_reader :drop_sql
|
38
|
+
attr_reader :name
|
23
39
|
end
|
24
40
|
|
25
41
|
class Definition < Change
|
@@ -41,7 +57,7 @@ class Definition < Change
|
|
41
57
|
|
42
58
|
def load_existing
|
43
59
|
table.order(:id).all.map do |row|
|
44
|
-
new row[:id], row[:sequence], row[:create_sql], row[:drop_sql]
|
60
|
+
new "existing definition: #{row[:id]}", row[:id], row[:sequence], row[:create_sql], row[:drop_sql]
|
45
61
|
end.group_by { |d| d.sequence }
|
46
62
|
end
|
47
63
|
|
@@ -51,8 +67,9 @@ class Definition < Change
|
|
51
67
|
|
52
68
|
definition_sequences.keys.each do |sequence|
|
53
69
|
definition_sequences[sequence] = definition_sequences[sequence].map do |f|
|
54
|
-
|
55
|
-
|
70
|
+
path = File.join(sequence_dir, f)
|
71
|
+
create_sql, drop_sql = parse File.read(path)
|
72
|
+
Definition.new path, nil, sequence, create_sql, drop_sql
|
56
73
|
end
|
57
74
|
end
|
58
75
|
|
@@ -62,10 +79,9 @@ class Definition < Change
|
|
62
79
|
|
63
80
|
attr_reader :id
|
64
81
|
attr_reader :sequence
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
def initialize(id, sequence, create_sql, drop_sql)
|
82
|
+
|
83
|
+
def initialize(name, id, sequence, create_sql, drop_sql)
|
84
|
+
@name = name
|
69
85
|
@id = id
|
70
86
|
@sequence = sequence
|
71
87
|
@create_sql = create_sql
|
@@ -73,12 +89,12 @@ class Definition < Change
|
|
73
89
|
end
|
74
90
|
|
75
91
|
def create
|
76
|
-
|
92
|
+
run create_sql, name
|
77
93
|
table.insert :sequence => sequence, :create_sql => create_sql, :drop_sql => drop_sql
|
78
94
|
end
|
79
95
|
|
80
96
|
def drop
|
81
|
-
|
97
|
+
run drop_sql, name
|
82
98
|
table.filter(:id => id).delete
|
83
99
|
end
|
84
100
|
|
@@ -88,13 +104,13 @@ class Definition < Change
|
|
88
104
|
end
|
89
105
|
|
90
106
|
class Alteration < Change
|
91
|
-
class IrreversibleAlteration <
|
107
|
+
class IrreversibleAlteration < TernError
|
92
108
|
end
|
93
109
|
|
94
|
-
class MissingAlteration <
|
110
|
+
class MissingAlteration < TernError
|
95
111
|
end
|
96
112
|
|
97
|
-
class DuplicateAlteration <
|
113
|
+
class DuplicateAlteration < TernError
|
98
114
|
end
|
99
115
|
|
100
116
|
class << self
|
@@ -126,7 +142,7 @@ class Alteration < Change
|
|
126
142
|
raise "This can't happen" unless File.basename(path) =~ /^(\d+)/
|
127
143
|
version = $1.to_i
|
128
144
|
create_sql, drop_sql = parse File.read(path)
|
129
|
-
new version, create_sql, drop_sql
|
145
|
+
new path, version, create_sql, drop_sql
|
130
146
|
end.sort_by(&:version)
|
131
147
|
|
132
148
|
alterations.each_with_index do |a, i|
|
@@ -140,23 +156,22 @@ class Alteration < Change
|
|
140
156
|
end
|
141
157
|
|
142
158
|
attr_reader :version
|
143
|
-
attr_reader :create_sql
|
144
|
-
attr_reader :drop_sql
|
145
159
|
|
146
|
-
def initialize(version, create_sql, drop_sql)
|
160
|
+
def initialize(name, version, create_sql, drop_sql)
|
161
|
+
@name = name
|
147
162
|
@version = version
|
148
163
|
@create_sql = create_sql
|
149
164
|
@drop_sql = drop_sql
|
150
165
|
end
|
151
166
|
|
152
167
|
def create
|
153
|
-
|
168
|
+
run create_sql, name
|
154
169
|
Alteration.version = version
|
155
170
|
end
|
156
171
|
|
157
172
|
def drop
|
158
173
|
raise IrreversibleAlteration, "Alteration #{version.to_s.rjust(3, "0")} is irreversible" unless drop_sql
|
159
|
-
|
174
|
+
run drop_sql, name
|
160
175
|
Alteration.version = version - 1
|
161
176
|
end
|
162
177
|
end
|
data/lib/tern/app.rb
CHANGED
@@ -33,7 +33,7 @@ class App < Thor
|
|
33
33
|
begin
|
34
34
|
tern = Tern.new(config['alterations']['table'], config['alterations']['column'], config['definitions']['table'])
|
35
35
|
tern.migrate(:version => options["alteration_version"], :sequences => options["definition_sequences"])
|
36
|
-
rescue
|
36
|
+
rescue TernError
|
37
37
|
say $!, :red
|
38
38
|
end
|
39
39
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
alterations:
|
2
|
+
table: tern_alterations
|
3
|
+
column: version
|
4
|
+
definitions:
|
5
|
+
table: tern_definitions
|
6
|
+
environments:
|
7
|
+
development:
|
8
|
+
adapter: postgres
|
9
|
+
database: tern_test_development
|
10
|
+
test:
|
11
|
+
adapter: postgres
|
12
|
+
database: tern_test_test
|
13
|
+
production:
|
14
|
+
adapter: postgres
|
15
|
+
database: tern_test_production
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Put the relative path to your definition files in the sequence they should run.
|
2
|
+
#
|
3
|
+
# Most definitions should go in the default list. These will be dropped and
|
4
|
+
# recreated every migration.
|
5
|
+
#
|
6
|
+
# Definitions that should not automatically be dropped and created can be put in
|
7
|
+
# different lists. This is useful for definitions that make take prohibitively
|
8
|
+
# to drop and create every migration such as check constraints.
|
9
|
+
#
|
10
|
+
# Run alternative sequences by specifying sequences in order to migrate command.
|
11
|
+
# Example: rake migrate sequences=expensive,default
|
12
|
+
#
|
13
|
+
# default:
|
14
|
+
# - ultimate_answer.sql
|
15
|
+
# expensive:
|
16
|
+
# - super_slow_check_constraint.sql
|
17
|
+
|
18
|
+
default: []
|
@@ -0,0 +1,15 @@
|
|
1
|
+
alterations:
|
2
|
+
table: tern_alterations
|
3
|
+
column: version
|
4
|
+
definitions:
|
5
|
+
table: tern_definitions
|
6
|
+
environments:
|
7
|
+
development:
|
8
|
+
adapter: postgres
|
9
|
+
database: tern_test_development
|
10
|
+
test:
|
11
|
+
adapter: postgres
|
12
|
+
database: tern_test_test
|
13
|
+
production:
|
14
|
+
adapter: postgres
|
15
|
+
database: tern_test_production
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Put the relative path to your definition files in the sequence they should run.
|
2
|
+
#
|
3
|
+
# Most definitions should go in the default list. These will be dropped and
|
4
|
+
# recreated every migration.
|
5
|
+
#
|
6
|
+
# Definitions that should not automatically be dropped and created can be put in
|
7
|
+
# different lists. This is useful for definitions that make take prohibitively
|
8
|
+
# to drop and create every migration such as check constraints.
|
9
|
+
#
|
10
|
+
# Run alternative sequences by specifying sequences in order to migrate command.
|
11
|
+
# Example: rake migrate sequences=expensive,default
|
12
|
+
#
|
13
|
+
# default:
|
14
|
+
# - ultimate_answer.sql
|
15
|
+
# expensive:
|
16
|
+
# - super_slow_check_constraint.sql
|
17
|
+
|
18
|
+
default:
|
19
|
+
- ultimate_answer.sql
|
data/spec/tern_spec.rb
CHANGED
@@ -233,5 +233,19 @@ describe "tern" do
|
|
233
233
|
expect { @dev_db[:a].all }.to raise_error(Sequel::DatabaseError)
|
234
234
|
end
|
235
235
|
end
|
236
|
+
|
237
|
+
context "alteration with database error" do
|
238
|
+
it "prints an error message with file name" do
|
239
|
+
tern_migrate("spec/projects/alteration_with_error").should match /Error in alterations\/003_create_plants.sql/
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
context "definition with database error" do
|
244
|
+
it "prints an error message with file name" do
|
245
|
+
tern_migrate("spec/projects/definition_with_error").should match /Error in definitions\/ultimate_answer.sql/
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
|
236
250
|
end
|
237
251
|
end
|
data/tern.gemspec
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 7
|
8
|
-
-
|
9
|
-
version: 0.7.
|
8
|
+
- 1
|
9
|
+
version: 0.7.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jack Christensen
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-06-25 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -73,6 +73,7 @@ extra_rdoc_files: []
|
|
73
73
|
|
74
74
|
files:
|
75
75
|
- .gitignore
|
76
|
+
- .rspec
|
76
77
|
- MIT-LICENSE
|
77
78
|
- README.markdown
|
78
79
|
- Rakefile
|
@@ -85,12 +86,22 @@ files:
|
|
85
86
|
- lib/tern/generators/new/config.yml.tt
|
86
87
|
- lib/tern/generators/new/definitions/sequence.yml
|
87
88
|
- lib/tern/generators/new/definitions/ultimate_answer.sql.example
|
89
|
+
- spec/projects/alteration_with_error/alterations/001_create_people.sql
|
90
|
+
- spec/projects/alteration_with_error/alterations/002_create_animals.sql
|
91
|
+
- spec/projects/alteration_with_error/alterations/003_create_plants.sql
|
92
|
+
- spec/projects/alteration_with_error/config.yml
|
93
|
+
- spec/projects/alteration_with_error/definitions/sequence.yml
|
94
|
+
- spec/projects/alteration_with_error/definitions/ultimate_answer.sql.example
|
88
95
|
- spec/projects/alterations/alterations/001_create_people.sql
|
89
96
|
- spec/projects/alterations/alterations/002_create_animals.sql
|
90
97
|
- spec/projects/alterations/alterations/003_create_plants.sql
|
91
98
|
- spec/projects/alterations/config.yml
|
92
99
|
- spec/projects/alterations/definitions/sequence.yml
|
93
100
|
- spec/projects/alterations/definitions/ultimate_answer.sql.example
|
101
|
+
- spec/projects/definition_with_error/alterations/001_create_people.sql.example
|
102
|
+
- spec/projects/definition_with_error/config.yml
|
103
|
+
- spec/projects/definition_with_error/definitions/sequence.yml
|
104
|
+
- spec/projects/definition_with_error/definitions/ultimate_answer.sql
|
94
105
|
- spec/projects/definitions/alterations/001_create_people.sql.example
|
95
106
|
- spec/projects/definitions/config.yml
|
96
107
|
- spec/projects/definitions/definitions/sequence.yml
|