scheman 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 13a488256dda03bd9e7c75477ab532b805ba3491
4
- data.tar.gz: c4f69982678f0427156d0d127f7fcdc0eaa9f5d6
3
+ metadata.gz: 456bdbc451ec84ddb6f377404e7654d2be2a9b8e
4
+ data.tar.gz: a3c758811636f4466abcc3fc82332931de0e8f69
5
5
  SHA512:
6
- metadata.gz: 7c2b41f51bf2f871e20e045c4f4828f292cdf288e4c5f2c8f4697b7a34950d16f05c9529d2f72ba8808f2afca3c3949c5b4b92fa254c4ddb3fb9da2d68d5f9cf
7
- data.tar.gz: 474496316452b1eb06fd78ff64cdd445dac31c75138d8beb9683c3b107cabfd4849d3a35052959575f51571e7138786c9b87d0ed228f62b24a29cd0c3b02e574
6
+ metadata.gz: 6da8d574d687da3d0394e4944032daecdc47eb15421412f1f26e798c7db22b6426a2cf3655549acf7ee8a21e712f6d0519349f5e8c0c337df6c2bb47d7d9e54d
7
+ data.tar.gz: 88bf79baf57946a03352ec156882243ed3cfb05753cce7660a70e60057ab3beb27d41c5503f2da1eb68512611a2a2bde26611fc6736370f96cd72826575143d9
data/CHANGELOG.md CHANGED
@@ -1,10 +1,14 @@
1
+ ## 0.0.4
2
+ * Add `schema diff` command
3
+ * Improve MySQL parser logic
4
+
1
5
  ## 0.0.3
2
- * Support DEFAULT field qualifier
6
+ * Support DEFAULT column qualifier
3
7
 
4
8
  ## 0.0.2
5
9
  * Support ADD INDEX
6
10
  * Support DROP INDEX
7
- * Detects altered column
11
+ * Detect altered column
8
12
 
9
13
  ## 0.0.1
10
14
  * 1st Release
data/bin/scheman ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
3
+ require "scheman"
4
+
5
+ Scheman::CommandBuilder.call(ARGV).call
data/lib/scheman.rb CHANGED
@@ -5,7 +5,11 @@ require "active_support/core_ext/object/blank"
5
5
  require "active_support/core_ext/object/try"
6
6
  require "active_support/core_ext/string/indent"
7
7
  require "parslet"
8
+ require "slop"
8
9
 
10
+ require "scheman/command_builder"
11
+ require "scheman/commands/base"
12
+ require "scheman/commands/diff"
9
13
  require "scheman/diff"
10
14
  require "scheman/errors"
11
15
  require "scheman/parser_builder"
