declare_schema 0.8.0.pre.6 → 0.10.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/.github/workflows/declare_schema_build.yml +1 -1
- data/CHANGELOG.md +28 -1
- data/Gemfile.lock +1 -1
- data/README.md +91 -13
- data/lib/declare_schema.rb +46 -0
- data/lib/declare_schema/dsl.rb +39 -0
- data/lib/declare_schema/extensions/active_record/fields_declaration.rb +23 -4
- data/lib/declare_schema/model.rb +51 -59
- data/lib/declare_schema/model/field_spec.rb +11 -8
- data/lib/declare_schema/model/foreign_key_definition.rb +4 -8
- data/lib/declare_schema/model/habtm_model_shim.rb +1 -1
- data/lib/declare_schema/model/index_definition.rb +0 -19
- 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/migrator.rb +189 -202
- data/lib/generators/declare_schema/support/model.rb +4 -4
- data/spec/lib/declare_schema/api_spec.rb +7 -7
- data/spec/lib/declare_schema/field_declaration_dsl_spec.rb +41 -15
- data/spec/lib/declare_schema/field_spec_spec.rb +50 -6
- data/spec/lib/declare_schema/generator_spec.rb +3 -3
- data/spec/lib/declare_schema/interactive_primary_key_spec.rb +116 -26
- data/spec/lib/declare_schema/migration_generator_spec.rb +1891 -845
- data/spec/lib/declare_schema/model/column_spec.rb +47 -17
- data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +134 -57
- data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +3 -3
- data/spec/lib/declare_schema/model/index_definition_spec.rb +188 -77
- data/spec/lib/declare_schema/model/table_options_definition_spec.rb +75 -11
- 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/declare_schema_spec.rb +101 -0
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +71 -13
- data/spec/support/acceptance_spec_helpers.rb +2 -2
- metadata +33 -3
- data/test_responses.txt +0 -2
@@ -47,9 +47,9 @@ module DeclareSchema
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def initialize(model, name, type, position: 0, **options)
|
50
|
-
|
50
|
+
_defined_primary_key = model._defined_primary_key
|
51
51
|
|
52
|
-
name.to_s ==
|
52
|
+
name.to_s == _defined_primary_key and raise ArgumentError, "you may not provide a field spec for the primary key #{name.inspect}"
|
53
53
|
|
54
54
|
@model = model
|
55
55
|
@name = name.to_sym
|
@@ -58,18 +58,21 @@ module DeclareSchema
|
|
58
58
|
@position = position
|
59
59
|
@options = options.dup
|
60
60
|
|
61
|
-
@options.has_key?(:null) or @options[:null] =
|
61
|
+
@options.has_key?(:null) or @options[:null] = ::DeclareSchema.default_null
|
62
|
+
@options[:null].nil? and raise "null: must be provided for field #{model}##{@name}: #{@options.inspect} since ::DeclareSchema#default_null is set to 'nil'; do you want `null: false`?"
|
62
63
|
|
63
64
|
case @type
|
64
65
|
when :text
|
65
66
|
if self.class.mysql_text_limits?
|
66
67
|
@options[:default].nil? or raise MysqlTextMayNotHaveDefault, "when using MySQL, non-nil default may not be given for :text field #{model}##{@name}"
|
67
|
-
@options[:limit]
|
68
|
+
@options[:limit] ||= ::DeclareSchema.default_text_limit or
|
69
|
+
raise("limit: must be provided for :text field #{model}##{@name}: #{@options.inspect} since ::DeclareSchema#default_text_limit is set to 'nil'; do you want `limit: 0xffff_ffff`?")
|
70
|
+
@options[:limit] = self.class.round_up_mysql_text_limit(@options[:limit])
|
68
71
|
else
|
69
72
|
@options.delete(:limit)
|
70
73
|
end
|
71
74
|
when :string
|
72
|
-
@options[:limit] or raise "limit: must be
|
75
|
+
@options[:limit] ||= ::DeclareSchema.default_string_limit or raise "limit: must be provided for :string field #{model}##{@name}: #{@options.inspect} since ::DeclareSchema#default_string_limit is set to 'nil'; do you want `limit: 255`?"
|
73
76
|
when :bigint
|
74
77
|
@type = :integer
|
75
78
|
@options[:limit] = 8
|
@@ -96,15 +99,15 @@ module DeclareSchema
|
|
96
99
|
|
97
100
|
if @type.in?([:text, :string])
|
98
101
|
if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
|
99
|
-
@options[:charset] ||= model.table_options[:charset] ||
|
100
|
-
@options[:collation] ||= model.table_options[:collation] ||
|
102
|
+
@options[:charset] ||= model.table_options[:charset] || ::DeclareSchema.default_charset
|
103
|
+
@options[:collation] ||= model.table_options[:collation] || ::DeclareSchema.default_collation
|
101
104
|
else
|
102
105
|
@options.delete(:charset)
|
103
106
|
@options.delete(:collation)
|
104
107
|
end
|
105
108
|
else
|
106
109
|
@options[:charset] and warn("charset may only given for :string and :text fields for SQL type #{@type} in field #{model}##{@name}")
|
107
|
-
@options[:collation] and
|
110
|
+
@options[:collation] and warn("collation may only given for :string and :text fields for SQL type #{@type} in field #{model}##{@name}")
|
108
111
|
end
|
109
112
|
|
110
113
|
@options = Hash[@options.sort_by { |k, _v| OPTION_INDEXES[k] || 9999 }]
|
@@ -7,14 +7,15 @@ module DeclareSchema
|
|
7
7
|
class ForeignKeyDefinition
|
8
8
|
include Comparable
|
9
9
|
|
10
|
-
attr_reader :constraint_name, :model, :foreign_key, :foreign_key_name, :options, :on_delete_cascade
|
10
|
+
attr_reader :constraint_name, :model, :foreign_key, :foreign_key_name, :parent_table_name, :child_table_name, :options, :on_delete_cascade
|
11
|
+
|
11
12
|
|
12
13
|
def initialize(model, foreign_key, options = {})
|
13
14
|
@model = model
|
14
15
|
@foreign_key = foreign_key.to_s.presence
|
15
16
|
@options = options
|
16
17
|
|
17
|
-
@
|
18
|
+
@child_table_name = model.table_name # unless a table rename, which would happen when a class is renamed??
|
18
19
|
@parent_table_name = options[:parent_table]&.to_s
|
19
20
|
@foreign_key_name = options[:foreign_key]&.to_s || @foreign_key
|
20
21
|
|
@@ -61,11 +62,6 @@ module DeclareSchema
|
|
61
62
|
foreign_key.sub(/_id\z/, '').camelize.constantize.table_name
|
62
63
|
end
|
63
64
|
|
64
|
-
def to_add_statement
|
65
|
-
"add_foreign_key(#{@child_table.inspect}, #{parent_table_name.inspect}, " +
|
66
|
-
"column: #{@foreign_key_name.inspect}, name: #{@constraint_name.inspect})"
|
67
|
-
end
|
68
|
-
|
69
65
|
def <=>(rhs)
|
70
66
|
key <=> rhs.send(:key)
|
71
67
|
end
|
@@ -75,7 +71,7 @@ module DeclareSchema
|
|
75
71
|
private
|
76
72
|
|
77
73
|
def key
|
78
|
-
@key ||= [@
|
74
|
+
@key ||= [@child_table_name, parent_table_name, @foreign_key_name, @on_delete_cascade].map(&:to_s)
|
79
75
|
end
|
80
76
|
|
81
77
|
def hash
|
@@ -93,25 +93,6 @@ module DeclareSchema
|
|
93
93
|
name == PRIMARY_KEY_NAME
|
94
94
|
end
|
95
95
|
|
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
96
|
def to_key
|
116
97
|
@key ||= [table, fields, name, unique, where].map(&:to_s)
|
117
98
|
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
|