Skip to content

Latest commit

 

History

History
217 lines (158 loc) · 5.16 KB

EXAMPLE.md

File metadata and controls

217 lines (158 loc) · 5.16 KB

Lotus::Model

This is a guide that helps you to getting started with Lotus::Model. You can find the full code source here.

Gems

First of all, we need to setup a Gemfile.

source 'https://rubygems.org'

gem 'sqlite3'
gem 'lotus-model'

Then we can fetch the dependencies with bundle install.

Setup

Lotus::Model doesn't have migrations, for this example we're gonna use Sequel. We create the database first, and then two tables: authors and articles.

require 'bundler/setup'
require 'sqlite3'
require 'lotus/model'
require 'lotus/model/adapters/sql_adapter'

connection_uri = "sqlite://#{ __dir__ }/test.db"

database = Sequel.connect(connection_uri)

database.create_table! :authors do
  primary_key :id
  String  :name
end

database.create_table! :articles do
  primary_key :id
  Integer :author_id,      null: false
  String  :title
  Integer :comments_count, default: 0
  Boolean :published,      default: false
end

Entities

We have two entities in our application: Author and Article. Author is a Struct, Lotus::Model can persist it. Article has a small API concerning its publishing process.

Author = Struct.new(:id, :name) do
  def initialize(attributes = {})
    @id, @name = attributes.values_at(:id, :name)
  end
end

class Article
  include Lotus::Entity
  self.attributes = :author_id, :title, :comments_count, :published # id is implicit

  def published?
    !!published
  end

  def publish!
    @published = true
  end
end

Repositories

In order to persist and query the entities above, we define two corresponding repositories:

class AuthorRepository
  include Lotus::Repository
end

class ArticleRepository
  include Lotus::Repository

  def self.most_recent_by_author(author, limit = 8)
    query do
      where(author_id: author.id).
        desc(:id).
        limit(limit)
    end
  end

  def self.most_recent_published_by_author(author, limit = 8)
    most_recent_by_author(author, limit).published
  end

  def self.published
    query do
      where(published: true)
    end
  end

  def self.drafts
    exclude published
  end

  def self.rank
    published.desc(:comments_count)
  end

  def self.best_article_ever
    rank.limit(1).first
  end

  def self.comments_average
    query.average(:comments_count)
  end
end

Mapper

We create a correspondence between the database columns with the entities' attributes.

mapper = Lotus::Model::Mapper.new do
  collection :authors do
    entity Author

    attribute :id,   Integer
    attribute :name, String
  end

  collection :articles do
    entity Article

    attribute :id,             Integer
    attribute :author_id,      Integer
    attribute :title,          String
    attribute :comments_count, Integer
    attribute :published,      Boolean
  end
end

Loading

We create an adapter instance, passing mapper and the connection URI (see above). Please remember that the setup code is only required for the standalone usage of Lotus::Model. A Lotus application will handle that configurations for you.

adapter = Lotus::Model::Adapters::SqlAdapter.new(mapper, connection_uri)
AuthorRepository.adapter  = adapter
ArticleRepository.adapter = adapter

mapper.load! # last operation

Persist

Let's instantiate and persist some objects for our example:

author = Author.new(name: 'Luca')
AuthorRepository.create(author)

articles = [
  Article.new(title: 'Announcing Lotus',              author_id: author.id, comments_count: 123, published: true),
  Article.new(title: 'Introducing Lotus::Router',     author_id: author.id, comments_count: 63,  published: true),
  Article.new(title: 'Introducing Lotus::Controller', author_id: author.id, comments_count: 82,  published: true),
  Article.new(title: 'Introducing Lotus::Model',      author_id: author.id)
]

articles.each do |article|
  ArticleRepository.create(article)
end

Query

We can use repositories to query the database and return the entities we're looking for:

ArticleRepository.first # => return the first article
ArticleRepository.last  # => return the last article

ArticleRepository.published # => return all the published articles
ArticleRepository.drafts    # => return all the drafts

ArticleRepository.rank      # => all the published articles, sorted by popularity

ArticleRepository.best_article_ever # => the most commented article

ArticleRepository.comments_average # => calculates the average of comments across all the published articles.

ArticleRepository.most_recent_by_author(author) # => most recent articles by an author (drafts and published).
ArticleRepository.most_recent_published_by_author(author) # => most recent published articles by an author

Business logic

As we've seen above, Article implements an API for publishing. We're gonna use that logic to alter the state of an article (from draft to published) and then we use the repository to persist this new state.

article = ArticleRepository.drafts.first

article.published? # => false
article.publish!

article.published? # => true

ArticleRepository.update(article)