@@ -0,0 +1,44 @@
1
+ module Scheman
2
+ class CommandBuilder
3
+ def self.call(*args)
4
+ new(*args).call
5
+ end
6
+
7
+ # @param argv [Array] ARGV
8
+ def initialize(argv)
9
+ @argv = argv
10
+ end
11
+
12
+ # @return [Scheman::Commands::Base]
13
+ def call
14
+ command_class.new(@argv)
15
+ rescue Errors::CommandNotFound
16
+ terminate
17
+ end
18
+
19
+ private
20
+
21
+ def command_class
22
+ case command_name
23
+ when "diff"
24
+ Commands::Diff
25
+ else
26
+ raise Errors::CommandNotFound
27
+ end
28
+ end
29
+
30
+ # @note You must pass a command name like "scheman diff"
31
+ def command_name
32
+ @argv[0]
33
+ end
34
+
35
+ def usage
36
+ "Usage: #{$0} <command> [options]"
37
+ end
38
+
39
+ def terminate
40
+ warn usage
41
+ exit(1)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,6 @@
1
+ module Scheman
2
+ module Commands
3
+ class Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,103 @@
1
+ module Scheman
2
+ module Commands
3
+ class Diff < Base
4
+ DEFAULT_AFTER_SCHEMA_PATH = "schema.sql"
5
+
6
+ DEFAULT_TYPE = "mysql"
7
+
8
+ # @param argv [Array] ARGV
9
+ def initialize(argv)
10
+ @argv = argv
11
+ end
12
+
13
+ # Outputs a schema diff
14
+ def call
15
+ print diff
16
+ end
17
+
18
+ private
19
+
20
+ def before
21
+ case
22
+ when has_input_from_stdin?
23
+ STDIN.read
24
+ when before_schema_path
25
+ File.read(before_schema_path)
26
+ else
27
+ raise Errors::NoBeforeSchema
28
+ end
29
+ end
30
+
31
+ def after
32
+ case
33
+ when after_schema_path
34
+ File.read(after_schema_path)
35
+ when has_default_schema_file?
36
+ default_schema
37
+ else
38
+ "CREATE DATABASE database_name;"
39
+ end
40
+ end
41
+
42
+ # @return [String]
43
+ # @example
44
+ # "mysql"
45
+ def type
46
+ options[:type] || DEFAULT_TYPE
47
+ end
48
+
49
+ # @return [Schema::Diff]
50
+ def diff
51
+ @diff ||= Scheman::Diff.new(
52
+ before: before,
53
+ after: after,
54
+ type: type,
55
+ )
56
+ end
57
+
58
+ # @return [true, false] True if any input given via STDIN
59
+ def has_input_from_stdin?
60
+ has_pipe_input? || has_redirect_input?
61
+ end
62
+
63
+ # @return [true, false] True if any input given from redirection
64
+ def has_pipe_input?
65
+ File.pipe?(STDIN)
66
+ end
67
+
68
+ # @return [true, false] True if any input given from redirection
69
+ def has_redirect_input?
70
+ File.select([STDIN], [], [], 0) != nil
71
+ end
72
+
73
+ # @return [String, nil] Path to a previous schema
74
+ def before_schema_path
75
+ options[:before]
76
+ end
77
+
78
+ # @return [String, nil] Path to a next schema
79
+ def after_schema_path
80
+ options[:after]
81
+ end
82
+
83
+ # @return [String, nil] True if a schema file exists in the default schema file path
84
+ def has_default_schema_file?
85
+ File.exist?(DEFAULT_AFTER_SCHEMA_PATH)
86
+ end
87
+
88
+ # @return [String, nil]
89
+ def default_schema
90
+ File.read(DEFAULT_AFTER_SCHEMA_PATH)
91
+ end
92
+
93
+ def options
94
+ @options ||= Slop.parse!(@argv, help: true) do
95
+ banner "Usage: #{$0} diff [options]"
96
+ on "type=", "SQL type (e.g. mysql)"
97
+ on "before=", "Path to the previous schema file"
98
+ on "after=", "Path to the next schema file"
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -8,5 +8,11 @@ module Scheman
8
8
 
9
9
  class ViewNotFound < Base
10
10
  end
11
+
12
+ class CommandNotFound < Base
13
+ end
14
+
15
+ class NoBeforeSchema < Base
16
+ end
11
17
  end
12
18
  end
@@ -67,7 +67,7 @@ module Scheman
67
67
  root(:statements)
68
68
 
69
69
  rule(:statements) do
70
- statement.repeat(1).as(:statements)
70
+ statement.repeat.as(:statements)
71
71
  end
72
72
 
73
73
  rule(:statement) do
@@ -80,7 +80,8 @@ module Scheman
80
80
  alter |
81
81
  insert |
82
82
  delimiter_statement |
83
- empty_statement
83
+ empty_statement |
84
+ spaces
84
85
  end
85
86
 
86
87
  rule(:newline) do
@@ -91,6 +92,10 @@ module Scheman
91
92
  match('\s')
92
93
  end
93
94
 
95
+ rule(:space?) do
96
+ space.maybe
97
+ end
98
+
94
99
  rule(:spaces) do
95
100
  space.repeat(1)
96
101
  end
@@ -138,8 +143,17 @@ module Scheman
138
143
  delimiter >> spaces?
139
144
  end
140
145
 
146
+ rule(:word) do
147
+ match('\w').repeat(1)
148
+ end
149
+
141
150
  rule(:comment) do
