declare_schema 0.10.0.pre.dc.1 → 0.12.0.pre.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 +4 -4
- data/CHANGELOG.md +32 -2
- data/Gemfile.lock +1 -1
- data/README.md +16 -6
- data/lib/declare_schema.rb +12 -1
- data/lib/declare_schema/dsl.rb +1 -2
- data/lib/declare_schema/extensions/active_record/fields_declaration.rb +4 -2
- data/lib/declare_schema/model.rb +59 -15
- data/lib/declare_schema/model/column.rb +2 -2
- data/lib/declare_schema/model/field_spec.rb +4 -4
- data/lib/declare_schema/model/foreign_key_definition.rb +6 -11
- data/lib/declare_schema/model/habtm_model_shim.rb +2 -2
- data/lib/declare_schema/model/index_definition.rb +8 -25
- data/lib/declare_schema/schema_change/all.rb +22 -0
- data/lib/declare_schema/schema_change/base.rb +45 -0
- data/lib/declare_schema/schema_change/column_add.rb +27 -0
- data/lib/declare_schema/schema_change/column_change.rb +32 -0
- data/lib/declare_schema/schema_change/column_remove.rb +20 -0
- data/lib/declare_schema/schema_change/column_rename.rb +23 -0
- data/lib/declare_schema/schema_change/foreign_key_add.rb +25 -0
- data/lib/declare_schema/schema_change/foreign_key_remove.rb +20 -0
- data/lib/declare_schema/schema_change/index_add.rb +33 -0
- data/lib/declare_schema/schema_change/index_remove.rb +20 -0
- data/lib/declare_schema/schema_change/primary_key_change.rb +33 -0
- data/lib/declare_schema/schema_change/table_add.rb +37 -0
- data/lib/declare_schema/schema_change/table_change.rb +36 -0
- data/lib/declare_schema/schema_change/table_remove.rb +22 -0
- data/lib/declare_schema/schema_change/table_rename.rb +22 -0
- data/lib/declare_schema/version.rb +1 -1
- data/lib/generators/declare_schema/migration/USAGE +14 -24
- data/lib/generators/declare_schema/migration/migration_generator.rb +40 -38
- data/lib/generators/declare_schema/migration/migrator.rb +190 -187
- data/lib/generators/declare_schema/migration/templates/migration.rb.erb +3 -3
- data/spec/lib/declare_schema/api_spec.rb +3 -1
- data/spec/lib/declare_schema/field_spec_spec.rb +3 -3
- data/spec/lib/declare_schema/generator_spec.rb +2 -2
- data/spec/lib/declare_schema/interactive_primary_key_spec.rb +60 -25
- data/spec/lib/declare_schema/migration_generator_spec.rb +471 -377
- data/spec/lib/declare_schema/model/column_spec.rb +2 -6
- data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +28 -16
- data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +4 -6
- data/spec/lib/declare_schema/model/index_definition_spec.rb +4 -4
- data/spec/lib/declare_schema/schema_change/base_spec.rb +75 -0
- data/spec/lib/declare_schema/schema_change/column_add_spec.rb +30 -0
- data/spec/lib/declare_schema/schema_change/column_change_spec.rb +33 -0
- data/spec/lib/declare_schema/schema_change/column_remove_spec.rb +30 -0
- data/spec/lib/declare_schema/schema_change/column_rename_spec.rb +28 -0
- data/spec/lib/declare_schema/schema_change/foreign_key_add_spec.rb +29 -0
- data/spec/lib/declare_schema/schema_change/foreign_key_remove_spec.rb +29 -0
- data/spec/lib/declare_schema/schema_change/index_add_spec.rb +56 -0
- data/spec/lib/declare_schema/schema_change/index_remove_spec.rb +29 -0
- data/spec/lib/declare_schema/schema_change/primary_key_change_spec.rb +69 -0
- data/spec/lib/declare_schema/schema_change/table_add_spec.rb +50 -0
- data/spec/lib/declare_schema/schema_change/table_change_spec.rb +30 -0
- data/spec/lib/declare_schema/schema_change/table_remove_spec.rb +27 -0
- data/spec/lib/declare_schema/schema_change/table_rename_spec.rb +27 -0
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +59 -11
- data/spec/spec_helper.rb +1 -1
- data/spec/support/acceptance_spec_helpers.rb +2 -2
- metadata +34 -5
@@ -37,7 +37,7 @@ module DeclareSchema
|
|
37
37
|
def for_model(model, old_table_name = nil)
|
38
38
|
t = old_table_name || model.table_name
|
39
39
|
|
40
|
-
primary_key_columns = Array(model.connection.primary_key(t)).presence ||
|
40
|
+
primary_key_columns = Array(model.connection.primary_key(t)).presence || fallback_find_primary_key(model, t) or
|
41
41
|
raise "could not find primary key for table #{t} in #{model.connection.columns(t).inspect}"
|
42
42
|
|
43
43
|
primary_key_found = false
|
@@ -67,8 +67,8 @@ module DeclareSchema
|
|
67
67
|
private
|
68
68
|
|
69
69
|
# This is the old approach which is still needed for MySQL in Rails 4 and SQLite
|
70
|
-
def
|
71
|
-
ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/) ||
|
70
|
+
def fallback_find_primary_key(model, table)
|
71
|
+
ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/) || ActiveSupport::VERSION::MAJOR < 5 or return nil
|
72
72
|
|
73
73
|
connection = model.connection.dup
|
74
74
|
|
@@ -83,9 +83,11 @@ module DeclareSchema
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
pk_index = connection.indexes(table).find { |index| index.name.to_s == PRIMARY_KEY_NAME }
|
87
|
-
|
88
|
-
|
86
|
+
if (pk_index = connection.indexes(table).find { |index| index.name.to_s == PRIMARY_KEY_NAME })
|
87
|
+
Array(pk_index.columns)
|
88
|
+
elsif model.connection.columns(table).any? { |col| col.name == 'id' }
|
89
|
+
['id']
|
90
|
+
end
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
@@ -93,25 +95,6 @@ module DeclareSchema
|
|
93
95
|
name == PRIMARY_KEY_NAME
|
94
96
|
end
|
95
97
|
|
96
|
-
def to_add_statement(new_table_name, existing_primary_key = nil)
|
97
|
-
if primary_key? && !ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/)
|
98
|
-
to_add_primary_key_statement(new_table_name, existing_primary_key)
|
99
|
-
else
|
100
|
-
# Note: + below keeps that interpolated string from being frozen, so we can << into it.
|
101
|
-
r = +"add_index #{new_table_name.to_sym.inspect}, #{fields.map(&:to_sym).inspect}"
|
102
|
-
r << ", unique: true" if unique
|
103
|
-
r << ", where: '#{where}'" if where.present?
|
104
|
-
r << ", name: '#{name}'"
|
105
|
-
r
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def to_add_primary_key_statement(new_table_name, existing_primary_key)
|
110
|
-
drop = "DROP PRIMARY KEY, " if existing_primary_key
|
111
|
-
statement = "ALTER TABLE #{new_table_name} #{drop}ADD PRIMARY KEY (#{fields.join(', ')})"
|
112
|
-
"execute #{statement.inspect}"
|
113
|
-
end
|
114
|
-
|
115
98
|
def to_key
|
116
99
|
@key ||= [table, fields, name, unique, where].map(&:to_s)
|
117
100
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeclareSchema
|
4
|
+
module SchemaChange
|
5
|
+
module All
|
6
|
+
end
|
7
|
+
autoload :Base, 'declare_schema/schema_change/base'
|
8
|
+
autoload :ColumnAdd, 'declare_schema/schema_change/column_add'
|
9
|
+
autoload :ColumnChange, 'declare_schema/schema_change/column_change'
|
10
|
+
autoload :ColumnRename, 'declare_schema/schema_change/column_rename'
|
11
|
+
autoload :ForeignKeyAdd, 'declare_schema/schema_change/foreign_key_add'
|
12
|
+
autoload :ForeignKeyRemove, 'declare_schema/schema_change/foreign_key_remove'
|
13
|
+
autoload :IndexAdd, 'declare_schema/schema_change/index_add'
|
14
|
+
autoload :IndexRemove, 'declare_schema/schema_change/index_remove'
|
15
|
+
autoload :PrimaryKeyChange, 'declare_schema/schema_change/primary_key_change'
|
16
|
+
autoload :TableAdd, 'declare_schema/schema_change/table_add'
|
17
|
+
autoload :TableChange, 'declare_schema/schema_change/table_change'
|
18
|
+
autoload :TableRemove, 'declare_schema/schema_change/table_remove'
|
19
|
+
autoload :TableRename, 'declare_schema/schema_change/table_rename'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class Base
|
8
|
+
class << self
|
9
|
+
def format_options(options)
|
10
|
+
options.map do |k, v|
|
11
|
+
value =
|
12
|
+
if v.is_a?(Hash)
|
13
|
+
"{ #{format_options(v).join(', ')} }"
|
14
|
+
else
|
15
|
+
v.inspect
|
16
|
+
end
|
17
|
+
if k.is_a?(Symbol)
|
18
|
+
"#{k}: #{value}"
|
19
|
+
else
|
20
|
+
"#{k.inspect} => #{value}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def up
|
27
|
+
up_command + spacing(up_command)
|
28
|
+
end
|
29
|
+
|
30
|
+
def down
|
31
|
+
down_command + spacing(down_command)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def spacing(command)
|
37
|
+
if command["\n"]
|
38
|
+
"\n\n"
|
39
|
+
else
|
40
|
+
"\n"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class ColumnAdd < Base
|
8
|
+
def initialize(table_name, column_name, column_type, **column_options)
|
9
|
+
@table_name = table_name
|
10
|
+
@column_name = column_name
|
11
|
+
@column_type = column_type
|
12
|
+
@column_options = column_options
|
13
|
+
end
|
14
|
+
|
15
|
+
def up_command
|
16
|
+
"add_column #{[@table_name.to_sym.inspect,
|
17
|
+
@column_name.to_sym.inspect,
|
18
|
+
@column_type.to_sym.inspect,
|
19
|
+
*self.class.format_options(@column_options)].join(", ")}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def down_command
|
23
|
+
"remove_column #{@table_name.to_sym.inspect}, #{@column_name.to_sym.inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class ColumnChange < Base
|
8
|
+
def initialize(table_name, column_name, old_type:, old_options:, new_type:, new_options:)
|
9
|
+
@table_name = table_name
|
10
|
+
@column_name = column_name
|
11
|
+
@old_type = old_type
|
12
|
+
@old_options = old_options
|
13
|
+
@new_type = new_type
|
14
|
+
@new_options = new_options
|
15
|
+
end
|
16
|
+
|
17
|
+
def up_command
|
18
|
+
"change_column #{[@table_name.to_sym.inspect,
|
19
|
+
@column_name.to_sym.inspect,
|
20
|
+
@new_type.to_sym.inspect,
|
21
|
+
*self.class.format_options(@new_options)].join(", ")}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def down_command
|
25
|
+
"change_column #{[@table_name.to_sym.inspect,
|
26
|
+
@column_name.to_sym.inspect,
|
27
|
+
@old_type.to_sym.inspect,
|
28
|
+
*self.class.format_options(@old_options)].join(", ")}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'column_add'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class ColumnRemove < ColumnAdd
|
8
|
+
alias column_add_up_command up_command
|
9
|
+
alias column_add_down_command down_command
|
10
|
+
|
11
|
+
def up_command
|
12
|
+
column_add_down_command
|
13
|
+
end
|
14
|
+
|
15
|
+
def down_command
|
16
|
+
column_add_up_command
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class ColumnRename < Base
|
8
|
+
def initialize(table_name, old_name, new_name)
|
9
|
+
@table_name = table_name
|
10
|
+
@old_name = old_name
|
11
|
+
@new_name = new_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def up_command
|
15
|
+
"rename_column #{@table_name.to_sym.inspect}, #{@old_name.to_sym.inspect}, #{@new_name.to_sym.inspect}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def down_command
|
19
|
+
"rename_column #{@table_name.to_sym.inspect}, #{@new_name.to_sym.inspect}, #{@old_name.to_sym.inspect}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class ForeignKeyAdd < Base
|
8
|
+
def initialize(table_name, parent_table_name, column_name:, name:)
|
9
|
+
@table_name = table_name
|
10
|
+
@parent_table_name = parent_table_name
|
11
|
+
@column_name = column_name
|
12
|
+
@name = name
|
13
|
+
end
|
14
|
+
|
15
|
+
def up_command
|
16
|
+
"add_foreign_key #{@table_name.to_sym.inspect}, #{@parent_table_name.to_sym.inspect}, " +
|
17
|
+
"column: #{@column_name.to_sym.inspect}, name: #{@name.to_sym.inspect}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def down_command
|
21
|
+
"remove_foreign_key #{@table_name.to_sym.inspect}, name: #{@name.to_sym.inspect}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'foreign_key_add'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class ForeignKeyRemove < ForeignKeyAdd
|
8
|
+
alias index_add_up_command up_command
|
9
|
+
alias index_add_down_command down_command
|
10
|
+
|
11
|
+
def up_command
|
12
|
+
index_add_down_command
|
13
|
+
end
|
14
|
+
|
15
|
+
def down_command
|
16
|
+
index_add_up_command
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class IndexAdd < Base
|
8
|
+
def initialize(table_name, column_names, name:, unique:, where: nil)
|
9
|
+
@table_name = table_name
|
10
|
+
@column_names = column_names
|
11
|
+
@name = name
|
12
|
+
@unique = unique
|
13
|
+
@where = where.presence
|
14
|
+
end
|
15
|
+
|
16
|
+
def up_command
|
17
|
+
options = {
|
18
|
+
name: @name.to_sym,
|
19
|
+
}
|
20
|
+
options[:unique] = true if @unique
|
21
|
+
options[:where] = @where if @where
|
22
|
+
|
23
|
+
"add_index #{[@table_name.to_sym.inspect,
|
24
|
+
@column_names.map(&:to_sym).inspect,
|
25
|
+
*self.class.format_options(options)].join(', ')}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def down_command
|
29
|
+
"remove_index #{@table_name.to_sym.inspect}, name: #{@name.to_sym.inspect}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'index_add'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class IndexRemove < IndexAdd
|
8
|
+
alias index_add_up_command up_command
|
9
|
+
alias index_add_down_command down_command
|
10
|
+
|
11
|
+
def up_command
|
12
|
+
index_add_down_command
|
13
|
+
end
|
14
|
+
|
15
|
+
def down_command
|
16
|
+
index_add_up_command
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class PrimaryKeyChange < Base
|
8
|
+
def initialize(table_name, old_column_names, new_column_names)
|
9
|
+
@table_name = table_name
|
10
|
+
@old_column_names = old_column_names.presence
|
11
|
+
@new_column_names = new_column_names.presence
|
12
|
+
end
|
13
|
+
|
14
|
+
def up_command
|
15
|
+
alter_primary_key(@old_column_names, @new_column_names)
|
16
|
+
end
|
17
|
+
|
18
|
+
def down_command
|
19
|
+
alter_primary_key(@new_column_names, @old_column_names)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def alter_primary_key(old_col_names, new_col_names)
|
25
|
+
drop_command = "DROP PRIMARY KEY" if old_col_names
|
26
|
+
add_command = "ADD PRIMARY KEY (#{new_col_names.join(', ')})" if new_col_names
|
27
|
+
commands = [drop_command, add_command].compact.join(', ')
|
28
|
+
statement = "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(@table_name)} #{commands}"
|
29
|
+
"execute #{statement.inspect}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class TableAdd < Base
|
8
|
+
def initialize(table_name, fields, create_table_options, sql_options: nil)
|
9
|
+
@table_name = table_name
|
10
|
+
fields.all? do |type, name, options|
|
11
|
+
type.is_a?(Symbol) && name.is_a?(Symbol) && options.is_a?(Hash)
|
12
|
+
end or raise ArgumentError, "fields must be Array(Array(Symbol, Symbol, Hash)); got #{fields.inspect}"
|
13
|
+
@fields = fields
|
14
|
+
@create_table_options = create_table_options
|
15
|
+
@create_table_options = @create_table_options.merge(options: sql_options) if sql_options.present?
|
16
|
+
end
|
17
|
+
|
18
|
+
def up_command
|
19
|
+
longest_field_type_length = @fields.map { |type, _name, _option| type.to_s.length }.max
|
20
|
+
|
21
|
+
<<~EOS.strip
|
22
|
+
create_table #{[@table_name.to_sym.inspect, *self.class.format_options(@create_table_options)].join(', ')} do |t|
|
23
|
+
#{@fields.map do |type, name, options|
|
24
|
+
padded_type = format("%-*s", longest_field_type_length, type)
|
25
|
+
args = [name.inspect, *self.class.format_options(options)].join(', ')
|
26
|
+
" t.#{padded_type} #{args}"
|
27
|
+
end.join("\n")}
|
28
|
+
end
|
29
|
+
EOS
|
30
|
+
end
|
31
|
+
|
32
|
+
def down_command
|
33
|
+
"drop_table #{@table_name.to_sym.inspect}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class TableChange < Base
|
8
|
+
def initialize(table_name, old_options, new_options)
|
9
|
+
@table_name = table_name
|
10
|
+
@old_options = old_options
|
11
|
+
@new_options = new_options
|
12
|
+
end
|
13
|
+
|
14
|
+
def up_command
|
15
|
+
alter_table(@table_name, @new_options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def down_command
|
19
|
+
alter_table(@table_name, @old_options)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
TABLE_OPTIONS_TO_SQL_MAPPINGS = {
|
25
|
+
charset: 'CHARACTER SET',
|
26
|
+
collation: 'COLLATE'
|
27
|
+
}.freeze
|
28
|
+
|
29
|
+
def alter_table(table_name, options)
|
30
|
+
sql_options = options.map { |key, value| [TABLE_OPTIONS_TO_SQL_MAPPINGS[key], value] }
|
31
|
+
statement = "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name)} #{sql_options.join(' ')}"
|
32
|
+
"execute #{statement.inspect}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|