ruby 一个简单的redis orm
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ruby 一个简单的redis orm相关的知识,希望对你有一定的参考价值。
# encoding: utf-8
require 'redis'
require 'thread'
begin
require "active_model/model/validations"
rescue LoadError
end
module RedisPersistence
# = Redis \Persistence
#
# Usage:
#
# class User
# include RedisPersistence
# self.redis = Redis.new
#
# attribute :age, ->(i) { i.to_i }
# attribute :name
#
# validates :name, presence: true
# end
#
# u = User.new(key: 1, age: 10, name: 'test')
# u.new_record? # => true
# u.valid? # => true
# u.save # => true
# User.count # => 1
#
# u = User.find(1)
# u.persisted? # => true
# u.age # => 10
#
def self.included(base)
base.extend ClassMethods
base.include ::ActiveModel::Validations
end
class RedisPersistenceError < StandardError; end
class RedisConnectionError < RedisPersistenceError; end
class StoreKeyMissing < RedisPersistenceError; end
class RecordAlreadyExist < RedisPersistenceError; end
class RecordNotSaved < RedisPersistenceError; end
class RecordNotDestroyed < RecordNotSaved; end
class UnknownAttributeError < RedisPersistenceError; end
module ClassMethods
def redis
raise RedisConnectionError if !connected?
@redis
end
def redis=(redis)
@redis = redis
@connected = true
end
def connected?
!!(@redis && @connected)
end
def mutex
@@mutex ||= Mutex.new
end
def synchronize(&block)
mutex.synchronize(&block)
end
def namespace
@namespace ||= self.name
end
def store_key(key)
"#{namespace}:#{key}"
end
def counter
"#{namespace}/counter"
end
def keys(key)
redis.keys(key)
end
def count
redis.get(counter).to_i
end
def find(key)
return nil if !exist?(key)
raw_data = redis.hgetall(store_key(key))
raw_data = raw_data.merge(key: key, _new_record: false)
new(raw_data.to_h)
end
def exist?(key)
redis.exists(store_key(key))
end
def delete(key)
return false if !exist?(key)
synchronize do
if redis.del(store_key(key)) == 1
redis.incrby(counter, -1)
true
else
false
end
end
end
def delete_all
keys("#{namespace}:*").each { |k| redis.del(k) }
redis.del(counter)
true
end
def insert(key, attributes = nil)
flattened_attributes = attributes.to_a.flatten
synchronize do
redis.hmset(store_key(key), flattened_attributes)
redis.incrby(counter, 1)
end
end
def insert_row(key, field, value)
redis.hset(store_key(key), field, value)
end
def attribute(name, block = nil)
attributes << name if !attributes.include?(name)
if block
define_method(name) { block.call(@attributes[name]) }
else
define_method(name) { @attributes[name] }
end
define_method(:"#{name}=") { |value| @attributes[name] = value }
end
# ==== Examples
# # Create a single new object
# User.create(key: '123', first_name: 'Jamie')
#
# # Create an Array of new objects
# User.create([{ key: '123', first_name: 'Jamie' }, { key: '456', first_name: 'Jeremy' }])
def create(attributes = nil)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr) }
else
object = new(attributes)
object.save
object
end
end
def create!(attributes = nil)
if attributes.is_a?(Array)
attributes.collect { |attr| create!(attr) }
else
object = new(attributes)
object.save!
object
end
end
protected
def attributes
@attributes ||= []
end
end
attr_reader :key, :attributes
def initialize(attributes = {})
@attributes = {}
@_destroyed = false
@_new_record = attributes.delete(:_new_record).nil? ? true : false
@key = attributes.delete(:key)
raise StoreKeyMissing if !@key
_assign_attributes(attributes)
super()
end
def new_record?
@_new_record
end
def destroyed?
@_destroyed
end
def persisted?
!(@_new_record || @_destroyed)
end
def save(*args)
create_or_update(*args)
end
def save!(*args)
create_or_update(*args) || raise(RecordNotSaved)
end
def delete
if persisted?
result = self.class.delete(key)
return false if !result
end
@_destroyed = true
freeze
end
alias :destroy :delete
def destroy!
destroy || raise(RecordNotDestroyed)
end
def update(attributes)
_assign_attributes(attributes)
save
end
alias update_attributes update
def update!(attributes)
_assign_attributes(attributes)
save!
end
alias update_attributes! update!
def reload
fresh_object = self.class.find(key)
@_new_record = false
_assign_attributes(fresh_object.attributes)
self
end
private
def _assign_attributes(attributes)
attributes.each do |k, v|
_assign_attribute(k, v)
end
end
def _assign_attribute(k, v)
if respond_to?("#{k}=")
public_send("#{k}=", v)
else
raise UnknownAttributeError.new
end
end
def create_or_update(*args)
result = new_record? ? _create_record : _update_record(*args)
result != false
end
def _update_record(attributes = self.attributes)
return false if !key || !valid?
attributes.each do |field, value|
self.class.insert_row(key, field, value)
end
true
end
def _create_record(attributes = self.attributes)
return false if !key || self.class.exist?(key) || !valid?
self.class.insert(key, attributes)
@_new_record = false
true
end
end
以上是关于ruby 一个简单的redis orm的主要内容,如果未能解决你的问题,请参考以下文章
是否可以使用 Ohm 更新模型属性,而 Redis DB 是 Ruby?