couchrest_model 1.0.0.beta8 → 1.0.0
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/.gitignore +9 -0
- data/{spec/spec.opts → .rspec} +0 -1
- data/Gemfile +4 -0
- data/Gemfile.lock +77 -0
- data/README.md +144 -57
- data/Rakefile +12 -43
- data/VERSION +1 -0
- data/couchrest_model.gemspec +35 -0
- data/history.txt +23 -1
- data/init.rb +1 -0
- data/lib/couchrest/model/associations.rb +17 -1
- data/lib/couchrest/model/base.rb +5 -5
- data/lib/couchrest/model/casted_model.rb +2 -2
- data/lib/couchrest/model/class_proxy.rb +6 -0
- data/lib/couchrest/model/collection.rb +3 -0
- data/lib/couchrest/model/configuration.rb +51 -0
- data/lib/couchrest/model/design_doc.rb +2 -5
- data/lib/couchrest/model/document_queries.rb +20 -3
- data/lib/couchrest/model/persistence.rb +15 -1
- data/lib/couchrest/model/properties.rb +97 -23
- data/lib/couchrest/model/property.rb +5 -4
- data/lib/couchrest/model/property_protection.rb +71 -0
- data/lib/couchrest/model/typecast.rb +12 -7
- data/lib/couchrest/model/view.rb +190 -0
- data/lib/couchrest/model/views.rb +3 -3
- data/lib/couchrest/model.rb +1 -1
- data/lib/couchrest/railtie.rb +3 -2
- data/lib/couchrest_model.rb +7 -14
- data/lib/rails/generators/couchrest_model/model/model_generator.rb +2 -1
- data/spec/.gitignore +1 -0
- data/spec/couchrest/base_spec.rb +3 -3
- data/spec/couchrest/casted_model_spec.rb +63 -49
- data/spec/couchrest/class_proxy_spec.rb +6 -0
- data/spec/couchrest/configuration_spec.rb +78 -0
- data/spec/couchrest/persistence_spec.rb +10 -4
- data/spec/couchrest/{attribute_protection_spec.rb → property_protection_spec.rb} +29 -2
- data/spec/couchrest/property_spec.rb +61 -0
- data/spec/couchrest/subclass_spec.rb +2 -2
- data/spec/couchrest/view_spec.rb +6 -0
- data/spec/fixtures/more/article.rb +1 -1
- data/spec/spec_helper.rb +4 -3
- metadata +96 -32
- data/lib/couchrest/model/attribute_protection.rb +0 -74
- data/lib/couchrest/model/attributes.rb +0 -75
@@ -0,0 +1,190 @@
|
|
1
|
+
|
2
|
+
#### NOTE Work in progress! Not yet used!
|
3
|
+
|
4
|
+
module CouchRest
|
5
|
+
module Model
|
6
|
+
|
7
|
+
# A proxy class that allows view queries to be created using
|
8
|
+
# chained method calls. After each call a new instance of the method
|
9
|
+
# is created based on the original in a similar fashion to ruby's sequel
|
10
|
+
# library, or Rails 3's Arel.
|
11
|
+
#
|
12
|
+
# CouchDB views have inherent limitations, so joins and filters as used in
|
13
|
+
# a normal relational database are not possible. At least not yet!
|
14
|
+
#
|
15
|
+
#
|
16
|
+
#
|
17
|
+
class View
|
18
|
+
|
19
|
+
attr_accessor :query, :design, :database, :name
|
20
|
+
|
21
|
+
# Initialize a new View object. This method should not be called from outside CouchRest Model.
|
22
|
+
def initialize(parent, new_query = {}, name = nil)
|
23
|
+
if parent.is_a? Base
|
24
|
+
raise "Name must be provided for view to be initialized" if name.nil?
|
25
|
+
@name = name
|
26
|
+
@database = parent.database
|
27
|
+
@query = { :reduce => false }
|
28
|
+
elsif parent.is_a? View
|
29
|
+
@database = parent.database
|
30
|
+
@query = parent.query.dup
|
31
|
+
else
|
32
|
+
raise "View cannot be initialized without a parent Model or View"
|
33
|
+
end
|
34
|
+
@query.update(new_query)
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# == View Execution Methods
|
40
|
+
#
|
41
|
+
# Send a request to the CouchDB database using the current query values.
|
42
|
+
|
43
|
+
# Inmediatly send a request to the database for all documents provided by the query.
|
44
|
+
#
|
45
|
+
def all(&block)
|
46
|
+
args = include_docs.query
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
# Inmediatly send a request for the first result of the dataset. This will override
|
51
|
+
# any limit set in the view previously.
|
52
|
+
def first(&block)
|
53
|
+
args = limit(1).include_docs.query
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def info
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
def offset
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
def total_rows
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def rows
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# == View Filter Methods
|
75
|
+
#
|
76
|
+
# View filters return an copy of the view instance with the query
|
77
|
+
# modified appropriatly. Errors will be raised if the methods
|
78
|
+
# are combined in an incorrect fashion.
|
79
|
+
#
|
80
|
+
|
81
|
+
|
82
|
+
# Find all entries in the index whose key matches the value provided.
|
83
|
+
#
|
84
|
+
# Cannot be used when the +#startkey+ or +#endkey+ have been set.
|
85
|
+
def key(value)
|
86
|
+
raise "View#key cannot be used when startkey or endkey have been set" unless query[:startkey].nil? && query[:endkey].nil?
|
87
|
+
update_query(:key => value)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Find all index keys that start with the value provided. May or may not be used in
|
91
|
+
# conjunction with the +endkey+ option.
|
92
|
+
#
|
93
|
+
# When the +#descending+ option is used (not the default), the start and end keys should
|
94
|
+
# be reversed.
|
95
|
+
#
|
96
|
+
# Cannot be used if the key has been set.
|
97
|
+
def startkey(value)
|
98
|
+
raise "View#startkey cannot be used when key has been set" unless query[:key].nil?
|
99
|
+
update_query(:startkey => value)
|
100
|
+
end
|
101
|
+
|
102
|
+
# The result set should start from the position of the provided document.
|
103
|
+
# The value may be provided as an object that responds to the +#id+ call
|
104
|
+
# or a string.
|
105
|
+
def startkey_doc(value)
|
106
|
+
update_query(:startkey_docid => value.is_a?(String) ? value : value.id
|
107
|
+
end
|
108
|
+
|
109
|
+
# The opposite of +#startkey+, finds all index entries whose key is before the value specified.
|
110
|
+
#
|
111
|
+
# See the +#startkey+ method for more details and the +#inclusive_end+ option.
|
112
|
+
def endkey(value)
|
113
|
+
raise "View#endkey cannot be used when key has been set" unless query[:key].nil?
|
114
|
+
update_query(:endkey => value)
|
115
|
+
end
|
116
|
+
|
117
|
+
# The result set should end at the position of the provided document.
|
118
|
+
# The value may be provided as an object that responds to the +#id+ call
|
119
|
+
# or a string.
|
120
|
+
def endkey_doc(value)
|
121
|
+
update_query(:endkey_docid => value.is_a?(String) ? value : value.id
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
# The results should be provided in descending order.
|
126
|
+
#
|
127
|
+
# Descending is false by default, this method will enable it and cannot be undone.
|
128
|
+
def descending
|
129
|
+
update_query(:descending => true)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Limit the result set to the value supplied.
|
133
|
+
def limit(value)
|
134
|
+
update_query(:limit => value)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Skip the number of entries in the index specified by value. This would be
|
138
|
+
# the equivilent of an offset in SQL.
|
139
|
+
#
|
140
|
+
# The CouchDB documentation states that the skip option should not be used
|
141
|
+
# with large data sets as it is inefficient. Use the +startkey_doc+ method
|
142
|
+
# instead to skip ranges efficiently.
|
143
|
+
def skip(value = 0)
|
144
|
+
update_query(:skip => value)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Use the reduce function on the view. If none is available this method will fail.
|
148
|
+
def reduce
|
149
|
+
update_query(:reduce => true)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Control whether the reduce function reduces to a set of distinct keys or to a single
|
153
|
+
# result row.
|
154
|
+
#
|
155
|
+
# By default the value is false, and can only be set when the view's +#reduce+ option
|
156
|
+
# has been set.
|
157
|
+
def group
|
158
|
+
raise "View#reduce must have been set before grouping is permitted" unless query[:reduce]
|
159
|
+
update_query(:group => true)
|
160
|
+
end
|
161
|
+
|
162
|
+
def group_level(value)
|
163
|
+
raise "View#reduce and View#group must have been set before group_level is called" unless query[:reduce] && query[:group]
|
164
|
+
update_query(:group_level => value.to_i)
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
protected
|
169
|
+
|
170
|
+
def update_query(new_query = {})
|
171
|
+
self.class.new(self, new_query)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Used internally to ensure that docs are provided. Should not be used outside of
|
175
|
+
# the view class under normal circumstances.
|
176
|
+
def include_docs
|
177
|
+
raise "Documents cannot be returned from a view that is prepared for a reduce" if query[:reduce]
|
178
|
+
update_query(:include_docs => true)
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
def execute(&block)
|
183
|
+
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -23,7 +23,7 @@ module CouchRest
|
|
23
23
|
# view_by :tags,
|
24
24
|
# :map =>
|
25
25
|
# "function(doc) {
|
26
|
-
# if (doc['
|
26
|
+
# if (doc['model'] == 'Post' && doc.tags) {
|
27
27
|
# doc.tags.forEach(function(tag){
|
28
28
|
# emit(doc.tag, 1);
|
29
29
|
# });
|
@@ -39,7 +39,7 @@ module CouchRest
|
|
39
39
|
# function:
|
40
40
|
#
|
41
41
|
# function(doc) {
|
42
|
-
# if (doc['
|
42
|
+
# if (doc['model'] == 'Post' && doc.date) {
|
43
43
|
# emit(doc.date, null);
|
44
44
|
# }
|
45
45
|
# }
|
@@ -77,7 +77,7 @@ module CouchRest
|
|
77
77
|
ducktype = opts.delete(:ducktype)
|
78
78
|
unless ducktype || opts[:map]
|
79
79
|
opts[:guards] ||= []
|
80
|
-
opts[:guards].push "(doc['
|
80
|
+
opts[:guards].push "(doc['#{model_type_key}'] == '#{self.to_s}')"
|
81
81
|
end
|
82
82
|
keys.push opts
|
83
83
|
design_doc.view_by(*keys)
|
data/lib/couchrest/model.rb
CHANGED
data/lib/couchrest/railtie.rb
CHANGED
@@ -4,8 +4,9 @@ require "active_model/railtie"
|
|
4
4
|
module CouchrestModel
|
5
5
|
# = Active Record Railtie
|
6
6
|
class Railtie < Rails::Railtie
|
7
|
-
config.generators.orm :
|
7
|
+
config.generators.orm :couchrest_model
|
8
|
+
config.generators.test_framework :test_unit, :fixture => false
|
8
9
|
end
|
9
10
|
|
10
11
|
end
|
11
|
-
|
12
|
+
|
data/lib/couchrest_model.rb
CHANGED
@@ -1,13 +1,3 @@
|
|
1
|
-
gem 'couchrest', ">= 1.0.0.beta"
|
2
|
-
require 'couchrest'
|
3
|
-
|
4
|
-
gem "tzinfo", ">= 0.3.22"
|
5
|
-
|
6
|
-
gem "activesupport", ">= 2.3.5"
|
7
|
-
require 'active_support/core_ext'
|
8
|
-
require 'active_support/json'
|
9
|
-
|
10
|
-
gem "activemodel", ">= 3.0.0.beta4"
|
11
1
|
require 'active_model'
|
12
2
|
require "active_model/callbacks"
|
13
3
|
require "active_model/conversion"
|
@@ -19,7 +9,9 @@ require "active_model/translation"
|
|
19
9
|
require "active_model/validator"
|
20
10
|
require "active_model/validations"
|
21
11
|
|
22
|
-
|
12
|
+
require 'active_support/core_ext'
|
13
|
+
require 'active_support/json'
|
14
|
+
|
23
15
|
require 'mime/types'
|
24
16
|
require "enumerator"
|
25
17
|
require "time"
|
@@ -28,11 +20,14 @@ require 'digest/md5'
|
|
28
20
|
require 'bigdecimal' # used in typecast
|
29
21
|
require 'bigdecimal/util' # used in typecast
|
30
22
|
|
23
|
+
require 'couchrest'
|
24
|
+
|
31
25
|
require 'couchrest/model'
|
32
26
|
require 'couchrest/model/errors'
|
33
27
|
require "couchrest/model/persistence"
|
34
28
|
require "couchrest/model/typecast"
|
35
29
|
require "couchrest/model/property"
|
30
|
+
require "couchrest/model/property_protection"
|
36
31
|
require "couchrest/model/casted_array"
|
37
32
|
require "couchrest/model/properties"
|
38
33
|
require "couchrest/model/validations"
|
@@ -43,9 +38,8 @@ require "couchrest/model/design_doc"
|
|
43
38
|
require "couchrest/model/extended_attachments"
|
44
39
|
require "couchrest/model/class_proxy"
|
45
40
|
require "couchrest/model/collection"
|
46
|
-
require "couchrest/model/attribute_protection"
|
47
|
-
require "couchrest/model/attributes"
|
48
41
|
require "couchrest/model/associations"
|
42
|
+
require "couchrest/model/configuration"
|
49
43
|
|
50
44
|
# Monkey patches applied to couchrest
|
51
45
|
require "couchrest/model/support/couchrest"
|
@@ -58,4 +52,3 @@ require "couchrest/model/base"
|
|
58
52
|
# Add rails support *after* everything has loaded
|
59
53
|
|
60
54
|
require "couchrest/railtie"
|
61
|
-
|
@@ -3,7 +3,6 @@ require 'rails/generators/couchrest_model'
|
|
3
3
|
module CouchrestModel
|
4
4
|
module Generators
|
5
5
|
class ModelGenerator < Base
|
6
|
-
|
7
6
|
check_class_collision
|
8
7
|
|
9
8
|
def create_model_file
|
@@ -14,6 +13,8 @@ module CouchrestModel
|
|
14
13
|
return if class_path.empty?
|
15
14
|
template 'module.rb', File.join('app/models', "#{class_path.join('/')}.rb") if behavior == :invoke
|
16
15
|
end
|
16
|
+
|
17
|
+
hook_for :test_framework
|
17
18
|
|
18
19
|
protected
|
19
20
|
|
data/spec/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
tmp
|
data/spec/couchrest/base_spec.rb
CHANGED
@@ -36,7 +36,7 @@ describe "Model Base" do
|
|
36
36
|
|
37
37
|
it "should not failed on a nil value in argument" do
|
38
38
|
@obj = Basic.new(nil)
|
39
|
-
@obj.
|
39
|
+
@obj.should_not be_nil
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -210,7 +210,7 @@ describe "Model Base" do
|
|
210
210
|
|
211
211
|
describe "a doc with template values (CR::Model spec)" do
|
212
212
|
before(:all) do
|
213
|
-
WithTemplateAndUniqueID.all.map{|o| o.destroy
|
213
|
+
WithTemplateAndUniqueID.all.map{|o| o.destroy}
|
214
214
|
WithTemplateAndUniqueID.database.bulk_delete
|
215
215
|
@tmpl = WithTemplateAndUniqueID.new
|
216
216
|
@tmpl2 = WithTemplateAndUniqueID.new(:preset => 'not_value', 'important-field' => '1')
|
@@ -233,7 +233,7 @@ describe "Model Base" do
|
|
233
233
|
describe "finding all instances of a model" do
|
234
234
|
before(:all) do
|
235
235
|
WithTemplateAndUniqueID.req_design_doc_refresh
|
236
|
-
WithTemplateAndUniqueID.all.map{|o| o.destroy
|
236
|
+
WithTemplateAndUniqueID.all.map{|o| o.destroy}
|
237
237
|
WithTemplateAndUniqueID.database.bulk_delete
|
238
238
|
WithTemplateAndUniqueID.new('important-field' => '1').save
|
239
239
|
WithTemplateAndUniqueID.new('important-field' => '2').save
|