class ObjectFramework::Persistence::Mapping
Describes how an ordinary Ruby class is hydrated and stored. An id field mapped to the id column is required. Declarations become immutable when their Mappings collection is validated at startup.
Constants
- TYPES
Attributes
Public Class Methods
Source
# File lib/object_framework/persistence/mapping.rb, line 71 def initialize(entity_class, table:) @entity_class, @table = entity_class, Query.identifier(table) @fields, @associations = [], [] @builder = ->(attributes) { entity_class.new(**attributes) } end
Public Instance Methods
Source
# File lib/object_framework/persistence/mapping.rb, line 93 def build(&builder) mutable! @builder = builder self end
Replaces keyword construction with a callable receiving an attributes hash. Use this when hydration needs a domain-specific constructor.
Source
# File lib/object_framework/persistence/mapping.rb, line 103 def columns fields.map(&:column) + associations.select { |item| item.kind == :belongs_to }.map(&:foreign_key) end
Source
# File lib/object_framework/persistence/mapping.rb, line 117 def dump(entity, baseline: nil, loaded: []) row = fields.to_h { |field| [field.column, field.converter.dump(field.reader.call(entity))] } associations.select { |association| association.kind == :belongs_to }.each do |association| target = association.reader.call(entity) row[association.foreign_key] = if target target.public_send(:id) || raise(InvalidInput, "Associated entities must be registered before flush") elsif baseline && !loaded.include?(association.name) baseline[association.foreign_key] end end Values.detach(baseline ? baseline.merge(row) : row) end
Source
# File lib/object_framework/persistence/mapping.rb, line 80 def field(name, column: name, type: :string, converter: Converter.new, read: nil, write: nil) mutable! name, column = Query.identifier(name), Query.identifier(column) raise ConfigurationError, "Unsupported column type" unless TYPES.include?(type) raise ConfigurationError, "Duplicate mapped column or attribute" if columns.include?(column) || (@fields + @associations).any? { |item| item.name == name } @fields << Field.new(name:, column:, type:, converter:, reader: read || ->(entity) { entity.public_send(name) }, writer: write || ->(entity, value) { entity.public_send("#{name}=", value) }) self end
Maps an attribute to a column using a type in TYPES. Optional read and write callables replace public attribute accessors. converter supplies dump and load transformations. Returns self.
Source
# File lib/object_framework/persistence/mapping.rb, line 130 def finalize! identity raise ConfigurationError, "Identity must map to the id column" unless identity.column == :id fields.freeze associations.freeze freeze end
Source
# File lib/object_framework/persistence/mapping.rb, line 113 def hydrate(row) @builder.call(fields.to_h { |field| [field.name, field.converter.load(Values.mutable_copy(row[field.column]))] }) end
Source
# File lib/object_framework/persistence/mapping.rb, line 99 def identity fields.find { |field| field.name == :id } || raise(ConfigurationError, "Mapping requires an id field") end
Source
# File lib/object_framework/persistence/mapping.rb, line 107 def schema fields.to_h { |field| [field.column, field.type] }.merge( associations.select { |item| item.kind == :belongs_to }.to_h { |item| [item.foreign_key, :string] } ).freeze end