Class: DeclareSchema::Model::FieldSpec
- Inherits:
-
Object
- Object
- DeclareSchema::Model::FieldSpec
- Defined in:
- lib/declare_schema/model/field_spec.rb
Constant Summary collapse
- MYSQL_TINYTEXT_LIMIT =
0xff
- MYSQL_TEXT_LIMIT =
0xffff
- MYSQL_MEDIUMTEXT_LIMIT =
0xff_ffff
- MYSQL_LONGTEXT_LIMIT =
0xffff_ffff
- MYSQL_TEXT_LIMITS_ASCENDING =
[MYSQL_TINYTEXT_LIMIT, MYSQL_TEXT_LIMIT, MYSQL_MEDIUMTEXT_LIMIT, MYSQL_LONGTEXT_LIMIT].freeze
- TYPE_SYNONYMS =
TODO: drop this synonym. -Colin
{ timestamp: :datetime }.freeze
- SQL_OPTIONS =
[:limit, :precision, :scale, :null, :default, :charset, :collation].freeze
- NON_SQL_OPTIONS =
[:ruby_default, :validates].freeze
- VALID_OPTIONS =
(SQL_OPTIONS + NON_SQL_OPTIONS).freeze
- OPTION_INDEXES =
Hash[VALID_OPTIONS.each_with_index.to_a].freeze
Instance Attribute Summary collapse
-
#model ⇒ Object
readonly
Returns the value of attribute model.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#position ⇒ Object
readonly
Returns the value of attribute position.
-
#sql_options ⇒ Object
readonly
Returns the value of attribute sql_options.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(model, name, type, position: 0, **options) ⇒ FieldSpec
constructor
A new instance of FieldSpec.
-
#schema_attributes(col_spec) ⇒ Object
returns the attributes for schema migrations as a Hash omits name and position since those are meta-data above the schema omits keys with nil values.
Constructor Details
#initialize(model, name, type, position: 0, **options) ⇒ FieldSpec
Returns a new instance of FieldSpec.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/declare_schema/model/field_spec.rb', line 49 def initialize(model, name, type, position: 0, **) _declared_primary_key = model._declared_primary_key name.to_s == _declared_primary_key and raise ArgumentError, "you may not provide a field spec for the primary key #{name.inspect}" @model = model @name = name.to_sym type.is_a?(Symbol) or raise ArgumentError, "type must be a Symbol; got #{type.inspect}" @type = TYPE_SYNONYMS[type] || type @position = position @options = .dup @options.has_key?(:null) or @options[:null] = ::DeclareSchema.default_null @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`?" case @type when :text if self.class.mysql_text_limits? @options[:default].nil? or raise MysqlTextMayNotHaveDefault, "when using MySQL, non-nil default may not be given for :text field #{model}##{@name}" @options[:limit] ||= ::DeclareSchema.default_text_limit or 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`?") @options[:limit] = self.class.round_up_mysql_text_limit(@options[:limit]) else @options.delete(:limit) end when :string @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`?" when :bigint @type = :integer @options[:limit] = 8 when :enum @options[:default].nil? || @options[:default].is_a?(Symbol) or raise ArgumentError, "enum default: must be nil or a Symbol; got #{@options[:default].inspect}" @options[:limit].is_a?(Array) && @options[:limit].size >= 1 && @options[:limit].all? { |value| value.is_a?(Symbol) } or raise ArgumentError, "enum limit: must be an array of 1 or more Symbols; got #{@options[:limit].inspect}" end Column.native_type?(@type) or raise UnknownTypeError, "#{@type.inspect} not found in #{Column.native_types.inspect} for adapter #{ActiveRecord::Base.connection.class.name}" if @type.in?([:string, :text, :binary, :varbinary, :integer]) @options[:limit] ||= Column.native_types.dig(@type, :limit) elsif @type.in?([:enum]) # nothing to do else @type != :decimal && @options.has_key?(:limit) and warn("unsupported limit: for SQL type #{@type} in field #{model}##{@name}") @options.delete(:limit) end if @type == :decimal @options[:precision] or warn("precision: required for :decimal type in field #{model}##{@name}") @options[:scale] or warn("scale: required for :decimal type in field #{model}##{@name}") else if @type != :datetime @options.has_key?(:precision) and warn("precision: only allowed for :decimal type or :datetime for SQL type #{@type} in field #{model}##{@name}") end @options.has_key?(:scale) and warn("scale: only allowed for :decimal type for SQL type #{@type} in field #{model}##{@name}") end if @type.in?([:text, :string]) if ActiveRecord::Base.connection.class.name.match?(/mysql/i) @options[:charset] ||= model.&.[](:charset) || ::DeclareSchema.default_charset @options[:charset] = DeclareSchema.normalize_charset(@options[:charset]) @options[:collation] ||= model.&.[](:collation) || ::DeclareSchema.default_collation @options[:collation] = DeclareSchema.normalize_collation(@options[:collation]) else @options.delete(:charset) @options.delete(:collation) end else @options[:charset] and warn("charset may only given for :string and :text fields for SQL type #{@type} in field #{model}##{@name}") @options[:collation] and warn("collation may only given for :string and :text fields for SQL type #{@type} in field #{model}##{@name}") end @options = Hash[@options.sort_by { |k, _v| OPTION_INDEXES[k] || 9999 }] @sql_options = @options.slice(*SQL_OPTIONS) end |
Instance Attribute Details
#model ⇒ Object (readonly)
Returns the value of attribute model.
36 37 38 |
# File 'lib/declare_schema/model/field_spec.rb', line 36 def model @model end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
36 37 38 |
# File 'lib/declare_schema/model/field_spec.rb', line 36 def name @name end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
36 37 38 |
# File 'lib/declare_schema/model/field_spec.rb', line 36 def @options end |
#position ⇒ Object (readonly)
Returns the value of attribute position.
36 37 38 |
# File 'lib/declare_schema/model/field_spec.rb', line 36 def position @position end |
#sql_options ⇒ Object (readonly)
Returns the value of attribute sql_options.
36 37 38 |
# File 'lib/declare_schema/model/field_spec.rb', line 36 def @sql_options end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
36 37 38 |
# File 'lib/declare_schema/model/field_spec.rb', line 36 def type @type end |
Class Method Details
.mysql_text_limits? ⇒ Boolean
19 20 21 22 23 24 25 |
# File 'lib/declare_schema/model/field_spec.rb', line 19 def mysql_text_limits? if defined?(@mysql_text_limits) @mysql_text_limits else @mysql_text_limits = ActiveRecord::Base.connection.class.name.match?(/mysql/i) end end |
.round_up_mysql_text_limit(limit) ⇒ Object
27 28 29 30 31 32 33 |
# File 'lib/declare_schema/model/field_spec.rb', line 27 def round_up_mysql_text_limit(limit) MYSQL_TEXT_LIMITS_ASCENDING.find do |mysql_supported_text_limit| if limit <= mysql_supported_text_limit mysql_supported_text_limit end end or raise ArgumentError, "limit of #{limit} is too large for MySQL" end |
Instance Method Details
#schema_attributes(col_spec) ⇒ Object
returns the attributes for schema migrations as a Hash omits name and position since those are meta-data above the schema omits keys with nil values
130 131 132 133 134 |
# File 'lib/declare_schema/model/field_spec.rb', line 130 def schema_attributes(col_spec) @sql_options.merge(type: @type).tap do |attrs| attrs[:default] = Column.deserialize_default_value(col_spec, @type, attrs[:default]) end.compact end |