couchbase-model 0.1.0 → 0.2.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/HISTORY.markdown +44 -0
- data/README.markdown +1 -1
- data/couchbase-model.gemspec +1 -1
- data/lib/couchbase/model.rb +79 -50
- data/lib/couchbase/model/ext/singleton_class.rb +24 -0
- data/lib/couchbase/model/version.rb +1 -1
- data/lib/couchbase/railtie.rb +16 -11
- data/test/test_model.rb +2 -2
- metadata +6 -4
data/HISTORY.markdown
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
## 0.2.0 / 2012-09-18
|
2
|
+
|
3
|
+
* Add Rails 3 configuration possibilities, allow configuring
|
4
|
+
ensure_design_documents to disable/enable the auto view upgrade
|
5
|
+
(thanks to David Rice)
|
6
|
+
* Ensure views directory is always set (thanks to David Rice)
|
7
|
+
* Fix tests for ruby 1.8.7
|
8
|
+
* Reword header in README
|
9
|
+
* Merge pull request #3 from davidjrice/master
|
10
|
+
* Use debugger gem
|
11
|
+
* Update Model wrapper to match latest API changes
|
12
|
+
* Strip contents of the JS file
|
13
|
+
* Do not submit empty views
|
14
|
+
* Allow to specify default view options
|
15
|
+
* Display only non-nil values
|
16
|
+
* Rename underscored methods
|
17
|
+
* Load spatial views into design document
|
18
|
+
|
19
|
+
## 0.1.0 / 2012-04-10
|
20
|
+
|
21
|
+
* Allows to define several attributes at once
|
22
|
+
* Allow to specify default value
|
23
|
+
* Add missing @since and @return tags
|
24
|
+
* Add railtie
|
25
|
+
* Add config generator
|
26
|
+
* Use verbose mode by default for GET operation
|
27
|
+
* Add views generators
|
28
|
+
* Update document wrapper
|
29
|
+
* Add code to upgrade design docs automatically
|
30
|
+
* Cache design document signature in memory
|
31
|
+
* Use symbols for attribute hash
|
32
|
+
* Skip connection errors during start up
|
33
|
+
* Don't show config warning for config generator
|
34
|
+
* Calculate mtime of the design document
|
35
|
+
* Assign current_doc after creation
|
36
|
+
* Update readme file
|
37
|
+
* Use preview repository for travis
|
38
|
+
* Do not make zipball
|
39
|
+
* Show model attributes with model class
|
40
|
+
* Update test. The couchbase gem is using new defaults
|
41
|
+
|
42
|
+
## 0.0.1/ 2012-03-17
|
43
|
+
|
44
|
+
* Initial version
|
data/README.markdown
CHANGED
@@ -83,7 +83,7 @@ You can define connection options on per model basis:
|
|
83
83
|
connect :port => 80, :bucket => 'blog'
|
84
84
|
end
|
85
85
|
|
86
|
-
## Views (aka Map/Reduce
|
86
|
+
## Views (aka Map/Reduce indexes)
|
87
87
|
|
88
88
|
Views are stored in models directory in subdirectory named after the
|
89
89
|
model (to be precious `design_document` attribute of the model class).
|
data/couchbase-model.gemspec
CHANGED
@@ -22,5 +22,5 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_development_dependency 'minitest'
|
23
23
|
s.add_development_dependency 'rdiscount'
|
24
24
|
s.add_development_dependency 'yard'
|
25
|
-
s.add_development_dependency
|
25
|
+
s.add_development_dependency 'debugger'
|
26
26
|
end
|
data/lib/couchbase/model.rb
CHANGED
@@ -22,6 +22,10 @@ require 'couchbase/model/version'
|
|
22
22
|
require 'couchbase/model/uuid'
|
23
23
|
require 'couchbase/model/configuration'
|
24
24
|
|
25
|
+
unless Object.respond_to?(:singleton_class)
|
26
|
+
require 'couchbase/model/ext/singleton_class'
|
27
|
+
end
|
28
|
+
|
25
29
|
module Couchbase
|
26
30
|
|
27
31
|
# @since 0.0.1
|
@@ -82,23 +86,23 @@ module Couchbase
|
|
82
86
|
# @since 0.0.1
|
83
87
|
attr_accessor :id
|
84
88
|
|
85
|
-
# @since 0.
|
86
|
-
attr_reader :
|
89
|
+
# @since 0.2.0
|
90
|
+
attr_reader :key
|
87
91
|
|
88
|
-
# @since 0.
|
89
|
-
attr_reader :
|
92
|
+
# @since 0.2.0
|
93
|
+
attr_reader :value
|
90
94
|
|
91
|
-
# @since 0.
|
92
|
-
attr_reader :
|
95
|
+
# @since 0.2.0
|
96
|
+
attr_reader :doc
|
93
97
|
|
94
|
-
# @since 0.
|
95
|
-
attr_reader :
|
98
|
+
# @since 0.2.0
|
99
|
+
attr_reader :meta
|
96
100
|
|
97
101
|
# @private Container for all attributes with defaults of all subclasses
|
98
102
|
@@attributes = ::Hash.new {|hash, key| hash[key] = {}}
|
99
103
|
|
100
104
|
# @private Container for all view names of all subclasses
|
101
|
-
@@views = ::Hash.new {|hash, key| hash[key] =
|
105
|
+
@@views = ::Hash.new {|hash, key| hash[key] = {}}
|
102
106
|
|
103
107
|
# Use custom connection options
|
104
108
|
#
|
@@ -190,20 +194,31 @@ module Couchbase
|
|
190
194
|
doc = {'_id' => "_design/#{design_document}", 'views' => {}}
|
191
195
|
digest = Digest::MD5.new
|
192
196
|
mtime = 0
|
193
|
-
views.each do |name|
|
194
|
-
doc['views'][name] =
|
195
|
-
['
|
197
|
+
views.each do |name, _|
|
198
|
+
doc['views'][name] = {}
|
199
|
+
doc['spatial'] = {}
|
200
|
+
['map', 'reduce', 'spatial'].each do |type|
|
196
201
|
Configuration.design_documents_paths.each do |path|
|
197
202
|
ff = File.join(path, design_document.to_s, name.to_s, "#{type}.js")
|
198
203
|
if File.file?(ff)
|
199
|
-
|
204
|
+
contents = File.read(ff).strip
|
205
|
+
next if contents.empty?
|
200
206
|
mtime = [mtime, File.mtime(ff).to_i].max
|
201
|
-
digest <<
|
207
|
+
digest << contents
|
208
|
+
case type
|
209
|
+
when 'map', 'reduce'
|
210
|
+
doc['views'][name][type] = contents
|
211
|
+
when 'spatial'
|
212
|
+
doc['spatial'][name] = contents
|
213
|
+
end
|
202
214
|
break # pick first matching file
|
203
215
|
end
|
204
216
|
end
|
205
217
|
end
|
206
218
|
end
|
219
|
+
|
220
|
+
doc['views'].delete_if {|_, v| v.empty? }
|
221
|
+
doc.delete('spatial') if doc['spatial'].empty?
|
207
222
|
doc['signature'] = digest.to_s
|
208
223
|
doc['timestamp'] = mtime
|
209
224
|
if doc['signature'] != thread_storage[:signature] && doc['timestamp'] > thread_storage[:timestamp].to_i
|
@@ -259,30 +274,48 @@ module Couchbase
|
|
259
274
|
options = names.pop
|
260
275
|
end
|
261
276
|
names.each do |name|
|
277
|
+
attributes[name] = options[:default]
|
262
278
|
name = name.to_sym
|
279
|
+
next if self.instance_methods.include?(name)
|
263
280
|
define_method(name) do
|
264
281
|
@_attributes[name]
|
265
282
|
end
|
266
283
|
define_method(:"#{name}=") do |value|
|
267
284
|
@_attributes[name] = value
|
268
285
|
end
|
269
|
-
attributes[name] = options[:default]
|
270
286
|
end
|
271
287
|
end
|
272
288
|
|
289
|
+
# Defines a view for the model
|
290
|
+
#
|
291
|
+
# @since 0.0.1
|
292
|
+
#
|
293
|
+
# @param [Symbol, String, Array] names names of the views
|
294
|
+
# @param [Hash] options options passed to the {Couchbase::View}
|
295
|
+
#
|
296
|
+
# @example Define some views for a model
|
297
|
+
# class Post < Couchbase::Model
|
298
|
+
# view :all, :published
|
299
|
+
# view :by_rating, :include_docs => false
|
300
|
+
# end
|
301
|
+
#
|
302
|
+
# post = Post.find("hello")
|
303
|
+
# post.by_rating.each do |r|
|
304
|
+
# # ...
|
305
|
+
# end
|
273
306
|
def self.view(*names)
|
274
|
-
options = {}
|
307
|
+
options = {:wrapper_class => self, :include_docs => true}
|
275
308
|
if names.last.is_a?(Hash)
|
276
|
-
options
|
309
|
+
options.update(names.pop)
|
277
310
|
end
|
311
|
+
is_spatial = options.delete(:spatial)
|
278
312
|
names.each do |name|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
EOV
|
313
|
+
path = "_design/%s/_%s/%s" % [design_document, is_spatial ? "spatial" : "view", name]
|
314
|
+
views[name] = lambda do |*params|
|
315
|
+
params = options.merge(params.first || {})
|
316
|
+
View.new(bucket, path, params)
|
317
|
+
end
|
318
|
+
singleton_class.send(:define_method, name, &views[name])
|
286
319
|
end
|
287
320
|
end
|
288
321
|
|
@@ -299,7 +332,7 @@ module Couchbase
|
|
299
332
|
def self.find(id)
|
300
333
|
if id && (res = bucket.get(id, :quiet => false, :extended => true))
|
301
334
|
obj, flags, cas = res
|
302
|
-
new({:id => id, :
|
335
|
+
new({:id => id, :meta => {'flags' => flags, 'cas' => cas}}.merge(obj))
|
303
336
|
end
|
304
337
|
end
|
305
338
|
|
@@ -316,7 +349,7 @@ module Couchbase
|
|
316
349
|
def self.find_by_id(id)
|
317
350
|
if id && (res = bucket.get(id, :quiet => true))
|
318
351
|
obj, flags, cas = res
|
319
|
-
new({:id => id, :
|
352
|
+
new({:id => id, :meta => {'flags' => flags, 'cas' => cas}}.merge(obj))
|
320
353
|
end
|
321
354
|
end
|
322
355
|
|
@@ -342,10 +375,10 @@ module Couchbase
|
|
342
375
|
attrs = attrs.with_indifferent_access
|
343
376
|
end
|
344
377
|
@id = attrs.delete(:id)
|
345
|
-
@
|
346
|
-
@
|
347
|
-
@
|
348
|
-
@
|
378
|
+
@key = attrs.delete(:key)
|
379
|
+
@value = attrs.delete(:value)
|
380
|
+
@doc = attrs.delete(:doc)
|
381
|
+
@meta = attrs.delete(:meta)
|
349
382
|
@_attributes = ::Hash.new do |h, k|
|
350
383
|
default = self.class.attributes[k]
|
351
384
|
h[k] = if default.respond_to?(:call)
|
@@ -354,7 +387,7 @@ module Couchbase
|
|
354
387
|
default
|
355
388
|
end
|
356
389
|
end
|
357
|
-
update_attributes(@
|
390
|
+
update_attributes(@doc || attrs)
|
358
391
|
end
|
359
392
|
|
360
393
|
# Create this model and assign new id if necessary
|
@@ -558,21 +591,13 @@ module Couchbase
|
|
558
591
|
# @return [Model]
|
559
592
|
def self.wrap(bucket, data)
|
560
593
|
doc = {
|
561
|
-
:
|
562
|
-
:
|
563
|
-
:
|
564
|
-
:id => data['id']
|
594
|
+
:id => data['id'],
|
595
|
+
:key => data['key'],
|
596
|
+
:value => data['value']
|
565
597
|
}
|
566
|
-
if doc[:_value].is_a?(Hash) && (_id = doc[:_value]['_id'])
|
567
|
-
doc[:id] = _id
|
568
|
-
end
|
569
598
|
if data['doc']
|
570
|
-
data['doc']
|
571
|
-
|
572
|
-
doc[:_meta][key.sub(/^\$/, '')] = data['doc'].delete(key)
|
573
|
-
end
|
574
|
-
end
|
575
|
-
doc.update(data['doc'])
|
599
|
+
doc[:meta] = data['doc']['meta']
|
600
|
+
doc[:doc] = data['doc']['json']
|
576
601
|
end
|
577
602
|
new(doc)
|
578
603
|
end
|
@@ -582,12 +607,16 @@ module Couchbase
|
|
582
607
|
#
|
583
608
|
# @since 0.0.1
|
584
609
|
def inspect
|
585
|
-
attrs =
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
610
|
+
attrs = []
|
611
|
+
attrs << ["key", @key.inspect] unless @key.nil?
|
612
|
+
attrs << ["value", @value.inspect] unless @value.nil?
|
613
|
+
model.attributes.map do |attr, default|
|
614
|
+
val = @_attributes[attr]
|
615
|
+
attrs << [attr.to_s, val.inspect] unless val.nil?
|
616
|
+
end
|
617
|
+
attrs.sort!
|
618
|
+
attrs.unshift([:id, id]) unless new?
|
619
|
+
sprintf("#<%s %s>", model, attrs.map{|a| a.join(": ")}.join(", "))
|
591
620
|
end
|
592
621
|
|
593
622
|
def self.inspect
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
class Object
|
19
|
+
def singleton_class
|
20
|
+
class << self
|
21
|
+
self
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/couchbase/railtie.rb
CHANGED
@@ -23,6 +23,9 @@ module Rails #:nodoc:
|
|
23
23
|
module Couchbase #:nodoc:
|
24
24
|
class Railtie < Rails::Railtie #:nodoc:
|
25
25
|
|
26
|
+
config.couchbase = ActiveSupport::OrderedOptions.new
|
27
|
+
config.couchbase.ensure_design_documents ||= true
|
28
|
+
|
26
29
|
# Determine which generator to use. app_generators was introduced after
|
27
30
|
# 3.0.0.
|
28
31
|
#
|
@@ -104,19 +107,21 @@ module Rails #:nodoc:
|
|
104
107
|
|
105
108
|
# Check (and upgrade if needed) all design documents
|
106
109
|
initializer "couchbase.upgrade_design_documents", :after =>"couchbase.setup_connection" do |app|
|
107
|
-
config.
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
110
|
+
::Couchbase::Model::Configuration.design_documents_paths ||= app.config.paths["app/models"]
|
111
|
+
if config.couchbase.ensure_design_documents
|
112
|
+
config.to_prepare do
|
113
|
+
app.config.paths["app/models"].each do |path|
|
114
|
+
Dir.glob("#{path}/**/*.rb").sort.each do |file|
|
115
|
+
require_dependency(file.gsub("#{path}/" , "").gsub(".rb", ""))
|
116
|
+
end
|
112
117
|
end
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
118
|
+
begin
|
119
|
+
::Couchbase::Model.descendants.each do |model|
|
120
|
+
model.ensure_design_document!
|
121
|
+
end
|
122
|
+
rescue ::Couchbase::Error::Timeout, ::Couchbase::Error::Connect
|
123
|
+
# skip connection errors for now
|
117
124
|
end
|
118
|
-
rescue ::Couchbase::Error::Timeout, ::Couchbase::Error::Connect
|
119
|
-
# skip connection errors for now
|
120
125
|
end
|
121
126
|
end
|
122
127
|
end
|
data/test/test_model.rb
CHANGED
@@ -21,7 +21,7 @@ class Post < Couchbase::Model
|
|
21
21
|
attribute :title
|
22
22
|
attribute :body
|
23
23
|
attribute :author, :default => 'Anonymous'
|
24
|
-
attribute :created_at, :default => lambda { Time.
|
24
|
+
attribute :created_at, :default => lambda { Time.utc("2010-01-01") }
|
25
25
|
end
|
26
26
|
|
27
27
|
class TestModel < MiniTest::Unit::TestCase
|
@@ -52,7 +52,7 @@ class TestModel < MiniTest::Unit::TestCase
|
|
52
52
|
|
53
53
|
def test_allows_lambda_as_default_value
|
54
54
|
post = Post.new(:title => "Hello, world")
|
55
|
-
expected = Time.
|
55
|
+
expected = Time.utc("2010-01-01")
|
56
56
|
assert_equal expected, post.created_at
|
57
57
|
assert_equal expected, post.attributes[:created_at]
|
58
58
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couchbase-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: couchbase
|
@@ -92,7 +92,7 @@ dependencies:
|
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
95
|
+
name: debugger
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
@@ -117,12 +117,14 @@ files:
|
|
117
117
|
- .travis.yml
|
118
118
|
- .yardopts
|
119
119
|
- Gemfile
|
120
|
+
- HISTORY.markdown
|
120
121
|
- README.markdown
|
121
122
|
- Rakefile
|
122
123
|
- couchbase-model.gemspec
|
123
124
|
- lib/couchbase-model.rb
|
124
125
|
- lib/couchbase/model.rb
|
125
126
|
- lib/couchbase/model/configuration.rb
|
127
|
+
- lib/couchbase/model/ext/singleton_class.rb
|
126
128
|
- lib/couchbase/model/uuid.rb
|
127
129
|
- lib/couchbase/model/version.rb
|
128
130
|
- lib/couchbase/railtie.rb
|
@@ -159,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
161
|
version: '0'
|
160
162
|
requirements: []
|
161
163
|
rubyforge_project:
|
162
|
-
rubygems_version: 1.8.
|
164
|
+
rubygems_version: 1.8.23
|
163
165
|
signing_key:
|
164
166
|
specification_version: 3
|
165
167
|
summary: Declarative interface to Couchbase
|