Class: Lotus::Model::Mapping::Collection

Inherits:
Object
  • Object
show all
Defined in:
lib/lotus/model/mapping/collection.rb

Overview

Maps a collection and its attributes.

A collection is a set of homogeneous records. Think of a table of a SQL database or about collection of MongoDB.

This is database independent. It can work with SQL, document, and even with key/value stores.

Examples:

require 'lotus/model'

mapper = Lotus::Model::Mapper.new do
  collection :users do
    entity User

    attribute :id,   Integer
    attribute :name, String
  end
end

See Also:

Since:

  • 0.1.0

Constant Summary collapse

REPOSITORY_SUFFIX =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Repository name suffix

See Also:

Since:

  • 0.1.0

'Repository'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, coercer_class, &blk) ⇒ Collection

Instantiate a new collection

Parameters:

  • name (Symbol)

    the name of the mapped collection. If used with a SQL database it’s the table name.

  • coercer_class (Class)

    the coercer class

  • blk (Proc)

    the block that maps the attributes of that collection.

See Also:

Since:

  • 0.1.0



73
74
75
76
77
78
# File 'lib/lotus/model/mapping/collection.rb', line 73

def initialize(name, coercer_class, &blk)
  @name = name
  @coercer_class = coercer_class
  @attributes = {}
  instance_eval(&blk) if block_given?
end

Instance Attribute Details

#adapterObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 0.1.0



60
61
62
# File 'lib/lotus/model/mapping/collection.rb', line 60

def adapter
  @adapter
end

#attributesObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 0.1.0



54
55
56
# File 'lib/lotus/model/mapping/collection.rb', line 54

def attributes
  @attributes
end

#coercer_classObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 0.1.0



48
49
50
# File 'lib/lotus/model/mapping/collection.rb', line 48

def coercer_class
  @coercer_class
end

#nameObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 0.1.0



42
43
44
# File 'lib/lotus/model/mapping/collection.rb', line 42

def name
  @name
end

Instance Method Details

#attribute(name, klass, options = {}) ⇒ Object

Map an attribute.

An attribute defines a property of an object. This is storage independent. For instance, it can map an SQL column, a MongoDB attribute or everything that makes sense for your database.

Each attribute defines a Ruby type, to coerce that value from the database. This fixes a huge problem, because database types don’t match Ruby types. Think of Redis, where everything is stored as a string or integer, the mapper translates values from/to the database.

It supports the following types:

* Array
* Boolean
* Date
* DateTime
* Float
* Hash
* Integer
* BigDecimal
* Set
* String
* Symbol
* Time

Examples:

Default schema

require 'lotus/model'

# Given the following schema:
#
# CREATE TABLE users (
#   id     integer NOT NULL,
#   name   varchar(64),
# );
#
# And the following entity:
#
# class User
#   include Lotus::Entity
#   attributes :name
# end

mapper = Lotus::Model::Mapper.new do
  collection :users do
    entity User

    attribute :id,   Integer
    attribute :name, String
  end
end

# The first argument (`:name`) always corresponds to the `User`
# attribute.

# The second one (`:klass`) is the Ruby type that we want for our
# attribute.

# We don't need to use `:as` because the database columns match the
# `User` attributes.

Customized schema

require 'lotus/model'

# Given the following schema:
#
# CREATE TABLE articles (
#   i_id           integer NOT NULL,
#   i_user_id      integer NOT NULL,
#   s_title        varchar(64),
#   comments_count varchar(8) # Not an error: it's for String => Integer coercion
# );
#
# And the following entity:
#
# class Article
#   include Lotus::Entity
#   attributes :user_id, :title, :comments_count
# end

mapper = Lotus::Model::Mapper.new do
  collection :articles do
    entity Article

    attribute :id,             Integer, as: :i_id
    attribute :user_id,        Integer, as: :i_user_id
    attribute :title,          String,  as: :s_title
    attribute :comments_count, Integer

    identity :i_id
  end
end

# The first argument (`:name`) always corresponds to the `Article`
# attribute.

# The second one (`:klass`) is the Ruby type that we want for our
# attribute.

# The third option (`:as`) is mandatory only when the database
# column doesn't match the name of the mapped attribute.
#
# For instance: we need to use it for translate `:s_title` to
# `:title`, but not for `:comments_count`.

Parameters:

  • name (Symbol)

    the name of the attribute, as we want it to be mapped in the object

  • klass (Class)

    the Ruby type that we want to assign as value

  • options (Hash) (defaults to: {})

    a set of options to customize the mapping

Options Hash (options):

  • :as (Symbol)

    the name of the original column

Since:

  • 0.1.0



