simply_stored 0.3.3 → 0.3.4
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.
- data/CHANGELOG.md +2 -0
- data/README.md +13 -0
- data/lib/simply_stored/class_methods_base.rb +2 -2
- data/lib/simply_stored/couch/belongs_to.rb +16 -15
- data/lib/simply_stored/couch/has_many.rb +47 -45
- data/lib/simply_stored/couch/has_one.rb +18 -14
- data/lib/simply_stored/instance_methods.rb +5 -4
- data/lib/simply_stored/simpledb/associations.rb +109 -90
- data/lib/simply_stored/simpledb.rb +6 -2
- data/lib/simply_stored.rb +1 -1
- data/test/fixtures/couch.rb +8 -0
- data/test/simply_stored_couch_test.rb +19 -0
- metadata +3 -3
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -136,6 +136,19 @@ The supported associations are: belongs_to, has_one, has_many, and has_many :thr
|
|
136
136
|
post.user_count
|
137
137
|
# => 2
|
138
138
|
|
139
|
+
|
140
|
+
CouchDB - Custom Associations
|
141
|
+
|
142
|
+
class Document
|
143
|
+
include SimplyStored::Couch
|
144
|
+
|
145
|
+
belongs_to :creator, :class_name => "User"
|
146
|
+
belongs_to :updater, :class_name => "User"
|
147
|
+
end
|
148
|
+
|
149
|
+
d = Document.new
|
150
|
+
d.creator = User.first
|
151
|
+
|
139
152
|
|
140
153
|
CouchDB - Validations
|
141
154
|
=============
|
@@ -2,7 +2,7 @@ module SimplyStored
|
|
2
2
|
module ClassMethods
|
3
3
|
module Base
|
4
4
|
def get_class_from_name(klass_name)
|
5
|
-
klass_name.to_s.gsub('__','/').
|
5
|
+
klass_name.to_s.gsub('__','/').classify.constantize
|
6
6
|
end
|
7
7
|
|
8
8
|
def foreign_key
|
@@ -28,4 +28,4 @@ module SimplyStored
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|
@@ -3,7 +3,7 @@ module SimplyStored
|
|
3
3
|
module Couch
|
4
4
|
module BelongsTo
|
5
5
|
|
6
|
-
def belongs_to(name)
|
6
|
+
def belongs_to(name, options = {})
|
7
7
|
map_definition_without_deleted = <<-eos
|
8
8
|
function(doc) {
|
9
9
|
if (doc['ruby_class'] == '#{self.to_s}' && doc['#{name.to_s}_id'] != null) {
|
@@ -43,32 +43,37 @@ module SimplyStored
|
|
43
43
|
:type => "custom",
|
44
44
|
:include_docs => true
|
45
45
|
|
46
|
-
properties << SimplyStored::Couch::BelongsTo::Property.new(self, name)
|
46
|
+
properties << SimplyStored::Couch::BelongsTo::Property.new(self, name, options)
|
47
47
|
end
|
48
48
|
|
49
49
|
class Property #:nodoc:
|
50
50
|
attr_accessor :name, :options
|
51
51
|
|
52
52
|
def initialize(owner_clazz, name, options = {})
|
53
|
-
@name
|
54
|
-
|
53
|
+
@name = name
|
54
|
+
@options = {
|
55
|
+
:class_name => name.to_s.singularize.camelize
|
56
|
+
}.update(options)
|
57
|
+
|
58
|
+
@options.assert_valid_keys(:class_name)
|
59
|
+
|
55
60
|
owner_clazz.class_eval do
|
56
61
|
attr_reader "#{name}_id"
|
57
62
|
attr_accessor "#{name}_id_was"
|
58
63
|
property "#{name}_id"
|
59
64
|
|
60
65
|
define_method name do |*args|
|
61
|
-
|
62
|
-
|
63
|
-
forced_reload =
|
64
|
-
with_deleted =
|
66
|
+
local_options = args.last.is_a?(Hash) ? args.last : {}
|
67
|
+
local_options.assert_valid_keys(:force_reload, :with_deleted)
|
68
|
+
forced_reload = local_options[:force_reload] || false
|
69
|
+
with_deleted = local_options[:with_deleted] || false
|
65
70
|
|
66
71
|
return instance_variable_get("@#{name}") unless instance_variable_get("@#{name}").nil? or forced_reload
|
67
|
-
instance_variable_set("@#{name}", send("#{name}_id").present? ? Object.const_get(
|
72
|
+
instance_variable_set("@#{name}", send("#{name}_id").present? ? Object.const_get(self.class._find_property(name).options[:class_name]).find(send("#{name}_id"), :with_deleted => with_deleted) : nil)
|
68
73
|
end
|
69
74
|
|
70
75
|
define_method "#{name}=" do |value|
|
71
|
-
klass = self.class.get_class_from_name(name)
|
76
|
+
klass = self.class.get_class_from_name(self.class._find_property(name).options[:class_name])
|
72
77
|
raise ArgumentError, "expected #{klass} got #{value.class}" unless value.nil? || value.is_a?(klass)
|
73
78
|
|
74
79
|
instance_variable_set("@#{name}", value)
|
@@ -107,11 +112,7 @@ module SimplyStored
|
|
107
112
|
json["#{name}_id"] = object.send("#{name}_id") if object.send("#{name}_id")
|
108
113
|
end
|
109
114
|
alias :value :serialize
|
110
|
-
|
111
|
-
def item_class_name
|
112
|
-
@name.to_s.camelize
|
113
|
-
end
|
114
|
-
|
115
|
+
|
115
116
|
def association?
|
116
117
|
true
|
117
118
|
end
|
@@ -5,15 +5,15 @@ module SimplyStored
|
|
5
5
|
properties << SimplyStored::Couch::HasMany::Property.new(self, name, options)
|
6
6
|
end
|
7
7
|
|
8
|
-
def define_has_many_getter(name)
|
8
|
+
def define_has_many_getter(name, options)
|
9
9
|
define_method(name) do |*args|
|
10
|
-
|
11
|
-
if
|
12
|
-
|
13
|
-
forced_reload =
|
14
|
-
with_deleted =
|
15
|
-
limit =
|
16
|
-
descending = (
|
10
|
+
local_options = args.first && args.first.is_a?(Hash) && args.first
|
11
|
+
if local_options
|
12
|
+
local_options.assert_valid_keys(:force_reload, :with_deleted, :limit, :order)
|
13
|
+
forced_reload = local_options.delete(:force_reload)
|
14
|
+
with_deleted = local_options[:with_deleted]
|
15
|
+
limit = local_options[:limit]
|
16
|
+
descending = (local_options[:order] == :desc) ? true : false
|
17
17
|
else
|
18
18
|
forced_reload = false
|
19
19
|
with_deleted = false
|
@@ -22,25 +22,25 @@ module SimplyStored
|
|
22
22
|
end
|
23
23
|
|
24
24
|
cached_results = cached_results = send("_get_cached_#{name}")
|
25
|
-
cache_key = _cache_key_for(
|
25
|
+
cache_key = _cache_key_for(local_options)
|
26
26
|
if forced_reload || cached_results[cache_key].nil?
|
27
|
-
cached_results[cache_key] = find_associated(
|
27
|
+
cached_results[cache_key] = find_associated(options[:class_name], self.class, :with_deleted => with_deleted, :limit => limit, :descending => descending, :foreign_key => options[:foreign_key])
|
28
28
|
instance_variable_set("@#{name}", cached_results)
|
29
29
|
end
|
30
30
|
cached_results[cache_key]
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
def define_has_many_through_getter(name, through)
|
34
|
+
def define_has_many_through_getter(name, options, through)
|
35
35
|
raise ArgumentError, "no such relation: #{self} - #{through}" unless instance_methods.map(&:to_sym).include?(through.to_sym)
|
36
36
|
|
37
37
|
define_method(name) do |*args|
|
38
|
-
|
39
|
-
if
|
40
|
-
|
41
|
-
forced_reload =
|
42
|
-
with_deleted =
|
43
|
-
limit =
|
38
|
+
local_options = args.first && args.first.is_a?(Hash) && args.first
|
39
|
+
if local_options
|
40
|
+
local_options.assert_valid_keys(:force_reload, :with_deleted, :limit)
|
41
|
+
forced_reload = local_options[:force_reload]
|
42
|
+
with_deleted = local_options[:with_deleted]
|
43
|
+
limit = local_options[:limit]
|
44
44
|
else
|
45
45
|
forced_reload = false
|
46
46
|
with_deleted = false
|
@@ -48,12 +48,12 @@ module SimplyStored
|
|
48
48
|
end
|
49
49
|
|
50
50
|
cached_results = send("_get_cached_#{name}")
|
51
|
-
cache_key = _cache_key_for(
|
51
|
+
cache_key = _cache_key_for(local_options)
|
52
52
|
|
53
53
|
if forced_reload || cached_results[cache_key].nil?
|
54
54
|
|
55
55
|
# there is probably a faster way to query this
|
56
|
-
intermediate_objects = find_associated(through, self.class, :with_deleted => with_deleted, :limit => limit)
|
56
|
+
intermediate_objects = find_associated(through, self.class, :with_deleted => with_deleted, :limit => limit, :foreign_key => options[:foreign_key])
|
57
57
|
|
58
58
|
through_objects = intermediate_objects.map do |intermediate_object|
|
59
59
|
intermediate_object.send(name.to_s.singularize.underscore, :with_deleted => with_deleted)
|
@@ -65,7 +65,7 @@ module SimplyStored
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
def define_has_many_setter_add(name)
|
68
|
+
def define_has_many_setter_add(name, options)
|
69
69
|
define_method("add_#{name.to_s.singularize}") do |value|
|
70
70
|
klass = self.class.get_class_from_name(name)
|
71
71
|
raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
|
@@ -79,15 +79,15 @@ module SimplyStored
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
def define_has_many_setter_remove(name)
|
82
|
+
def define_has_many_setter_remove(name, options)
|
83
83
|
define_method "remove_#{name.to_s.singularize}" do |value|
|
84
84
|
klass = self.class.get_class_from_name(name)
|
85
85
|
raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
|
86
86
|
raise ArgumentError, "cannot remove not mine" unless value.send(self.class.foreign_key.to_sym) == id
|
87
87
|
|
88
|
-
if
|
88
|
+
if options[:dependent] == :destroy
|
89
89
|
value.destroy
|
90
|
-
elsif
|
90
|
+
elsif options[:dependent] == :ignore
|
91
91
|
# skip
|
92
92
|
else # nullify
|
93
93
|
value.send("#{self.class.foreign_key}=", nil)
|
@@ -100,7 +100,7 @@ module SimplyStored
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
def define_has_many_setter_remove_all(name)
|
103
|
+
def define_has_many_setter_remove_all(name, options)
|
104
104
|
define_method "remove_all_#{name}" do
|
105
105
|
all = send("#{name}", :force_reload => true)
|
106
106
|
|
@@ -110,27 +110,27 @@ module SimplyStored
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
def define_has_many_count(name, through = nil)
|
113
|
+
def define_has_many_count(name, options, through = nil)
|
114
114
|
method_name = name.to_s.singularize.underscore + "_count"
|
115
115
|
define_method(method_name) do |*args|
|
116
|
-
|
117
|
-
if
|
118
|
-
|
119
|
-
forced_reload =
|
120
|
-
with_deleted =
|
116
|
+
local_options = args.first && args.first.is_a?(Hash) && args.first
|
117
|
+
if local_options
|
118
|
+
local_options.assert_valid_keys(:force_reload, :with_deleted)
|
119
|
+
forced_reload = local_options[:force_reload]
|
120
|
+
with_deleted = local_options[:with_deleted]
|
121
121
|
else
|
122
122
|
forced_reload = false
|
123
123
|
with_deleted = false
|
124
124
|
end
|
125
125
|
|
126
126
|
if forced_reload || instance_variable_get("@#{method_name}").nil?
|
127
|
-
instance_variable_set("@#{method_name}", count_associated(through ||
|
127
|
+
instance_variable_set("@#{method_name}", count_associated(through || options[:class_name], self.class, :with_deleted => with_deleted, :foreign_key => options[:foreign_key]))
|
128
128
|
end
|
129
129
|
instance_variable_get("@#{method_name}")
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
133
|
-
def define_cache_accessors(name)
|
133
|
+
def define_cache_accessors(name, options)
|
134
134
|
define_method "_get_cached_#{name}" do
|
135
135
|
instance_variable_get("@#{name}") || {}
|
136
136
|
end
|
@@ -141,8 +141,8 @@ module SimplyStored
|
|
141
141
|
instance_variable_set("@#{name}", cached)
|
142
142
|
end
|
143
143
|
|
144
|
-
define_method "_cache_key_for" do |
|
145
|
-
|
144
|
+
define_method "_cache_key_for" do |opt|
|
145
|
+
opt.blank? ? :all : opt.to_s
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
@@ -152,26 +152,28 @@ module SimplyStored
|
|
152
152
|
def initialize(owner_clazz, name, options = {})
|
153
153
|
options = {
|
154
154
|
:dependent => :nullify,
|
155
|
-
:through => nil
|
155
|
+
:through => nil,
|
156
|
+
:class_name => name.to_s.singularize.camelize,
|
157
|
+
:foreign_key => owner_clazz.name.singularize.underscore.foreign_key
|
156
158
|
}.update(options)
|
157
159
|
@name, @options = name, options
|
158
160
|
|
159
|
-
options.assert_valid_keys(:dependent, :through)
|
161
|
+
options.assert_valid_keys(:dependent, :through, :class_name, :foreign_key)
|
160
162
|
|
161
163
|
if options[:through]
|
162
164
|
owner_clazz.class_eval do
|
163
|
-
define_cache_accessors(name)
|
164
|
-
define_has_many_through_getter(name, options[:through])
|
165
|
-
define_has_many_count(name, options[:through])
|
165
|
+
define_cache_accessors(name, options)
|
166
|
+
define_has_many_through_getter(name, options, options[:through])
|
167
|
+
define_has_many_count(name, options, options[:through])
|
166
168
|
end
|
167
169
|
else
|
168
170
|
owner_clazz.class_eval do
|
169
|
-
define_cache_accessors(name)
|
170
|
-
define_has_many_getter(name)
|
171
|
-
define_has_many_setter_add(name)
|
172
|
-
define_has_many_setter_remove(name)
|
173
|
-
define_has_many_setter_remove_all(name)
|
174
|
-
define_has_many_count(name)
|
171
|
+
define_cache_accessors(name, options)
|
172
|
+
define_has_many_getter(name, options)
|
173
|
+
define_has_many_setter_add(name, options)
|
174
|
+
define_has_many_setter_remove(name, options)
|
175
|
+
define_has_many_setter_remove_all(name, options)
|
176
|
+
define_has_many_count(name, options)
|
175
177
|
end
|
176
178
|
end
|
177
179
|
end
|
@@ -5,9 +5,9 @@ module SimplyStored
|
|
5
5
|
properties << SimplyStored::Couch::HasOne::Property.new(self, name, options)
|
6
6
|
end
|
7
7
|
|
8
|
-
def define_has_one_setter(name)
|
8
|
+
def define_has_one_setter(name, options)
|
9
9
|
define_method("#{name}=") do |value|
|
10
|
-
klass = self.class.get_class_from_name(name)
|
10
|
+
klass = self.class.get_class_from_name(self.class._find_property(name).options[:class_name])
|
11
11
|
raise ArgumentError, "expected #{klass} got #{value.class}" unless value.nil? || value.is_a?(klass)
|
12
12
|
old_value = send("#{name}", :force_reload => true)
|
13
13
|
if value.nil?
|
@@ -19,7 +19,7 @@ module SimplyStored
|
|
19
19
|
end
|
20
20
|
|
21
21
|
if old_value
|
22
|
-
if
|
22
|
+
if options[:dependent] == :destroy
|
23
23
|
old_value.destroy
|
24
24
|
else
|
25
25
|
old_value.send("#{self.class.foreign_property}=", nil)
|
@@ -30,20 +30,20 @@ module SimplyStored
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def define_has_one_getter(name)
|
33
|
+
def define_has_one_getter(name, options)
|
34
34
|
define_method(name) do |*args|
|
35
|
-
|
36
|
-
if
|
37
|
-
|
38
|
-
forced_reload =
|
39
|
-
with_deleted =
|
35
|
+
local_options = args.first && args.first.is_a?(Hash) && args.first
|
36
|
+
if local_options
|
37
|
+
local_options.assert_valid_keys(:force_reload, :with_deleted)
|
38
|
+
forced_reload = local_options[:force_reload]
|
39
|
+
with_deleted = local_options[:with_deleted]
|
40
40
|
else
|
41
41
|
forced_reload = false
|
42
42
|
with_deleted = false
|
43
43
|
end
|
44
44
|
|
45
45
|
if forced_reload || instance_variable_get("@#{name}").nil?
|
46
|
-
instance_variable_set("@#{name}", find_one_associated(
|
46
|
+
instance_variable_set("@#{name}", find_one_associated(options[:class_name], self.class, :with_deleted => with_deleted, :foreign_key => options[:foreign_key]))
|
47
47
|
end
|
48
48
|
instance_variable_get("@#{name}")
|
49
49
|
end
|
@@ -53,14 +53,18 @@ module SimplyStored
|
|
53
53
|
attr_reader :name, :options
|
54
54
|
|
55
55
|
def initialize(owner_clazz, name, options = {})
|
56
|
-
options = {
|
56
|
+
options = {
|
57
|
+
:dependent => :nullify,
|
58
|
+
:class_name => name.to_s.singularize.camelize,
|
59
|
+
:foreign_key => owner_clazz.name.singularize.underscore.foreign_key
|
60
|
+
}.update(options)
|
57
61
|
@name, @options = name, options
|
58
62
|
|
59
|
-
options.assert_valid_keys(:dependent)
|
63
|
+
options.assert_valid_keys(:dependent, :class_name, :foreign_key)
|
60
64
|
|
61
65
|
owner_clazz.class_eval do
|
62
|
-
define_has_one_getter(name)
|
63
|
-
define_has_one_setter(name)
|
66
|
+
define_has_one_getter(name, options)
|
67
|
+
define_has_one_setter(name, options)
|
64
68
|
end
|
65
69
|
end
|
66
70
|
|
@@ -72,8 +72,8 @@ module SimplyStored
|
|
72
72
|
retry_count = 0
|
73
73
|
begin
|
74
74
|
blk.call
|
75
|
-
rescue RestClient::Conflict => e
|
76
|
-
if self.class.auto_conflict_resolution_on_save && retry_count < max_retries && try_to_merge_conflict
|
75
|
+
rescue RestClient::Exception, RestClient::Conflict => e
|
76
|
+
if (e.http_code == 409 || e.is_a?(RestClient::Conflict)) && self.class.auto_conflict_resolution_on_save && retry_count < max_retries && try_to_merge_conflict
|
77
77
|
retry_count += 1
|
78
78
|
retry
|
79
79
|
else
|
@@ -175,6 +175,7 @@ module SimplyStored
|
|
175
175
|
end
|
176
176
|
|
177
177
|
def find_associated(from, to, options = {})
|
178
|
+
foreign_key = options.delete(:foreign_key).gsub(/_id$/, '')
|
178
179
|
view_options = {}
|
179
180
|
view_options[:reduce] = false
|
180
181
|
view_options[:descending] = options[:descending] if options[:descending]
|
@@ -189,11 +190,11 @@ module SimplyStored
|
|
189
190
|
if options[:with_deleted]
|
190
191
|
CouchPotato.database.view(
|
191
192
|
self.class.get_class_from_name(from).send(
|
192
|
-
"association_#{from.to_s.singularize.underscore}_belongs_to_#{
|
193
|
+
"association_#{from.to_s.singularize.underscore}_belongs_to_#{foreign_key}_with_deleted", view_options))
|
193
194
|
else
|
194
195
|
CouchPotato.database.view(
|
195
196
|
self.class.get_class_from_name(from).send(
|
196
|
-
"association_#{from.to_s.singularize.underscore}_belongs_to_#{
|
197
|
+
"association_#{from.to_s.singularize.underscore}_belongs_to_#{foreign_key}", view_options))
|
197
198
|
end
|
198
199
|
end
|
199
200
|
|
@@ -6,98 +6,112 @@ module SimplyStored
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module ClassMethods
|
9
|
-
def belongs_to(
|
10
|
-
|
11
|
-
|
9
|
+
def belongs_to(name, options = nil)
|
10
|
+
options = {
|
11
|
+
:class_name => self.formalize_class_name(name),
|
12
|
+
:foreign_key => "#{name}_id"
|
13
|
+
}.update(options || {})
|
14
|
+
define_belongs_to_getter(name, options)
|
15
|
+
define_belongs_to_setter(name, options)
|
12
16
|
end
|
13
17
|
|
14
|
-
def has_one(
|
18
|
+
def has_one(name, options = {})
|
15
19
|
options = {
|
16
20
|
:clear => :nullify, # or :destroy
|
17
|
-
:dependent => :nullify # or :destroy
|
21
|
+
:dependent => :nullify, # or :destroy
|
22
|
+
:class_name => self.formalize_class_name(name),
|
23
|
+
:foreign_key => self.foreign_key
|
18
24
|
}.update(options)
|
19
25
|
|
20
|
-
define_has_one_getter(
|
21
|
-
define_has_one_setter(
|
22
|
-
define_has_one_dependent_clearing(
|
26
|
+
define_has_one_getter(name, options)
|
27
|
+
define_has_one_setter(name, options)
|
28
|
+
define_has_one_dependent_clearing(name, options)
|
23
29
|
end
|
24
30
|
|
25
|
-
def has_many(
|
31
|
+
def has_many(name, options = {})
|
26
32
|
options = {
|
27
33
|
:clear => :nullify, # or :destroy
|
28
|
-
:dependent => :nullify # or :destroy
|
34
|
+
:dependent => :nullify, # or :destroy
|
35
|
+
:class_name => self.formalize_class_name(name.to_s.singularize),
|
36
|
+
:foreign_key => self.foreign_key
|
29
37
|
}.update(options)
|
30
38
|
|
31
|
-
define_has_many_getter(
|
32
|
-
define_has_many_setter_add(
|
33
|
-
define_has_many_setter_remove(
|
34
|
-
define_has_many_setter_remove_all(
|
35
|
-
define_has_many_dependent_clearing(
|
39
|
+
define_has_many_getter(name, options)
|
40
|
+
define_has_many_setter_add(name, options)
|
41
|
+
define_has_many_setter_remove(name, options)
|
42
|
+
define_has_many_setter_remove_all(name, options)
|
43
|
+
define_has_many_dependent_clearing(name, options)
|
36
44
|
end
|
37
45
|
|
38
|
-
def define_belongs_to_getter(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
46
|
+
def define_belongs_to_getter(name, options)
|
47
|
+
foreign_key_column = options[:foreign_key]
|
48
|
+
define_method(name.to_s) do
|
49
|
+
klass = options[:class_name].constantize
|
50
|
+
cached_version = instance_variable_get("@_cached_belongs_to_#{name}")
|
51
|
+
if cached_version.nil? and self[foreign_key_column].present?
|
52
|
+
cached_version = klass.find(self.send(foreign_key_column), :auto_load => true)
|
53
|
+
instance_variable_set("@_cached_belongs_to_#{name}", cached_version)
|
45
54
|
end
|
46
55
|
cached_version
|
47
56
|
end
|
48
57
|
end
|
49
58
|
|
50
|
-
def define_belongs_to_setter(
|
51
|
-
|
52
|
-
|
59
|
+
def define_belongs_to_setter(name, options)
|
60
|
+
foreign_key_column = options[:foreign_key]
|
61
|
+
define_method("#{name}=") do |val|
|
62
|
+
klass = options[:class_name].constantize
|
53
63
|
raise ArgumentError, "expected #{klass} got #{val.class}" unless val.is_a?(klass)
|
54
|
-
self.send("#{
|
55
|
-
instance_variable_set("@_cached_belongs_to_#{
|
64
|
+
self.send("#{foreign_key_column}=", val.id)
|
65
|
+
instance_variable_set("@_cached_belongs_to_#{name}", val)
|
56
66
|
end
|
57
67
|
end
|
58
68
|
|
59
|
-
def define_has_one_getter(
|
60
|
-
|
61
|
-
|
62
|
-
|
69
|
+
def define_has_one_getter(name, options)
|
70
|
+
foreign_key_column = options[:foreign_key]
|
71
|
+
define_method(name.to_s) do
|
72
|
+
klass = options[:class_name].constantize
|
73
|
+
cached_version = instance_variable_get("@_cached_has_one_#{name}")
|
63
74
|
if cached_version
|
64
|
-
|
75
|
+
cached_version
|
65
76
|
else
|
66
|
-
cached_version = klass.send("find_by_#{
|
67
|
-
instance_variable_set("@_cached_has_one_#{
|
68
|
-
|
77
|
+
cached_version = klass.send("find_by_#{foreign_key_column}".to_sym, self.id, {:auto_load => true})
|
78
|
+
instance_variable_set("@_cached_has_one_#{name}", cached_version)
|
79
|
+
cached_version
|
69
80
|
end
|
70
81
|
end
|
71
82
|
end
|
72
83
|
|
73
|
-
def define_has_one_setter(
|
74
|
-
|
75
|
-
|
84
|
+
def define_has_one_setter(name, options)
|
85
|
+
foreign_key_column = options[:foreign_key]
|
86
|
+
define_method("#{name}=") do |val|
|
87
|
+
klass = options[:class_name].constantize
|
76
88
|
raise ArgumentError, "expected #{klass} got #{val.class}" unless val.is_a?(klass)
|
77
89
|
|
78
90
|
# clear old
|
79
|
-
old = self.send("#{
|
80
|
-
old.send("#{
|
91
|
+
old = self.send("#{name}")
|
92
|
+
old.send("#{foreign_key_column}=", nil) if old && options[:clear] == :nullify
|
81
93
|
old.delete if old && options[:clear] == :destroy
|
82
94
|
|
83
95
|
# store new
|
84
|
-
val.send("#{
|
85
|
-
instance_variable_set("@_cached_has_one_#{
|
96
|
+
val.send("#{foreign_key_column}=", self.id)
|
97
|
+
instance_variable_set("@_cached_has_one_#{name}", val)
|
86
98
|
end
|
87
99
|
end
|
88
100
|
|
89
|
-
def define_has_one_dependent_clearing(
|
101
|
+
def define_has_one_dependent_clearing(name, options)
|
90
102
|
# add method to list of methods to run when deleted
|
91
103
|
@_clear_dependents_after_delete_methods ||= []
|
92
|
-
@_clear_dependents_after_delete_methods << "has_one_clear_#{
|
104
|
+
@_clear_dependents_after_delete_methods << "has_one_clear_#{name}_after_destroy"
|
93
105
|
|
94
106
|
# define actual clearing/deleting
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
107
|
+
foreign_key_column = options[:foreign_key]
|
108
|
+
define_method("has_one_clear_#{name}_after_destroy") do
|
109
|
+
klass = options[:class_name].constantize
|
110
|
+
dependent = klass.send("find_by_#{foreign_key_column}".to_sym, self.id)
|
111
|
+
case options[:dependent]
|
112
|
+
when :nullify then
|
113
|
+
dependent.send("#{foreign_key_column}=", nil) if dependent
|
114
|
+
when :destroy then
|
101
115
|
dependent.delete if dependent
|
102
116
|
else
|
103
117
|
raise ArgumentError, "unknown dependent method: #{options[:dependent].inspect}"
|
@@ -105,76 +119,81 @@ module SimplyStored
|
|
105
119
|
end
|
106
120
|
end
|
107
121
|
|
108
|
-
def define_has_many_getter(
|
109
|
-
|
110
|
-
|
111
|
-
|
122
|
+
def define_has_many_getter(name, options)
|
123
|
+
foreign_key_column = options[:foreign_key]
|
124
|
+
define_method(name.to_s) do
|
125
|
+
klass = options[:class_name].constantize
|
126
|
+
cached_version = instance_variable_get("@_cached_has_many_#{name}")
|
112
127
|
if cached_version
|
113
|
-
|
128
|
+
cached_version
|
114
129
|
else
|
115
|
-
cached_version = klass.send("find_all_by_#{
|
116
|
-
instance_variable_set("@_cached_has_many_#{
|
117
|
-
|
130
|
+
cached_version = klass.send("find_all_by_#{foreign_key_column}".to_sym, self.id, {:auto_load => true})
|
131
|
+
instance_variable_set("@_cached_has_many_#{name}", cached_version)
|
132
|
+
cached_version
|
118
133
|
end
|
119
134
|
end
|
120
135
|
end
|
121
136
|
|
122
|
-
def define_has_many_setter_add(
|
123
|
-
|
124
|
-
|
137
|
+
def define_has_many_setter_add(name, options)
|
138
|
+
foreign_key_column = options[:foreign_key]
|
139
|
+
define_method("add_#{name.to_s.singularize}") do |val|
|
140
|
+
klass = options[:class_name].constantize
|
125
141
|
raise ArgumentError, "expected #{klass} got #{val.class}" unless val.is_a?(klass)
|
126
|
-
val.send("#{
|
142
|
+
val.send("#{foreign_key_column}=", self.id)
|
127
143
|
val.save(false)
|
128
|
-
cached_version = instance_variable_get("@_cached_has_many_#{
|
129
|
-
instance_variable_set("@_cached_has_many_#{
|
144
|
+
cached_version = instance_variable_get("@_cached_has_many_#{name}") || []
|
145
|
+
instance_variable_set("@_cached_has_many_#{name}", cached_version << val)
|
130
146
|
end
|
131
147
|
end
|
132
148
|
|
133
|
-
def define_has_many_setter_remove(
|
134
|
-
|
135
|
-
|
149
|
+
def define_has_many_setter_remove(name, options)
|
150
|
+
foreign_key_column = options[:foreign_key]
|
151
|
+
define_method("remove_#{name.to_s.singularize}") do |val|
|
152
|
+
klass = options[:class_name].constantize
|
136
153
|
raise ArgumentError, "expected #{klass} got #{val.class}" unless val.is_a?(klass)
|
137
|
-
raise ArgumentError, "cannot remove not mine" unless val.send(
|
138
|
-
|
139
|
-
|
154
|
+
raise ArgumentError, "cannot remove not mine" unless val.send(foreign_key_column) == self.id
|
155
|
+
case options[:clear]
|
156
|
+
when :nullify then
|
157
|
+
val.send("#{foreign_key_column}=", nil)
|
140
158
|
val.save(false)
|
141
|
-
|
159
|
+
when :destroy then
|
142
160
|
val.delete
|
143
161
|
else
|
144
162
|
raise "Unknown option for clear: #{option[:clear]}"
|
145
163
|
end
|
146
|
-
cached_version = instance_variable_get("@_cached_has_many_#{
|
147
|
-
instance_variable_set("@_cached_has_many_#{
|
164
|
+
cached_version = instance_variable_get("@_cached_has_many_#{name}") || []
|
165
|
+
instance_variable_set("@_cached_has_many_#{name}", cached_version.delete_if{|x| x.id == val.id})
|
148
166
|
end
|
149
167
|
end
|
150
168
|
|
151
|
-
def define_has_many_setter_remove_all(
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
all = klass.send("find_all_by_#{
|
156
|
-
|
169
|
+
def define_has_many_setter_remove_all(name, options)
|
170
|
+
foreign_key_column = options[:foreign_key]
|
171
|
+
define_method("remove_all_#{name}") do
|
172
|
+
klass = options[:class_name].constantize
|
173
|
+
all = klass.send("find_all_by_#{foreign_key_column}".to_sym, self.id)
|
157
174
|
all.each do |item|
|
158
|
-
self.send("remove_#{
|
175
|
+
self.send("remove_#{name.to_s.singularize}", item)
|
159
176
|
end
|
160
|
-
instance_variable_set("@_cached_has_many_#{
|
177
|
+
instance_variable_set("@_cached_has_many_#{name}", [])
|
161
178
|
end
|
162
179
|
end
|
163
180
|
|
164
|
-
def define_has_many_dependent_clearing(
|
181
|
+
def define_has_many_dependent_clearing(name, options)
|
165
182
|
# add method to list of methods to run when deleted
|
166
183
|
@_clear_dependents_after_delete_methods ||= []
|
167
|
-
@_clear_dependents_after_delete_methods << "has_many_clear_#{
|
184
|
+
@_clear_dependents_after_delete_methods << "has_many_clear_#{name}_after_destroy"
|
168
185
|
|
169
186
|
# define actual clearing/deleting
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
187
|
+
foreign_key_column = options[:foreign_key]
|
188
|
+
define_method("has_many_clear_#{name}_after_destroy") do
|
189
|
+
klass = options[:class_name].constantize
|
190
|
+
dependents = klass.send("find_all_by_#{foreign_key_column}".to_sym, self.id)
|
191
|
+
case options[:dependent]
|
192
|
+
when :nullify then
|
174
193
|
dependents.each do |dependent|
|
175
|
-
dependent.send("#{
|
194
|
+
dependent.send("#{foreign_key_column}=", nil)
|
176
195
|
end
|
177
|
-
|
196
|
+
when :destroy then
|
178
197
|
dependents.each do |dependent|
|
179
198
|
dependent.delete
|
180
199
|
end
|
@@ -193,4 +212,4 @@ module SimplyStored
|
|
193
212
|
end
|
194
213
|
end
|
195
214
|
end
|
196
|
-
end
|
215
|
+
end
|
@@ -206,7 +206,11 @@ module SimplyStored
|
|
206
206
|
end
|
207
207
|
|
208
208
|
def self.get_class_from_name(klass_name)
|
209
|
-
klass_name.to_s.gsub('__','/').
|
209
|
+
klass_name.to_s.gsub('__','/').classify.constantize
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.formalize_class_name(name)
|
213
|
+
name.to_s.gsub('__','/').gsub('__','::').classify
|
210
214
|
end
|
211
215
|
end
|
212
|
-
end
|
216
|
+
end
|
data/lib/simply_stored.rb
CHANGED
@@ -4,7 +4,7 @@ require File.expand_path(File.dirname(__FILE__) + '/simply_stored/storage')
|
|
4
4
|
require File.expand_path(File.dirname(__FILE__) + '/simply_stored/class_methods_base')
|
5
5
|
|
6
6
|
module SimplyStored
|
7
|
-
VERSION = '0.3.
|
7
|
+
VERSION = '0.3.4'
|
8
8
|
class Error < RuntimeError; end
|
9
9
|
class RecordNotFound < RuntimeError; end
|
10
10
|
end
|
data/test/fixtures/couch.rb
CHANGED
@@ -10,6 +10,7 @@ class User
|
|
10
10
|
has_many :strict_posts
|
11
11
|
has_many :hemorrhoids
|
12
12
|
has_many :pains, :through => :hemorrhoids
|
13
|
+
has_many :docs, :class_name => "Document", :foreign_key => "editor_id"
|
13
14
|
|
14
15
|
view :by_name_and_created_at, :key => [:name, :created_at]
|
15
16
|
end
|
@@ -44,6 +45,13 @@ class Category
|
|
44
45
|
validates_inclusion_of :name, :in => ["food", "drinks", "party"], :allow_blank => true
|
45
46
|
end
|
46
47
|
|
48
|
+
class Document
|
49
|
+
include SimplyStored::Couch
|
50
|
+
|
51
|
+
belongs_to :author, :class_name => "User"
|
52
|
+
belongs_to :editor, :class_name => "User"
|
53
|
+
end
|
54
|
+
|
47
55
|
class Tag
|
48
56
|
include SimplyStored::Couch
|
49
57
|
|
@@ -474,6 +474,25 @@ class CouchTest < Test::Unit::TestCase
|
|
474
474
|
assert_nil post.user
|
475
475
|
end
|
476
476
|
end
|
477
|
+
|
478
|
+
context "with aliased associations" do
|
479
|
+
should "allow different names for the same class" do
|
480
|
+
editor = User.create(:name => 'Editor', :title => 'Dr.')
|
481
|
+
author = User.create(:name => 'author', :title => 'Dr.')
|
482
|
+
assert_not_nil editor.id, editor.errors.inspect
|
483
|
+
assert_not_nil author.id, author.errors.inspect
|
484
|
+
|
485
|
+
doc = Document.create(:editor => editor, :author => author)
|
486
|
+
doc.save!
|
487
|
+
assert_equal editor.id, doc.editor_id
|
488
|
+
assert_equal author.id, doc.author_id
|
489
|
+
doc = Document.find(doc.id)
|
490
|
+
assert_not_nil doc.editor, doc.inspect
|
491
|
+
assert_not_nil doc.author
|
492
|
+
assert_equal editor.id, doc.editor.id
|
493
|
+
assert_equal author.id, doc.author.id
|
494
|
+
end
|
495
|
+
end
|
477
496
|
end
|
478
497
|
|
479
498
|
context "with has_many" do
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 3
|
8
|
-
-
|
9
|
-
version: 0.3.
|
8
|
+
- 4
|
9
|
+
version: 0.3.4
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Mathias Meyer, Jonathan Weiss
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-06-17 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|