Class: Redpear::Model
- Inherits:
-
Hash
- Object
- Hash
- Redpear::Model
- Extended by:
- Machinist::Machinable
- Includes:
- Expiration, FactoryGirl, Finders, Schema
- Defined in:
- lib/redpear/model.rb,
lib/redpear/model/machinist.rb,
lib/redpear/model/factory_girl.rb
Overview
Redis is a simple key/value store, hence storing structured data can be a challenge. Redpear::Model allows you to store/find/associate “records” in a Redis DB very efficiently, minimising IO operations and storage space where possible.
For example:
class Post < Redpear::Model
column :title
column :body
end
class Comment < Redpear::Model
column :body
index :post_id
end
Redpear::Model is VERY lightweight. It is optimised for raw speed at the expense of convenience.
Defined Under Namespace
Modules: Expiration, FactoryGirl, Finders, Machinist
Class Attribute Summary collapse
-
.connection ⇒ Redis
The connection.
-
.scope ⇒ String
The scope of this model.
Class Method Summary collapse
-
.blueprint_class ⇒ Class
Used internally by Machinist.
-
.destroy(id) ⇒ Redpear::Model
Destroys a record.
-
.instantiate(id) ⇒ Object
Allocate an instance.
-
.members ⇒ Redpear::Store::Set
The IDs of all existing records.
-
.nested_key(*tokens) ⇒ String
Examples: Comment.nested_key(123) # => “comments:123” Comment.nested_key(“abc”, 123) # => “comments:abc:123”.
-
.pipelined { ... } ⇒ Object
Runs a bulk-operation.
-
.pk_counter ⇒ Redpear::Store::Counter
The generator of primary keys.
-
.transaction { ... } ⇒ Object
Runs a transactional bulk-operation.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
(also: #eql?)
Custom comparator, inspired by ActiveRecord::Base#==.
-
#[](name) ⇒ Object
Reads and (caches) a single value.
-
#[]=(name, value) ⇒ Object
Write a single attribute.
-
#after_save(attrs) ⇒ Object
Cheap after save callback, override in subclasses and don’t forget to call ‘super()`.
-
#attributes ⇒ Redpear::Store::Hash
Returns the attributes store.
-
#clear ⇒ Hash
Clear all the cached attributes, but keep ID.
-
#decrement(name, by = 1) ⇒ Object
Decrements the value of a counter attribute.
-
#destroy ⇒ Boolean
Destroy the record.
-
#hash ⇒ Object
Use ID as base for hash.
-
#id ⇒ String
The ID of this record.
-
#increment(name, by = 1) ⇒ Object
Increments the value of a counter attribute.
-
#initialize(attrs = {}) ⇒ Model
constructor
A new instance of Model.
-
#inspect ⇒ String
Show information about this record.
-
#lookups ⇒ Array<Redpear::Store::Enumerable>
Return lookups, relevant to this record.
-
#update(hash) ⇒ Hash
Bulk-updates the model.
Methods included from FactoryGirl
Methods included from Expiration
Methods included from Concern
Constructor Details
#initialize(attrs = {}) ⇒ Model
Returns a new instance of Model.
102 103 104 105 106 107 |
# File 'lib/redpear/model.rb', line 102 def initialize(attrs = {}) super() store 'id', (attrs.delete("id") || attrs.delete(:id) || self.class.pk_counter.next).to_s update(attrs) after_create(attrs) end |
Class Attribute Details
.connection ⇒ Redis
Returns the connection.
43 44 45 |
# File 'lib/redpear/model.rb', line 43 def connection @connection ||= (superclass.respond_to?(:connection) ? superclass.connection : Redis.current) end |
.scope ⇒ String
Returns the scope of this model. Example: Comment.scope # => “comments”.
49 50 51 |
# File 'lib/redpear/model.rb', line 49 def scope @scope ||= "#{name.split('::').last.downcase}s" end |
Class Method Details
.blueprint_class ⇒ Class
Used internally by Machinist
9 10 11 |
# File 'lib/redpear/model/machinist.rb', line 9 def self.blueprint_class self::Machinist::Blueprint end |
.destroy(id) ⇒ Redpear::Model
Destroys a record. Example:
88 89 90 |
# File 'lib/redpear/model.rb', line 88 def destroy(id) instantiate(id).tap(&:destroy) end |
.instantiate(id) ⇒ Object
Allocate an instance
93 94 95 96 97 |
# File 'lib/redpear/model.rb', line 93 def instantiate(id) instance = allocate instance.send :store, 'id', id.to_s instance end |
.members ⇒ Redpear::Store::Set
Returns the IDs of all existing records.
64 65 66 |
# File 'lib/redpear/model.rb', line 64 def members @_members ||= Redpear::Store::Set.new nested_key(:~), connection end |
.nested_key(*tokens) ⇒ String
Examples:
Comment.nested_key(123) # => "comments:123"
Comment.nested_key("abc", 123) # => "comments:abc:123"
59 60 61 |
# File 'lib/redpear/model.rb', line 59 def nested_key(*tokens) [scope, *tokens].join(':') end |
.pipelined { ... } ⇒ Object
Runs a bulk-operation.
81 82 83 |
# File 'lib/redpear/model.rb', line 81 def pipelined(&block) connection.pipelined(&block) end |
.pk_counter ⇒ Redpear::Store::Counter
Returns the generator of primary keys.
69 70 71 |
# File 'lib/redpear/model.rb', line 69 def pk_counter @_pk_counter ||= Redpear::Store::Counter.new nested_key(:+), connection end |
.transaction { ... } ⇒ Object
Runs a transactional bulk-operation.
75 76 77 |
# File 'lib/redpear/model.rb', line 75 def transaction(&block) connection.multi(&block) end |
Instance Method Details
#==(other) ⇒ Boolean Also known as: eql?
Custom comparator, inspired by ActiveRecord::Base#==
117 118 119 120 121 122 123 124 |
# File 'lib/redpear/model.rb', line 117 def ==(other) case other when Redpear::Model other.instance_of?(self.class) && other.id == id else super end end |
#[](name) ⇒ Object
Reads and (caches) a single value
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/redpear/model.rb', line 137 def [](name) return if frozen? column = self.class.columns[name] return super if column.nil? || key?(column) value = case column when Redpear::Schema::Score column.members[id] when Redpear::Schema::Column attributes[column] end store column, column.type_cast(value) end |
#[]=(name, value) ⇒ Object
Write a single attribute
158 159 160 161 162 |
# File 'lib/redpear/model.rb', line 158 def []=(name, value) column = self.class.columns[name] || return delete column.to_s store_attribute attributes, column, value end |
#after_save(attrs) ⇒ Object
Cheap after save callback, override in subclasses and don’t forget to call ‘super()`.
268 269 |
# File 'lib/redpear/model.rb', line 268 def after_save(attrs) end |
#attributes ⇒ Redpear::Store::Hash
Returns the attributes store
210 211 212 |
# File 'lib/redpear/model.rb', line 210 def attributes @_attributes ||= Redpear::Store::Hash.new self.class.nested_key("", id), self.class.connection end |
#clear ⇒ Hash
Clear all the cached attributes, but keep ID
201 202 203 204 205 206 |
# File 'lib/redpear/model.rb', line 201 def clear value = self.id super ensure store 'id', value end |
#decrement(name, by = 1) ⇒ Object
Decrements the value of a counter attribute
181 182 183 |
# File 'lib/redpear/model.rb', line 181 def decrement(name, by = 1) increment name, -by end |
#destroy ⇒ Boolean
Destroy the record.
222 223 224 225 226 227 228 |
# File 'lib/redpear/model.rb', line 222 def destroy before_destroy lookups.each {|l| l.delete(id) } attributes.purge! after_destroy freeze end |
#hash ⇒ Object
Use ID as base for hash
128 129 130 |
# File 'lib/redpear/model.rb', line 128 def hash id.hash end |
#id ⇒ String
Returns the ID of this record.
110 111 112 |
# File 'lib/redpear/model.rb', line 110 def id fetch 'id' end |
#increment(name, by = 1) ⇒ Object
Increments the value of a counter attribute
169 170 171 172 173 174 |
# File 'lib/redpear/model.rb', line 169 def increment(name, by = 1) column = self.class.columns[name] return false unless column && column.type == :counter store column, attributes.increment(column, by) end |
#inspect ⇒ String
Show information about this record
232 233 234 |
# File 'lib/redpear/model.rb', line 232 def inspect "#<#{self.class.name} #{super}>" end |
#lookups ⇒ Array<Redpear::Store::Enumerable>
Return lookups, relevant to this record
216 217 218 |
# File 'lib/redpear/model.rb', line 216 def lookups @_lookups ||= [self.class.members] + self.class.columns.indicies.map {|i| i.for(self) } end |
#update(hash) ⇒ Hash
Bulk-updates the model
187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/redpear/model.rb', line 187 def update(hash) clear bulk = {} hash.each do |name, value| column = self.class.columns[name] || next store_attribute bulk, column, value end attributes.merge! bulk after_save(hash) self end |