declare_schema 0.6.4 → 0.7.0
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 +6 -0
- data/Gemfile.lock +4 -4
- data/lib/declare_schema/model/column.rb +168 -0
- data/lib/declare_schema/model/field_spec.rb +59 -143
- data/lib/declare_schema/version.rb +1 -1
- data/lib/generators/declare_schema/migration/migration_generator.rb +1 -1
- data/lib/generators/declare_schema/migration/migrator.rb +107 -129
- data/spec/lib/declare_schema/field_declaration_dsl_spec.rb +1 -1
- data/spec/lib/declare_schema/field_spec_spec.rb +135 -38
- data/spec/lib/declare_schema/migration_generator_spec.rb +45 -42
- data/spec/lib/declare_schema/model/column_spec.rb +141 -0
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +2 -11
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 640e3580d2babdce916a3127b95cd1c84eb8d87b89ca67116496cd3729eea33c
|
4
|
+
data.tar.gz: 30b86c95f516f37ce979ac558e64ac84f0150493392a0626495e83e68b5dc14d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60e109345bc7d2551e441a7c5618f69b3e4df28551bc6c7807329f8831eb3090770fc70c2692487495935bd7c3394f83ccb77cfff1370afccb5a33105229f790
|
7
|
+
data.tar.gz: 5f4cf408c53d963995795786ea847f6e5e4c7319fe91fd95d8eb6d4c05348ddb6cf1fcbbded15764e9b80af0e0903ec26b984d82c467a3a0a6956e421f7d5ace
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,11 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
4
4
|
|
5
5
|
Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [0.7.0] - 2020-02-14
|
8
|
+
### Changed
|
9
|
+
- Use `schema_attributes` for generating both up and down change migrations, so they are guaranteed to be symmetrical.
|
10
|
+
Note: Rails schema dumper is still used for the down migration to replace a model that has been dropped.
|
11
|
+
|
7
12
|
## [0.6.4] - 2020-02-08
|
8
13
|
- Fixed a bug where the generated call to add_foreign_key() was not setting `column:`,
|
9
14
|
so it only worked in cases where Rails could infer the foreign key by convention.
|
@@ -114,6 +119,7 @@ using the appropriate Rails configuration attributes.
|
|
114
119
|
### Added
|
115
120
|
- Initial version from https://github.com/Invoca/hobo_fields v4.1.0.
|
116
121
|
|
122
|
+
[0.7.0]: https://github.com/Invoca/declare_schema/compare/v0.6.3...v0.7.0
|
117
123
|
[0.6.4]: https://github.com/Invoca/declare_schema/compare/v0.6.3...v0.6.4
|
118
124
|
[0.6.3]: https://github.com/Invoca/declare_schema/compare/v0.6.2...v0.6.3
|
119
125
|
[0.6.2]: https://github.com/Invoca/declare_schema/compare/v0.6.1...v0.6.2
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
declare_schema (0.
|
4
|
+
declare_schema (0.7.0)
|
5
5
|
rails (>= 4.2)
|
6
6
|
|
7
7
|
GEM
|
@@ -54,7 +54,7 @@ GEM
|
|
54
54
|
thor (>= 0.14.0)
|
55
55
|
arel (9.0.0)
|
56
56
|
ast (2.4.1)
|
57
|
-
bootsnap (1.
|
57
|
+
bootsnap (1.7.2)
|
58
58
|
msgpack (~> 1.0)
|
59
59
|
builder (3.2.4)
|
60
60
|
byebug (11.1.3)
|
@@ -84,7 +84,7 @@ GEM
|
|
84
84
|
mini_mime (1.0.2)
|
85
85
|
mini_portile2 (2.4.0)
|
86
86
|
minitest (5.14.2)
|
87
|
-
msgpack (1.
|
87
|
+
msgpack (1.4.2)
|
88
88
|
nio4r (2.5.4)
|
89
89
|
nokogiri (1.10.10)
|
90
90
|
mini_portile2 (~> 2.4.0)
|
@@ -175,7 +175,7 @@ GEM
|
|
175
175
|
websocket-driver (0.7.3)
|
176
176
|
websocket-extensions (>= 0.1.0)
|
177
177
|
websocket-extensions (0.1.5)
|
178
|
-
yard (0.9.
|
178
|
+
yard (0.9.26)
|
179
179
|
|
180
180
|
PLATFORMS
|
181
181
|
ruby
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeclareSchema
|
4
|
+
class UnknownSqlTypeError < RuntimeError; end
|
5
|
+
|
6
|
+
module Model
|
7
|
+
# This class is a wrapper for the ActiveRecord::...::Column class
|
8
|
+
class Column
|
9
|
+
class << self
|
10
|
+
def native_type?(type)
|
11
|
+
type != :primary_key && native_types.has_key?(type)
|
12
|
+
end
|
13
|
+
|
14
|
+
# MySQL example:
|
15
|
+
# { primary_key: "bigint auto_increment PRIMARY KEY",
|
16
|
+
# string: { name: "varchar", limit: 255 },
|
17
|
+
# text: { name: "text", limit: 65535},
|
18
|
+
# integer: {name: "int", limit: 4 },
|
19
|
+
# float: {name: "float", limit: 24 },
|
20
|
+
# decimal: { name: "decimal" },
|
21
|
+
# datetime: { name: "datetime" },
|
22
|
+
# timestamp: { name: "timestamp" },
|
23
|
+
# time: { name: "time" },
|
24
|
+
# date: { name: "date" },
|
25
|
+
# binary: { name>: "blob", limit: 65535 },
|
26
|
+
# boolean: { name: "tinyint", limit: 1 },
|
27
|
+
# json: { name: "json" } }
|
28
|
+
#
|
29
|
+
# SQLite example:
|
30
|
+
# { primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
|
31
|
+
# string: { name: "varchar" },
|
32
|
+
# text: { name: "text"},
|
33
|
+
# integer: { name: "integer" },
|
34
|
+
# float: { name: "float" },
|
35
|
+
# decimal: { name: "decimal" },
|
36
|
+
# datetime: { name: "datetime" },
|
37
|
+
# time: { name: "time" },
|
38
|
+
# date: { name: "date" },
|
39
|
+
# binary: { name: "blob" },
|
40
|
+
# boolean: { name: "boolean" },
|
41
|
+
# json: { name: "json" } }
|
42
|
+
def native_types
|
43
|
+
@native_types ||= ActiveRecord::Base.connection.native_database_types.tap do |types|
|
44
|
+
if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
|
45
|
+
types[:text][:limit] ||= 0xffff
|
46
|
+
types[:binary][:limit] ||= 0xffff
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def sql_type(type)
|
52
|
+
if native_type?(type)
|
53
|
+
type
|
54
|
+
else
|
55
|
+
if (field_class = DeclareSchema.to_class(type))
|
56
|
+
field_class::COLUMN_TYPE
|
57
|
+
end or raise UnknownSqlTypeError, "#{type.inspect} for type #{type.inspect}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def deserialize_default_value(column, sql_type, default_value)
|
62
|
+
sql_type or raise ArgumentError, "must pass sql_type; got #{sql_type.inspect}"
|
63
|
+
|
64
|
+
case Rails::VERSION::MAJOR
|
65
|
+
when 4
|
66
|
+
# TODO: Delete this Rails 4 support ASAP! This could be wrong, since it's using the type of the old column...which
|
67
|
+
# might be getting migrated to a new type. We should be using just sql_type as below. -Colin
|
68
|
+
column.type_cast_from_database(default_value)
|
69
|
+
else
|
70
|
+
cast_type = ActiveRecord::Base.connection.send(:lookup_cast_type, sql_type) or
|
71
|
+
raise "cast_type not found for #{sql_type}"
|
72
|
+
cast_type.deserialize(default_value)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Normalizes schema attributes for the specific database adapter that is currently running
|
77
|
+
# Note that the un-normalized attributes are still useful for generating migrations because those
|
78
|
+
# may be run with a different adapter.
|
79
|
+
# This method never mutates its argument. In fact it freezes it to be certain.
|
80
|
+
def normalize_schema_attributes(schema_attributes)
|
81
|
+
schema_attributes[:type] or raise ArgumentError, ":type key not found; keys: #{schema_attributes.keys.inspect}"
|
82
|
+
schema_attributes.freeze
|
83
|
+
|
84
|
+
case ActiveRecord::Base.connection.class.name
|
85
|
+
when /mysql/i
|
86
|
+
schema_attributes
|
87
|
+
when /sqlite/i
|
88
|
+
case schema_attributes[:type]
|
89
|
+
when :text
|
90
|
+
schema_attributes = schema_attributes.merge(limit: nil)
|
91
|
+
when :integer
|
92
|
+
schema_attributes = schema_attributes.dup
|
93
|
+
schema_attributes[:limit] ||= 8
|
94
|
+
end
|
95
|
+
schema_attributes
|
96
|
+
else
|
97
|
+
schema_attributes
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def equivalent_schema_attributes?(schema_attributes_lhs, schema_attributes_rhs)
|
102
|
+
normalize_schema_attributes(schema_attributes_lhs) == normalize_schema_attributes(schema_attributes_rhs)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def initialize(model, current_table_name, column)
|
107
|
+
@model = model or raise ArgumentError, "must pass model"
|
108
|
+
@current_table_name = current_table_name or raise ArgumentError, "must pass current_table_name"
|
109
|
+
@column = column or raise ArgumentError, "must pass column"
|
110
|
+
end
|
111
|
+
|
112
|
+
def sql_type
|
113
|
+
@sql_type ||= self.class.sql_type(@column.type)
|
114
|
+
end
|
115
|
+
|
116
|
+
SCHEMA_KEYS = [:type, :limit, :precision, :scale, :null, :default].freeze
|
117
|
+
|
118
|
+
# omits keys with nil values
|
119
|
+
def schema_attributes
|
120
|
+
SCHEMA_KEYS.each_with_object({}) do |key, result|
|
121
|
+
value =
|
122
|
+
case key
|
123
|
+
when :default
|
124
|
+
self.class.deserialize_default_value(@column, sql_type, @column.default)
|
125
|
+
else
|
126
|
+
col_value = @column.send(key)
|
127
|
+
if col_value.nil? && (native_type = self.class.native_types[@column.type])
|
128
|
+
native_type[key]
|
129
|
+
else
|
130
|
+
col_value
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
result[key] = value unless value.nil?
|
135
|
+
end.tap do |result|
|
136
|
+
if ActiveRecord::Base.connection.class.name.match?(/mysql/i) && @column.type.in?([:string, :text])
|
137
|
+
result.merge!(collation_and_charset_for_column(@current_table_name, @column.name))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def collation_and_charset_for_column(current_table_name, column_name)
|
145
|
+
connection = ActiveRecord::Base.connection
|
146
|
+
connection.class.name.match?(/mysql/i) or raise ArgumentError, "only supported for MySQL"
|
147
|
+
|
148
|
+
database_name = connection.current_database
|
149
|
+
|
150
|
+
defaults = connection.select_one(<<~EOS)
|
151
|
+
SELECT C.character_set_name, C.collation_name
|
152
|
+
FROM information_schema.`COLUMNS` C
|
153
|
+
WHERE C.table_schema = '#{connection.quote_string(database_name)}' AND
|
154
|
+
C.table_name = '#{connection.quote_string(current_table_name)}' AND
|
155
|
+
C.column_name = '#{connection.quote_string(column_name)}';
|
156
|
+
EOS
|
157
|
+
|
158
|
+
defaults && defaults["character_set_name"] or raise "character_set_name missing from #{defaults.inspect} from #{database_name}.#{current_table_name}.#{column_name}"
|
159
|
+
defaults && defaults["collation_name"] or raise "collation_name missing from #{defaults.inspect}"
|
160
|
+
|
161
|
+
{
|
162
|
+
charset: defaults["character_set_name"],
|
163
|
+
collation: defaults["collation_name"]
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'column'
|
4
|
+
|
3
5
|
module DeclareSchema
|
6
|
+
class MysqlTextMayNotHaveDefault < RuntimeError; end
|
7
|
+
|
4
8
|
module Model
|
5
9
|
class FieldSpec
|
6
|
-
class UnknownSqlTypeError < RuntimeError; end
|
7
10
|
|
8
11
|
MYSQL_TINYTEXT_LIMIT = 0xff
|
9
12
|
MYSQL_TEXT_LIMIT = 0xffff
|
@@ -30,7 +33,18 @@ module DeclareSchema
|
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
33
|
-
attr_reader :model, :name, :type, :position, :options
|
36
|
+
attr_reader :model, :name, :type, :sql_type, :position, :options, :sql_options
|
37
|
+
|
38
|
+
TYPE_SYNONYMS = { timestamp: :datetime }.freeze # TODO: drop this synonym. -Colin
|
39
|
+
|
40
|
+
SQL_OPTIONS = [:limit, :precision, :scale, :null, :default, :charset, :collation].freeze
|
41
|
+
NON_SQL_OPTIONS = [:ruby_default, :validates].freeze
|
42
|
+
VALID_OPTIONS = (SQL_OPTIONS + NON_SQL_OPTIONS).freeze
|
43
|
+
OPTION_INDEXES = Hash[VALID_OPTIONS.each_with_index.to_a].freeze
|
44
|
+
|
45
|
+
VALID_OPTIONS.each do |option|
|
46
|
+
define_method(option) { @options[option] }
|
47
|
+
end
|
34
48
|
|
35
49
|
def initialize(model, name, type, position: 0, **options)
|
36
50
|
# TODO: TECH-5116
|
@@ -42,170 +56,72 @@ module DeclareSchema
|
|
42
56
|
@model = model
|
43
57
|
@name = name.to_sym
|
44
58
|
type.is_a?(Symbol) or raise ArgumentError, "type must be a Symbol; got #{type.inspect}"
|
45
|
-
@type = type
|
59
|
+
@type = TYPE_SYNONYMS[type] || type
|
46
60
|
@position = position
|
47
|
-
@options = options
|
61
|
+
@options = options.dup
|
62
|
+
|
63
|
+
@options.has_key?(:null) or @options[:null] = false
|
64
|
+
|
48
65
|
case type
|
49
66
|
when :text
|
50
|
-
@options[:default] and raise "default may not be given for :text field #{model}##{@name}"
|
51
67
|
if self.class.mysql_text_limits?
|
68
|
+
@options[:default].nil? or raise MysqlTextMayNotHaveDefault, "when using MySQL, non-nil default may not be given for :text field #{model}##{@name}"
|
52
69
|
@options[:limit] = self.class.round_up_mysql_text_limit(@options[:limit] || MYSQL_LONGTEXT_LIMIT)
|
70
|
+
else
|
71
|
+
@options[:limit] = nil
|
53
72
|
end
|
54
73
|
when :string
|
55
|
-
@options[:limit] or raise "limit must be given for :string field #{model}##{@name}: #{@options.inspect}; do you want `limit: 255`?"
|
74
|
+
@options[:limit] or raise "limit: must be given for :string field #{model}##{@name}: #{@options.inspect}; do you want `limit: 255`?"
|
56
75
|
when :bigint
|
57
76
|
@type = :integer
|
58
|
-
@options =
|
77
|
+
@options[:limit] = 8
|
59
78
|
end
|
60
79
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
80
|
+
# TODO: Do we really need to support a :sql_type option? Ideally, drop it. -Colin
|
81
|
+
@sql_type = @options.delete(:sql_type) || Column.sql_type(@type)
|
82
|
+
|
83
|
+
if @sql_type.in?([:string, :text, :binary, :varbinary, :integer, :enum])
|
84
|
+
@options[:limit] ||= Column.native_types[@sql_type][:limit]
|
66
85
|
else
|
67
|
-
@options
|
68
|
-
@options
|
86
|
+
@sql_type != :decimal && @options.has_key?(:limit) and warn("unsupported limit: for SQL type #{@sql_type} in field #{model}##{@name}")
|
87
|
+
@options.delete(:limit)
|
69
88
|
end
|
70
|
-
end
|
71
89
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
90
|
+
if @sql_type == :decimal
|
91
|
+
@options[:precision] or warn("precision: required for :decimal type in field #{model}##{@name}")
|
92
|
+
@options[:scale] or warn("scale: required for :decimal type in field #{model}##{@name}")
|
93
|
+
else
|
94
|
+
if @sql_type != :datetime
|
95
|
+
@options.has_key?(:precision) and warn("precision: only allowed for :decimal type or :datetime for SQL type #{@sql_type} in field #{model}##{@name}")
|
96
|
+
end
|
97
|
+
@options.has_key?(:scale) and warn("scale: only allowed for :decimal type for SQL type #{@sql_type} in field #{model}##{@name}")
|
79
98
|
end
|
80
99
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
else
|
86
|
-
field_class = DeclareSchema.to_class(type)
|
87
|
-
field_class && field_class::COLUMN_TYPE or raise UnknownSqlTypeError, "#{type.inspect} for #{model}##{@name}"
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def sql_options
|
93
|
-
@options.except(:ruby_default, :validates)
|
94
|
-
end
|
95
|
-
|
96
|
-
def limit
|
97
|
-
@options[:limit] || native_types[sql_type][:limit]
|
98
|
-
end
|
99
|
-
|
100
|
-
def precision
|
101
|
-
@options[:precision]
|
102
|
-
end
|
103
|
-
|
104
|
-
def scale
|
105
|
-
@options[:scale]
|
106
|
-
end
|
107
|
-
|
108
|
-
def null
|
109
|
-
!:null.in?(@options) || @options[:null]
|
110
|
-
end
|
111
|
-
|
112
|
-
def default
|
113
|
-
@options[:default]
|
114
|
-
end
|
115
|
-
|
116
|
-
def charset
|
117
|
-
@options[:charset]
|
118
|
-
end
|
119
|
-
|
120
|
-
def collation
|
121
|
-
@options[:collation]
|
122
|
-
end
|
123
|
-
|
124
|
-
def same_type?(col_spec)
|
125
|
-
type = sql_type
|
126
|
-
normalized_type = TYPE_SYNONYMS[type] || type
|
127
|
-
normalized_col_spec_type = TYPE_SYNONYMS[col_spec.type] || col_spec.type
|
128
|
-
normalized_type == normalized_col_spec_type
|
129
|
-
end
|
130
|
-
|
131
|
-
def different_to?(table_name, col_spec)
|
132
|
-
!same_as(table_name, col_spec)
|
133
|
-
end
|
134
|
-
|
135
|
-
def same_as(table_name, col_spec)
|
136
|
-
same_type?(col_spec) &&
|
137
|
-
same_attributes?(col_spec) &&
|
138
|
-
(!type.in?([:text, :string]) || same_charset_and_collation?(table_name, col_spec))
|
139
|
-
end
|
140
|
-
|
141
|
-
private
|
142
|
-
|
143
|
-
def same_attributes?(col_spec)
|
144
|
-
native_type = native_types[type]
|
145
|
-
check_attributes = [:null, :default]
|
146
|
-
check_attributes += [:precision, :scale] if sql_type == :decimal && !col_spec.is_a?(SQLITE_COLUMN_CLASS) # remove when rails fixes https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2872
|
147
|
-
check_attributes -= [:default] if sql_type == :text && col_spec.class.name =~ /mysql/i
|
148
|
-
check_attributes << :limit if sql_type.in?([:string, :binary, :varbinary, :integer, :enum]) ||
|
149
|
-
(sql_type == :text && self.class.mysql_text_limits?)
|
150
|
-
check_attributes.all? do |k|
|
151
|
-
if k == :default
|
152
|
-
case Rails::VERSION::MAJOR
|
153
|
-
when 4
|
154
|
-
col_spec.type_cast_from_database(col_spec.default) == col_spec.type_cast_from_database(default)
|
155
|
-
else
|
156
|
-
cast_type = ActiveRecord::Base.connection.lookup_cast_type_from_column(col_spec) or raise "cast_type not found for #{col_spec.inspect}"
|
157
|
-
cast_type.deserialize(col_spec.default) == cast_type.deserialize(default)
|
158
|
-
end
|
100
|
+
if @type.in?([:text, :string])
|
101
|
+
if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
|
102
|
+
@options[:charset] ||= model.table_options[:charset] || Generators::DeclareSchema::Migration::Migrator.default_charset
|
103
|
+
@options[:collation] ||= model.table_options[:collation] || Generators::DeclareSchema::Migration::Migrator.default_collation
|
159
104
|
else
|
160
|
-
|
161
|
-
|
162
|
-
col_value = native_type[k]
|
163
|
-
end
|
164
|
-
col_value == send(k)
|
105
|
+
@options.delete(:charset)
|
106
|
+
@options.delete(:collation)
|
165
107
|
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def same_charset_and_collation?(table_name, col_spec)
|
170
|
-
current_collation_and_charset = collation_and_charset_for_column(table_name, col_spec)
|
171
|
-
|
172
|
-
collation == current_collation_and_charset[:collation] &&
|
173
|
-
charset == current_collation_and_charset[:charset]
|
174
|
-
end
|
175
|
-
|
176
|
-
def collation_and_charset_for_column(table_name, col_spec)
|
177
|
-
column_name = col_spec.name
|
178
|
-
connection = ActiveRecord::Base.connection
|
179
|
-
|
180
|
-
if connection.class.name.match?(/mysql/i)
|
181
|
-
database_name = connection.current_database
|
182
|
-
|
183
|
-
defaults = connection.select_one(<<~EOS)
|
184
|
-
SELECT C.character_set_name, C.collation_name
|
185
|
-
FROM information_schema.`COLUMNS` C
|
186
|
-
WHERE C.table_schema = '#{connection.quote_string(database_name)}' AND
|
187
|
-
C.table_name = '#{connection.quote_string(table_name)}' AND
|
188
|
-
C.column_name = '#{connection.quote_string(column_name)}';
|
189
|
-
EOS
|
190
|
-
|
191
|
-
defaults["character_set_name"] or raise "character_set_name missing from #{defaults.inspect}"
|
192
|
-
defaults["collation_name"] or raise "collation_name missing from #{defaults.inspect}"
|
193
|
-
|
194
|
-
{
|
195
|
-
charset: defaults["character_set_name"],
|
196
|
-
collation: defaults["collation_name"]
|
197
|
-
}
|
198
108
|
else
|
199
|
-
{}
|
109
|
+
@options[:charset] and warn("charset may only given for :string and :text fields for SQL type #{@sql_type} in field #{model}##{@name}")
|
110
|
+
@options[:collation] and warne("collation may only given for :string and :text fields for SQL type #{@sql_type} in field #{model}##{@name}")
|
200
111
|
end
|
201
|
-
end
|
202
112
|
|
203
|
-
|
204
|
-
|
113
|
+
@options = Hash[@options.sort_by { |k, _v| OPTION_INDEXES[k] || 9999 }]
|
114
|
+
|
115
|
+
@sql_options = @options.except(*NON_SQL_OPTIONS)
|
205
116
|
end
|
206
117
|
|
207
|
-
|
208
|
-
|
118
|
+
# returns the attributes for schema migrations as a Hash
|
119
|
+
# omits name and position since those are meta-data above the schema
|
120
|
+
# omits keys with nil values
|
121
|
+
def schema_attributes(col_spec)
|
122
|
+
@options.merge(type: @type).tap do |attrs|
|
123
|
+
attrs[:default] = Column.deserialize_default_value(col_spec, @sql_type, attrs[:default])
|
124
|
+
end.compact
|
209
125
|
end
|
210
126
|
end
|
211
127
|
end
|