couchbase-model 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|