couchbase-model 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.markdown +9 -1
- data/couchbase-model.gemspec +9 -8
- data/lib/couchbase-model.rb +1 -1
- data/lib/couchbase/model.rb +47 -29
- data/lib/couchbase/model/uuid.rb +8 -8
- data/lib/couchbase/model/version.rb +1 -1
- data/lib/couchbase/railtie.rb +13 -13
- data/lib/rails/generators/couchbase/config/config_generator.rb +3 -3
- data/lib/rails/generators/couchbase/view/view_generator.rb +2 -2
- data/lib/rails/generators/couchbase_generator.rb +2 -2
- data/test/setup.rb +14 -14
- data/test/test_model.rb +82 -44
- metadata +88 -57
data/HISTORY.markdown
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
## 0.5.
|
1
|
+
## 0.5.3 / 2013-06-06
|
2
|
+
|
3
|
+
* Prefer single-quoted strings (Andrey Koleshko)
|
4
|
+
* Test for Model.design_document (Andrey Koleshko)
|
5
|
+
* Support for batch finding multiple objects by id (Jon Moses)
|
6
|
+
* Test for activemodel instead of rails for activemodel validations
|
7
|
+
* Update couchbase dependency to 1.3.0
|
8
|
+
|
9
|
+
## 0.5.2 / 2013-02-25
|
2
10
|
|
3
11
|
* Fix attribute inheritance when subclassing (Mike Evans)
|
4
12
|
* Added as_json method for rails JSON responses (Stephen von Takach)
|
data/couchbase-model.gemspec
CHANGED
@@ -1,23 +1,24 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path(
|
3
|
-
require
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'couchbase/model/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
6
|
+
s.name = 'couchbase-model'
|
7
7
|
s.version = Couchbase::Model::VERSION
|
8
|
-
s.author =
|
9
|
-
s.email =
|
10
|
-
s.homepage =
|
8
|
+
s.author = 'Couchbase'
|
9
|
+
s.email = 'support@couchbase.com'
|
10
|
+
s.homepage = 'https://github.com/couchbase/couchbase-ruby-model'
|
11
11
|
s.summary = %q{Declarative interface to Couchbase}
|
12
12
|
s.description = %q{ORM-like interface allows you to persist your models to Couchbase}
|
13
13
|
|
14
14
|
s.files = `git ls-files`.split("\n")
|
15
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
16
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
-
s.require_paths = [
|
17
|
+
s.require_paths = ['lib']
|
18
18
|
|
19
|
-
s.add_runtime_dependency 'couchbase', '~> 1.
|
19
|
+
s.add_runtime_dependency 'couchbase', '~> 1.3.0'
|
20
20
|
|
21
21
|
s.add_development_dependency 'rake'
|
22
22
|
s.add_development_dependency 'minitest'
|
23
|
+
s.add_development_dependency 'activesupport'
|
23
24
|
end
|
data/lib/couchbase-model.rb
CHANGED
data/lib/couchbase/model.rb
CHANGED
@@ -25,10 +25,10 @@ require 'couchbase/model/configuration'
|
|
25
25
|
unless Object.respond_to?(:singleton_class)
|
26
26
|
require 'couchbase/model/ext/singleton_class'
|
27
27
|
end
|
28
|
-
unless
|
28
|
+
unless ''.respond_to?(:constantize)
|
29
29
|
require 'couchbase/model/ext/constantize'
|
30
30
|
end
|
31
|
-
unless
|
31
|
+
unless ''.respond_to?(:camelize)
|
32
32
|
require 'couchbase/model/ext/camelize'
|
33
33
|
end
|
34
34
|
|
@@ -43,9 +43,9 @@ module Couchbase
|
|
43
43
|
def initialize(record)
|
44
44
|
@record = record
|
45
45
|
if @record.errors
|
46
|
-
super(@record.errors.full_messages.join(
|
46
|
+
super(@record.errors.full_messages.join(', '))
|
47
47
|
else
|
48
|
-
super(
|
48
|
+
super('Record invalid')
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
@@ -221,7 +221,7 @@ module Couchbase
|
|
221
221
|
# +by_session_id` and `total_views`.
|
222
222
|
def self.ensure_design_document!
|
223
223
|
unless Configuration.design_documents_paths
|
224
|
-
raise
|
224
|
+
raise 'Configuration.design_documents_path must be directory'
|
225
225
|
end
|
226
226
|
|
227
227
|
doc = {'_id' => "_design/#{design_document}", 'views' => {}}
|
@@ -351,7 +351,7 @@ module Couchbase
|
|
351
351
|
end
|
352
352
|
is_spatial = options.delete(:spatial)
|
353
353
|
names.each do |name|
|
354
|
-
path =
|
354
|
+
path = '_design/%s/_%s/%s' % [design_document, is_spatial ? 'spatial' : 'view', name]
|
355
355
|
views[name] = lambda do |*params|
|
356
356
|
params = options.merge(params.first || {})
|
357
357
|
View.new(bucket, path, params)
|
@@ -389,40 +389,58 @@ module Couchbase
|
|
389
389
|
end
|
390
390
|
end
|
391
391
|
|
392
|
+
class << self
|
393
|
+
def _find(quiet, *ids)
|
394
|
+
wants_array = ids.first.kind_of?(Array)
|
395
|
+
ids = ids.flatten.compact.uniq
|
396
|
+
unless ids.empty?
|
397
|
+
res = bucket.get(ids, :quiet => quiet, :extended => true).map do |id, (obj, flags, cas)|
|
398
|
+
obj = {:raw => obj} unless obj.is_a?(Hash)
|
399
|
+
new({:id => id, :meta => {'flags' => flags, 'cas' => cas}}.merge(obj))
|
400
|
+
end
|
401
|
+
wants_array ? res : res.first
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
private :_find
|
406
|
+
end
|
407
|
+
|
392
408
|
# Find the model using +id+ attribute
|
393
409
|
#
|
394
410
|
# @since 0.0.1
|
395
411
|
#
|
396
|
-
# @param [String, Symbol] id model identificator
|
397
|
-
# @return [Couchbase::Model] an instance of the model
|
412
|
+
# @param [String, Symbol, Array] id model identificator(s)
|
413
|
+
# @return [Couchbase::Model, Array] an instance of the model, or an array of instances
|
398
414
|
# @raise [Couchbase::Error::NotFound] when given key isn't exist
|
399
415
|
#
|
400
416
|
# @example Find model using +id+
|
401
417
|
# post = Post.find('the-id')
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
end
|
418
|
+
#
|
419
|
+
# @example Find multiple models using +id+
|
420
|
+
# post = Post.find('one', 'two')
|
421
|
+
def self.find(*id)
|
422
|
+
_find(false, *id)
|
408
423
|
end
|
409
424
|
|
410
425
|
# Find the model using +id+ attribute
|
411
426
|
#
|
427
|
+
# Unlike {Couchbase::Model.find}, this method won't raise
|
428
|
+
# {Couchbase::Error::NotFound} error when key doesn't exist in the
|
429
|
+
# bucket
|
430
|
+
#
|
412
431
|
# @since 0.1.0
|
413
432
|
#
|
414
|
-
# @param [String, Symbol] id model identificator
|
415
|
-
# @return [Couchbase::Model, nil] an instance of the model
|
433
|
+
# @param [String, Symbol] id model identificator(s)
|
434
|
+
# @return [Couchbase::Model, Array, nil] an instance of the model, an array
|
435
|
+
# of found instances of the model, or +nil+ if
|
416
436
|
# given key isn't exist
|
417
437
|
#
|
418
438
|
# @example Find model using +id+
|
419
439
|
# post = Post.find_by_id('the-id')
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
new({:id => id, :meta => {'flags' => flags, 'cas' => cas}}.merge(obj))
|
425
|
-
end
|
440
|
+
# @example Find multiple models using +id+
|
441
|
+
# posts = Post.find_by_id(['the-id', 'the-id2'])
|
442
|
+
def self.find_by_id(*id)
|
443
|
+
_find(true, *id)
|
426
444
|
end
|
427
445
|
|
428
446
|
# Create the model with given attributes
|
@@ -586,7 +604,7 @@ module Couchbase
|
|
586
604
|
# p = Post.find('hello-world')
|
587
605
|
# p.delete
|
588
606
|
def delete(options = {})
|
589
|
-
raise Couchbase::Error::MissingId,
|
607
|
+
raise Couchbase::Error::MissingId, 'missing id attribute' unless @id
|
590
608
|
model.bucket.delete(@id, options)
|
591
609
|
@id = nil
|
592
610
|
@meta = nil
|
@@ -704,7 +722,7 @@ module Couchbase
|
|
704
722
|
# @raise [Error::MissingId] for records without +id+
|
705
723
|
# attribute
|
706
724
|
def reload
|
707
|
-
raise Couchbase::Error::MissingId,
|
725
|
+
raise Couchbase::Error::MissingId, 'missing id attribute' unless @id
|
708
726
|
attrs = model.find(@id).attributes
|
709
727
|
update_attributes(attrs)
|
710
728
|
self
|
@@ -779,15 +797,15 @@ module Couchbase
|
|
779
797
|
# @since 0.0.1
|
780
798
|
def inspect
|
781
799
|
attrs = []
|
782
|
-
attrs << [
|
783
|
-
attrs << [
|
800
|
+
attrs << ['key', @key.inspect] unless @key.nil?
|
801
|
+
attrs << ['value', @value.inspect] unless @value.nil?
|
784
802
|
model.attributes.map do |attr, default|
|
785
803
|
val = read_attribute(attr)
|
786
804
|
attrs << [attr.to_s, val.inspect] unless val.nil?
|
787
805
|
end
|
788
806
|
attrs.sort!
|
789
807
|
attrs.unshift([:id, id]) unless new?
|
790
|
-
sprintf(
|
808
|
+
sprintf('#<%s %s>', model, attrs.map { |a| a.join(': ') }.join(', '))
|
791
809
|
end
|
792
810
|
|
793
811
|
def self.inspect
|
@@ -811,7 +829,7 @@ module Couchbase
|
|
811
829
|
|
812
830
|
protected :attributes_with_values
|
813
831
|
|
814
|
-
if defined?(::
|
832
|
+
if defined?(::ActiveModel)
|
815
833
|
extend ActiveModel::Callbacks
|
816
834
|
extend ActiveModel::Naming
|
817
835
|
include ActiveModel::Conversion
|
@@ -839,7 +857,7 @@ module Couchbase
|
|
839
857
|
def to_param
|
840
858
|
keys = to_key
|
841
859
|
if keys && !keys.empty?
|
842
|
-
keys.join(
|
860
|
+
keys.join('-')
|
843
861
|
end
|
844
862
|
end
|
845
863
|
end
|
data/lib/couchbase/model/uuid.rb
CHANGED
@@ -43,7 +43,7 @@ module Couchbase
|
|
43
43
|
# @param [Fixnum] seed seed for pseudorandom number generator.
|
44
44
|
def initialize(seed = nil)
|
45
45
|
seed ? srand(seed) : srand
|
46
|
-
@prefix, _ = rand_bytes(13).unpack(
|
46
|
+
@prefix, _ = rand_bytes(13).unpack('H26')
|
47
47
|
@inc = rand(0xfff) + 1
|
48
48
|
@lock = Mutex.new
|
49
49
|
end
|
@@ -69,14 +69,14 @@ module Couchbase
|
|
69
69
|
# @return [String, Array] single string value or array of strings. Where
|
70
70
|
# each value represents 128-bit number written in hexadecimal format.
|
71
71
|
def next(count = 1, algorithm = :sequential)
|
72
|
-
raise ArgumentError,
|
72
|
+
raise ArgumentError, 'count should be a positive number' unless count > 0
|
73
73
|
uuids = case algorithm
|
74
74
|
when :random
|
75
|
-
rand_bytes(16 * count).unpack(
|
75
|
+
rand_bytes(16 * count).unpack('H32' * count)
|
76
76
|
when :utc_random
|
77
77
|
now = Time.now.utc
|
78
|
-
prefix =
|
79
|
-
rand_bytes(9 * count).unpack(
|
78
|
+
prefix = '%014x' % [now.to_i * 1_000_000 + now.usec]
|
79
|
+
rand_bytes(9 * count).unpack('H18' * count).map do |tail|
|
80
80
|
"#{prefix}#{tail}"
|
81
81
|
end
|
82
82
|
when :sequential
|
@@ -92,16 +92,16 @@ module Couchbase
|
|
92
92
|
def next_seq
|
93
93
|
@lock.synchronize do
|
94
94
|
if @inc >= 0xfff000
|
95
|
-
@prefix, _ = rand_bytes(13).unpack(
|
95
|
+
@prefix, _ = rand_bytes(13).unpack('H26')
|
96
96
|
@inc = rand(0xfff) + 1
|
97
97
|
end
|
98
98
|
@inc += rand(0xfff) + 1
|
99
|
-
|
99
|
+
'%s%06x' % [@prefix, @inc]
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
103
|
def rand_bytes(count)
|
104
|
-
bytes =
|
104
|
+
bytes = ''
|
105
105
|
count.times { bytes << rand(256) }
|
106
106
|
bytes
|
107
107
|
end
|
data/lib/couchbase/railtie.rb
CHANGED
@@ -49,9 +49,9 @@ module Rails #:nodoc:
|
|
49
49
|
# @return [Hash] rescued responses
|
50
50
|
def self.rescue_responses
|
51
51
|
{
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
'Couchbase::Error::NotFound' => :not_found,
|
53
|
+
'Couchbase::Error::NotStored' => :unprocessable_entity,
|
54
|
+
'Couchbase::Error::RecordInvalid' => :unprocessable_entity
|
55
55
|
}
|
56
56
|
end
|
57
57
|
|
@@ -85,8 +85,8 @@ module Rails #:nodoc:
|
|
85
85
|
# <<: *common
|
86
86
|
# bucket: example_development
|
87
87
|
#
|
88
|
-
initializer
|
89
|
-
config_file = Rails.root.join(
|
88
|
+
initializer 'couchbase.setup_connection' do
|
89
|
+
config_file = Rails.root.join('config', 'couchbase.yml')
|
90
90
|
if config_file.file? &&
|
91
91
|
config = YAML.load(ERB.new(File.read(config_file)).result)[Rails.env]
|
92
92
|
::Couchbase.connection_options = config.with_indifferent_access
|
@@ -95,10 +95,10 @@ module Rails #:nodoc:
|
|
95
95
|
|
96
96
|
# After initialization we will warn the user if we can't find a couchbase.yml and
|
97
97
|
# alert to create one.
|
98
|
-
initializer
|
99
|
-
unless ARGV.include?(
|
98
|
+
initializer 'couchbase.warn_configuration_missing' do
|
99
|
+
unless ARGV.include?('couchbase:config')
|
100
100
|
config.after_initialize do
|
101
|
-
unless Rails.root.join(
|
101
|
+
unless Rails.root.join('config', 'couchbase.yml').file?
|
102
102
|
puts "\nCouchbase config not found. Create a config file at: config/couchbase.yml"
|
103
103
|
puts "to generate one run: rails generate couchbase:config\n\n"
|
104
104
|
end
|
@@ -107,13 +107,13 @@ module Rails #:nodoc:
|
|
107
107
|
end
|
108
108
|
|
109
109
|
# Check (and upgrade if needed) all design documents
|
110
|
-
initializer
|
111
|
-
::Couchbase::Model::Configuration.design_documents_paths ||= app.config.paths[
|
110
|
+
initializer 'couchbase.upgrade_design_documents', :after => 'couchbase.setup_connection' do |app|
|
111
|
+
::Couchbase::Model::Configuration.design_documents_paths ||= app.config.paths['app/models']
|
112
112
|
if config.couchbase.ensure_design_documents
|
113
113
|
config.to_prepare do
|
114
|
-
app.config.paths[
|
114
|
+
app.config.paths['app/models'].each do |path|
|
115
115
|
Dir.glob("#{path}/**/*.rb").sort.each do |file|
|
116
|
-
require_dependency(file.gsub("#{path}/" ,
|
116
|
+
require_dependency(file.gsub("#{path}/" , '').gsub('.rb', ''))
|
117
117
|
end
|
118
118
|
end
|
119
119
|
begin
|
@@ -129,7 +129,7 @@ module Rails #:nodoc:
|
|
129
129
|
|
130
130
|
# Set the proper error types for Rails. NotFound errors should be
|
131
131
|
# 404s and not 500s, validation errors are 422s.
|
132
|
-
initializer
|
132
|
+
initializer 'couchbase.load_http_errors' do |app|
|
133
133
|
config.after_initialize do
|
134
134
|
unless config.action_dispatch.rescue_responses
|
135
135
|
ActionDispatch::ShowExceptions.rescue_responses.update(Railtie.rescue_responses)
|
@@ -22,12 +22,12 @@ require 'rails/generators/couchbase_generator'
|
|
22
22
|
module Couchbase
|
23
23
|
module Generators
|
24
24
|
class ConfigGenerator < Rails::Generators::Base
|
25
|
-
desc
|
25
|
+
desc 'Creates a Couchbase configuration file at config/couchbase.yml'
|
26
26
|
|
27
27
|
argument :database_name, :type => :string, :optional => true
|
28
28
|
|
29
29
|
def self.source_root
|
30
|
-
@_couchbase_source_root ||= File.expand_path(
|
30
|
+
@_couchbase_source_root ||= File.expand_path('../templates', __FILE__)
|
31
31
|
end
|
32
32
|
|
33
33
|
def app_name
|
@@ -35,7 +35,7 @@ module Couchbase
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def create_config_file
|
38
|
-
template 'couchbase.yml', File.join('config',
|
38
|
+
template 'couchbase.yml', File.join('config', 'couchbase.yml')
|
39
39
|
end
|
40
40
|
|
41
41
|
end
|
@@ -22,12 +22,12 @@ require 'rails/generators/couchbase_generator'
|
|
22
22
|
module Couchbase
|
23
23
|
module Generators
|
24
24
|
class ViewGenerator < Rails::Generators::Base
|
25
|
-
desc
|
25
|
+
desc 'Creates a Couchbase views skeletons for map/reduce functions'
|
26
26
|
|
27
27
|
argument :model_name, :type => :string
|
28
28
|
argument :view_name, :type => :string
|
29
29
|
|
30
|
-
source_root File.expand_path(
|
30
|
+
source_root File.expand_path('../templates', __FILE__)
|
31
31
|
|
32
32
|
def app_name
|
33
33
|
Rails::Application.subclasses.first.parent.to_s.underscore
|
@@ -17,8 +17,8 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
20
|
+
require 'rails/generators/named_base'
|
21
|
+
require 'rails/generators/active_model'
|
22
22
|
|
23
23
|
module Couchbase #:nodoc:
|
24
24
|
module Generators #:nodoc:
|
data/test/setup.rb
CHANGED
@@ -34,12 +34,12 @@ class CouchbaseServer
|
|
34
34
|
@port = @port.to_i
|
35
35
|
|
36
36
|
if @host.nil? || @host.empty? || @port == 0
|
37
|
-
raise ArgumentError,
|
37
|
+
raise ArgumentError, 'Check COUCHBASE_SERVER variable. It should be hostname:port'
|
38
38
|
end
|
39
39
|
|
40
40
|
@config = Yajl::Parser.parse(open("http://#{@host}:#{@port}/pools/default"))
|
41
|
-
@num_nodes = @config[
|
42
|
-
@buckets_spec = params[:buckets_spec] ||
|
41
|
+
@num_nodes = @config['nodes'].size
|
42
|
+
@buckets_spec = params[:buckets_spec] || 'default:' # "default:,protected:secret,cache::memcache"
|
43
43
|
end
|
44
44
|
|
45
45
|
def start
|
@@ -67,17 +67,17 @@ class CouchbaseMock
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def initialize(params = {})
|
70
|
-
@host =
|
70
|
+
@host = '127.0.0.1'
|
71
71
|
@port = 0
|
72
72
|
@num_nodes = 10
|
73
73
|
@num_vbuckets = 4096
|
74
|
-
@buckets_spec =
|
74
|
+
@buckets_spec = 'default:' # "default:,protected:secret,cache::memcache"
|
75
75
|
params.each do |key, value|
|
76
76
|
send("#{key}=", value)
|
77
77
|
end
|
78
78
|
yield self if block_given?
|
79
79
|
if @num_vbuckets < 1 || (@num_vbuckets & (@num_vbuckets - 1) != 0)
|
80
|
-
raise ArgumentError,
|
80
|
+
raise ArgumentError, 'Number of vbuckets should be a power of two and greater than zero'
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
@@ -86,15 +86,15 @@ class CouchbaseMock
|
|
86
86
|
@monitor.socket = TCPServer.new(nil, 0)
|
87
87
|
@monitor.socket.listen(10)
|
88
88
|
_, @monitor.port, _, _ = @monitor.socket.addr
|
89
|
-
trap(
|
90
|
-
puts
|
89
|
+
trap('CLD') do
|
90
|
+
puts 'CouchbaseMock.jar died unexpectedly during startup'
|
91
91
|
exit(1)
|
92
92
|
end
|
93
93
|
@monitor.pid = fork
|
94
94
|
if @monitor.pid.nil?
|
95
95
|
rc = exec(command_line("--harakiri-monitor=:#{@monitor.port}"))
|
96
96
|
else
|
97
|
-
trap(
|
97
|
+
trap('CLD', 'SIG_DFL')
|
98
98
|
@monitor.client, _ = @monitor.socket.accept
|
99
99
|
@port = @monitor.client.recv(100).to_i
|
100
100
|
end
|
@@ -103,15 +103,15 @@ class CouchbaseMock
|
|
103
103
|
def stop
|
104
104
|
@monitor.client.close
|
105
105
|
@monitor.socket.close
|
106
|
-
Process.kill(
|
106
|
+
Process.kill('TERM', @monitor.pid)
|
107
107
|
Process.wait(@monitor.pid)
|
108
108
|
end
|
109
109
|
|
110
|
-
def failover_node(index, bucket =
|
110
|
+
def failover_node(index, bucket = 'default')
|
111
111
|
@monitor.client.send("failover,#{index},#{bucket}", 0)
|
112
112
|
end
|
113
113
|
|
114
|
-
def respawn_node(index, bucket =
|
114
|
+
def respawn_node(index, bucket = 'default')
|
115
115
|
@monitor.client.send("respawn,#{index},#{bucket}", 0)
|
116
116
|
end
|
117
117
|
|
@@ -137,7 +137,7 @@ class MiniTest::Unit::TestCase
|
|
137
137
|
mock = CouchbaseServer.new(params)
|
138
138
|
if (params[:port] && mock.port != params[:port]) ||
|
139
139
|
(params[:host] && mock.host != params[:host]) ||
|
140
|
-
mock.buckets_spec !=
|
140
|
+
mock.buckets_spec != 'default:'
|
141
141
|
skip("Unable to configure real cluster. Requested config is: #{params.inspect}")
|
142
142
|
end
|
143
143
|
else
|
@@ -163,6 +163,6 @@ class MiniTest::Unit::TestCase
|
|
163
163
|
end
|
164
164
|
|
165
165
|
def uniq_id(*suffixes)
|
166
|
-
[caller.first[/.*[` ](.*)'/, 1], suffixes].join(
|
166
|
+
[caller.first[/.*[` ](.*)'/, 1], suffixes].join('_')
|
167
167
|
end
|
168
168
|
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.utc(
|
24
|
+
attribute :created_at, :default => lambda { Time.utc('2010-01-01') }
|
25
25
|
end
|
26
26
|
|
27
27
|
class ValidPost < Couchbase::Model
|
@@ -50,6 +50,10 @@ class Comments < Couchbase::Model
|
|
50
50
|
attribute :comments, :default => []
|
51
51
|
end
|
52
52
|
|
53
|
+
class User < Couchbase::Model
|
54
|
+
design_document :people
|
55
|
+
end
|
56
|
+
|
53
57
|
class TestModel < MiniTest::Unit::TestCase
|
54
58
|
|
55
59
|
def setup
|
@@ -64,80 +68,86 @@ class TestModel < MiniTest::Unit::TestCase
|
|
64
68
|
stop_mock(@mock)
|
65
69
|
end
|
66
70
|
|
71
|
+
def test_design_document
|
72
|
+
assert_equal 'people', User.design_document
|
73
|
+
assert_equal 'new_people', User.design_document('new_people')
|
74
|
+
assert_equal 'post', Post.design_document
|
75
|
+
end
|
76
|
+
|
67
77
|
def test_it_supports_value_property
|
68
78
|
doc = {
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
79
|
+
'id' => 'x',
|
80
|
+
'key' => 'x',
|
81
|
+
'value' => 'x',
|
82
|
+
'doc' => {
|
83
|
+
'value' => {'title' => 'foo'}
|
74
84
|
}
|
75
85
|
}
|
76
86
|
post = Post.wrap(Post.bucket, doc)
|
77
|
-
assert_equal
|
87
|
+
assert_equal 'foo', post.title
|
78
88
|
end
|
79
89
|
|
80
90
|
def test_it_supports_json_property
|
81
91
|
doc = {
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
92
|
+
'id' => 'x',
|
93
|
+
'key' => 'x',
|
94
|
+
'value' => 'x',
|
95
|
+
'doc' => {
|
96
|
+
'json' => {'title' => 'foo'}
|
87
97
|
}
|
88
98
|
}
|
89
99
|
post = Post.wrap(Post.bucket, doc)
|
90
|
-
assert_equal
|
100
|
+
assert_equal 'foo', post.title
|
91
101
|
end
|
92
102
|
|
93
103
|
def test_assigns_attributes_from_the_hash
|
94
|
-
post = Post.new(:title =>
|
95
|
-
assert_equal
|
104
|
+
post = Post.new(:title => 'Hello, world')
|
105
|
+
assert_equal 'Hello, world', post.title
|
96
106
|
refute post.body
|
97
107
|
refute post.id
|
98
108
|
end
|
99
109
|
|
100
110
|
def test_uses_default_value_or_nil
|
101
|
-
post = Post.new(:title =>
|
111
|
+
post = Post.new(:title => 'Hello, world')
|
102
112
|
refute post.body
|
103
113
|
assert_equal 'Anonymous', post.author
|
104
114
|
assert_equal 'Anonymous', post.attributes[:author]
|
105
115
|
end
|
106
116
|
|
107
117
|
def test_allows_lambda_as_default_value
|
108
|
-
post = Post.new(:title =>
|
109
|
-
expected = Time.utc(
|
118
|
+
post = Post.new(:title => 'Hello, world')
|
119
|
+
expected = Time.utc('2010-01-01')
|
110
120
|
assert_equal expected, post.created_at
|
111
121
|
assert_equal expected, post.attributes[:created_at]
|
112
122
|
end
|
113
123
|
|
114
124
|
def test_assings_id_and_saves_the_object
|
115
|
-
post = Post.create(:title =>
|
125
|
+
post = Post.create(:title => 'Hello, world')
|
116
126
|
assert post.id
|
117
127
|
end
|
118
128
|
|
119
129
|
def test_updates_attributes
|
120
|
-
post = Post.create(:title =>
|
121
|
-
post.update(:body =>
|
122
|
-
assert_equal
|
130
|
+
post = Post.create(:title => 'Hello, world')
|
131
|
+
post.update(:body => 'This is my first example')
|
132
|
+
assert_equal 'This is my first example', post.body
|
123
133
|
end
|
124
134
|
|
125
135
|
def test_refreshes_the_attributes_with_reload_method
|
126
|
-
orig = Post.create(:title =>
|
136
|
+
orig = Post.create(:title => 'Hello, world')
|
127
137
|
double = Post.find(orig.id)
|
128
|
-
double.update(:title =>
|
138
|
+
double.update(:title => 'Good bye, world')
|
129
139
|
orig.reload
|
130
|
-
assert_equal
|
140
|
+
assert_equal 'Good bye, world', orig.title
|
131
141
|
end
|
132
142
|
|
133
143
|
def test_it_raises_not_found_exception
|
134
144
|
assert_raises Couchbase::Error::NotFound do
|
135
|
-
Post.find(
|
145
|
+
Post.find('missing_key')
|
136
146
|
end
|
137
147
|
end
|
138
148
|
|
139
149
|
def test_it_returns_nil_when_key_not_found
|
140
|
-
refute Post.find_by_id(
|
150
|
+
refute Post.find_by_id('missing_key')
|
141
151
|
end
|
142
152
|
|
143
153
|
def test_doesnt_raise_if_the_attribute_redefined
|
@@ -163,22 +173,22 @@ class TestModel < MiniTest::Unit::TestCase
|
|
163
173
|
end
|
164
174
|
|
165
175
|
def test_allows_arbitrary_ids
|
166
|
-
Post.create(:id => uniq_id, :title =>
|
167
|
-
assert_equal
|
176
|
+
Post.create(:id => uniq_id, :title => 'Foo')
|
177
|
+
assert_equal 'Foo', Post.find(uniq_id).title
|
168
178
|
end
|
169
179
|
|
170
180
|
def test_returns_an_instance_of_post
|
171
181
|
Post.bucket.set(uniq_id, {:title => 'foo'})
|
172
182
|
assert Post.find(uniq_id).kind_of?(Post)
|
173
183
|
assert_equal uniq_id, Post.find(uniq_id).id
|
174
|
-
assert_equal
|
184
|
+
assert_equal 'foo', Post.find(uniq_id).title
|
175
185
|
end
|
176
186
|
|
177
187
|
def test_changes_its_attributes
|
178
|
-
post = Post.create(:title =>
|
179
|
-
post.title =
|
188
|
+
post = Post.create(:title => 'Hello, world')
|
189
|
+
post.title = 'Good bye, world'
|
180
190
|
post.save.reload
|
181
|
-
assert_equal
|
191
|
+
assert_equal 'Good bye, world', post.title
|
182
192
|
end
|
183
193
|
|
184
194
|
def test_assings_a_new_id_to_each_record
|
@@ -199,7 +209,7 @@ class TestModel < MiniTest::Unit::TestCase
|
|
199
209
|
end
|
200
210
|
|
201
211
|
def test_fails_to_delete_model_without_id
|
202
|
-
post = Post.new(:title =>
|
212
|
+
post = Post.new(:title => 'Hello')
|
203
213
|
refute post.id
|
204
214
|
assert_raises Couchbase::Error::MissingId do
|
205
215
|
post.delete
|
@@ -207,38 +217,38 @@ class TestModel < MiniTest::Unit::TestCase
|
|
207
217
|
end
|
208
218
|
|
209
219
|
def test_belongs_to_assoc
|
210
|
-
brewery = Brewery.create(:name =>
|
220
|
+
brewery = Brewery.create(:name => 'Anheuser-Busch')
|
211
221
|
assert_includes Beer.attributes.keys, :brewery_id
|
212
|
-
beer = Beer.create(:name =>
|
222
|
+
beer = Beer.create(:name => 'Budweiser', :brewery_id => brewery.id)
|
213
223
|
assert_respond_to beer, :brewery
|
214
224
|
assoc = beer.brewery
|
215
225
|
assert_instance_of Brewery, assoc
|
216
|
-
assert_equal
|
226
|
+
assert_equal 'Anheuser-Busch', assoc.name
|
217
227
|
end
|
218
228
|
|
219
229
|
def test_to_key
|
220
|
-
assert_equal [
|
221
|
-
assert_equal [
|
230
|
+
assert_equal ['the-id'], Post.new(:id => 'the-id').to_key
|
231
|
+
assert_equal ['the-key'], Post.new(:key => 'the-key').to_key
|
222
232
|
end
|
223
233
|
|
224
234
|
def test_to_param
|
225
|
-
assert_equal
|
226
|
-
assert_equal
|
235
|
+
assert_equal 'the-id', Post.new(:id => 'the-id').to_param
|
236
|
+
assert_equal 'the-key', Post.new(:key => ['the', 'key']).to_param
|
227
237
|
end
|
228
238
|
|
229
239
|
def test_as_json
|
230
240
|
require 'active_support/json/encoding'
|
231
241
|
|
232
242
|
response = {'id' => 'the-id'}
|
233
|
-
assert_equal response, Post.new(:id =>
|
243
|
+
assert_equal response, Post.new(:id => 'the-id').as_json
|
234
244
|
|
235
245
|
response = {}
|
236
|
-
assert_equal response, Post.new(:id =>
|
246
|
+
assert_equal response, Post.new(:id => 'the-id').as_json(:except => :id)
|
237
247
|
end
|
238
248
|
|
239
249
|
def test_validation
|
240
250
|
post = ValidPost.create(:title => 'Hello, World!')
|
241
|
-
assert post.valid?,
|
251
|
+
assert post.valid?, 'post with title should be valid'
|
242
252
|
post.title = nil
|
243
253
|
refute post.save
|
244
254
|
assert_raises(Couchbase::Error::RecordInvalid) do
|
@@ -261,4 +271,32 @@ class TestModel < MiniTest::Unit::TestCase
|
|
261
271
|
assert_equal Couchbase::Model, Comments.couchbase_ancestor
|
262
272
|
end
|
263
273
|
|
274
|
+
def test_returns_multiple_instances_of_post
|
275
|
+
Post.create(:id => uniq_id('first'), :title => 'foo')
|
276
|
+
Post.create(:id => uniq_id('second'), :title => 'bar')
|
277
|
+
|
278
|
+
results = Post.find([uniq_id('first'), uniq_id('second')])
|
279
|
+
assert results.kind_of?(Array)
|
280
|
+
assert results.size == 2
|
281
|
+
assert results.detect { |post| post.id == uniq_id('first') }.title == 'foo'
|
282
|
+
assert results.detect { |post| post.id == uniq_id('second') }.title == 'bar'
|
283
|
+
end
|
284
|
+
|
285
|
+
def test_returns_array_for_array_of_ids
|
286
|
+
Post.create(:id => uniq_id('first'), :title => 'foo')
|
287
|
+
|
288
|
+
results = Post.find([uniq_id('first')])
|
289
|
+
assert results.kind_of?(Array)
|
290
|
+
assert results.size == 1
|
291
|
+
assert results[0].title == 'foo'
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_returns_array_for_array_of_ids_using_find_by_id
|
295
|
+
Post.create(:id => uniq_id('first'), :title => 'foo')
|
296
|
+
|
297
|
+
results = Post.find_by_id([uniq_id('first')])
|
298
|
+
assert results.kind_of?(Array)
|
299
|
+
assert results.size == 1
|
300
|
+
assert results[0].title == 'foo'
|
301
|
+
end
|
264
302
|
end
|
metadata
CHANGED
@@ -1,70 +1,90 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: couchbase-model
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 13
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 5
|
9
|
+
- 3
|
10
|
+
version: 0.5.3
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Couchbase
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
|
18
|
+
date: 2013-06-06 00:00:00 +03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
type: :runtime
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
17
24
|
none: false
|
18
|
-
requirements:
|
25
|
+
requirements:
|
19
26
|
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
|
22
|
-
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 27
|
29
|
+
segments:
|
30
|
+
- 1
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
version: 1.3.0
|
34
|
+
name: couchbase
|
35
|
+
version_requirements: *id001
|
23
36
|
prerelease: false
|
24
|
-
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
type: :development
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
25
40
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
version: "0"
|
31
48
|
name: rake
|
32
|
-
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '0'
|
38
|
-
type: :development
|
49
|
+
version_requirements: *id002
|
39
50
|
prerelease: false
|
40
|
-
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
type: :development
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
54
|
none: false
|
42
|
-
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
|
46
|
-
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
47
62
|
name: minitest
|
48
|
-
|
49
|
-
none: false
|
50
|
-
requirements:
|
51
|
-
- - ! '>='
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
|
-
type: :development
|
63
|
+
version_requirements: *id003
|
55
64
|
prerelease: false
|
56
|
-
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
type: :development
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
57
68
|
none: false
|
58
|
-
requirements:
|
59
|
-
- -
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
name: activesupport
|
77
|
+
version_requirements: *id004
|
78
|
+
prerelease: false
|
62
79
|
description: ORM-like interface allows you to persist your models to Couchbase
|
63
80
|
email: support@couchbase.com
|
64
81
|
executables: []
|
82
|
+
|
65
83
|
extensions: []
|
84
|
+
|
66
85
|
extra_rdoc_files: []
|
67
|
-
|
86
|
+
|
87
|
+
files:
|
68
88
|
- .gitignore
|
69
89
|
- .travis.yml
|
70
90
|
- .yardopts
|
@@ -96,28 +116,39 @@ files:
|
|
96
116
|
- test/test_model.rb
|
97
117
|
- test/test_model_rails_integration.rb
|
98
118
|
- test/test_uuid.rb
|
119
|
+
has_rdoc: true
|
99
120
|
homepage: https://github.com/couchbase/couchbase-ruby-model
|
100
121
|
licenses: []
|
122
|
+
|
101
123
|
post_install_message:
|
102
124
|
rdoc_options: []
|
103
|
-
|
125
|
+
|
126
|
+
require_paths:
|
104
127
|
- lib
|
105
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
129
|
none: false
|
107
|
-
requirements:
|
108
|
-
- -
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
|
111
|
-
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
hash: 3
|
134
|
+
segments:
|
135
|
+
- 0
|
136
|
+
version: "0"
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
138
|
none: false
|
113
|
-
requirements:
|
114
|
-
- -
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
hash: 3
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
version: "0"
|
117
146
|
requirements: []
|
147
|
+
|
118
148
|
rubyforge_project:
|
119
|
-
rubygems_version: 1.
|
149
|
+
rubygems_version: 1.6.2
|
120
150
|
signing_key:
|
121
151
|
specification_version: 3
|
122
152
|
summary: Declarative interface to Couchbase
|
123
153
|
test_files: []
|
154
|
+
|