2020年10月13日火曜日

Ruby で redis にあるデータをオブジェクトにバインドする方法

概要

Ruby で Redis を扱う場合にデータ構造が決まっている場合はオブジェクトにしたい場合があります
そんな場合は redis-objects というライブラリを使うと簡単にオブジェクト操作できます

環境

  • macOS 10.15.7
  • Ruby 2.7.1p83
    • redis-objects 1.5.0

インストール

  • bundle init
  • vim Gemfile
gem "redis-objects"
  • bundle install

接続

内部的には redis ライブラリを使っているので初期化方法などは redis ライブラリと同じように行えます

  • vim app.rb
require 'redis'

Redis.current = Redis.new(
  :host => '127.0.0.1',
  :port => 6379
)

データを保存する

データを保存する場合も一度 redis-objects のオブジェクトを作成してから保存します
redis のオブジェクトとして操作するクラスは必ず Redis::Objects を include する必要があります

今回は単純な文字列を保存してみます
Redis::Objects には様々なタイプが用意されており文字列を保存したい場合には value を使って宣言します
そしてキーを一意に特定するために必ず id というメソッドを実装する必要があります

  • vim app.rb
require 'redis'
require 'redis/objects'

Redis.current = Redis.new(
  :host => '127.0.0.1',
  :port => 6379
)

class User
  include Redis::Objects
  value :name
  def id
    1
  end
end

user = User.new
user.name = "hawk"

これで実行すると redis 側には以下のようなデータが保存されているのが確認できると思います

127.0.0.1:6379> keys *
1) "user:1:name"
127.0.0.1:6379> get user:1:name
"hawk"

データを取得する

次に保存したデータを取得してみましょう
とは言ってもやることはオブジェクトを作成するだけです
データを参照する場合は .value を使います

  • vim app.rb
require 'redis'
require 'redis/objects'

Redis.current = Redis.new(
  :host => '127.0.0.1',
  :port => 6379
)

class User
  include Redis::Objects
  value :name
  def id
    1
  end
end

user = User.new
puts user.name.value # => hawk

カウンタを使う

先程は value というタイプを使いました
次は counter というタイプを使ってみます
これは数字の情報を redis で管理する他にカウントアップするための専用のメソッドが用意されています
increment を呼び出すと値を 1 つプラスしてくれます

  • vim app.rb
require 'redis'
require 'redis/objects'

Redis.current = Redis.new(
  :host => '127.0.0.1',
  :port => 6379
)

class User
  include Redis::Objects
  counter :my_posts
  def id
    1
  end
end

user = User.new
user.my_posts.increment
user.my_posts.increment
user.my_posts.increment
puts user.my_posts.value # 3
user.my_posts.reset
puts user.my_posts.value # 0
user.my_posts.reset 5
puts user.my_posts.value # 5
127.0.0.1:6379> keys *
1) "user:1:name"
2) "user:1:my_posts"
127.0.0.1:6379> type user:1:my_posts
string
127.0.0.1:6379> get user:1:my_posts
"5"

配列を使う

配列も扱えます
list を使ってキーを宣言します

require 'redis'
require 'redis/objects'

Redis.current = Redis.new(
  :host => '127.0.0.1',
  :port => 6379
)

class User
  include Redis::Objects
  list :favorites
  def id
    1
  end
end

user = User.new
['ruby', 'swift', 'python'].each do |lang|
  user.favorites << lang
end
127.0.0.1:6379> LLEN user:1:favorites
(integer) 3
127.0.0.1:6379> LRANGE user:1:favorites 0 -1
1) "ruby"
2) "swift"
3) "python"

ハッシュを使う

ハッシュも扱えます
hask_key を使ってキーを宣言します

  • vim app.rb
require 'redis'
require 'redis/objects'

Redis.current = Redis.new(
  :host => '127.0.0.1',
  :port => 6379
)

class User
  include Redis::Objects
  hash_key :score
  def id
    1
  end
end

user = User.new
user.score['japanese'] = 10
user.score['arithmetic'] = 20
user.score['science'] = 30
127.0.0.1:6379> hgetall user:1:score
1) "japanese"
2) "10"
3) "arithmetic"
4) "20"
5) "science"
6) "30"

直接 redis オブジェクトを使う

get や set といった redis のコマンドを直接実行することもできます
ただその場合はキーの指定も直接行う必要があります
クラス名、id メソッド、キー名を使って自動生成される redis のキーを指定します

  • vim app.rb
require 'redis'
require 'redis/objects'

Redis.current = Redis.new(
  :host => '127.0.0.1',
  :port => 6379
)

class User
  include Redis::Objects
  hash_key :score
  def id
    1
  end
end

score = User.redis.hgetall('user:1:score')
puts score

=> {"japanese"=>"10", "arithmetic"=>"20", "science"=>"30"}

最後に

redis-objects を使って redis にあるデータをオブジェクトにシリアライズしてから使用する方法を紹介しました
コード上でどういったデータが redis に入っているのか一目で確認することができるのも嬉しい点かなと思います

こちらのほうがオブジェクト指向っぽく書けますがデータ構造が変わった場合はクラス側も修正必要があるので手間であります
今回は基本的なシリアライズ/デシリアライズの方法しか紹介しませんでしたがカスタムシリアライザも作成できるので複雑なデータのオブジェクト化も自作すれば可能になります

参考サイト

0 件のコメント:

コメントを投稿