142
- (str("#") | str("--")) >> non(newline) >> newline >> spaces?
151
+ (
152
+ (str("#") | str("--")) >> non(newline) >> newline
153
+ ) | (
154
+ str("/") >> space? >> str("*") >>
155
+ ((str("*") >> space? >> str("/")).absent? >> any).repeat >> (str("*") >> space? >> str("/"))
156
+ )
143
157
  end
144
158
 
145
159
  rule(:use) do
@@ -172,7 +186,26 @@ module Scheman
172
186
 
173
187
  rule(:create_table) do
174
188
  create_table_beginning >> spaces >> table_name >>
175
- spaces? >> table_components >> eol
189
+ spaces? >> table_components >> (spaces? >> create_table_options >> spaces?).maybe >> eol
190
+ end
191
+
192
+ rule(:create_table_options) do
193
+ (comment_table_option | charset_table_option | other_table_option) >>
194
+ (spaces >> (comment_table_option | charset_table_option | other_table_option)).repeat
195
+ end
196
+
197
+ rule(:comment_table_option) do
198
+ case_insensitive_str("comment") >> spaces? >> str("=") >> spaces? >> single_quoted(match("[^']").repeat(1))
199
+ end
200
+
201
+ rule(:charset_table_option) do
202
+ case_insensitive_str("default ").maybe >>
203
+ (case_insensitive_str("charset") | case_insensitive_str("character set")) >>
204
+ spaces? >> str("=") >> spaces? >> word
205
+ end
206
+
207
+ rule(:other_table_option) do
208
+ word >> spaces? >> str("=") >> spaces? >> (word | single_quoted(word) | double_quoted(word))
176
209
  end
177
210
 
178
211
  rule(:table_components) do
@@ -336,11 +369,11 @@ module Scheman
336
369
  end
337
370
 
338
371
  rule(:auto_increment_qualifier) do
339
- case_insensitive_str("auto increment").as(:auto_increment_qualifier)
372
+ case_insensitive_str("auto_increment").as(:auto_increment_qualifier)
340
373
  end
341
374
 
342
375
  rule(:field_comment) do
343
- case_insensitive_str("comment") >> spaces >> single_quoted(match("[^']"))
376
+ case_insensitive_str("comment") >> spaces >> single_quoted(match("[^']").repeat(1))
344
377
  end
345
378
 
346
379
  rule(:on_update) do
@@ -45,7 +45,7 @@ module Scheman
45
45
  # @return [Array<Field>]
46
46
  def fields
47
47
  @table[:fields].map do |field|
48
- Field.new(field: field[:field], table: self)
48
+ Field.new(field[:field])
49
49
  end
50
50
  end
51
51
 
@@ -74,9 +74,8 @@ module Scheman
74
74
  end
75
75
 
76
76
  class Field
77
- def initialize(field: nil, table: nil)
77
+ def initialize(field)
78
78
  @field = field
79
- @table = table
80
79
  end
81
80
 
82
81
  # @note Overridden
@@ -1,3 +1,3 @@
1
1
  module Scheman
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -19,13 +19,17 @@ module Scheman
19
19
 
20
20
  class Transform < Parslet::Transform
21
21
  rule(root: subtree(:root)) do
22
- [
23
- "BEGIN;",
24
- "SET foreign_key_checks=0;",
25
- root,
26
- "SET foreign_key_checks=1;",
27
- "COMMIT;",
28
- ].join("\n\n") + "\n"
22
+ if root.to_s.present?
23
+ [
24
+ "BEGIN;",
25
+ "SET foreign_key_checks=0;",
26
+ root,
27
+ "SET foreign_key_checks=1;",
28
+ "COMMIT;",
29
+ ].join("\n\n") + "\n"
30
+ else
31
+ ""
32
+ end
29
33
  end
30
34
 
