db_schema 0.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/Guardfile +17 -0
- data/LICENSE.txt +21 -0
- data/README.md +522 -0
- data/Rakefile +6 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/db_schema.gemspec +35 -0
- data/lib/db_schema.rb +125 -0
- data/lib/db_schema/awesome_print.rb +246 -0
- data/lib/db_schema/changes.rb +396 -0
- data/lib/db_schema/configuration.rb +29 -0
- data/lib/db_schema/definitions.rb +122 -0
- data/lib/db_schema/definitions/field.rb +38 -0
- data/lib/db_schema/definitions/field/array.rb +19 -0
- data/lib/db_schema/definitions/field/base.rb +90 -0
- data/lib/db_schema/definitions/field/binary.rb +9 -0
- data/lib/db_schema/definitions/field/bit_string.rb +15 -0
- data/lib/db_schema/definitions/field/boolean.rb +9 -0
- data/lib/db_schema/definitions/field/character.rb +19 -0
- data/lib/db_schema/definitions/field/custom.rb +22 -0
- data/lib/db_schema/definitions/field/datetime.rb +30 -0
- data/lib/db_schema/definitions/field/geometric.rb +33 -0
- data/lib/db_schema/definitions/field/json.rb +13 -0
- data/lib/db_schema/definitions/field/monetary.rb +9 -0
- data/lib/db_schema/definitions/field/network.rb +17 -0
- data/lib/db_schema/definitions/field/numeric.rb +30 -0
- data/lib/db_schema/definitions/field/range.rb +29 -0
- data/lib/db_schema/definitions/field/text_search.rb +13 -0
- data/lib/db_schema/definitions/field/uuid.rb +9 -0
- data/lib/db_schema/dsl.rb +145 -0
- data/lib/db_schema/reader.rb +270 -0
- data/lib/db_schema/runner.rb +220 -0
- data/lib/db_schema/utils.rb +50 -0
- data/lib/db_schema/validator.rb +89 -0
- data/lib/db_schema/version.rb +3 -0
- metadata +239 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module DbSchema
|
2
|
+
class Configuration
|
3
|
+
attr_reader :adapter, :host, :port, :database, :user, :password
|
4
|
+
|
5
|
+
def initialize(adapter: 'postgres', host: 'localhost', port: 5432, database:, user: nil, password: '', log_changes: true, dry_run: false, post_check: true)
|
6
|
+
@adapter = adapter
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
@database = database
|
10
|
+
@user = user
|
11
|
+
@password = password
|
12
|
+
@log_changes = log_changes
|
13
|
+
@dry_run = dry_run
|
14
|
+
@post_check = post_check
|
15
|
+
end
|
16
|
+
|
17
|
+
def log_changes?
|
18
|
+
@log_changes
|
19
|
+
end
|
20
|
+
|
21
|
+
def dry_run?
|
22
|
+
@dry_run
|
23
|
+
end
|
24
|
+
|
25
|
+
def post_check_enabled?
|
26
|
+
@post_check
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'dry/equalizer'
|
2
|
+
|
3
|
+
module DbSchema
|
4
|
+
module Definitions
|
5
|
+
class Index
|
6
|
+
include Dry::Equalizer(:name, :fields, :unique?, :type, :condition)
|
7
|
+
attr_reader :name, :fields, :type, :condition
|
8
|
+
|
9
|
+
def initialize(name:, fields:, unique: false, type: :btree, condition: nil)
|
10
|
+
@name = name.to_sym
|
11
|
+
@fields = fields
|
12
|
+
@unique = unique
|
13
|
+
@type = type
|
14
|
+
@condition = condition
|
15
|
+
end
|
16
|
+
|
17
|
+
def unique?
|
18
|
+
@unique
|
19
|
+
end
|
20
|
+
|
21
|
+
def btree?
|
22
|
+
type == :btree
|
23
|
+
end
|
24
|
+
|
25
|
+
class Field
|
26
|
+
include Dry::Equalizer(:name, :order, :nulls)
|
27
|
+
attr_reader :name, :order, :nulls
|
28
|
+
|
29
|
+
def initialize(name, order: :asc, nulls: order == :asc ? :last : :first)
|
30
|
+
@name = name
|
31
|
+
@order = order
|
32
|
+
@nulls = nulls
|
33
|
+
end
|
34
|
+
|
35
|
+
def asc?
|
36
|
+
@order == :asc
|
37
|
+
end
|
38
|
+
|
39
|
+
def desc?
|
40
|
+
@order == :desc
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_sequel
|
44
|
+
if asc?
|
45
|
+
Sequel.asc(name, nulls: nulls)
|
46
|
+
else
|
47
|
+
Sequel.desc(name, nulls: nulls)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class ForeignKey
|
54
|
+
include Dry::Equalizer(:name, :fields, :table, :keys, :on_update, :on_delete, :deferrable?)
|
55
|
+
attr_reader :name, :fields, :table, :keys, :on_update, :on_delete
|
56
|
+
|
57
|
+
def initialize(name:, fields:, table:, keys: [], on_update: :no_action, on_delete: :no_action, deferrable: false)
|
58
|
+
@name = name
|
59
|
+
@fields = fields
|
60
|
+
@table = table
|
61
|
+
@keys = keys
|
62
|
+
@on_update = on_update
|
63
|
+
@on_delete = on_delete
|
64
|
+
@deferrable = deferrable
|
65
|
+
end
|
66
|
+
|
67
|
+
def references_primary_key?
|
68
|
+
keys.empty?
|
69
|
+
end
|
70
|
+
|
71
|
+
def deferrable?
|
72
|
+
@deferrable
|
73
|
+
end
|
74
|
+
|
75
|
+
def options
|
76
|
+
{
|
77
|
+
deferrable: deferrable?,
|
78
|
+
name: name,
|
79
|
+
on_delete: on_delete,
|
80
|
+
on_update: on_update
|
81
|
+
}.tap do |options|
|
82
|
+
options[:key] = keys unless references_primary_key?
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class CheckConstraint
|
88
|
+
include Dry::Equalizer(:name, :condition)
|
89
|
+
attr_reader :name, :condition
|
90
|
+
|
91
|
+
def initialize(name:, condition:)
|
92
|
+
@name = name
|
93
|
+
@condition = condition
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Table
|
98
|
+
include Dry::Equalizer(:name, :fields, :indices, :checks, :foreign_keys)
|
99
|
+
attr_reader :name, :fields, :indices, :checks, :foreign_keys
|
100
|
+
|
101
|
+
def initialize(name, fields: [], indices: [], checks: [], foreign_keys: [])
|
102
|
+
@name = name.to_sym
|
103
|
+
@fields = fields
|
104
|
+
@indices = indices
|
105
|
+
@checks = checks
|
106
|
+
@foreign_keys = foreign_keys
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class Enum
|
111
|
+
include Dry::Equalizer(:name, :values)
|
112
|
+
attr_reader :name, :values
|
113
|
+
|
114
|
+
def initialize(name, values)
|
115
|
+
@name = name
|
116
|
+
@values = values
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
require_relative 'definitions/field'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
module Field
|
4
|
+
class << self
|
5
|
+
def build(name, type, **options)
|
6
|
+
type_class_for(type).new(name, **options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def type_class_for(type)
|
10
|
+
registry.fetch(type) do |type|
|
11
|
+
raise ArgumentError, "#{type.inspect} type is not supported."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def registry
|
16
|
+
@registry ||= {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require_relative 'field/base'
|
24
|
+
require_relative 'field/numeric'
|
25
|
+
require_relative 'field/monetary'
|
26
|
+
require_relative 'field/character'
|
27
|
+
require_relative 'field/binary'
|
28
|
+
require_relative 'field/datetime'
|
29
|
+
require_relative 'field/boolean'
|
30
|
+
require_relative 'field/geometric'
|
31
|
+
require_relative 'field/network'
|
32
|
+
require_relative 'field/bit_string'
|
33
|
+
require_relative 'field/text_search'
|
34
|
+
require_relative 'field/uuid'
|
35
|
+
require_relative 'field/json'
|
36
|
+
require_relative 'field/array'
|
37
|
+
require_relative 'field/range'
|
38
|
+
require_relative 'field/custom'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
module Field
|
4
|
+
class Array < Base
|
5
|
+
register :array
|
6
|
+
attr_reader :element_type
|
7
|
+
|
8
|
+
def initialize(name, of:, **options)
|
9
|
+
super(name, **options)
|
10
|
+
@element_type = Field.type_class_for(of)
|
11
|
+
end
|
12
|
+
|
13
|
+
def attributes
|
14
|
+
super.merge(element_type: element_type.type)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
module Field
|
4
|
+
class Base
|
5
|
+
include Dry::Equalizer(:name, :type, :primary_key?, :options)
|
6
|
+
attr_reader :name, :default
|
7
|
+
|
8
|
+
def initialize(name, primary_key: false, null: true, default: nil, **attributes)
|
9
|
+
@name = name
|
10
|
+
@primary_key = primary_key
|
11
|
+
@null = null
|
12
|
+
@default = process_default(default)
|
13
|
+
@attributes = attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
def primary_key?
|
17
|
+
@primary_key
|
18
|
+
end
|
19
|
+
|
20
|
+
def null?
|
21
|
+
!primary_key? && @null
|
22
|
+
end
|
23
|
+
|
24
|
+
def options
|
25
|
+
attributes.tap do |options|
|
26
|
+
options[:null] = false unless null?
|
27
|
+
options[:default] = default unless default.nil?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def attributes
|
32
|
+
self.class.valid_attributes.reduce({}) do |hash, attr_name|
|
33
|
+
if attr_value = @attributes[attr_name]
|
34
|
+
hash.merge(attr_name => attr_value)
|
35
|
+
elsif default_value = self.class.default_attribute_values[attr_name]
|
36
|
+
hash.merge(attr_name => default_value)
|
37
|
+
else
|
38
|
+
hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def custom_type?
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def type
|
48
|
+
self.class.type
|
49
|
+
end
|
50
|
+
|
51
|
+
def process_default(default)
|
52
|
+
if default.is_a?(Symbol)
|
53
|
+
Sequel.function(default)
|
54
|
+
else
|
55
|
+
default
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class << self
|
60
|
+
def register(*types)
|
61
|
+
types.each do |type|
|
62
|
+
Field.registry[type] = self
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def attributes(*attr_names, **attributes_with_defaults)
|
67
|
+
valid_attributes.push(*attr_names)
|
68
|
+
|
69
|
+
attributes_with_defaults.each do |attr_name, default_value|
|
70
|
+
valid_attributes.push(attr_name)
|
71
|
+
default_attribute_values[attr_name] = default_value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def valid_attributes
|
76
|
+
@valid_attributes ||= []
|
77
|
+
end
|
78
|
+
|
79
|
+
def default_attribute_values
|
80
|
+
@default_attribute_values ||= {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def type
|
84
|
+
Field.registry.key(self)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
module Field
|
4
|
+
class Char < Base
|
5
|
+
register :char, :character
|
6
|
+
attributes length: 1
|
7
|
+
end
|
8
|
+
|
9
|
+
class Varchar < Base
|
10
|
+
register :varchar, :'character varying'
|
11
|
+
attributes :length
|
12
|
+
end
|
13
|
+
|
14
|
+
class Text < Base
|
15
|
+
register :text
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
module Field
|
4
|
+
class Custom < Base
|
5
|
+
attr_reader :type_name
|
6
|
+
|
7
|
+
def initialize(name, type_name:, **options)
|
8
|
+
super(name, **options)
|
9
|
+
@type_name = type_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def custom_type?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def type
|
17
|
+
type_name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
module Field
|
4
|
+
class Timestamp < Base
|
5
|
+
register :timestamp, :'timestamp without time zone'
|
6
|
+
end
|
7
|
+
|
8
|
+
class Timestamptz < Base
|
9
|
+
register :timestamptz, :'timestamp with time zone'
|
10
|
+
end
|
11
|
+
|
12
|
+
class Date < Base
|
13
|
+
register :date
|
14
|
+
end
|
15
|
+
|
16
|
+
class Time < Base
|
17
|
+
register :time, :'time without time zone'
|
18
|
+
end
|
19
|
+
|
20
|
+
class Timetz < Base
|
21
|
+
register :timetz, :'time with time zone'
|
22
|
+
end
|
23
|
+
|
24
|
+
class Interval < Base
|
25
|
+
register :interval
|
26
|
+
attributes :fields, :precision
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DbSchema
|
2
|
+
module Definitions
|
3
|
+
module Field
|
4
|
+
class Point < Base
|
5
|
+
register :point
|
6
|
+
end
|
7
|
+
|
8
|
+
class Line < Base
|
9
|
+
register :line
|
10
|
+
end
|
11
|
+
|
12
|
+
class Lseg < Base
|
13
|
+
register :lseg
|
14
|
+
end
|
15
|
+
|
16
|
+
class Box < Base
|
17
|
+
register :box
|
18
|
+
end
|
19
|
+
|
20
|
+
class Path < Base
|
21
|
+
register :path
|
22
|
+
end
|
23
|
+
|
24
|
+
class Polygon < Base
|
25
|
+
register :polygon
|
26
|
+
end
|
27
|
+
|
28
|
+
class Circle < Base
|
29
|
+
register :circle
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|