333
334
335
# File 'lib/lotus/model/mapping/collection.rb', line 333

def attribute(name, klass, options = {})
  @attributes[name] = [klass, (options.fetch(:as) { name }).to_sym]
end

#deserialize(records) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Deserialize a set of records fetched from the database.

Parameters:

  • records (Array)

    a set of raw records

Since:

  • 0.1.0



353
354
355
356
357
# File 'lib/lotus/model/mapping/collection.rb', line 353

def deserialize(records)
  records.map do |record|
    @coercer.from_record(record)
  end
end

#deserialize_attribute(attribute, value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Deserialize only one attribute from a raw value.

Parameters:

  • attribute (Symbol)

    the attribute name

  • value (Object, nil)

    the value to be coerced

Since:

  • 0.1.0



366
367
368
# File 'lib/lotus/model/mapping/collection.rb', line 366

def deserialize_attribute(attribute, value)
  @coercer.public_send(:"deserialize_#{ attribute }", value)
end

#entity(klass = nil) ⇒ Object

Defines the entity that is persisted with this collection.

The entity can be any kind of object as long as it implements the following interface: ‘#initialize(attributes = {})`.

Examples:

Set entity with class name

require 'lotus/model'

mapper = Lotus::Model::Mapper.new do
  collection :articles do
    entity Article
  end
end

mapper.entity #=> Article

Set entity with class name string

require 'lotus/model'

mapper = Lotus::Model::Mapper.new do
  collection :articles do
    entity 'Article'
  end
end

mapper.entity #=> Article

Parameters:

  • klass (Class, String) (defaults to: nil)

    the entity persisted with this collection.

See Also:

Since:

  • 0.1.0



113
114
115
116
117
118
119
# File 'lib/lotus/model/mapping/collection.rb', line 113

def entity(klass = nil)
  if klass
    @entity = klass
  else
    @entity
  end
end

#identity(name = nil) ⇒ Object

Defines the identity for a collection.

An identity is a unique value that identifies a record. If used with an SQL table it corresponds to the primary key.

This is an optional feature. By default the system assumes that your identity is ‘:id`. If this is the case, you can omit the value, otherwise you have to specify it.

Examples:

Default

require 'lotus/model'

# We have an SQL table `users` with a primary key `id`.
#
# This this is compliant to the mapper default, we can omit
# `#identity`.

mapper = Lotus::Model::Mapper.new do
  collection :users do
    entity User

    # attribute definitions..
  end
end

Custom identity

require 'lotus/model'

# We have an SQL table `articles` with a primary key `i_id`.
#
# This schema diverges from the expected default: `id`, that's why
# we need to use #identity to let the mapper to recognize the
# primary key.

mapper = Lotus::Model::Mapper.new do
  collection :articles do
    entity Article

    # attribute definitions..

    identity :i_id
  end
end

Parameters:

  • name (Symbol) (defaults to: nil)

    the name of the identity

Since:

  • 0.1.0



210
211
212
213
214
215
216
# File 'lib/lotus/model/mapping/collection.rb', line 210

def identity(name = nil)
  if name
    @identity = name
  else
    @identity || :id
  end
end

#load!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Loads the internals of the mapper, in order to guarantee thread safety.

Since:

  • 0.1.0



374
375
376
377
378
379
380
# File 'lib/lotus/model/mapping/collection.rb', line 374

def load!
  _load_entity!
  _load_repository!
  _load_coercer!

  _configure_repository!
end

#repository(klass = nil) ⇒ Object

Defines the repository that interacts with this collection.

Examples:

Set repository with class name

require 'lotus/model'

mapper = Lotus::Model::Mapper.new do
  collection :articles do
    entity Article

    repository RemoteArticleRepository
  end
end

mapper.repository #=> RemoteArticleRepository

Set repository with class name string

require 'lotus/model'

mapper = Lotus::Model::Mapper.new do
  collection :articles do
    entity Article

    repository 'RemoteArticleRepository'
  end
end

mapper.repository #=> RemoteArticleRepository

Parameters:

  • klass (Class, String) (defaults to: nil)

    the repository that interacts with this collection.

See Also:

Since:

  • 0.2.0



154
155
156
157
158
159
160
# File 'lib/lotus/model/mapping/collection.rb', line 154

def repository(klass = nil)
  if klass
    @repository = klass
  else
    @repository ||= default_repository_klass
  end
end

#serialize(entity) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Serializes an entity to be persisted in the database.

Parameters:

  • entity (Object)

    an entity

Since:

  • 0.1.0



343
344
345
# File 'lib/lotus/model/mapping/collection.rb', line 343

def serialize(entity)
  @coercer.to_record(entity)
end