couchbase-model 0.5.2 → 0.5.3
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 +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
|
+
|