金子邦彦研究室プログラミングRuby による Web/データベース・プログラミングRuby で SQL のテーブル定義

Ruby で SQL のテーブル定義

リレーショナルデータベースのテーブルのデータ型 (Data Types of Relational Database Table)

MySQL の主なデータ型 (MySQL main data types) PostgreSQL の主なデータ型 (PostgreSQL main data types) SQLite 3 の主なデータ型 (SQLite 3 main data types) DataMapper のプロパティ(DataMapper properties) ActiveRecord で SQLite 3 を使う場合 (*1)
真偽値 (boolean) bool, boolean boolean Boolean :boolean
文字列 (character string) 固定長 (fixed length and padded) character(n), char(n) character(n), char(n)
可変長 (variable length) tinytext, text, mediumtext, longtext, character varing(n), varchar(n) text, character varing(n), varchar(n) text String, Text :string, :text
整数 (integer) [-32768, 32767] smallint smallint integer Integer :integer
[-2147483648, 2147483648] integer, int integer, int
[-9223372036854775808, 9223372036854775807] bigint bigint
可変長 (variable length) decimal, fixed, dec, numeric decimal, numeric Decimal :decimal
浮動小数点数 (floating point number) single precision float real Float
double precision double, double precision, real double precision real :float
年月日時分秒 (datetime) datetime, timestamp timestamp(n) DateTime :datetime, :timestamp
年月日 (date) date date Date :date
時分秒 (time) time time(n) Time :time
可変長バイナリ型 (variable length binary data) tinyblob, blob, mediumblob, longblob bytea blob Binary :binary
marshalled object Object
a NULL value NULL NULL NULL

*1: Active Record が対応しているデータ型

:primary_key, :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean です.

