12/08/2018, 11:34

Model, Database trong Lotus Framwork

1 Model Lotus có xây dựng một ORM riêng, gọi là lotus-model và xây dựng dựa trên sequel. Lotus model cung cấp cho bạn các thành phần chính sau: Entity – An object defined by its identity. Repository – An object that mediates between the entities and the persistence layer. Data Mapper – ...

rsz_lotus-1a.jpg

1 Model

  • Lotus có xây dựng một ORM riêng, gọi là lotus-model và xây dựng dựa trên sequel. Lotus model cung cấp cho bạn các thành phần chính sau:
  • Entity – An object defined by its identity.
  • Repository – An object that mediates between the entities and the persistence layer.
  • Data Mapper – A persistence mapper that keep entities independent from database details.
  • Adapter – A database adapter.
  • Query – An object that represents a database query.

1.1 Entity là gì?

  • Entity là 1 object nó được định nghĩa dựa vào những gì nó có.
  • Ví dụ: ta có 1 Article và ta cần biết thông tin gì về user như title, content, user_id...
  • Theo như mô tả ở trên thì Entity là Article, và Article được định nghĩa dựa trên title, content, user_id...
  • Cách định nghĩa 1 Entity
require 'lotus/entity'
class Article
  include Lotus::Entity
  attributes :title, :content, :user_id, :created_at, :updated_at
end

1.2 Repository là gì?

  • Repository nó giống như là một trung gian giúp bạn giao tiếp với cơ sở dữ liệu một cách dễ dàng hơn hay nói cách khác thì repository sẽ làm nhiệm vụ persist data cũng như query logic
  • Ví dụ: theo như mô tả 1 Article trên nếu chúng ta muốn lưu 1 article thì phải làm như thế nào?--> Repository sẽ giúp chúng ta làm những công việc đó
require 'lotus/repository'
class ArticleRepository
  include Lotus::Repository
end
  • Về query logic
# thông tin về 1 article
article = Article.new(title: 'bai 1', content: 'hello world')
# tạo 1 new article trong repository
ArticleRepository.create(article)
# giờ ta thay đổi title của article
article.title = 'lesson1'
article = ArticleRepository.update(article)
# remove article khỏi list
ArticleRepository.delete(article)
  • Việc query data trong lotus không giống như ActiveRecord nữa. Trong repository thì query là một private component. Nghĩa là các query logic của bạn sẽ được encapsulated, khi dùng thì chỉ cần gọi ra method cần thiết của Repository class thôi, còn logic như nào thì không visible nữa.

1.3 Data Mapper là gì?

  • Để lotus-model biết được là phải map column nào dưới database lên attribute nào của entity, ta cần phải map chúng lại với nhau. Trong folder config, mình có sẵn một file mapping.rb, là nơi bạn sẽ khai báo tất cả các mapping giữa entity với table.
collection :articles do
  entity     Article
  repository ArticleRepository

  attribute :id,         Integer
  attribute :title,      String
  attribute :content,    String
  attribute :user_id,    Integer
  attribute :created_at, DateTime
  attribute :updated_at, DateTime
end

Trong đó

  • collection :articles => table articles trong database
  • entity Article => mỗi record trong table articles ứng với một instance article của class Article
  • repository ArticleRepository => khai báo repository cho Artilce, giúp tách rời nhiệm vụ persist data, query logic ra khỏi model
  • attribute: map column và attribute giữa database với Ruby object.

Tuy nhiên ta cần phải config thêm trong file lotus-part1.rb để báo cho Lotus biết là bạn định nghĩa mapping trong file mapping.rb

mapping "#{__dir__}/config/mapping"

Ngoài viết mapping trong file mapping.rb thì chúng ta có thể viết inline trực tiếp trong file config lotus-part1.rb như sau

mapping do
    collection :articles do
  entity     Article
  repository ArticleRepository

  attribute :id,         Integer
  attribute :title,      String
  attribute :content,    String
  attribute :user_id,    Integer
  attribute :created_at, DateTime
  attribute :updated_at, DateTime
  end
end

###1.4 Query

  • Về cách query dữ liệu trong lotus cơ bản như Active Record chỉ khác là cách thể hiện và chỗ viết các câu query, trong lotus thì viết ở repository
  • Ví dụ :
  • In Active Record:
 Article.where(user_id: user.id).order(:created_at).limit(10)

  • In lotus:
 class ArticleRepository
  include Lotus::Repository
  def self.most_recent_by_user(user, limit: 10)
    query do
      where(user_id: user.id).order(:created_at)
    end.limit(limit)
  end
end

##2 Database

  • Ta có thể lựa chọn adapter trong file lotus-tutorial.rb, bạn sẽ thấy phần comment giới thiệu cũng như hướng dẫn cấu hình
# * SQL adapter

     adapter type: :sql, uri: 'sqlite://db/lotus-part1_development.sqlite3'

# adapter type: :sql, uri: 'postgres://localhost/lotus-part1_development'

# adapter type: :sql, uri: 'mysql://localhost/lotus-part1_development'uby

Ở đây tôi dùng sqlite

  • Lotus hỗ trợ 3 loại adapters
  • File system (default)
  • Memory
  • SQL

Tùy vào môi trường thì sẽ dùng các config khác nhau

  • Ví dụ môi trường dev thì config như sau
# Define ENV variables for development environment

LOTUS_PART1_DATABASE_URL="sqlite:///db/lotus-part1_development"     //đường dẫn tới file db trong project
WEB_SESSIONS_SECRET="7c0fd875aa778bf97ebcff1eb5eef60a1d2c2fb690c48297947ffb4658ce5277"

  • Để test xem url của bạn có đúng không thì chỉ cần chạy lệnh lotus db create

###2.1 Generate migration

  • lotus generate migration create_articles
  • Lotus migration cũng tương tự như Rails migration. Lúc này lotus sẽ tạo dùm bạn một file mới trong folder db/migrations, prefix sẽ là timestamp lúc generate ra.
Lotus::Model.migration do
  change do
  	create_table :articles do
      primary_key :id

      column :user_id, Integer
      column :title, String, null: false
      column :content, String
      column :created_at, DateTime
      column :updated_at, DateTime
    end

  end
end

sau đó chạy lệnh bundle exec lotus db migrate để run file migrate

###2.2 Tạo seeds data

  • Về tạo data mẫu trong lotus thì không có gì khác so với rails
[
  {
    title: "Article1",
    content: "Nguyen Van Dung",
    user_id: 1
  },
  {
    title: "Article2",
    content: "Pham Thi Chieu",
    user_id: 1
  }
].each do |article|
  new_article = Article.new(article)
  ArticleRepository.persist(new_article)
end

  • Viết rake file để chạy file seeds
namespace :db do
  task :migrate do
    require_relative 'lib/lotus-part1/migrator'
    LotusPart1::Migrator.migrate!
  end

  task :seed => [:migrate] do
    load 'db/seeds.rb'
  end
end

Chạy lệnh bundle exec rake db:seed để run file seeds.rb

Source code tại đây

0