Class: Record

Inherits:
Object
  • Object
show all
Includes:
AttributeBuilder, IndexBuilder, RelationBuilder, SearchBuilder
Defined in:
lib/redisant/records.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SearchBuilder

included

Methods included from IndexBuilder

included

Methods included from RelationBuilder

#find_relation, included, #relations, #setup_relations

Methods included from AttributeBuilder

included

Constructor Details

#initialize(attributes = nil) ⇒ Record

Returns a new instance of Record.



16
17
18
19
20
21
22
23
24
25
# File 'lib/redisant/records.rb', line 16

def initialize attributes=nil
  raise Redisant::InvalidArgument.new('Wrong arguments') unless attributes==nil or attributes.is_a? Hash
  @id = attributes.delete(:id) if attributes
  @attributes = stringify_attributes(attributes) || {}
  @prev_attributes = {}
  @dirty = @attributes.keys
  setup_relations if respond_to? :setup_relations
  @id_saved = false
  @errors = nil
end

Instance Attribute Details

#attributesObject

Returns the value of attribute attributes.



12
13
14
# File 'lib/redisant/records.rb', line 12

def attributes
  @attributes
end

#dirty(keys) ⇒ Object (readonly)

Returns the value of attribute dirty.



13
14
15
# File 'lib/redisant/records.rb', line 13

def dirty
  @dirty
end

#errorsObject (readonly)

Returns the value of attribute errors.



14
15
16
# File 'lib/redisant/records.rb', line 14

def errors
  @errors
end

#idObject (readonly)

Returns the value of attribute id.



11
12
13
# File 'lib/redisant/records.rb', line 11

def id
  @id
end

Class Method Details

.all(options = {}) ⇒ Object



58
59
60
61
62
63
64
65
66
67
# File 'lib/redisant/records.rb', line 58

def self.all options={}
  sort = options.delete :sort
  if sort
    index = self.find_index sort.to_s
    raise Redisant::InvalidArgument.new("Cannot order by #{sort}") unless index
    index.objects options
  else
    ids.map { |id| self.find id }
  end
end

.any?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/redisant/records.rb', line 69

def self.any?
  $redis.scard( id_key ) > 0
end

.build(attributes = nil) ⇒ Object

crud



115
116
117
118
119
# File 'lib/redisant/records.rb', line 115

def self.build attributes=nil
  object = self.new attributes
  object.save
  object
end

.class_key(str) ⇒ Object



183
184
185
# File 'lib/redisant/records.rb', line 183

def self.class_key str
  "#{self.name.downcase}:#{str}"
end

.countObject



89
90
91
# File 'lib/redisant/records.rb', line 89

def self.count
  Criteria.new(self).count
end

.destroy_allObject



170
171
172
173
174
175
# File 'lib/redisant/records.rb', line 170

def self.destroy_all
  keys = ids.map {|id| "#{self.name.downcase}:#{id}:attributes" }
  keys << id_key
  keys << class_key('ids:counter')
  $redis.del keys if keys.any?
end

.exists?(id) ⇒ Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/redisant/records.rb', line 54

def self.exists? id
  $redis.sismember( id_key, id )
end

.find(id) ⇒ Object

query



38
39
40
41
42
43
44
45
# File 'lib/redisant/records.rb', line 38

def self.find id
  raise Redisant::InvalidArgument.new("Invalid argument") unless id
  return nil unless exists? id
  t = self.new id:id
  
  t.load
  t
end

.find!(id) ⇒ Object



47
48
49
50
51
52
# File 'lib/redisant/records.rb', line 47

def self.find! id
  raise Redisant::InvalidArgument.new("Not found") unless exists? id
  t = self.new id:id
  t.load
  t
end

.first(attributes = {}) ⇒ Object



73
74
75
# File 'lib/redisant/records.rb', line 73

def self.first attributes={}
  Criteria.new(self).first attributes
end

.id_keyObject

ids



261
262
263
# File 'lib/redisant/records.rb', line 261

def self.id_key
  class_key 'id'
end

.idsObject



278
279
280
# File 'lib/redisant/records.rb', line 278

def self.ids
  Criteria.new(self).ids
end

.last(attributes = {}) ⇒ Object



77
78
79
# File 'lib/redisant/records.rb', line 77

def self.last attributes={}
  Criteria.new(self).last attributes
end

.load(id) ⇒ Object



31
32
33
34
35
# File 'lib/redisant/records.rb', line 31

def self.load id
  t = self.new id:id
  t.load
  t
end

.order(options) ⇒ Object



97
98
99
# File 'lib/redisant/records.rb', line 97

def self.order options
  Criteria.new(self).order options
end

.randomObject



81
82
83
# File 'lib/redisant/records.rb', line 81

def self.random
  Criteria.new(self).random
end

.sort(options) ⇒ Object



93
94
95
# File 'lib/redisant/records.rb', line 93

def self.sort options
  Criteria.new(self).sort options
end

.where(attributes) ⇒ Object



85
86
87
# File 'lib/redisant/records.rb', line 85

def self.where attributes
  Criteria.new(self).where attributes
end

Instance Method Details

#add_idObject



282
283
284
285
286
287
# File 'lib/redisant/records.rb', line 282

