# This is intended to provide a cheap, throw-away persistence solution # for luca collections. Based on redis. # # it provides a Backbone.sync adapter and API endpoint for accessing it. # # It is used to make luca.collections persistent for # multiple users. Not intended to be used in production or for any apps # which require data integrity. require 'json' module Luca class Collection class RedisBackend def self.default_redis require 'redis' @default_redis ||= Redis.new host: "localhost", port: 6379, db: 5 end attr_accessor :namespace, :redis, :id_storage, :required_attributes, :redis_database def initialize options={} @namespace = options[:namespace].to_s @redis = options[:redis] || Luca::Collection::RedisBackend.default_redis @id_storage = options[:id_storage] ||= "#{ @namespace }:ids" @required_attributes = options[:required_attributes] || [] validate_redis_connection end def sync method, hash={}, options={} if method == "read" and !hash[:id].nil? return index() end if method == "read" and !hash[:id].nil? return show( hash[:id] ) end if method == "create" return create( hash ) end if method == "update" return update( hash ) end if method == "delete" return destroy( hash ) end end alias_method :backbone_sync, :sync def validate_redis_connection unless @redis end unless @redis.respond_to?(:get) and @redis.respond_to?(:incr) and @redis.respond_to?(:mget) throw "Must specify a valid redis instance." end end def record_ids Array(redis.smembers( id_storage )).map {|id| "#{ namespace }/#{ id }"} end def clear! return unless record_ids.length > 0 redis.del( *record_ids ) redis.del( id_storage ) end def generate_id id_base=nil id_base ||= id_storage redis.incr("next:#{ id_base }:id") end def index search=nil return [] unless record_ids.length > 0 redis.mget( *record_ids ).map {|serialized| JSON.parse(serialized) rescue nil }.compact end def show id record = redis.get("#{ namespace }/#{ id }") JSON.parse( record ) if record end def create hash hash.symbolize_keys! if required_attributes.any? {|attribute| hash[attribute].nil?} return {success: false, error:"Missing required attributes."} end next_id = hash[:id] ||= generate_id serialized = JSON.generate(hash) response = redis.set "#{ namespace }/#{ next_id }", serialized if response == "OK" redis.sadd id_storage, hash[:id] return {success: true, id: hash[:id], record: hash} else return {success: false, error:"Error adding record in data store."} end end def destroy hash hash.symbolize_keys! stored = redis.get("#{ namespace }/#{ hash[:id] }") if stored redis.del "#{ namespace }/#{ hash[:id] }" return {success: true} else return {success: false, error:"Could not find record with #{ hash[:id] }"} end end def update hash hash.symbolize_keys! if required_attributes.any? {|attribute| hash[attribute].nil?} return {success: false, error:"Missing required attributes."} end stored = redis.get("#{ namespace }/#{ hash[:id] }") if stored.nil? return {success: false, error:"Could not find record with #{ hash[:id] }"} end serialized = JSON.generate(hash) result = redis.set "#{ namespace }/#{ hash[:id] }", serialized if result == "OK" return {success: true} else return {success: false, error:"Error adding record in data store."} end end end end end