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
@@ -1,29 +1,48 @@
|
|
1
|
+
require 'dry/equalizer'
|
2
|
+
|
1
3
|
module DbSchema
|
2
4
|
class Configuration
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
include Dry::Equalizer(:params)
|
6
|
+
|
7
|
+
DEFAULT_VALUES = {
|
8
|
+
adapter: 'postgres',
|
9
|
+
host: 'localhost',
|
10
|
+
port: 5432,
|
11
|
+
database: nil,
|
12
|
+
user: nil,
|
13
|
+
password: '',
|
14
|
+
log_changes: true,
|
15
|
+
dry_run: false,
|
16
|
+
post_check: true
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
def initialize(params = {})
|
20
|
+
@params = DEFAULT_VALUES.merge(params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def merge(new_params)
|
24
|
+
Configuration.new(@params.merge(new_params))
|
25
|
+
end
|
26
|
+
|
27
|
+
[:adapter, :host, :port, :database, :user, :password].each do |param_name|
|
28
|
+
define_method(param_name) do
|
29
|
+
@params[param_name]
|
30
|
+
end
|
15
31
|
end
|
16
32
|
|
17
33
|
def log_changes?
|
18
|
-
@log_changes
|
34
|
+
@params[:log_changes]
|
19
35
|
end
|
20
36
|
|
21
37
|
def dry_run?
|
22
|
-
@dry_run
|
38
|
+
@params[:dry_run]
|
23
39
|
end
|
24
40
|
|
25
41
|
def post_check_enabled?
|
26
|
-
@post_check
|
42
|
+
@params[:post_check]
|
27
43
|
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
attr_reader :params
|
28
47
|
end
|
29
48
|
end
|
@@ -1,255 +1,10 @@
|
|
1
1
|
require 'dry/equalizer'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class Schema
|
6
|
-
include Dry::Equalizer(:tables, :enums, :extensions)
|
7
|
-
attr_reader :tables, :enums, :extensions
|
8
|
-
attr_writer :tables
|
9
|
-
|
10
|
-
def initialize(tables: [], enums: [], extensions: [])
|
11
|
-
@tables = tables
|
12
|
-
@enums = enums
|
13
|
-
@extensions = extensions
|
14
|
-
end
|
15
|
-
|
16
|
-
def [](table_name)
|
17
|
-
tables.find { |table| table.name == table_name } || NullTable.new
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class Table
|
22
|
-
include Dry::Equalizer(:name, :fields, :indices, :checks, :foreign_keys)
|
23
|
-
attr_reader :name, :fields, :indices, :checks, :foreign_keys
|
24
|
-
|
25
|
-
def initialize(name, fields: [], indices: [], checks: [], foreign_keys: [])
|
26
|
-
@name = name.to_sym
|
27
|
-
@fields = fields
|
28
|
-
@indices = indices
|
29
|
-
@checks = checks
|
30
|
-
@foreign_keys = foreign_keys
|
31
|
-
end
|
32
|
-
|
33
|
-
def has_expressions?
|
34
|
-
fields.any?(&:default_is_expression?) ||
|
35
|
-
indices.any?(&:has_expressions?) ||
|
36
|
-
checks.any?
|
37
|
-
end
|
38
|
-
|
39
|
-
def [](field_name)
|
40
|
-
fields.find { |field| field.name == field_name }
|
41
|
-
end
|
42
|
-
|
43
|
-
def with_name(new_name)
|
44
|
-
Table.new(
|
45
|
-
new_name,
|
46
|
-
fields: fields,
|
47
|
-
indices: indices,
|
48
|
-
checks: checks,
|
49
|
-
foreign_keys: foreign_keys
|
50
|
-
)
|
51
|
-
end
|
52
|
-
|
53
|
-
def with_fields(new_fields)
|
54
|
-
Table.new(
|
55
|
-
name,
|
56
|
-
fields: new_fields,
|
57
|
-
indices: indices,
|
58
|
-
checks: checks,
|
59
|
-
foreign_keys: foreign_keys
|
60
|
-
)
|
61
|
-
end
|
62
|
-
|
63
|
-
def with_indices(new_indices)
|
64
|
-
Table.new(
|
65
|
-
name,
|
66
|
-
fields: fields,
|
67
|
-
indices: new_indices,
|
68
|
-
checks: checks,
|
69
|
-
foreign_keys: foreign_keys
|
70
|
-
)
|
71
|
-
end
|
72
|
-
|
73
|
-
def with_foreign_keys(new_foreign_keys)
|
74
|
-
Table.new(
|
75
|
-
name,
|
76
|
-
fields: fields,
|
77
|
-
indices: indices,
|
78
|
-
checks: checks,
|
79
|
-
foreign_keys: new_foreign_keys
|
80
|
-
)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class NullTable < Table
|
85
|
-
def initialize; end
|
86
|
-
end
|
87
|
-
|
88
|
-
class Index
|
89
|
-
include Dry::Equalizer(:name, :columns, :unique?, :type, :condition)
|
90
|
-
attr_reader :name, :columns, :type, :condition
|
91
|
-
|
92
|
-
def initialize(name:, columns:, unique: false, type: :btree, condition: nil)
|
93
|
-
@name = name.to_sym
|
94
|
-
@columns = columns
|
95
|
-
@unique = unique
|
96
|
-
@type = type
|
97
|
-
@condition = condition
|
98
|
-
end
|
99
|
-
|
100
|
-
def unique?
|
101
|
-
@unique
|
102
|
-
end
|
103
|
-
|
104
|
-
def btree?
|
105
|
-
type == :btree
|
106
|
-
end
|
107
|
-
|
108
|
-
def columns_to_sequel
|
109
|
-
if btree?
|
110
|
-
columns.map(&:ordered_expression)
|
111
|
-
else
|
112
|
-
columns.map(&:to_sequel)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def has_expressions?
|
117
|
-
!condition.nil? || columns.any?(&:expression?)
|
118
|
-
end
|
119
|
-
|
120
|
-
def with_name(new_name)
|
121
|
-
Index.new(
|
122
|
-
name: new_name,
|
123
|
-
columns: columns,
|
124
|
-
unique: unique?,
|
125
|
-
type: type,
|
126
|
-
condition: condition
|
127
|
-
)
|
128
|
-
end
|
129
|
-
|
130
|
-
class Column
|
131
|
-
include Dry::Equalizer(:name, :order, :nulls)
|
132
|
-
attr_reader :name, :order, :nulls
|
133
|
-
|
134
|
-
def initialize(name, order: :asc, nulls: order == :asc ? :last : :first)
|
135
|
-
@name = name
|
136
|
-
@order = order
|
137
|
-
@nulls = nulls
|
138
|
-
end
|
139
|
-
|
140
|
-
def asc?
|
141
|
-
@order == :asc
|
142
|
-
end
|
143
|
-
|
144
|
-
def desc?
|
145
|
-
@order == :desc
|
146
|
-
end
|
147
|
-
|
148
|
-
def ordered_expression
|
149
|
-
if asc?
|
150
|
-
Sequel.asc(to_sequel, nulls: nulls)
|
151
|
-
else
|
152
|
-
Sequel.desc(to_sequel, nulls: nulls)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
class TableField < Column
|
158
|
-
def expression?
|
159
|
-
false
|
160
|
-
end
|
161
|
-
|
162
|
-
def index_name_segment
|
163
|
-
name
|
164
|
-
end
|
165
|
-
|
166
|
-
def to_sequel
|
167
|
-
name
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
class Expression < Column
|
172
|
-
def expression?
|
173
|
-
true
|
174
|
-
end
|
175
|
-
|
176
|
-
def index_name_segment
|
177
|
-
name.scan(/\b[A-Za-z0-9_]+\b/).join('_')
|
178
|
-
end
|
179
|
-
|
180
|
-
def to_sequel
|
181
|
-
Sequel.lit("(#{name})")
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
class ForeignKey
|
187
|
-
include Dry::Equalizer(:name, :fields, :table, :keys, :on_update, :on_delete, :deferrable?)
|
188
|
-
attr_reader :name, :fields, :table, :keys, :on_update, :on_delete
|
189
|
-
|
190
|
-
def initialize(name:, fields:, table:, keys: [], on_update: :no_action, on_delete: :no_action, deferrable: false)
|
191
|
-
@name = name
|
192
|
-
@fields = fields
|
193
|
-
@table = table
|
194
|
-
@keys = keys
|
195
|
-
@on_update = on_update
|
196
|
-
@on_delete = on_delete
|
197
|
-
@deferrable = deferrable
|
198
|
-
end
|
199
|
-
|
200
|
-
def references_primary_key?
|
201
|
-
keys.empty?
|
202
|
-
end
|
203
|
-
|
204
|
-
def deferrable?
|
205
|
-
@deferrable
|
206
|
-
end
|
207
|
-
|
208
|
-
def options
|
209
|
-
{
|
210
|
-
deferrable: deferrable?,
|
211
|
-
name: name,
|
212
|
-
on_delete: on_delete,
|
213
|
-
on_update: on_update
|
214
|
-
}.tap do |options|
|
215
|
-
options[:key] = keys unless references_primary_key?
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
class CheckConstraint
|
221
|
-
include Dry::Equalizer(:name, :condition)
|
222
|
-
attr_reader :name, :condition
|
223
|
-
|
224
|
-
def initialize(name:, condition:)
|
225
|
-
@name = name.to_sym
|
226
|
-
@condition = condition
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
class Enum
|
231
|
-
include Dry::Equalizer(:name, :values)
|
232
|
-
attr_reader :name, :values
|
233
|
-
|
234
|
-
def initialize(name, values)
|
235
|
-
@name = name
|
236
|
-
@values = values
|
237
|
-
end
|
238
|
-
|
239
|
-
def with_name(new_name)
|
240
|
-
Enum.new(new_name, values)
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
class Extension
|
245
|
-
include Dry::Equalizer(:name)
|
246
|
-
attr_reader :name
|
247
|
-
|
248
|
-
def initialize(name)
|
249
|
-
@name = name
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
3
|
+
require_relative 'definitions/schema'
|
4
|
+
require_relative 'definitions/table'
|
255
5
|
require_relative 'definitions/field'
|
6
|
+
require_relative 'definitions/index'
|
7
|
+
require_relative 'definitions/foreign_key'
|
8
|
+
require_relative 'definitions/check_constraint'
|
9
|
+
require_relative 'definitions/enum'
|
10
|
+
require_relative 'definitions/extension'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
class CheckConstraint
|
4
|
+
include Dry::Equalizer(:name, :condition)
|
5
|
+
attr_reader :name, :condition
|
6
|
+
|
7
|
+
def initialize(name:, condition:)
|
8
|
+
@name = name.to_sym
|
9
|
+
@condition = condition
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class NullCheckConstraint < CheckConstraint
|
14
|
+
def initialize; end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
class Enum
|
4
|
+
include Dry::Equalizer(:name, :values)
|
5
|
+
attr_reader :name, :values
|
6
|
+
|
7
|
+
def initialize(name, values)
|
8
|
+
@name = name
|
9
|
+
@values = values
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_name(new_name)
|
13
|
+
Enum.new(new_name, values)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class NullEnum < Enum
|
18
|
+
def initialize; end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
class ForeignKey
|
4
|
+
include Dry::Equalizer(:name, :fields, :table, :keys, :on_update, :on_delete, :deferrable?)
|
5
|
+
attr_reader :name, :fields, :table, :keys, :on_update, :on_delete
|
6
|
+
|
7
|
+
def initialize(name:, fields:, table:, keys: [], on_update: :no_action, on_delete: :no_action, deferrable: false)
|
8
|
+
@name = name
|
9
|
+
@fields = fields
|
10
|
+
@table = table
|
11
|
+
@keys = keys
|
12
|
+
@on_update = on_update
|
13
|
+
@on_delete = on_delete
|
14
|
+
@deferrable = deferrable
|
15
|
+
end
|
16
|
+
|
17
|
+
def references_primary_key?
|
18
|
+
keys.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def deferrable?
|
22
|
+
@deferrable
|
23
|
+
end
|
24
|
+
|
25
|
+
def options
|
26
|
+
{
|
27
|
+
deferrable: deferrable?,
|
28
|
+
name: name,
|
29
|
+
on_delete: on_delete,
|
30
|
+
on_update: on_update
|
31
|
+
}.tap do |options|
|
32
|
+
options[:key] = keys unless references_primary_key?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class NullForeignKey < ForeignKey
|
38
|
+
def initialize; end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
class Index
|
4
|
+
include Dry::Equalizer(:name, :columns, :unique?, :type, :condition)
|
5
|
+
attr_reader :name, :columns, :type, :condition
|
6
|
+
|
7
|
+
def initialize(name:, columns:, unique: false, type: :btree, condition: nil)
|
8
|
+
@name = name.to_sym
|
9
|
+
@columns = columns
|
10
|
+
@unique = unique
|
11
|
+
@type = type
|
12
|
+
@condition = condition
|
13
|
+
end
|
14
|
+
|
15
|
+
def unique?
|
16
|
+
@unique
|
17
|
+
end
|
18
|
+
|
19
|
+
def btree?
|
20
|
+
type == :btree
|
21
|
+
end
|
22
|
+
|
23
|
+
def columns_to_sequel
|
24
|
+
if btree?
|
25
|
+
columns.map(&:ordered_expression)
|
26
|
+
else
|
27
|
+
columns.map(&:to_sequel)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_expressions?
|
32
|
+
!condition.nil? || columns.any?(&:expression?)
|
33
|
+
end
|
34
|
+
|
35
|
+
def with_name(new_name)
|
36
|
+
Index.new(
|
37
|
+
name: new_name,
|
38
|
+
columns: columns,
|
39
|
+
unique: unique?,
|
40
|
+
type: type,
|
41
|
+
condition: condition
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class NullIndex < Index
|
47
|
+
def initialize
|
48
|
+
@columns = []
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require_relative 'index/column'
|
55
|
+
require_relative 'index/table_field'
|
56
|
+
require_relative 'index/expression'
|