db_schema 0.2.5 → 0.3.rc1
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 +4 -4
- data/.travis.yml +5 -3
- data/README.md +2 -2
- data/lib/db_schema.rb +81 -38
- data/lib/db_schema/awesome_print.rb +37 -36
- data/lib/db_schema/changes.rb +68 -217
- data/lib/db_schema/configuration.rb +34 -15
- data/lib/db_schema/definitions.rb +7 -252
- data/lib/db_schema/definitions/check_constraint.rb +17 -0
- data/lib/db_schema/definitions/enum.rb +21 -0
- data/lib/db_schema/definitions/extension.rb +12 -0
- data/lib/db_schema/definitions/field/base.rb +6 -0
- data/lib/db_schema/definitions/foreign_key.rb +41 -0
- data/lib/db_schema/definitions/index.rb +56 -0
- data/lib/db_schema/definitions/index/column.rb +32 -0
- data/lib/db_schema/definitions/index/expression.rb +19 -0
- data/lib/db_schema/definitions/index/table_field.rb +19 -0
- data/lib/db_schema/definitions/schema.rb +36 -0
- data/lib/db_schema/definitions/table.rb +115 -0
- data/lib/db_schema/dsl.rb +96 -76
- data/lib/db_schema/dsl/migration.rb +24 -0
- data/lib/db_schema/migration.rb +12 -0
- data/lib/db_schema/migrator.rb +177 -0
- data/lib/db_schema/normalizer.rb +19 -17
- data/lib/db_schema/operations.rb +211 -0
- data/lib/db_schema/reader.rb +46 -36
- data/lib/db_schema/runner.rb +147 -171
- data/lib/db_schema/version.rb +1 -1
- metadata +18 -4
@@ -0,0 +1,177 @@
|
|
1
|
+
module DbSchema
|
2
|
+
class Migrator
|
3
|
+
attr_reader :migration
|
4
|
+
|
5
|
+
def initialize(migration)
|
6
|
+
@migration = migration
|
7
|
+
end
|
8
|
+
|
9
|
+
def applicable?(schema)
|
10
|
+
migration.conditions[:apply].all? do |condition|
|
11
|
+
condition.call(schema)
|
12
|
+
end && migration.conditions[:skip].none? do |condition|
|
13
|
+
condition.call(schema)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def run!(connection)
|
18
|
+
migration.body.call(BodyYielder.new(connection)) unless migration.body.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
class BodyYielder
|
22
|
+
attr_reader :connection
|
23
|
+
|
24
|
+
def initialize(connection)
|
25
|
+
@connection = connection
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_table(name, &block)
|
29
|
+
table_yielder = DSL::TableYielder.new(name, block)
|
30
|
+
|
31
|
+
table = Definitions::Table.new(
|
32
|
+
name,
|
33
|
+
fields: table_yielder.fields,
|
34
|
+
indices: table_yielder.indices,
|
35
|
+
checks: table_yielder.checks,
|
36
|
+
foreign_keys: table_yielder.foreign_keys
|
37
|
+
)
|
38
|
+
|
39
|
+
run Operations::CreateTable.new(table)
|
40
|
+
|
41
|
+
table.foreign_keys.each do |fkey|
|
42
|
+
run Operations::CreateForeignKey.new(table.name, fkey)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def drop_table(name)
|
47
|
+
run Operations::DropTable.new(name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def rename_table(from, to:)
|
51
|
+
run Operations::RenameTable.new(old_name: from, new_name: to)
|
52
|
+
end
|
53
|
+
|
54
|
+
def alter_table(name, &block)
|
55
|
+
run AlterTableYielder.new(name).run(block)
|
56
|
+
end
|
57
|
+
|
58
|
+
class AlterTableYielder
|
59
|
+
attr_reader :alter_table, :fkey_operations
|
60
|
+
|
61
|
+
def initialize(table_name)
|
62
|
+
@alter_table = Operations::AlterTable.new(table_name)
|
63
|
+
@fkey_operations = []
|
64
|
+
end
|
65
|
+
|
66
|
+
def run(block)
|
67
|
+
block.call(self)
|
68
|
+
|
69
|
+
[alter_table, *fkey_operations]
|
70
|
+
end
|
71
|
+
|
72
|
+
def add_column(name, type, **options)
|
73
|
+
alter_table.changes << Operations::CreateColumn.new(
|
74
|
+
Definitions::Field.build(name, type, options)
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def drop_column(name)
|
79
|
+
alter_table.changes << Operations::DropColumn.new(name)
|
80
|
+
end
|
81
|
+
|
82
|
+
def rename_column(from, to:)
|
83
|
+
alter_table.changes << Operations::RenameColumn.new(old_name: from, new_name: to)
|
84
|
+
end
|
85
|
+
|
86
|
+
def alter_column_type(name, new_type, using: nil, **new_attributes)
|
87
|
+
alter_table.changes << Operations::AlterColumnType.new(
|
88
|
+
name,
|
89
|
+
new_type: new_type,
|
90
|
+
using: using,
|
91
|
+
**new_attributes
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def allow_null(name)
|
96
|
+
alter_table.changes << Operations::AllowNull.new(name)
|
97
|
+
end
|
98
|
+
|
99
|
+
def disallow_null(name)
|
100
|
+
alter_table.changes << Operations::DisallowNull.new(name)
|
101
|
+
end
|
102
|
+
|
103
|
+
def alter_column_default(name, new_default)
|
104
|
+
alter_table.changes << Operations::AlterColumnDefault.new(name, new_default: new_default)
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_index(*columns, **index_options)
|
108
|
+
alter_table.changes << Operations::CreateIndex.new(
|
109
|
+
DSL::TableYielder.build_index(
|
110
|
+
columns,
|
111
|
+
table_name: alter_table.table_name,
|
112
|
+
**index_options
|
113
|
+
)
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
def drop_index(name)
|
118
|
+
alter_table.changes << Operations::DropIndex.new(name)
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_check(name, condition)
|
122
|
+
alter_table.changes << Operations::CreateCheckConstraint.new(
|
123
|
+
Definitions::CheckConstraint.new(name: name, condition: condition)
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
def drop_check(name)
|
128
|
+
alter_table.changes << Operations::DropCheckConstraint.new(name)
|
129
|
+
end
|
130
|
+
|
131
|
+
def add_foreign_key(*fkey_fields, **fkey_options)
|
132
|
+
fkey_operations << Operations::CreateForeignKey.new(
|
133
|
+
alter_table.table_name,
|
134
|
+
DSL::TableYielder.build_foreign_key(
|
135
|
+
fkey_fields,
|
136
|
+
table_name: alter_table.table_name,
|
137
|
+
**fkey_options
|
138
|
+
)
|
139
|
+
)
|
140
|
+
end
|
141
|
+
|
142
|
+
def drop_foreign_key(fkey_name)
|
143
|
+
fkey_operations << Operations::DropForeignKey.new(
|
144
|
+
alter_table.table_name,
|
145
|
+
fkey_name
|
146
|
+
)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def create_enum(name, values)
|
151
|
+
run Operations::CreateEnum.new(Definitions::Enum.new(name, values))
|
152
|
+
end
|
153
|
+
|
154
|
+
def drop_enum(name)
|
155
|
+
run Operations::DropEnum.new(name)
|
156
|
+
end
|
157
|
+
|
158
|
+
def create_extension(name)
|
159
|
+
run Operations::CreateExtension.new(Definitions::Extension.new(name))
|
160
|
+
end
|
161
|
+
|
162
|
+
def drop_extension(name)
|
163
|
+
run Operations::DropExtension.new(name)
|
164
|
+
end
|
165
|
+
|
166
|
+
def execute(query)
|
167
|
+
run Operations::ExecuteQuery.new(query)
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def run(operation)
|
173
|
+
Runner.new(Array(operation), connection).run!
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
data/lib/db_schema/normalizer.rb
CHANGED
@@ -2,20 +2,21 @@ require 'digest/md5'
|
|
2
2
|
|
3
3
|
module DbSchema
|
4
4
|
class Normalizer
|
5
|
-
attr_reader :schema
|
5
|
+
attr_reader :schema, :connection
|
6
6
|
|
7
|
-
def initialize(schema)
|
8
|
-
@schema
|
7
|
+
def initialize(schema, connection)
|
8
|
+
@schema = schema
|
9
|
+
@connection = connection
|
9
10
|
end
|
10
11
|
|
11
12
|
def normalize_tables
|
12
|
-
|
13
|
+
connection.transaction do
|
13
14
|
create_extensions!
|
14
15
|
create_enums!
|
15
16
|
|
16
17
|
schema.tables = schema.tables.map do |table|
|
17
18
|
if table.has_expressions?
|
18
|
-
Table.new(table, hash).normalized_table
|
19
|
+
Table.new(table, hash, connection).normalized_table
|
19
20
|
else
|
20
21
|
table
|
21
22
|
end
|
@@ -27,19 +28,19 @@ module DbSchema
|
|
27
28
|
|
28
29
|
private
|
29
30
|
def create_extensions!
|
30
|
-
operations = (schema.extensions - Reader.read_extensions).map do |extension|
|
31
|
-
|
31
|
+
operations = (schema.extensions - Reader.read_extensions(connection)).map do |extension|
|
32
|
+
Operations::CreateExtension.new(extension)
|
32
33
|
end
|
33
34
|
|
34
|
-
Runner.new(operations).run!
|
35
|
+
Runner.new(operations, connection).run!
|
35
36
|
end
|
36
37
|
|
37
38
|
def create_enums!
|
38
39
|
operations = schema.enums.map do |enum|
|
39
|
-
|
40
|
+
Operations::CreateEnum.new(enum.with_name(append_hash(enum.name)))
|
40
41
|
end
|
41
42
|
|
42
|
-
Runner.new(operations).run!
|
43
|
+
Runner.new(operations, connection).run!
|
43
44
|
end
|
44
45
|
|
45
46
|
def append_hash(name)
|
@@ -57,11 +58,12 @@ module DbSchema
|
|
57
58
|
end
|
58
59
|
|
59
60
|
class Table
|
60
|
-
attr_reader :table, :hash
|
61
|
+
attr_reader :table, :hash, :connection
|
61
62
|
|
62
|
-
def initialize(table, hash)
|
63
|
-
@table
|
64
|
-
@hash
|
63
|
+
def initialize(table, hash, connection)
|
64
|
+
@table = table
|
65
|
+
@hash = hash
|
66
|
+
@connection = connection
|
65
67
|
end
|
66
68
|
|
67
69
|
def normalized_table
|
@@ -71,17 +73,17 @@ module DbSchema
|
|
71
73
|
|
72
74
|
private
|
73
75
|
def create_temporary_table!
|
74
|
-
operation =
|
76
|
+
operation = Operations::CreateTable.new(
|
75
77
|
table.with_name(temporary_table_name)
|
76
78
|
.with_fields(rename_types(table.fields))
|
77
79
|
.with_indices(rename_indices(table.indices))
|
78
80
|
)
|
79
81
|
|
80
|
-
Runner.new([operation]).run!
|
82
|
+
Runner.new([operation], connection).run!
|
81
83
|
end
|
82
84
|
|
83
85
|
def read_temporary_table
|
84
|
-
temporary_table = Reader.read_table(temporary_table_name)
|
86
|
+
temporary_table = Reader.read_table(temporary_table_name, connection)
|
85
87
|
|
86
88
|
temporary_table.with_name(table.name)
|
87
89
|
.with_fields(rename_types_back(temporary_table.fields))
|
@@ -0,0 +1,211 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Operations
|
3
|
+
class CreateTable
|
4
|
+
include Dry::Equalizer(:table)
|
5
|
+
attr_reader :table
|
6
|
+
|
7
|
+
def initialize(table)
|
8
|
+
@table = table
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class DropTable
|
13
|
+
include Dry::Equalizer(:name)
|
14
|
+
attr_reader :name
|
15
|
+
|
16
|
+
def initialize(name)
|
17
|
+
@name = name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class RenameTable
|
22
|
+
include Dry::Equalizer(:old_name, :new_name)
|
23
|
+
attr_reader :old_name, :new_name
|
24
|
+
|
25
|
+
def initialize(old_name:, new_name:)
|
26
|
+
@old_name = old_name
|
27
|
+
@new_name = new_name
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class AlterTable
|
32
|
+
include Dry::Equalizer(:table_name, :changes)
|
33
|
+
attr_reader :table_name, :changes
|
34
|
+
|
35
|
+
def initialize(table_name, changes = [])
|
36
|
+
@table_name = table_name
|
37
|
+
@changes = changes
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Abstract base class for single-column toggle operations.
|
42
|
+
class ColumnOperation
|
43
|
+
include Dry::Equalizer(:name)
|
44
|
+
attr_reader :name
|
45
|
+
|
46
|
+
def initialize(name)
|
47
|
+
@name = name
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class CreateColumn
|
52
|
+
include Dry::Equalizer(:field)
|
53
|
+
attr_reader :field
|
54
|
+
|
55
|
+
def initialize(field)
|
56
|
+
@field = field
|
57
|
+
end
|
58
|
+
|
59
|
+
def name
|
60
|
+
field.name
|
61
|
+
end
|
62
|
+
|
63
|
+
def type
|
64
|
+
field.type
|
65
|
+
end
|
66
|
+
|
67
|
+
def primary_key?
|
68
|
+
field.primary_key?
|
69
|
+
end
|
70
|
+
|
71
|
+
def options
|
72
|
+
field.options
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class DropColumn < ColumnOperation
|
77
|
+
end
|
78
|
+
|
79
|
+
class RenameColumn
|
80
|
+
include Dry::Equalizer(:old_name, :new_name)
|
81
|
+
attr_reader :old_name, :new_name
|
82
|
+
|
83
|
+
def initialize(old_name:, new_name:)
|
84
|
+
@old_name = old_name
|
85
|
+
@new_name = new_name
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class AlterColumnType
|
90
|
+
include Dry::Equalizer(:name, :new_type, :using, :new_attributes)
|
91
|
+
attr_reader :name, :new_type, :using, :new_attributes
|
92
|
+
|
93
|
+
def initialize(name, new_type:, using: nil, **new_attributes)
|
94
|
+
@name = name
|
95
|
+
@new_type = new_type
|
96
|
+
@using = using
|
97
|
+
@new_attributes = new_attributes
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class CreatePrimaryKey < ColumnOperation
|
102
|
+
end
|
103
|
+
|
104
|
+
class DropPrimaryKey < ColumnOperation
|
105
|
+
end
|
106
|
+
|
107
|
+
class AllowNull < ColumnOperation
|
108
|
+
end
|
109
|
+
|
110
|
+
class DisallowNull < ColumnOperation
|
111
|
+
end
|
112
|
+
|
113
|
+
class AlterColumnDefault
|
114
|
+
include Dry::Equalizer(:name, :new_default)
|
115
|
+
attr_reader :name, :new_default
|
116
|
+
|
117
|
+
def initialize(name, new_default:)
|
118
|
+
@name = name
|
119
|
+
@new_default = new_default
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class CreateIndex
|
124
|
+
include Dry::Equalizer(:index)
|
125
|
+
attr_reader :index
|
126
|
+
|
127
|
+
def initialize(index)
|
128
|
+
@index = index
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class DropIndex < ColumnOperation
|
133
|
+
end
|
134
|
+
|
135
|
+
class CreateCheckConstraint
|
136
|
+
include Dry::Equalizer(:check)
|
137
|
+
attr_reader :check
|
138
|
+
|
139
|
+
def initialize(check)
|
140
|
+
@check = check
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class DropCheckConstraint < ColumnOperation
|
145
|
+
end
|
146
|
+
|
147
|
+
class CreateForeignKey
|
148
|
+
include Dry::Equalizer(:table_name, :foreign_key)
|
149
|
+
attr_reader :table_name, :foreign_key
|
150
|
+
|
151
|
+
def initialize(table_name, foreign_key)
|
152
|
+
@table_name = table_name
|
153
|
+
@foreign_key = foreign_key
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class DropForeignKey
|
158
|
+
include Dry::Equalizer(:table_name, :fkey_name)
|
159
|
+
attr_reader :table_name, :fkey_name
|
160
|
+
|
161
|
+
def initialize(table_name, fkey_name)
|
162
|
+
@table_name = table_name
|
163
|
+
@fkey_name = fkey_name
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class CreateEnum
|
168
|
+
include Dry::Equalizer(:enum)
|
169
|
+
attr_reader :enum
|
170
|
+
|
171
|
+
def initialize(enum)
|
172
|
+
@enum = enum
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
class DropEnum < ColumnOperation
|
177
|
+
end
|
178
|
+
|
179
|
+
class AlterEnumValues
|
180
|
+
include Dry::Equalizer(:enum_name, :new_values, :enum_fields)
|
181
|
+
attr_reader :enum_name, :new_values, :enum_fields
|
182
|
+
|
183
|
+
def initialize(enum_name, new_values, enum_fields)
|
184
|
+
@enum_name = enum_name
|
185
|
+
@new_values = new_values
|
186
|
+
@enum_fields = enum_fields
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class CreateExtension
|
191
|
+
include Dry::Equalizer(:extension)
|
192
|
+
attr_reader :extension
|
193
|
+
|
194
|
+
def initialize(extension)
|
195
|
+
@extension = extension
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
class DropExtension < ColumnOperation
|
200
|
+
end
|
201
|
+
|
202
|
+
class ExecuteQuery
|
203
|
+
include Dry::Equalizer(:query)
|
204
|
+
attr_reader :query
|
205
|
+
|
206
|
+
def initialize(query)
|
207
|
+
@query = query
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|