def add_id
  raise Redisant::InvalidArgument.new('Cannot add empty id') unless @id
  return if @id_saved
  $redis.sadd self.class.id_key, @id.to_i
  @id_saved = true
end

#attribute(key) ⇒ Object

single attribute



188
189
190
# File 'lib/redisant/records.rb', line 188

def attribute key
  @attributes[key.to_s]
end

#class_nameObject



27
28
29
# File 'lib/redisant/records.rb', line 27

def class_name
  self.class.name.downcase
end

#cleanObject



110
111
112
# File 'lib/redisant/records.rb', line 110

def clean
  @dirty = []
end

#cleanup_attributesObject



253
254
255
256
257
258
# File 'lib/redisant/records.rb', line 253

def cleanup_attributes
  # delete attribues in the hash that's not in our local attributes
  keys = $redis.hkeys member_key('attributes')
  delete = keys - @attributes.keys
  $redis.hdel member_key('attributes'), delete
end

#destroyObject



121
122
123
124
125
# File 'lib/redisant/records.rb', line 121

def destroy
  destroy_relations
  destroy_attributes
  remove_id
end

#destroy_attributesObject



247
248
249
250
251
# File 'lib/redisant/records.rb', line 247

def destroy_attributes
  $redis.del member_key('attributes')
  @attributes = nil
  update_search
end

#dirty?Boolean

dirty

Returns:

  • (Boolean)


102
103
104
# File 'lib/redisant/records.rb', line 102

def dirty?
  @dirty.any?
end

#loadObject



131
132
133
134
# File 'lib/redisant/records.rb', line 131

def load
  load_attributes
  @id_saved = true
end

#load_attributes(keys = nil) ⇒ Object



218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/redisant/records.rb', line 218

def load_attributes keys=nil
  if keys
    keys = keys.map { |key| key.to_s }
    values = $redis.hmget(member_key('attributes'), keys)
    raw = keys.zip(values).to_h
  else
    raw = $redis.hgetall(member_key('attributes'))
  end
  decoded = decode_attributes(raw)
  @attributes = restore_attribute_types decoded
  keep_attributes
end

#make_unique_idObject



265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/redisant/records.rb', line 265

def make_unique_id
  return if @id
  #use optimistic concurrency control:
  #if id is taken, try again until we succeed
  while true
    id = $redis.incr(self.class.class_key('ids:counter')).to_i
    unless self.class.exists? id
      @id = id
      return
    end
  end
end

#member_key(str) ⇒ Object

keys



178
179
180
181
# File 'lib/redisant/records.rb', line 178

def member_key str
  raise Redisant::InvalidArgument.new('Cannot make key without id') unless @id
  "#{class_name}:#{@id}:#{str}"
end

#new?Boolean

Returns:

  • (Boolean)


127
128
129
# File 'lib/redisant/records.rb', line 127

def new?
  id == nil
end

#remove_idObject



289
290
291
292
293
294
# File 'lib/redisant/records.rb', line 289

def remove_id
  raise Redisant::InvalidArgument.new('Cannot remove empty id') unless @id
  $redis.srem self.class.id_key, @id
  @id = nil
  @id_saved = false
end

#saveObject



136
137
138
139
140
141
142
# File 'lib/redisant/records.rb', line 136

def save
  return false unless validate
  make_unique_id
  add_id
  save_attributes
  true
end

#save!Object



144
145
146
# File 'lib/redisant/records.rb', line 144

def save!
  raise Redisant::ValidationFailed.new('Validation failed') unless save
end

#save_attributesObject



231
232
233
234
235
236
237
238
# File 'lib/redisant/records.rb', line 231

def save_attributes
  if dirty?
    synthesize_attributes
    $redis.hmset member_key('attributes'), encode_attributes
    clean
  end
  update_search
end

#set_attribute(key, value) ⇒ Object



192
193
194
195
196
197
# File 'lib/redisant/records.rb', line 192

def set_attribute key, value
  if value != @attributes[key.to_s]
    @attributes[key.to_s] = value
    dirty [key]
  end
end

#update_attribute(key, value) ⇒ Object



199
200
201
202
203
204
205
# File 'lib/redisant/records.rb', line 199

def update_attribute key, value
  if value != @attributes[key.to_s]
    @attributes[key.to_s] = value
    $redis.hset member_key('attributes'), key, value
    update_search
  end
end

#update_attributes(attributes) ⇒ Object



240
241
242
243
244
245
# File 'lib/redisant/records.rb', line 240

def update_attributes attributes
  raise Redisant::InvalidArgument.new("Invalid arguments") unless attributes.is_a? Hash
  @attributes.merge! stringify_attributes(attributes)
  dirty attributes.keys
  save_attributes
end

#validateObject



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/redisant/records.rb', line 148

def validate
  @errors = nil
  self.class.attributes.each_pair do |key,options|
    v = attribute(key)
    if options[:required]
      if v==nil
        @errors ||= {}
        @errors[key] = "is required"
      end
    end
    if v && options[:unique]
      conditions = {}
      conditions[key] = v
      if self.class.where(conditions).count > 0
        @errors ||= {}
        @errors[key] = "must be unique"
      end
    end
  end
  @errors == nil
end