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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +17 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +522 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +10 -0
  11. data/bin/setup +8 -0
  12. data/db_schema.gemspec +35 -0
  13. data/lib/db_schema.rb +125 -0
  14. data/lib/db_schema/awesome_print.rb +246 -0
  15. data/lib/db_schema/changes.rb +396 -0
  16. data/lib/db_schema/configuration.rb +29 -0
  17. data/lib/db_schema/definitions.rb +122 -0
  18. data/lib/db_schema/definitions/field.rb +38 -0
  19. data/lib/db_schema/definitions/field/array.rb +19 -0
  20. data/lib/db_schema/definitions/field/base.rb +90 -0
  21. data/lib/db_schema/definitions/field/binary.rb +9 -0
  22. data/lib/db_schema/definitions/field/bit_string.rb +15 -0
  23. data/lib/db_schema/definitions/field/boolean.rb +9 -0
  24. data/lib/db_schema/definitions/field/character.rb +19 -0
  25. data/lib/db_schema/definitions/field/custom.rb +22 -0
  26. data/lib/db_schema/definitions/field/datetime.rb +30 -0
  27. data/lib/db_schema/definitions/field/geometric.rb +33 -0
  28. data/lib/db_schema/definitions/field/json.rb +13 -0
  29. data/lib/db_schema/definitions/field/monetary.rb +9 -0
  30. data/lib/db_schema/definitions/field/network.rb +17 -0
  31. data/lib/db_schema/definitions/field/numeric.rb +30 -0
  32. data/lib/db_schema/definitions/field/range.rb +29 -0
  33. data/lib/db_schema/definitions/field/text_search.rb +13 -0
  34. data/lib/db_schema/definitions/field/uuid.rb +9 -0
  35. data/lib/db_schema/dsl.rb +145 -0
  36. data/lib/db_schema/reader.rb +270 -0
  37. data/lib/db_schema/runner.rb +220 -0
  38. data/lib/db_schema/utils.rb +50 -0
  39. data/lib/db_schema/validator.rb +89 -0
  40. data/lib/db_schema/version.rb +3 -0
  41. 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,9 @@
1
+ module DbSchema
2
+ module Definitions
3
+ module Field
4
+ class Bytea < Base
5
+ register :bytea
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ module DbSchema
2
+ module Definitions
3
+ module Field
4
+ class Bit < Base
5
+ register :bit
6
+ attributes length: 1
7
+ end
8
+
9
+ class Varbit < Base
10
+ register :varbit, :'bit varying'
11
+ attributes :length
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module DbSchema
2
+ module Definitions
3
+ module Field
4
+ class Boolean < Base
5
+ register :boolean
6
+ end
7
+ end
8
+ end
9
+ 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