redis_orm 0.5.1 → 0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +29 -0
- data/README.md +66 -2
- data/TODO +5 -0
- data/lib/rails/generators/redis_orm/model/model_generator.rb +21 -0
- data/lib/rails/generators/redis_orm/model/templates/model.rb.erb +5 -0
- data/lib/redis_orm.rb +8 -11
- data/lib/redis_orm/active_model_behavior.rb +0 -2
- data/lib/redis_orm/associations/belongs_to.rb +49 -11
- data/lib/redis_orm/associations/has_many.rb +29 -21
- data/lib/redis_orm/associations/has_many_helper.rb +1 -1
- data/lib/redis_orm/associations/has_many_proxy.rb +19 -8
- data/lib/redis_orm/associations/has_one.rb +36 -2
- data/lib/redis_orm/redis_orm.rb +486 -173
- data/lib/redis_orm/utils.rb +12 -0
- metadata +93 -80
- data/Manifest +0 -30
- data/Rakefile +0 -33
- data/redis_orm.gemspec +0 -45
- data/test/association_indices_test.rb +0 -145
- data/test/associations_test.rb +0 -306
- data/test/atomicity_test.rb +0 -64
- data/test/basic_functionality_test.rb +0 -173
- data/test/callbacks_test.rb +0 -119
- data/test/changes_array_test.rb +0 -31
- data/test/dynamic_finders_test.rb +0 -68
- data/test/exceptions_test.rb +0 -45
- data/test/has_one_has_many_test.rb +0 -54
- data/test/indices_test.rb +0 -81
- data/test/options_test.rb +0 -243
- data/test/polymorphic_test.rb +0 -104
- data/test/redis.conf +0 -417
- data/test/test_helper.rb +0 -25
- data/test/uuid_as_id_test.rb +0 -210
- data/test/validations_test.rb +0 -28
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2ca054af9087bbd76a32022f1fee369a5ef0292c15e1b091fddbab2aadb2649f
|
4
|
+
data.tar.gz: 142417a34ecdd550195ec800aff8157d24c5cde06601e69a99c2916d23577e5c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7855dfe1ea7f968d17546eb9ff1ade0d9a50b7548f1a297a31cd1ecd1d60329c89dcefedf6affbc107634425b4f0a3828b6b573a5fa46d807c4167e0cea9dbc3
|
7
|
+
data.tar.gz: 2313d1c202ca558573468a93ec4d47beb278069b454e245aaeb65280ce8bc891ac1e89e03df85980c303787ea1e15f4f4220ba61d2f515823b05dcb1a8e939a6
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
v0.7 [03-05-2013]
|
2
|
+
FEATURES
|
3
|
+
* implemented Array and Hash properties types
|
4
|
+
* added ability to specify an *expire* value for the record via method of the class and added inline *expire_in* key that can be used while saving objects (referencial keys in expireable record also expireables)
|
5
|
+
* Add model generator [Tatsuya Sato]
|
6
|
+
BUGS
|
7
|
+
* fixed a bug with Date property implementation
|
8
|
+
* refactored *save* method
|
9
|
+
|
10
|
+
v0.6.2 [23-05-2012]
|
11
|
+
* adds an ability to specify/create indices on *has_one* and *belongs_to* associations
|
12
|
+
* fixed error with updating indices in *belongs_to* association with :as option
|
13
|
+
* tests refactoring, now all tests are run with Rake::TestTask
|
14
|
+
* moved all classes and modules from test cases to special folders (test/classes, test/modules)
|
15
|
+
* fixed bug: :default values should be properly transformed to the right classes (if :default values are wrong) so when comparing them to other/stored instances they'll be the same
|
16
|
+
|
17
|
+
v0.6.1 [05-12-2011]
|
18
|
+
* rewritten sortable functionality for attributes which values are strings
|
19
|
+
* added Gemfile to the project, improved tests
|
20
|
+
|
21
|
+
v0.6 [12-09-2011]
|
22
|
+
* added equality operator for object, #to_s method for inspecting objects, #find! which could throw RecordNotFound error
|
23
|
+
* added self.descendants class method which returns all inherited from RedisOrm::Base classes
|
24
|
+
* introduced :sortable option (in property declaration and #find conditions hash) - rudimentary ability to sort records by any property (not just by default 'created_at')
|
25
|
+
* now handling models withing modules definitions (test for this in associations_test.rb)
|
26
|
+
* properly handling :as parameter in options for has_many/belongs_to self-references
|
27
|
+
* binding related models while creating model instance (like this: Article.create(:comment => comment))
|
28
|
+
* bunch of small fixes, updated tests and README.md
|
29
|
+
|
1
30
|
v0.5.1 [27-07-2011]
|
2
31
|
* added support of uuid as an id/primary key
|
3
32
|
* added documentation on uuid support and connection to the redis server
|
data/README.md
CHANGED
@@ -27,6 +27,28 @@ class User < RedisOrm::Base
|
|
27
27
|
end
|
28
28
|
```
|
29
29
|
|
30
|
+
## Installing redis_orm
|
31
|
+
|
32
|
+
stable release:
|
33
|
+
|
34
|
+
```sh
|
35
|
+
gem install redis_orm
|
36
|
+
```
|
37
|
+
|
38
|
+
or edge version:
|
39
|
+
|
40
|
+
```sh
|
41
|
+
git clone git://github.com/german/redis_orm.git
|
42
|
+
cd redis_orm
|
43
|
+
bundle install
|
44
|
+
```
|
45
|
+
|
46
|
+
To run the tests you should have redis installed already. Please check [Redis download/installation page](http://redis.io/download).
|
47
|
+
|
48
|
+
```sh
|
49
|
+
rspec
|
50
|
+
```
|
51
|
+
|
30
52
|
## Setting up a connection to the redis server
|
31
53
|
|
32
54
|
If you are using Rails you should initialize redis and set up global $redis variable in *config/initializers/redis.rb* file:
|
@@ -60,14 +82,48 @@ Supported property types:
|
|
60
82
|
* **RedisOrm::Boolean**
|
61
83
|
there is no Boolean class in Ruby so it's a special class to store TrueClass or FalseClass objects
|
62
84
|
|
63
|
-
* **Time**
|
85
|
+
* **Time** or **DateTime**
|
64
86
|
|
87
|
+
* **Array** or **Hash**
|
88
|
+
RedisOrm automatically will handle serializing/deserializing arrays and hashes into strings using Marshal class
|
89
|
+
|
65
90
|
Following options are available in property declaration:
|
66
91
|
|
67
92
|
* **:default**
|
68
93
|
|
69
94
|
The default value of the attribute when it's getting saved w/o any.
|
70
95
|
|
96
|
+
* **:sortable**
|
97
|
+
|
98
|
+
if *true* is specified then you could sort records by this property later
|
99
|
+
|
100
|
+
*Note* that when you're using :sortable option redis_orm maintains one additional list per attribute. Also note that the #create method could be 3 times slower in some cases (this will be improved in future releases), while the #find performance is basically the same (see the "benchmarks/sortable_benchmark.rb").
|
101
|
+
|
102
|
+
## Expiring record after certain period of time
|
103
|
+
|
104
|
+
You could expire record stored in Redis by specifying TTL in seconds invoking *expire* method of the class like this:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
class PhantomUser < RedisOrm::Base
|
108
|
+
property :name, String
|
109
|
+
property :persist, RedisOrm::Boolean, :default => true
|
110
|
+
|
111
|
+
expire 15.minutes.from_now
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
Also you could specify a condition when *expire* would be set on record's key:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
expire 15.minutes.from_now, :if => Proc.new {|r| !r.persist?}
|
119
|
+
```
|
120
|
+
|
121
|
+
Also you could override class method *expire* by using *expire_in* key when saving object:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
ExpireUser.create :name => "Ghost record", :expire_in => 50.minutes.from_now
|
125
|
+
```
|
126
|
+
|
71
127
|
## Searching records by the value
|
72
128
|
|
73
129
|
Usually it's done via declaring an index and using *:conditions* hash or dynamic finders. For example:
|
@@ -102,7 +158,11 @@ To extract all or part of the associated records you could use 4 options:
|
|
102
158
|
|
103
159
|
* :order
|
104
160
|
|
105
|
-
Either :desc or :asc (default), since records are stored with *Time.now.to_f* scores, by default they could be fetched only in that (or reversed) order. To
|
161
|
+
Either :desc or :asc (default), since records are stored with *Time.now.to_f* scores, by default they could be fetched only in that (or reversed) order. To order by different property you should:
|
162
|
+
|
163
|
+
1. specify *:sortable => true* as option in property declaration
|
164
|
+
|
165
|
+
2. specify the property by which you wish to order *:order => [:name, :desc]* or *:order => [:name]* (:asc order is default)
|
106
166
|
|
107
167
|
* :conditions
|
108
168
|
|
@@ -508,6 +568,10 @@ end
|
|
508
568
|
|
509
569
|
To run all tests just invoke *rake test*
|
510
570
|
|
571
|
+
## Contributors
|
572
|
+
|
573
|
+
[Tatsuya Sato](https://github.com/satoryu)
|
574
|
+
|
511
575
|
Copyright © 2011 Dmitrii Samoilov, released under the MIT license
|
512
576
|
|
513
577
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
data/TODO
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
* add rake task to create index keys to existing records after the index was added to the column, something like *rake redis_orm:update_index_on zip*
|
2
|
+
* add named_scopes
|
3
|
+
* Sinatra based admin interface to overview all redis_orm keys in redis
|
4
|
+
* ActiveRecord 3.x API
|
5
|
+
* refactoring ;)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/named_base'
|
3
|
+
|
4
|
+
module RedisOrm
|
5
|
+
module Generators
|
6
|
+
class ModelGenerator < ::Rails::Generators::NamedBase
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
desc "Creates a RedisOrm model"
|
10
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
11
|
+
|
12
|
+
check_class_collision
|
13
|
+
|
14
|
+
def create_model_file
|
15
|
+
template "model.rb.erb", File.join('app/models', class_path, "#{file_name}.rb")
|
16
|
+
end
|
17
|
+
|
18
|
+
hook_for :test_framework
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/redis_orm.rb
CHANGED
@@ -1,17 +1,14 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
1
|
require 'active_model'
|
4
2
|
require 'redis'
|
5
3
|
require 'uuid'
|
6
|
-
require File.join(File.dirname(File.expand_path(__FILE__)), 'redis_orm', 'active_model_behavior')
|
7
|
-
|
8
|
-
require File.join(File.dirname(File.expand_path(__FILE__)), 'redis_orm', 'associations', 'belongs_to')
|
9
|
-
|
10
|
-
require File.join(File.dirname(File.expand_path(__FILE__)), 'redis_orm', 'associations', 'has_many_helper')
|
11
4
|
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
require_relative 'redis_orm/active_model_behavior'
|
6
|
+
require_relative 'redis_orm/associations/belongs_to'
|
7
|
+
require_relative 'redis_orm/associations/has_many_helper'
|
8
|
+
require_relative 'redis_orm/associations/has_many_proxy'
|
9
|
+
require_relative 'redis_orm/associations/has_many'
|
10
|
+
require_relative 'redis_orm/associations/has_one'
|
11
|
+
require_relative 'redis_orm/utils'
|
15
12
|
|
16
13
|
class String
|
17
14
|
def i18n_key
|
@@ -23,4 +20,4 @@ class String
|
|
23
20
|
end
|
24
21
|
end
|
25
22
|
|
26
|
-
|
23
|
+
require_relative 'redis_orm/redis_orm'
|
@@ -1,14 +1,12 @@
|
|
1
1
|
module ActiveModelBehavior
|
2
2
|
module ClassMethods
|
3
3
|
def model_name
|
4
|
-
#@_model_name ||= ActiveModel::Name.new(self).to_s.downcase
|
5
4
|
@_model_name ||= ActiveModel::Name.new(self).to_s.tableize.singularize
|
6
5
|
end
|
7
6
|
end
|
8
7
|
|
9
8
|
module InstanceMethods
|
10
9
|
def model_name
|
11
|
-
#@_model_name ||= ActiveModel::Name.new(self.class).to_s.downcase
|
12
10
|
@_model_name ||= ActiveModel::Name.new(self.class).to_s.tableize.singularize
|
13
11
|
end
|
14
12
|
end
|
@@ -14,28 +14,37 @@ module RedisOrm
|
|
14
14
|
class_associations = class_variable_get(:"@@associations")
|
15
15
|
class_variable_get(:"@@associations")[model_name] << {:type => :belongs_to, :foreign_model => foreign_model, :options => options}
|
16
16
|
|
17
|
-
foreign_model_name =
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
foreign_model_name = options[:as] ? options[:as].to_sym : foreign_model.to_sym
|
18
|
+
|
19
|
+
if options[:index]
|
20
|
+
class_variable_get(:"@@indices")[model_name] << {:name => foreign_model_name, :options => {:reference => true}}
|
21
21
|
end
|
22
|
-
|
23
|
-
define_method foreign_model_name
|
22
|
+
|
23
|
+
define_method foreign_model_name do
|
24
24
|
if options[:polymorphic]
|
25
25
|
model_type = $redis.get("#{model_name}:#{id}:#{foreign_model_name}_type")
|
26
26
|
if model_type
|
27
27
|
model_type.to_s.camelize.constantize.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}_id")
|
28
28
|
end
|
29
29
|
else
|
30
|
-
|
30
|
+
# find model even if it's in some module
|
31
|
+
full_model_scope = RedisOrm::Base.descendants.detect{|desc| desc.to_s.split('::').include?(foreign_model.to_s.camelize) }
|
32
|
+
if full_model_scope
|
33
|
+
full_model_scope.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}")
|
34
|
+
else
|
35
|
+
foreign_model.to_s.camelize.constantize.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}")
|
36
|
+
end
|
31
37
|
end
|
32
38
|
end
|
33
|
-
|
39
|
+
|
34
40
|
# look = Look.create :title => 'test'
|
35
41
|
# look.user = User.find(1) => look:23:user => 1
|
36
42
|
define_method "#{foreign_model_name}=" do |assoc_with_record|
|
37
43
|
# we need to store this to clear old association later
|
38
44
|
old_assoc = self.send(foreign_model_name)
|
45
|
+
|
46
|
+
# find model even if it's in some module
|
47
|
+
full_model_scope = RedisOrm::Base.descendants.detect{|desc| desc.to_s.split('::').include?(foreign_model.to_s.camelize) }
|
39
48
|
|
40
49
|
if options[:polymorphic]
|
41
50
|
$redis.set("#{model_name}:#{id}:#{foreign_model_name}_type", assoc_with_record.model_name)
|
@@ -43,13 +52,42 @@ module RedisOrm
|
|
43
52
|
else
|
44
53
|
if assoc_with_record.nil?
|
45
54
|
$redis.del("#{model_name}:#{id}:#{foreign_model_name}")
|
46
|
-
elsif assoc_with_record.model_name
|
55
|
+
elsif [foreign_model.to_s, full_model_scope.model_name].include?(assoc_with_record.model_name)
|
47
56
|
$redis.set("#{model_name}:#{id}:#{foreign_model_name}", assoc_with_record.id)
|
48
57
|
else
|
49
58
|
raise TypeMismatchError
|
50
59
|
end
|
51
60
|
end
|
61
|
+
|
62
|
+
# handle indices for references
|
63
|
+
self.get_indices.select{|index| index[:options][:reference]}.each do |index|
|
64
|
+
# delete old reference that points to the old associated record
|
65
|
+
if !old_assoc.nil?
|
66
|
+
prepared_index = [self.model_name, index[:name], old_assoc.id].join(':')
|
67
|
+
prepared_index.downcase! if index[:options][:case_insensitive]
|
68
|
+
|
69
|
+
if index[:options][:unique]
|
70
|
+
$redis.del(prepared_index, id)
|
71
|
+
else
|
72
|
+
$redis.zrem(prepared_index, id)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# if new associated record is nil then skip to next index (since old associated record was already unreferenced)
|
77
|
+
next if assoc_with_record.nil?
|
78
|
+
|
79
|
+
prepared_index = [self.model_name, index[:name], assoc_with_record.id].join(':')
|
80
|
+
|
81
|
+
prepared_index.downcase! if index[:options][:case_insensitive]
|
82
|
+
|
83
|
+
if index[:options][:unique]
|
84
|
+
$redis.set(prepared_index, id)
|
85
|
+
else
|
86
|
+
$redis.zadd(prepared_index, Time.now.to_f, id)
|
87
|
+
end
|
88
|
+
end
|
52
89
|
|
90
|
+
# we should have an option to delete created earlier associasion (like 'node.owner = nil')
|
53
91
|
if assoc_with_record.nil?
|
54
92
|
# remove old assoc
|
55
93
|
$redis.zrem("#{old_assoc.model_name}:#{old_assoc.id}:#{model_name.to_s.pluralize}", self.id) if old_assoc
|
@@ -57,7 +95,7 @@ module RedisOrm
|
|
57
95
|
# check whether *assoc_with_record* object has *has_many* declaration and TODO it states *self.model_name* in plural and there is no record yet from the *assoc_with_record*'s side (in order not to provoke recursion)
|
58
96
|
if class_associations[assoc_with_record.model_name].detect{|h| h[:type] == :has_many && h[:foreign_models] == model_name.pluralize.to_sym} && !$redis.zrank("#{assoc_with_record.model_name}:#{assoc_with_record.id}:#{model_name.pluralize}", self.id)
|
59
97
|
# remove old assoc
|
60
|
-
$redis.zrem("#{old_assoc.model_name}:#{old_assoc.id}:#{model_name.to_s.pluralize}", self.id) if old_assoc
|
98
|
+
$redis.zrem("#{old_assoc.model_name}:#{old_assoc.id}:#{model_name.to_s.pluralize}", self.id) if old_assoc
|
61
99
|
assoc_with_record.send(model_name.pluralize.to_sym).send(:"<<", self)
|
62
100
|
|
63
101
|
# check whether *assoc_with_record* object has *has_one* declaration and TODO it states *self.model_name* and there is no record yet from the *assoc_with_record*'s side (in order not to provoke recursion)
|
@@ -70,4 +108,4 @@ module RedisOrm
|
|
70
108
|
end
|
71
109
|
end
|
72
110
|
end
|
73
|
-
end
|
111
|
+
end
|
@@ -7,12 +7,8 @@ module RedisOrm
|
|
7
7
|
def has_many(foreign_models, options = {})
|
8
8
|
class_associations = class_variable_get(:"@@associations")
|
9
9
|
class_associations[model_name] << {:type => :has_many, :foreign_models => foreign_models, :options => options}
|
10
|
-
|
11
|
-
foreign_models_name =
|
12
|
-
options[:as].to_sym
|
13
|
-
else
|
14
|
-
foreign_models.to_sym
|
15
|
-
end
|
10
|
+
|
11
|
+
foreign_models_name = options[:as] ? options[:as].to_sym : foreign_models.to_sym
|
16
12
|
|
17
13
|
define_method foreign_models_name.to_sym do
|
18
14
|
Associations::HasManyProxy.new(model_name, id, foreign_models, options)
|
@@ -26,9 +22,13 @@ module RedisOrm
|
|
26
22
|
old_records = self.send(foreign_models).to_a
|
27
23
|
if !old_records.empty?
|
28
24
|
# cache here which association with current model have old record's model
|
29
|
-
has_many_assoc = old_records[0].get_associations.detect
|
25
|
+
has_many_assoc = old_records[0].get_associations.detect do |h|
|
26
|
+
h[:type] == :has_many && h[:foreign_models] == model_name.pluralize.to_sym
|
27
|
+
end
|
30
28
|
|
31
|
-
has_one_or_belongs_to_assoc = old_records[0].get_associations.detect
|
29
|
+
has_one_or_belongs_to_assoc = old_records[0].get_associations.detect do |h|
|
30
|
+
[:has_one, :belongs_to].include?(h[:type]) && h[:foreign_model] == model_name.to_sym
|
31
|
+
end
|
32
32
|
|
33
33
|
old_records.each do |record|
|
34
34
|
if has_many_assoc
|
@@ -45,23 +45,31 @@ module RedisOrm
|
|
45
45
|
|
46
46
|
records.to_a.each do |record|
|
47
47
|
# we use here *foreign_models_name* not *record.model_name.pluralize* because of the :as option
|
48
|
-
|
49
|
-
|
48
|
+
key = "#{model_name}:#{id}:#{foreign_models_name}"
|
49
|
+
$redis.zadd(key, Time.now.to_f, record.id)
|
50
|
+
set_expire_on_reference_key(key)
|
51
|
+
|
50
52
|
record.get_indices.each do |index|
|
51
53
|
save_index_for_associated_record(index, record, [model_name, id, record.model_name.pluralize]) # record.model_name.pluralize => foreign_models_name
|
52
54
|
end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
56
|
+
# article.comments = [comment1, comment2]
|
57
|
+
# iterate through the array of comments and create backlink
|
58
|
+
# check whether *record* object has *has_many* declaration and it states *self.model_name* in plural
|
59
|
+
if assoc = class_associations[record.model_name].detect{|h| h[:type] == :has_many && h[:foreign_models] == model_name.pluralize.to_sym} #&& !$redis.zrank("#{record.model_name}:#{record.id}:#{model_name.pluralize}", id)#record.model_name.to_s.camelize.constantize.find(id).nil?
|
60
|
+
assoc_foreign_models_name = assoc[:options][:as] ? assoc[:options][:as] : model_name.pluralize
|
61
|
+
key = "#{record.model_name}:#{record.id}:#{assoc_foreign_models_name}"
|
62
|
+
$redis.zadd(key, Time.now.to_f, id) if !$redis.zrank(key, id)
|
63
|
+
set_expire_on_reference_key(key)
|
64
|
+
end
|
65
|
+
|
66
|
+
# check whether *record* object has *has_one* declaration and it states *self.model_name*
|
67
|
+
if assoc = record.get_associations.detect{|h| [:has_one, :belongs_to].include?(h[:type]) && h[:foreign_model] == model_name.to_sym}
|
68
|
+
foreign_model_name = assoc[:options][:as] ? assoc[:options][:as] : model_name
|
69
|
+
key = "#{record.model_name}:#{record.id}:#{foreign_model_name}"
|
70
|
+
# overwrite assoc anyway so we don't need to check record.send(model_name.to_sym).nil? here
|
71
|
+
$redis.set(key, id)
|
72
|
+
set_expire_on_reference_key(key)
|
65
73
|
end
|
66
74
|
end
|
67
75
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RedisOrm
|
2
2
|
module Associations
|
3
3
|
module HasManyHelper
|
4
|
-
private
|
4
|
+
private
|
5
5
|
def save_index_for_associated_record(index, record, inception)
|
6
6
|
prepared_index = if index[:name].is_a?(Array) # TODO sort alphabetically
|
7
7
|
index[:name].inject(inception) do |sum, index_part|
|
@@ -3,15 +3,19 @@ module RedisOrm
|
|
3
3
|
class HasManyProxy
|
4
4
|
include HasManyHelper
|
5
5
|
|
6
|
-
def initialize(
|
6
|
+
def initialize(receiver_model_name, reciever_id, foreign_models, options)
|
7
7
|
@records = [] #records.to_a
|
8
|
-
@reciever_model_name =
|
8
|
+
@reciever_model_name = receiver_model_name
|
9
9
|
@reciever_id = reciever_id
|
10
10
|
@foreign_models = foreign_models
|
11
11
|
@options = options
|
12
12
|
@fetched = false
|
13
13
|
end
|
14
14
|
|
15
|
+
def receiver_instance
|
16
|
+
@receiver_instance ||= @reciever_model_name.camelize.constantize.find(@reciever_id)
|
17
|
+
end
|
18
|
+
|
15
19
|
def fetch
|
16
20
|
@records = @foreign_models.to_s.singularize.camelize.constantize.find($redis.zrevrangebyscore __key__, Time.now.to_f, 0)
|
17
21
|
@fetched = true
|
@@ -31,8 +35,10 @@ module RedisOrm
|
|
31
35
|
# user.avatars << Avatar.find(23) => user:1:avatars => [23]
|
32
36
|
def <<(new_records)
|
33
37
|
new_records.to_a.each do |record|
|
34
|
-
$redis.zadd(__key__, Time.now.to_f, record.id)
|
35
|
-
|
38
|
+
$redis.zadd(__key__, Time.now.to_f, record.id)
|
39
|
+
|
40
|
+
receiver_instance.set_expire_on_reference_key(__key__)
|
41
|
+
|
36
42
|
record.get_indices.each do |index|
|
37
43
|
save_index_for_associated_record(index, record, [@reciever_model_name, @reciever_id, record.model_name.pluralize]) # record.model_name.pluralize => @foreign_models
|
38
44
|
end
|
@@ -50,8 +56,11 @@ module RedisOrm
|
|
50
56
|
@reciever_model_name.pluralize
|
51
57
|
end
|
52
58
|
|
53
|
-
|
54
|
-
|
59
|
+
reference_key = "#{record.model_name}:#{record.id}:#{pluralized_reciever_model_name}"
|
60
|
+
|
61
|
+
if !$redis.zrank(reference_key, @reciever_id)
|
62
|
+
$redis.zadd(reference_key, Time.now.to_f, @reciever_id)
|
63
|
+
receiver_instance.set_expire_on_reference_key(reference_key)
|
55
64
|
end
|
56
65
|
# check whether *record* object has *has_one* declaration and TODO it states *self.model_name* and there is no record yet from the *record*'s side (in order not to provoke recursion)
|
57
66
|
elsif has_one_assoc = record_associations.detect{|h| [:has_one, :belongs_to].include?(h[:type]) && h[:foreign_model] == @reciever_model_name.to_sym}
|
@@ -61,7 +70,9 @@ module RedisOrm
|
|
61
70
|
@reciever_model_name
|
62
71
|
end
|
63
72
|
if record.send(reciever_model_name).nil?
|
64
|
-
|
73
|
+
key = "#{record.model_name}:#{record.id}:#{reciever_model_name}"
|
74
|
+
$redis.set(key, @reciever_id)
|
75
|
+
receiver_instance.set_expire_on_reference_key(key)
|
65
76
|
end
|
66
77
|
end
|
67
78
|
end
|
@@ -82,7 +93,7 @@ module RedisOrm
|
|
82
93
|
prepared_index = if options[:conditions] && options[:conditions].is_a?(Hash)
|
83
94
|
properties = options[:conditions].collect{|key, value| key}
|
84
95
|
|
85
|
-
index = @foreign_models.to_s.singularize.camelize.constantize.
|
96
|
+
index = @foreign_models.to_s.singularize.camelize.constantize.find_indices(properties, :first => true)
|
86
97
|
|
87
98
|
raise NotIndexFound if !index
|
88
99
|
|