31
35
  rule(
@@ -296,7 +300,12 @@ module Scheman
296
300
  # @example
297
301
  # "NOT NULL"
298
302
  def type
299
- @element[:type].upcase.gsub("_", " ")
303
+ case @element[:type]
304
+ when "auto_increment"
305
+ @element[:type].upcase
306
+ else
307
+ @element[:type].upcase.gsub("_", " ")
308
+ end
300
309
  end
301
310
 
302
311
  # @example
data/scheman.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.add_dependency "activesupport"
20
20
  spec.add_dependency "parslet"
21
+ spec.add_dependency "slop"
21
22
  spec.add_development_dependency "bundler", "~> 1.6"
22
23
  spec.add_development_dependency "pry"
23
24
  spec.add_development_dependency "rake"
@@ -0,0 +1,9 @@
1
+ CREATE TABLE `table1` (
2
+ `column1` INTEGER(11) PRIMARY KEY NOT NULL AUTO INCREMENT,
3
+ `column2` DATETIME DEFAULT NOW()
4
+ );
5
+
6
+ CREATE TABLE `table2` (
7
+ `column1` INTEGER(11) NOT NULL AUTO INCREMENT,
8
+ PRIMARY KEY (`column1`)
9
+ );
@@ -20,12 +20,12 @@ describe Scheman::Diff do
20
20
  let(:before_schema) do
21
21
  <<-EOS.strip_heredoc
22
22
  CREATE TABLE `table1` (
23
- `column1` INTEGER(11) PRIMARY KEY NOT NULL AUTO INCREMENT,
23
+ `column1` INTEGER(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
24
24
  `column2` DATETIME DEFAULT NOW()
25
25
  );
26
26
 
27
27
  CREATE TABLE `table2` (
28
- `column1` INTEGER(11) NOT NULL AUTO INCREMENT,
28
+ `column1` INTEGER(11) NOT NULL AUTO_INCREMENT,
29
29
  PRIMARY KEY (`column1`)
30
30
  );
31
31
  EOS
@@ -34,14 +34,14 @@ describe Scheman::Diff do
34
34
  let(:after_schema) do
35
35
  <<-EOS.strip_heredoc
36
36
  CREATE TABLE `table1` (
37
- `column1` CHAR(11) NOT NULL AUTO INCREMENT,
37
+ `column1` CHAR(11) NOT NULL AUTO_INCREMENT,
38
38
  `column2` DATETIME DEFAULT CURRENT_TIMESTAMP(),
39
39
  `column3` VARCHAR(255) NOT NULL DEFAULT "a",
40
40
  PRIMARY KEY (`column2`)
41
41
  );
42
42
 
43
43
  CREATE TABLE `table3` (
44
- `column1` INTEGER(11) NOT NULL AUTO INCREMENT,
44
+ `column1` INTEGER(11) NOT NULL AUTO_INCREMENT,
45
45
  PRIMARY KEY (`column1`)
46
46
  );
47
47
  EOS
@@ -59,12 +59,12 @@ describe Scheman::Diff do
59
59
  SET foreign_key_checks=0;
60
60
 
61
61
  CREATE TABLE `table3` (
62
- `column1` INTEGER(11) NOT NULL AUTO INCREMENT,
62
+ `column1` INTEGER(11) NOT NULL AUTO_INCREMENT,
63
63
  PRIMARY KEY (`column1`)
64
64
  );
65
65
 
66
66
  ALTER TABLE `table1` ADD COLUMN `column3` VARCHAR(255) NOT NULL DEFAULT "a",
67
- CHANGE COLUMN `column1` CHAR(11) NOT NULL AUTO INCREMENT,
67
+ CHANGE COLUMN `column1` CHAR(11) NOT NULL AUTO_INCREMENT,
68
68
  DROP PRIMARY KEY,
69
69
  ADD PRIMARY KEY `column2`;
70
70
 
@@ -29,7 +29,7 @@ describe Scheman::Parsers::Mysql do
29
29
  CREATE DATABASE database_name;
30
30
 
31
31
  CREATE TABLE `table1` (
32
- `column1` INTEGER(11) NOT NULL AUTO INCREMENT,
32
+ `column1` INTEGER(11) NOT NULL AUTO_INCREMENT,
33
33
  `column2` VARCHAR(255) NOT NULL,
34
34
  PRIMARY KEY (`column1`)
35
35
  );
@@ -141,9 +141,9 @@ describe Scheman::Parsers::Mysql do
141
141
  end
142
142
  end
143
143
 
144
- context "with AUTO INCREMENT field qualifier" do
144
+ context "with AUTO_INCREMENT field qualifier" do
145
145
  let(:str) do
146
- "CREATE TABLE `table1` (`column1` INTEGER AUTO INCREMENT);"
146
+ "CREATE TABLE `table1` (`column1` INTEGER AUTO_INCREMENT);"
147
147
  end
148
148
 
149
149
  it "succeeds in parse" do
@@ -494,5 +494,65 @@ describe Scheman::Parsers::Mysql do
494
494
  }
495
495
  end
496
496
  end
497
+
498
+ context "with empty string" do
499
+ let(:str) do
500
+ ""
501
+ end
502
+
503
+ it "succeeds in parse" do
504
+ should == []
505
+ end
506
+ end
507
+
508
+ context "with multi-line comment" do
509
+ let(:str) do
510
+ "/ * xy * /"
511
+ end
512
+
513
+ it "succeeds in parse" do
514
+ should == []
515
+ end
516
+ end
517
+
518
+ context "with comment table option" do
519
+ let(:str) do
520
+ "CREATE TABLE `table1` (`column1` INTEGER) COMMENT='test';"
521
+ end
522
+
523
+ it "succeeds in parse" do
524
+ expect { subject }.not_to raise_error
525
+ end
526
+ end
527
+
528
+ context "with charset table option" do
529
+ let(:str) do
530
+ "CREATE TABLE `table1` (`column1` INTEGER) DEFAULT CHARSET=latin1;"
531
+ end
532
+
533
+ it "succeeds in parse" do
534
+ expect { subject }.not_to raise_error
535
+ end
536
+ end
537
+
538
+ context "with another charset table option" do
539
+ let(:str) do
540
+ "CREATE TABLE `table1` (`column1` INTEGER) CHARACTER SET=latin1;"
541
+ end
542
+
543
+ it "succeeds in parse" do
544
+ expect { subject }.not_to raise_error
545
+ end
546
+ end
547
+
548
+ context "with engine table option" do
549
+ let(:str) do
550
+ "CREATE TABLE `table1` (`column1` INTEGER) ENGINE=MyISAM AUTO_INCREMENT=1;"
551
+ end
552
+
553
+ it "succeeds in parse" do
554
+ expect { subject }.not_to raise_error
555
+ end
556
+ end
497
557
  end
498
558
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scheman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Nakamura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-09 00:00:00.000000000 Z
11
+ date: 2014-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: slop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -97,7 +111,8 @@ dependencies:
97
111
  description:
98
112
  email:
99
113
  - r7kamura@gmail.com
100
- executables: []
114
+ executables:
115
+ - scheman
101
116
  extensions: []
102
117
  extra_rdoc_files: []
103
118
  files:
@@ -107,7 +122,11 @@ files:
107
122
  - LICENSE.txt
108
123
  - README.md
109
124
  - Rakefile
125
+ - bin/scheman
110
126
  - lib/scheman.rb
127
+ - lib/scheman/command_builder.rb
128
+ - lib/scheman/commands/base.rb
129
+ - lib/scheman/commands/diff.rb
111
130
  - lib/scheman/diff.rb
112
131
  - lib/scheman/errors.rb
113
132
  - lib/scheman/parser_builder.rb
@@ -118,6 +137,7 @@ files:
118
137
  - lib/scheman/views/base.rb
119
138
  - lib/scheman/views/mysql.rb
120
139
  - scheman.gemspec
140
+ - spec/fixtures/example1.sql
121
141
  - spec/scheman/diff_spec.rb
122
142
  - spec/scheman/parsers/mysql_spec.rb
123
143
  - spec/spec_helper.rb
@@ -146,6 +166,7 @@ signing_key:
146
166
  specification_version: 4
147
167
  summary: SQL schema parser.
148
168
  test_files:
169
+ - spec/fixtures/example1.sql
149
170
  - spec/scheman/diff_spec.rb
150
171
  - spec/scheman/parsers/mysql_spec.rb
151
172
  - spec/spec_helper.rb