(参考: http://guides.rails.info/migrations.html). これ以外を使うとうまく動かない(しかも、ひな形の生成時には、エラーメッセージは出ない)

ruby script/rails generate scaffold t id:primary_key a1:integer a2:string a3:text a4:integer a5:float a6:decimal a7:datetime a8:timestamp a9:time a10:date a11:binary a12:boolean

[image]
SQLite 3 の場合は,activerecord の connection_adapters/sqlite_adapter.rb を見てください. (see connection_adapters/sqlite_adapter.rb when SQLite 3)

[image]

SQLite 3 での列制約とテーブル制約 (Column Constraint and Table Constraint of SQLite 3)

Active Record での列制約の記述

主なものを次に挙げます.詳しくは https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html を見てください

DataMapper での列制約

主なものを次に挙げます.詳しくは https://rom-rb.org

テーブル定義に反映される列制約

Ruby 側で妥当性検査 (validation) が行われるもの

DataMapper のインストール

ここで行うこと.

Ruby のプログラムから DataMapper を使って sqlite3 のデータベースを扱えるように、いくつかのソフトウェアをインストールする.

  1. dm-sqlite-adapter のインストール
    • Ubuntu
      sudo apt -y update
      sudo apt -y install libsqlite3-dev
      
    • RedHat / Fedora
      sudo yum install sqlite-devel
      
    • MacPorts
      sudo port install sqlite3
      
  2. rvm を用いて Ruby 1.9.2 のインストール
    rvm install ruby-1.9.2-head
    rvm list
    rvm use ruby-1.9.2-head
    
  3. rails のインストール
    gem install rails
    
  4. Rails アプリケーションの生成と,DataMapper 等のインストール
    rails new hogeapp -d sqlite3 -m http://datamapper.org/templates/rails.rb
    cd hogeapp
    bundle install
    
  5. gem を用いて data_mapper のインストール

    あとで使いたい

    sudo gem install data_mapper
    

DataMapper を使ってみる

ここで行うこと

  1. テーブル定義

    次の手順で、irb を使って、プログラムを実行する ここでは、OrderRecord クラスを定義し, 「DataMapper.auto_migrate!」でマイグレーションを行なって、テーブル order_records を作る(この時点では、テーブルは空)。

    irb
    require 'rubygems'
    # require 'data_mapper' 
    require 'dm-core' 
    #  # An in-memory Sqlite3 connection:
    #  DataMapper.setup(:default, 'sqlite::memory:')
    
    # A Sqlite3 connection to a persistent database
    DataMapper.setup(:default, 'sqlite:///home/windowslike/hoge.db')
    
    class OrderRecord
        include DataMapper::Resource
    
        property :id,             Serial      # INTEGER not null PRIMARY KEY autoincrement
        property :year,           Integer,   :required => true, :min => 2011
        property :month,          Integer,   :required => true, :min => 1, :max => 12
        property :day,            Integer,   :required => true, :min => 1, :max => 31
        property :customer_name,  String,    :required => true
        property :product,        String,    :required => true
        property :unit_price,     Float,     :required => true, :min => 0
        property :qty,            Integer,   :required => true, :default => 1, :min => 1
        property :created_at,     DateTime,  :required => true
        property :updated_at,     DateTime
    end
    
    DataMapper.finalize
    
    require  'dm-migrations'
    DataMapper.auto_migrate!
    exit
    

    [image]
  2. テーブル定義の確認

    テーブル order_records が定義されていることを確認

    sqlite3 /home/windowslike/hoge.db
    select * from sqlite_master;
    .exit
    

    [image]
  3. テーブルの作成

    次の手順で、irb を使って、プログラムを実行する

    OrderRecord クラスのクラス定義の部分は、先のものと同じ (本格的に使うなら、クラス定義を別ファイルに分けてインクルードする)

    new メソッドでオブジェクトを生成し、save メソッドを発行すると、データベースに保存される(テーブルが1行増える)

    irb
    require 'rubygems'
    # require 'data_mapper' 
    require 'dm-core' 
    #  # An in-memory Sqlite3 connection:
    #  DataMapper.setup(:default, 'sqlite::memory:')
    
    # A Sqlite3 connection to a persistent database
    DataMapper.setup(:default, 'sqlite:///home/windowslike/hoge.db')
    
    class OrderRecord
        include DataMapper::Resource
    
        property :id,             Serial      # INTEGER not null PRIMARY KEY autoincrement
        property :year,           Integer,   :required => true, :min => 2011
        property :month,          Integer,   :required => true, :min => 1, :max => 12
        property :day,            Integer,   :required => true, :min => 1, :max => 31
        property :customer_name,  String,    :required => true
        property :product,        String,    :required => true
        property :unit_price,     Float,     :required => true, :min => 0
        property :qty,            Integer,   :required => true, :default => 1, :min => 1
        property :created_at,     DateTime,  :required => true
        property :updated_at,     DateTime
    end
    
    
    obj = OrderRecord.new
    obj.year  = 2011
    obj.month = 11
    obj.day   = 25
    obj.customer_name = "kaneko"
    obj.product       = "orange"
    obj.unit_price    = 120
    obj.qty           = 3
    obj.created_at    = "2011/11/25 11:24:11" 
    obj.save
    
    obj = OrderRecord.new
    obj.year  = 2011
    obj.month = 11
    obj.day   = 25
    obj.customer_name = "kaneko"
    obj.product       = "apple"
    obj.unit_price    = 220
    obj.qty           = 10
    obj.created_at    = "2011/11/25 11:26:30" 
    obj.save
    
    DataMapper.finalize
    exit
    

    [image]
  4. テーブルの確認

    念のためテーブル order_records を確認する

    sqlite3 /home/windowslike/hoge.db
    select * from order_records;
    .exit
    

    [image]
  5. 問い合わせの発行と評価結果の確認.(Issue SQL queries and inspect the results)

    次の手順で、irb を使って、プログラムを実行

    テーブルの1行がオブジェクトにマッピングされ、テーブルがクラスにマッピングされている. 問い合わせは、get メソッド、all メソッドなどを使って行う.

    irb
    require 'rubygems'
    # require 'data_mapper' 
    require 'dm-core' 
    #  # An in-memory Sqlite3 connection:
    #  DataMapper.setup(:default, 'sqlite::memory:')
    
    # A Sqlite3 connection to a persistent database
    DataMapper.setup(:default, 'sqlite:///home/windowslike/hoge.db')
    
    class OrderRecord
        include DataMapper::Resource
    
        property :id,             Serial      # INTEGER not null PRIMARY KEY autoincrement
        property :year,           Integer,   :required => true, :min => 2011
        property :month,          Integer,   :required => true, :min => 1, :max => 12
        property :day,            Integer,   :required => true, :min => 1, :max => 31
        property :customer_name,  String,    :required => true
        property :product,        String,    :required => true
        property :unit_price,     Float,     :required => true, :min => 0
        property :qty,            Integer,   :required => true, :default => 1, :min => 1
        property :created_at,     DateTime,  :required => true
        property :updated_at,     DateTime
    end
    
    
    # SELECT * FROM order_records WHERE id = 1; 
    p OrderRecord.get(1)
    
    # SELECT * FROM order_records;
    p OrderRecord.all 
    
    # SELECT * FROM order_records WHERE day = 25;
    p OrderRecord.all( :conditions => ["day = ?", 100] )
    
    # SELECT * FROM order_records WHERE customer_name = 'kaneko';
    p OrderRecord.all( :conditions => ["customer_name = ?", 'kaneko'] )
    
    # SELECT * FROM order_records WHERE unit_price > 200;
    p OrderRecord.all( :conditions => ["unit_price > ?", 200] )
    
    DataMapper.finalize
    exit
    

    [image]

    テーブルの定義(データ型と制約)、テーブルの生成、問い合わせを行った。 テーブルはRuby のクラスにマッピングされていて、SQLを使うことは(確認を除き)ありませんでした。

    ※ ActiveRecord と比べて、機能的には遜色はないように見えます.使用感は違う. DataMapperではクラスを定義してマイグレーションを行うこと、SQL で定められている列制約を簡単な形で記述できることが特徴に見えます.

Rails でも DataMapper を使ってみる

scaffold を動かしてみる.scaffold を動かす程度ならば、ActiveRecord と DataMapper での使用感 には差がみえません。

  1. Rails で,データベースの生成とテーブル定義
    cd hogeapp
    rails g scaffold order_record year:integer month:integer day:integer customer_name:string product:string unit_price:float qty:integer created_at:datetime updated_at:datetime
    rake db:create
    rake db:automigrate
    
  2. 引き続き、テーブル定義の確認
    sqlite3 db/hogeapp_development.db
    select * from sqlite_master;
    .exit
    

    [image]
  3. Rails のサーバを立ち上げて、
    rails s 
    

    Web ブラウザで http://localhost:3000/order_records

    [image]
  4. 試しに、さきほど作ったデータベースファイルをコピーしてみる
    cp ../hoge.db db/hogeapp_development.db
    

    もう1度、Web ブラウザで http://localhost:3000/order_records

    [image]

    DataMapper と Rails を使いたい人 (テーブル定義の操作感が AcriveRecord 風なんだけど、実際には DataMapper), DataMapper と Rails 以外を使いたい人が同じデータベースを使うこともできそうです.