scheman 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7c96927177dfbde154defcf9c902c953c60a580a
4
+ data.tar.gz: 51e98f13cdf9ea43eec4a515be4b883ab855b880
5
+ SHA512:
6
+ metadata.gz: 09fb8220340760be61f9a6ad057313604657dc4425fb97bc0ac10bf41c05295e7800da6a2ae0bfb8857dc407393a3edd5c6892b5af81ffb783a8c69acdf14ffe
7
+ data.tar.gz: a1a90f9957eec8d37e83a367d5d3417016a1032143702c3e6c26834cbf3b678797f289b855c757faf05d0fc14923a986ff6606ea7c5b262454e7e686faee5d3b
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in scheman.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Ryo Nakamura
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # Scheman
2
+ Manage database schema based on schema definition file.
3
+
4
+ ## Usage
5
+ Creates Diff with 2 schema files and logs out their diff.
6
+
7
+ ```ruby
8
+ before = <<-SQL
9
+ CREATE TABLE `table1` (
10
+ `column1` INTEGER NOT NULL AUTO INCREMENT,
11
+ PRIMARY KEY (`column1`)
12
+ );
13
+
14
+ CREATE TABLE `table2` (
15
+ `column1` INTEGER NOT NULL AUTO INCREMENT,
16
+ PRIMARY KEY (`column1`)
17
+ );
18
+ SQL
19
+
20
+ after = <<-SQL
21
+ CREATE TABLE `table1` (
22
+ `column2` VARCHAR(255) NOT NULL,
23
+ PRIMARY KEY (`column1`)
24
+ );
25
+
26
+ CREATE TABLE `table3` (
27
+ `column1` INTEGER NOT NULL AUTO INCREMENT,
28
+ PRIMARY KEY (`column1`)
29
+ );
30
+ SQL
31
+
32
+ puts Scheman::Diff.new(before: before, after: after, type: "mysql")
33
+ ```
34
+
35
+ The result would be the following:
36
+
37
+ ```sql
38
+ BEGIN;
39
+
40
+ SET foreign_key_checks=0;
41
+
42
+ CREATE TABLE `table3` (
43
+ `column1` INTEGER NOT NULL AUTO INCREMENT,
44
+ PRIMARY KEY (`column1`)
45
+ );
46
+
47
+ ALTER TABLE `table1` ADD COLUMN `column2` VARCHAR(255) NOT NULL;
48
+
49
+ ALTER TABLE `table1` DROP COLUMN `column1`;
50
+
51
+ DROP TABLE `table2`;
52
+
53
+ SET foreign_key_checks=1;
54
+
55
+ COMMIT;
56
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,143 @@
1
+ module Scheman
2
+ class Diff
3
+ # @param before [String] The previous schema
4
+ # @param after [String] The next schema
5
+ # @param type [String] The type of schema syntax, default types of the both schemata (e.g. "mysql")
6
+ # @param before_type [String] Specify the type of the previous schema if needed
7
+ # @param after_type [String] Specify the type of the next schema if needed
8
+ # @param output_type [String] Specify the type of the output schema if needed
9
+ # @raise [Scheman::Errors::ParserNotFound]
10
+ def initialize(before: nil, after: nil, type: nil, before_type: nil, after_type: nil, output_type: nil)
11
+ @before = before
12
+ @after = after
13
+ @type = type
14
+ @before_type = before_type
15
+ @after_type = after_type
16
+ @output_type = output_type
17
+ validate!
18
+ end
19
+
20
+ # @return [String] A string representation of this diff
21
+ def to_s
22
+ view_class.new(to_hash).to_s
23
+ end
24
+
25
+ # @note Passed to Parslet::Transform to convert into SQL string
26
+ # @return [Hash] A hash representation of this diff
27
+ def to_hash
28
+ {
29
+ alter_tables: alter_tables,
30
+ create_tables: create_tables,
31
+ drop_tables: drop_tables,
32
+ }
33
+ end
34
+
35
+ private
36
+
37
+ # TODO
38
+ # @return [Array<Hash>] ALTER TABLE statements we need to apply
39
+ def alter_tables
40
+ after_schema.tables.inject([]) do |result, after_table|
41
+ if before_table = before_schema.tables_indexed_by_name[after_table.name]
42
+ after_table.fields.each do |after_field|
43
+ unless before_table.fields_indexed_by_name[after_field.name]
44
+ result << {
45
+ add_field: after_field.to_hash.merge(table_name: after_table.name),
46
+ }
47
+ end
48
+ end
49
+
50
+ before_table.fields.each do |before_field|
51
+ unless after_table.fields_indexed_by_name[before_field.name]
52
+ result << {
53
+ drop_field: before_field.to_hash.merge(table_name: after_table.name),
54
+ }
55
+ end
56
+ end
57
+ end
58
+ result
59
+ end
60
+ end
61
+
62
+ # @return [Array<Hash>] DROP TABLE statements we need to apply
63
+ def drop_tables
64
+ table_names_to_drop.map do |name|
65
+ {
66
+ drop_table: {
67
+ name: name,
68
+ },
69
+ }
70
+ end
71
+ end
72
+
73
+ # @return [Array<Hash>] CREATE TABLE statements we need to apply
74
+ def create_tables
75
+ after_schema.create_tables.select do |statement|
76
+ table_names_to_create.include?(statement[:create_table][:name])
77
+ end
78
+ end
79
+
80
+ # @return [Array<String>]
81
+ def table_names_to_create
82
+ @table_names_to_create ||= after_schema.table_names - before_schema.table_names
83
+ end
84
+
85
+ # @return [Array<String>]
86
+ def table_names_to_drop
87
+ @table_names_to_drop ||= before_schema.table_names - after_schema.table_names
88
+ end
89
+
90
+ # @return [Scheman::Schema]
91
+ def before_schema
92
+ @before_schema ||= before_parser.parse(@before)
93
+ end
94
+
95
+ # @return [Scheman::Schema]
96
+ def after_schema
97
+ @after_schema ||= after_parser.parse(@after)
98
+ end
99
+
100
+ # @return [Scheman::Parsers::Base]
101
+ # @raise [Scheman::Errors::ParserNotFound]
102
+ def before_parser
103
+ @before_parser ||= ParserBuilder.build(before_type)
104
+ end
105
+
106
+ # @return [Scheman::Parsers::Base]
107
+ # @raise [Scheman::Errors::ParserNotFound]
108
+ def after_parser
109
+ @after_parser ||= ParserBuilder.build(after_type)
110
+ end
111
+
112
+ # @raise [Scheman::Errors::ParserNotFound]
113
+ def validate!
114
+ before_parser
115
+ after_parser
116
+ end
117
+
118
+ # @return [String]
119
+ def before_type
120
+ @before_type || @type
121
+ end
122
+
123
+ # @return [String]
124
+ def after_type
125
+ @after_type || @type
126
+ end
127
+
128
+ # @return [String]
129
+ def output_type
130
+ @output_type || @type
131
+ end
132
+
133
+ # @return [Class]
134
+ def view_class
135
+ case output_type
136
+ when "mysql"
137
+ Views::Mysql
138
+ else
139
+ raise Errors::ViewNotFound
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,12 @@
1
+ module Scheman
2
+ module Errors
3
+ class Base < StandardError
4
+ end
5
+
6
+ class ParserNotFound < Base
7
+ end
8
+
9
+ class ViewNotFound < Base
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ module Scheman
2
+ class ParserBuilder
3
+ # @param type [String] A type of parser (e.g. "mysql")
4
+ # @return [Scheman::Parsers::Base]
5
+ def self.build(type)
6
+ new(type).build
7
+ end
8
+
9
+ # @param type [String]
10
+ def initialize(type)
11
+ @type = type
12
+ end
13
+
14
+ def build
15
+ parser_class.new
16
+ end
17
+
18
+ private
19
+
20
+ def parser_class
21
+ case @type
22
+ when "mysql"
23
+ Parsers::Mysql
24
+ else
25
+ raise Errors::ParserNotFound
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ module Scheman
2
+ module Parsers
3
+ class Base
4
+ def initialize(options = {})
5
+ @options = options
6
+ end
7
+ end
8
+ end
9
+ end