中秋節!突然後悔沒有提早一點開賽,有些參賽者已經完賽了...
廢話不多說,直接進入主題吧!
我們現在有支援 SQlite
,接下來我們也要支援 Postgresql 的部分,但這時候問題就來了,應該要讓開發者可以選擇用那種資料庫才對?那這部分怎麼實作呢?我們隨便打開一個 Rails 專案看看,可以發現在專案底下,關於資料庫的設定應該會是在 config/database.yml
裡面
# config/database.yml
default: &default
adapter: sqlite3
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
development:
<<: *default
database: db/development.sqlite3
所以透過 Rails 這樣的機制,我們大概可以猜到,應該是靠 Ruby 的 Std-lib
YAML
來讀取檔案,那我們就來實作一個吧,首先我們在 just_do 簡單建立一個 database.yml
檔案
# just_do/config/database.yml
default:
adapter: postgresql
development:
database: just_do
透過這個檔案,我們告訴 Mavericks 我們要用 postgresql
,並且要用 just_do 這個資料庫名稱,所以在這之間,要先安裝 PostgreSQL,安裝過程請參照官網,Mac 的話建議使用 homebrew
來進行套件管理
接著我們進入 postgresql
$ psql postgres
建立一個 just_do 的資料庫,語法如下
CREATE DATABASE just_do;
建立好資料庫以後,我們修改一下 mini_migration.rb
,把原本的 sqlite 換掉
# just_do/mini_migration.rb
require 'pg'
conn = PG.connect(dbname: 'just_do')
conn.exec <<SQL
CREATE SEQUENCE users_id_seq START 1;
CREATE TABLE tasks(id bigint DEFAULT nextval('users_id_seq') PRIMARY KEY
,title character varying, content character varying);
SQL
因為我們現在開始用的是 postgresql
,所以記得到 Gemfile
加上pg
這個套件,別忘了記得 bundle install
# Gemfile
gem 'pg'
然後執行 migration
$ bundle exec ruby mini_migration.rb
有了資料庫以後,我們將要來建立基本的連線,因為接下來程式碼會越來越多,所以需要整理一下,我們先建立一個 data_record.rb
的檔案
# mavericks/lib/data_record.rb
require 'mavericks/support'
require_relative "./data_record/connection_adapter.rb"
require_relative "./data_record/persistence"
require_relative "./data_record/method"
require_relative "./data_record/base"
module Mavericks
module DataRecord
end
end
接下來建立一個 data_record/
的資料夾,裡面會存放我們威力加強版的 Model,首先建立 base.rb
# mavericks/lib/data_record/base.rb
module Mavericks
module DataRecord
class Base
include Persistence
extend Method
end
end
end
include
和 extend
相信大家都不陌生,一個是載入 instance method
,一個是載入 class method
persistence.rb
之後會用來處理 save
部分,現在可以先不用管他
# mavericks/lib/data_record/persistence.rb
module Mavericks
module DataRecord
module Persistence
end
end
end
接著建立 connection_adapter
來建立連線,利用 pg
這個套件寫好的 method,我們只要使用 connect
就可以輕鬆連到資料庫,另外 pg
也提供另一個方便的 method 叫 exec
,可以用來執行 SQL 語法
# mavericks/lib/data_record/connection_adapter.rb
module Mavericks
module DataRecord
module ConnectionAdapter
class PostgreSQLAdapter
def initialize(dbname)
require 'pg'
@db = PG.connect(dbname: dbname)
end
def execute(sql)
@db.exec(sql)
end
end
end
end
end
接著是 method.rb 部分
# mavericks/lib/data_record/method.rb
require 'yaml'
module Mavericks
module DataRecord
module Method
def establish_connection
raw = File.read('config/database.yml')
database_config = YAML.safe_load(raw)
case database_config['default']['adapter']
when 'postgresql'
@@connection = ConnectionAdapter::PostgreSQLAdapter.new(database_config['development']['database'])
when 'sqlite'
# sqlite connection
end
end
def connection
@@connection
end
def schema
self.connection.execute("SELECT column_name FROM information_schema.columns
WHERE table_name= '#{self.table_name}'").map{|m| m["column_name"]}
end
def table_name
singular_table_name = Mavericks.to_underscore name
Mavericks.to_plural singular_table_name
end
end
end
end
我們這裡建立了一個 class method
叫 establish_connection
,用來建立資料庫連線,連線的設定是靠載入 config/database.yml
來決定,透過 YAML
的解析,我們可以拿到資料庫的資訊,選擇用哪一種方式來處理,schema
和 table_name
相信大家已經不陌生之前實作 sqlite_model.rb
就有用到一樣觀念
比較特別的是我們將 new 出來的資料庫物件放到 @@connection
這個類別變數,讓之後繼承的 Model 也可以使用,例如像是 Task
一樣回到 jsut_do 來測試看看
# just_do/sqlite_test.rb
# 換成載入 data_record
require 'mavericks/data_record'
# 建立連線
Mavericks::DataRecord::Base.establish_connection
class Task < Mavericks::DataRecord::Base
end
# 看看能不能取得 shcema
puts Task.schema
如果最後有印出資料欄位,代表成功了!