couchbase-orm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Couchbase <info@couchbase.com>
4
+ # Copyright:: 2012 Couchbase, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'rails/generators/couchbase_orm_generator'
21
+
22
+ module CouchbaseOrm
23
+ module Generators
24
+ class ConfigGenerator < Rails::Generators::Base
25
+ desc 'Creates a Couchbase configuration file at config/couchbase.yml'
26
+ argument :database_name, :type => :string, :optional => true
27
+
28
+ def self.source_root
29
+ @_couchbase_source_root ||= File.expand_path('../templates', __FILE__)
30
+ end
31
+
32
+ def app_name
33
+ Rails::Application.subclasses.first.parent.to_s.underscore
34
+ end
35
+
36
+ def create_config_file
37
+ template 'couchbase.yml', File.join('config', 'couchbase.yml')
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ common: &common
2
+ hosts: localhost
3
+ password:
4
+
5
+ development:
6
+ <<: *common
7
+ bucket: <%= database_name || 'default' %>
8
+
9
+ test:
10
+ <<: *common
11
+ bucket: <%= database_name || app_name %>_test
12
+ password: for_test_bucket
13
+
14
+ # set these environment variables on your production server
15
+ production:
16
+ hosts: <%%= ENV['COUCHBASE_HOST'] || ENV['COUCHBASE_HOSTS'] %>
17
+ bucket: <%%= ENV['COUCHBASE_BUCKET'] %>
18
+ password: <%%= ENV['COUCHBASE_PASSWORD'] %>
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Couchbase <info@couchbase.com>
4
+ # Copyright:: 2012 Couchbase, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'rails/generators/named_base'
21
+ require 'rails/generators/active_model'
22
+
23
+ module CouchbaseOrm #:nodoc:
24
+ module Generators #:nodoc:
25
+
26
+ class Base < ::Rails::Generators::NamedBase #:nodoc:
27
+
28
+ def self.source_root
29
+ @_couchbase_source_root ||=
30
+ File.expand_path("../#{base_name}/#{generator_name}/templates", __FILE__)
31
+ end
32
+
33
+ unless methods.include?(:module_namespacing)
34
+ def module_namespacing(&block)
35
+ yield if block
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ require File.expand_path("../support", __FILE__)
4
+
5
+
6
+ class Parent < CouchbaseOrm::Base
7
+ attribute :name
8
+ end
9
+
10
+ class Child < CouchbaseOrm::Base
11
+ attribute :name
12
+
13
+ belongs_to :parent, dependent: :destroy
14
+ end
15
+
16
+
17
+ describe CouchbaseOrm::Associations do
18
+ it "should work with dependent associations" do
19
+ parent = Parent.create!(name: 'joe')
20
+ child = Child.create!(name: 'bob', parent_id: parent.id)
21
+
22
+ expect(parent.persisted?).to be(true)
23
+ expect(child.persisted?).to be(true)
24
+ id = parent.id
25
+
26
+ child.destroy
27
+ expect(child.destroyed?).to be(true)
28
+ expect(parent.destroyed?).to be(false)
29
+
30
+ # Ensure that parent has been destroyed
31
+ expect { Parent.find(id) }.to raise_error(Libcouchbase::Error::KeyNotFound)
32
+ expect(Parent.find_by_id(id)).to be(nil)
33
+
34
+ expect { parent.reload }.to raise_error(Libcouchbase::Error::KeyNotFound)
35
+
36
+ # Save will always return true unless the model is changed (won't touch the database)
37
+ parent.name = 'should fail'
38
+ expect { parent.save }.to raise_error(Libcouchbase::Error::KeyNotFound)
39
+ expect { parent.save! }.to raise_error(Libcouchbase::Error::KeyNotFound)
40
+ end
41
+
42
+ it "should cache associations" do
43
+ parent = Parent.create!(name: 'joe')
44
+ child = Child.create!(name: 'bob', parent_id: parent.id)
45
+
46
+ id = child.parent.__id__
47
+ expect(parent.__id__).not_to eq(child.parent.__id__)
48
+ expect(parent).to eq(child.parent)
49
+ expect(child.parent.__id__).to eq(id)
50
+
51
+ child.reload
52
+ expect(parent).to eq(child.parent)
53
+ expect(child.parent.__id__).not_to eq(id)
54
+
55
+ child.destroy
56
+ end
57
+
58
+ it "should ignore associations when delete is used" do
59
+ parent = Parent.create!(name: 'joe')
60
+ child = Child.create!(name: 'bob', parent_id: parent.id)
61
+
62
+ id = child.id
63
+ child.delete
64
+
65
+ expect(Child.exists?(id)).to be(false)
66
+ expect(Parent.exists?(parent.id)).to be(true)
67
+
68
+ id = parent.id
69
+ parent.delete
70
+ expect(Parent.exists?(id)).to be(false)
71
+ end
72
+
73
+ describe Parent do
74
+ it_behaves_like "ActiveModel"
75
+ end
76
+
77
+ describe Child do
78
+ it_behaves_like "ActiveModel"
79
+ end
80
+ end
data/spec/base_spec.rb ADDED
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ require File.expand_path("../support", __FILE__)
4
+
5
+
6
+ class BaseTest < CouchbaseOrm::Base
7
+ attribute :name, :job
8
+ end
9
+
10
+ class CompareTest < CouchbaseOrm::Base
11
+ attribute :age
12
+ end
13
+
14
+
15
+
16
+ describe CouchbaseOrm::Base do
17
+ it "should be comparable to other objects" do
18
+ base = BaseTest.create!(name: 'joe')
19
+ base2 = BaseTest.create!(name: 'joe')
20
+
21
+ expect(base).to eq(base)
22
+ expect(base).to be(base)
23
+ expect(base).not_to eq(base2)
24
+
25
+ same_base = BaseTest.find(base.id)
26
+ expect(base).to eq(same_base)
27
+ expect(base).not_to be(same_base)
28
+ expect(base2).not_to eq(same_base)
29
+
30
+ base.delete
31
+ base2.delete
32
+ end
33
+
34
+ it "should load database responses" do
35
+ base = BaseTest.create!(name: 'joe')
36
+ resp = BaseTest.bucket.get(base.id, extended: true)
37
+
38
+ expect(resp.key).to eq(base.id)
39
+
40
+ base_loaded = BaseTest.new(resp)
41
+ expect(base_loaded).to eq(base)
42
+ expect(base_loaded).not_to be(base)
43
+
44
+ base.destroy
45
+ end
46
+
47
+ it "should not load objects if there is a type mismatch" do
48
+ base = BaseTest.create!(name: 'joe')
49
+
50
+ expect { CompareTest.find_by_id(base.id) }.to raise_error(RuntimeError)
51
+
52
+ base.destroy
53
+ end
54
+
55
+ it "should support serialisation" do
56
+ base = BaseTest.create!(name: 'joe')
57
+
58
+ base_id = base.id
59
+ expect(base.to_json).to eq({name: 'joe', job: nil, id: base_id}.to_json)
60
+ expect(base.to_json(only: :name)).to eq({name: 'joe'}.to_json)
61
+
62
+ base.destroy
63
+ end
64
+
65
+ describe BaseTest do
66
+ it_behaves_like "ActiveModel"
67
+ end
68
+
69
+ describe CompareTest do
70
+ it_behaves_like "ActiveModel"
71
+ end
72
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ require File.expand_path("../support", __FILE__)
4
+
5
+
6
+ class ObjectRatingTest < CouchbaseOrm::Base
7
+ join :object_test, :rating_test
8
+ view :all
9
+ end
10
+
11
+ class RatingTest < CouchbaseOrm::Base
12
+ enum rating: [:awesome, :good, :okay, :bad], default: :okay
13
+ belongs_to :object_test
14
+
15
+ has_many :object_tests, through: :object_rating_test
16
+ view :all
17
+ end
18
+
19
+ class ObjectTest < CouchbaseOrm::Base
20
+ attribute :name, type: String
21
+ has_many :rating_tests, dependent: :destroy
22
+
23
+ view :all
24
+ end
25
+
26
+
27
+ describe CouchbaseOrm::HasMany do
28
+ before :all do
29
+ RatingTest.ensure_design_document!
30
+ ObjectTest.ensure_design_document!
31
+ ObjectRatingTest.ensure_design_document!
32
+ end
33
+
34
+ after :each do
35
+ ObjectTest.all.stream { |ob| ob.delete }
36
+ RatingTest.all.stream { |ob| ob.delete }
37
+ ObjectRatingTest.all.stream { |ob| ob.delete }
38
+ end
39
+
40
+ it "should return matching results" do
41
+ first = ObjectTest.create! name: :bob
42
+ second = ObjectTest.create! name: :jane
43
+
44
+ rate = RatingTest.create! rating: :awesome, object_test: first
45
+ RatingTest.create! rating: :bad, object_test: second
46
+ RatingTest.create! rating: :good, object_test: first
47
+
48
+ expect(rate.object_test_id).to eq(first.id)
49
+ expect(RatingTest.respond_to?(:find_by_object_test_id)).to be(true)
50
+ expect(first.respond_to?(:rating_tests)).to be(true)
51
+
52
+ docs = first.rating_tests.collect { |ob|
53
+ ob.rating
54
+ }
55
+
56
+ expect(docs).to eq([1, 2])
57
+
58
+ first.destroy
59
+ expect { RatingTest.find rate.id }.to raise_error(::Libcouchbase::Error::KeyNotFound)
60
+ expect(RatingTest.all.count).to be(1)
61
+ end
62
+
63
+ it "should work through a join model" do
64
+ first = ObjectTest.create! name: :bob
65
+ second = ObjectTest.create! name: :jane
66
+
67
+ rate1 = RatingTest.create! rating: :awesome, object_test: first
68
+ rate2 = RatingTest.create! rating: :bad, object_test: second
69
+ rate3 = RatingTest.create! rating: :good, object_test: first
70
+
71
+ ort = ObjectRatingTest.create! object_test: first, rating_test: rate1
72
+ ObjectRatingTest.create! object_test: second, rating_test: rate1
73
+
74
+ expect(ort.rating_test_id).to eq(rate1.id)
75
+ expect(rate1.respond_to?(:object_tests)).to be(true)
76
+ docs = rate1.object_tests.collect { |ob|
77
+ ob.name
78
+ }
79
+
80
+ expect(docs).to eq(['bob', 'jane'])
81
+ end
82
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ require 'couchbase-orm'
4
+ require 'thread'
5
+
6
+ class IdTestModel < CouchbaseOrm::Base; end
7
+
8
+ describe CouchbaseOrm::IdGenerator do
9
+ it "should not generate ID clashes" do
10
+ model = IdTestModel.new
11
+
12
+ ids1 = []
13
+ thread1 = Thread.new do
14
+ (1..10000).each {
15
+ ids1 << CouchbaseOrm::IdGenerator.next(model)
16
+ }
17
+ end
18
+
19
+ ids2 = []
20
+ thread2 = Thread.new do
21
+ (1..10000).each {
22
+ ids2 << CouchbaseOrm::IdGenerator.next(model)
23
+ }
24
+ end
25
+
26
+ ids3 = []
27
+ thread3 = Thread.new do
28
+ (1..10000).each {
29
+ ids3 << CouchbaseOrm::IdGenerator.next(model)
30
+ }
31
+ end
32
+
33
+ ids4 = []
34
+ thread4 = Thread.new do
35
+ (1..10000).each {
36
+ ids4 << CouchbaseOrm::IdGenerator.next(model)
37
+ }
38
+ end
39
+
40
+ thread1.join
41
+ thread2.join
42
+ thread3.join
43
+ thread4.join
44
+
45
+ results = [ids1, ids2, ids3, ids4].flatten
46
+ expect(results.uniq).to eq(results)
47
+ end
48
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ require File.expand_path("../support", __FILE__)
4
+
5
+
6
+ class IndexTest < CouchbaseOrm::Base
7
+ attribute :email
8
+ ensure_unique :email
9
+ end
10
+
11
+ class EnumTest < CouchbaseOrm::Base
12
+ enum visibility: [:group, :authority, :public], default: :authority
13
+ end
14
+
15
+
16
+ describe CouchbaseOrm::Index do
17
+ it "should prevent models being created if they should have unique keys" do
18
+ joe = IndexTest.create!(email: 'joe@aca.com')
19
+ expect { IndexTest.create!(email: 'joe@aca.com') }.to raise_error(CouchbaseOrm::Error::RecordInvalid)
20
+
21
+ joe.email = 'other@aca.com'
22
+ joe.save
23
+ other = IndexTest.new(email: 'joe@aca.com')
24
+ expect(other.save).to be(true)
25
+
26
+ expect { IndexTest.create!(email: 'joe@aca.com') }.to raise_error(CouchbaseOrm::Error::RecordInvalid)
27
+ expect { IndexTest.create!(email: 'other@aca.com') }.to raise_error(CouchbaseOrm::Error::RecordInvalid)
28
+
29
+ joe.destroy
30
+ other.destroy
31
+
32
+ again = IndexTest.new(email: 'joe@aca.com')
33
+ expect(again.save).to be(true)
34
+
35
+ again.destroy
36
+ end
37
+
38
+ it "should provide helper methods for looking up the model" do
39
+ joe = IndexTest.create!(email: 'joe@aca.com')
40
+
41
+ joe_again = IndexTest.find_by_email('joe@aca.com')
42
+ expect(joe).to eq(joe_again)
43
+
44
+ joe.destroy
45
+ end
46
+
47
+ it "should clean up itself if dangling keys are left" do
48
+ joe = IndexTest.create!(email: 'joe@aca.com')
49
+ joe.delete # no callbacks are executed
50
+
51
+ again = IndexTest.new(email: 'joe@aca.com')
52
+ expect(again.save).to be(true)
53
+
54
+ again.destroy
55
+ end
56
+
57
+ it "should work with enumerators" do
58
+ # Test symbol
59
+ enum = EnumTest.create!(visibility: :public)
60
+ expect(enum.visibility).to eq(3)
61
+ enum.destroy
62
+
63
+ # Test number
64
+ enum = EnumTest.create!(visibility: 2)
65
+ expect(enum.visibility).to eq(2)
66
+ enum.destroy
67
+
68
+ # Test default
69
+ enum = EnumTest.create!
70
+ expect(enum.visibility).to eq(2)
71
+ enum.destroy
72
+ end
73
+ end