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 – ...
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