lib/rom/sql/schema/attributes_inferrer.rb in rom-sql-2.0.0.beta2 vs lib/rom/sql/schema/attributes_inferrer.rb in rom-sql-2.0.0.beta3
- old
+ new
@@ -6,58 +6,26 @@
# @api private
class AttributesInferrer
extend Dry::Core::ClassAttributes
extend Initializer
- defines :ruby_type_mapping, :numeric_pk_type, :db_type, :registry
+ defines :type_builders
- class << self
- def inherited(klass)
- super
-
- registry[klass.db_type] = klass.new.freeze unless klass.name.nil?
- end
-
- def [](type)
- Class.new(self) { db_type(type) }
- end
-
- def get(db_type)
- registry[db_type]
- end
- end
-
CONSTRAINT_DB_TYPE = 'add_constraint'.freeze
- DECIMAL_REGEX = /(?:decimal|numeric)\((\d+)(?:,\s*(\d+))?\)/.freeze
- registry Hash.new(new.freeze)
+ option :type_builder
- ruby_type_mapping(
- integer: Types::Int,
- string: Types::String,
- time: Types::Time,
- date: Types::Date,
- datetime: Types::Time,
- boolean: Types::Bool,
- decimal: Types::Decimal,
- float: Types::Float,
- blob: Types::Blob
- ).freeze
-
- numeric_pk_type Types::Serial
-
option :attr_class, optional: true
# @api private
def call(schema, gateway)
dataset = schema.name.dataset
columns = filter_columns(gateway.connection.schema(dataset))
- fks = fks_for(gateway, dataset)
inferred = columns.map do |(name, definition)|
- type = build_type(**definition, foreign_key: fks[name])
+ type = type_builder.(definition)
attr_class.new(type.meta(name: name, source: schema.name)) if type
end.compact
missing = columns.map(&:first) - inferred.map { |attr| attr.meta[:name] }
@@ -68,96 +36,12 @@
# @api private
def with(new_options)
self.class.new(options.merge(new_options))
end
-
# @api private
def filter_columns(schema)
schema.reject { |(_, definition)| definition[:db_type] == CONSTRAINT_DB_TYPE }
- end
-
- # @api private
- def build_type(primary_key:, db_type:, type:, allow_null:, foreign_key:, **rest)
- if primary_key
- map_pk_type(type, db_type)
- else
- mapped_type = map_type(type, db_type, rest)
-
- if mapped_type
- read_type = mapped_type.meta[:read]
- mapped_type = mapped_type.optional if allow_null
- mapped_type = mapped_type.meta(foreign_key: true, target: foreign_key) if foreign_key
-
- if read_type && allow_null
- mapped_type.meta(read: read_type.optional)
- elsif read_type
- mapped_type.meta(read: read_type)
- else
- mapped_type
- end
- end
- end
- end
-
- # @api private
- def map_pk_type(_ruby_type, _db_type)
- self.class.numeric_pk_type.meta(primary_key: true)
- end
-
- # @api private
- def map_type(ruby_type, db_type, **kw)
- type = self.class.ruby_type_mapping[ruby_type]
-
- if db_type.is_a?(String) && db_type.include?('numeric') || db_type.include?('decimal')
- map_decimal_type(db_type)
- elsif db_type.is_a?(String) && db_type.include?('char') && kw[:max_length]
- type.meta(limit: kw[:max_length])
- else
- type
- end
- end
-
- # @api private
- def fks_for(gateway, dataset)
- gateway.connection.foreign_key_list(dataset).each_with_object({}) do |definition, fks|
- column, fk = build_fk(definition)
-
- fks[column] = fk if fk
- end
- end
-
- # @api private
- def column_indexes(indexes, column)
- indexes.each_with_object(Set.new) do |(name, idx), set|
- set << name if idx[:columns][0] == column
- end
- end
-
- # @api private
- def build_fk(columns: , table: , **rest)
- if columns.size == 1
- [columns[0], table]
- else
- # We don't have support for multicolumn foreign keys
- columns[0]
- end
- end
-
- # @api private
- def map_decimal_type(type)
- precision = DECIMAL_REGEX.match(type)
-
- if precision
- prcsn, scale = precision[1..2].map(&:to_i)
-
- self.class.ruby_type_mapping[:decimal].meta(
- precision: prcsn,
- scale: scale
- )
- else
- self.class.ruby_type_mapping[:decimal]
- end
end
end
end
end
end