redis_orm 0.5.1 → 0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|