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.
@@ -0,0 +1,12 @@
1
+ module DbSchema
2
+ class Migration
3
+ include Dry::Equalizer(:name, :conditions, :body)
4
+ attr_reader :name, :conditions
5
+ attr_accessor :body
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ @conditions = { apply: [], skip: [] }
10
+ end
11
+ end
12
+ end
@@ -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
@@ -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 = schema
7
+ def initialize(schema, connection)
8
+ @schema = schema
9
+ @connection = connection
9
10
  end
10
11
 
11
12
  def normalize_tables
12
- DbSchema.connection.transaction do
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
- Changes::CreateExtension.new(extension)
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
- Changes::CreateEnum.new(enum.with_name(append_hash(enum.name)))
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 = table
64
- @hash = 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 = Changes::CreateTable.new(
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