couchbase-jruby-model 0.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +203 -0
- data/README.md +155 -0
- data/Rakefile +22 -0
- data/couchbase-jruby-model.gemspec +27 -0
- data/lib/couchbase-jruby-model.rb +23 -0
- data/lib/couchbase/active_model.rb +69 -0
- data/lib/couchbase/model.rb +859 -0
- data/lib/couchbase/model/configuration.rb +30 -0
- data/lib/couchbase/model/ext/camelize.rb +23 -0
- data/lib/couchbase/model/ext/constantize.rb +29 -0
- data/lib/couchbase/model/ext/singleton_class.rb +24 -0
- data/lib/couchbase/model/uuid.rb +113 -0
- data/lib/couchbase/model/version.rb +26 -0
- data/lib/couchbase/railtie.rb +142 -0
- data/lib/rails/generators/couchbase/config/config_generator.rb +43 -0
- data/lib/rails/generators/couchbase/config/templates/couchbase.yml +23 -0
- data/lib/rails/generators/couchbase/view/templates/map.js +40 -0
- data/lib/rails/generators/couchbase/view/templates/reduce.js +61 -0
- data/lib/rails/generators/couchbase/view/view_generator.rb +43 -0
- data/lib/rails/generators/couchbase_generator.rb +42 -0
- data/tasks/package.rake +27 -0
- data/tasks/test.rake +34 -0
- data/tasks/util.rake +21 -0
- data/test/setup.rb +168 -0
- data/test/test_active_model_integration.rb +124 -0
- data/test/test_model.rb +311 -0
- data/test/test_model_rails_integration.rb +76 -0
- data/test/test_uuid.rb +32 -0
- metadata +151 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
// The map function is the most critical part of any view as it provides the
|
2
|
+
// logical mapping between the input fields of the individual objects stored
|
3
|
+
// within Couchbase to the information output when the view is accessed.
|
4
|
+
//
|
5
|
+
// Read more about how to write map functions at:
|
6
|
+
// http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-writing-map.html
|
7
|
+
|
8
|
+
function(doc, meta) {
|
9
|
+
emit(meta.id, null);
|
10
|
+
}
|
11
|
+
|
12
|
+
// You can also check out following examples
|
13
|
+
//
|
14
|
+
// The simplest example of a map function:
|
15
|
+
//
|
16
|
+
// function(doc, meta) {
|
17
|
+
// emit(meta.id, doc);
|
18
|
+
// }
|
19
|
+
//
|
20
|
+
// Slightly more complex example of a function that defines a view on values
|
21
|
+
// computed from customer documents:
|
22
|
+
//
|
23
|
+
// function(doc, meta) {
|
24
|
+
// if (doc.type == "customer") {
|
25
|
+
// emit(meta.id, {last_name: doc.last_name, first_name: doc.first_name});
|
26
|
+
// }
|
27
|
+
// }
|
28
|
+
//
|
29
|
+
// To be able to filter or sort the view by some document property, you
|
30
|
+
// would use that property for the key. For example, the following view
|
31
|
+
// would allow you to lookup customer documents by the last_name or
|
32
|
+
// first_name fields (your keys could be compound, e.g. arrays):
|
33
|
+
//
|
34
|
+
// function(doc, meta) {
|
35
|
+
// if (doc.type == "customer") {
|
36
|
+
// emit(doc.last_name, {first_name: doc.first_name});
|
37
|
+
// emit(doc.first_name, {last_name: doc.last_name});
|
38
|
+
// }
|
39
|
+
// }
|
40
|
+
//
|
@@ -0,0 +1,61 @@
|
|
1
|
+
// If a view has a reduce function, it is used to produce aggregate results
|
2
|
+
// for that view. A reduce function is passed a set of intermediate values
|
3
|
+
// and combines them to a single value. Reduce functions must accept, as
|
4
|
+
// input, results emitted by its corresponding map function as well as
|
5
|
+
// results returned by the reduce function itself. The latter case is
|
6
|
+
// referred to as a rereduce.
|
7
|
+
//
|
8
|
+
// function (key, values, rereduce) {
|
9
|
+
// return sum(values);
|
10
|
+
// }
|
11
|
+
//
|
12
|
+
// Reduce functions must handle two cases:
|
13
|
+
//
|
14
|
+
// 1. When rereduce is false:
|
15
|
+
//
|
16
|
+
// reduce([ [key1,id1], [key2,id2], [key3,id3] ], [value1,value2,value3], false)
|
17
|
+
//
|
18
|
+
// * key will be an array whose elements are arrays of the form [key,id],
|
19
|
+
// where key is a key emitted by the map function and id is that of the
|
20
|
+
// document from which the key was generated.
|
21
|
+
// * values will be an array of the values emitted for the respective
|
22
|
+
// elements in keys
|
23
|
+
//
|
24
|
+
// 2. When rereduce is true:
|
25
|
+
//
|
26
|
+
// reduce(null, [intermediate1,intermediate2,intermediate3], true)
|
27
|
+
//
|
28
|
+
// * key will be null
|
29
|
+
// * values will be an array of values returned by previous calls to the
|
30
|
+
// reduce function
|
31
|
+
//
|
32
|
+
// Reduce functions should return a single value, suitable for both the
|
33
|
+
// value field of the final view and as a member of the values array passed
|
34
|
+
// to the reduce function.
|
35
|
+
//
|
36
|
+
// NOTE: If this file is empty, reduce part will be skipped in design document
|
37
|
+
//
|
38
|
+
// There is number of built-in functions, which could be used instead of
|
39
|
+
// javascript implementation of reduce function.
|
40
|
+
//
|
41
|
+
// The _count function provides a simple count of the input rows from the
|
42
|
+
// map function, using the keys and group level to provide to provide a
|
43
|
+
// count of the correlated items. The values generated during the map()
|
44
|
+
// stage are ignored.
|
45
|
+
//
|
46
|
+
// _count
|
47
|
+
//
|
48
|
+
// The built-in _sum function collates the output from the map function
|
49
|
+
// call. The information can either be a single number or an array of numbers.
|
50
|
+
//
|
51
|
+
// _sum
|
52
|
+
//
|
53
|
+
// The _stats built-in produces statistical calculations for the input data.
|
54
|
+
// Like the _sum call the source information should be a number. The
|
55
|
+
// generated statistics include the sum, count, minimum (min), maximum (max)
|
56
|
+
// and sum squared (sumsqr) of the input rows.
|
57
|
+
//
|
58
|
+
// _stats
|
59
|
+
//
|
60
|
+
// Read more about how to write reduce functions at:
|
61
|
+
// http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-writing-reduce.html
|
@@ -0,0 +1,43 @@
|
|
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_generator'
|
21
|
+
|
22
|
+
module Couchbase
|
23
|
+
module Generators
|
24
|
+
class ViewGenerator < Rails::Generators::Base
|
25
|
+
desc 'Creates a Couchbase views skeletons for map/reduce functions'
|
26
|
+
|
27
|
+
argument :model_name, :type => :string
|
28
|
+
argument :view_name, :type => :string
|
29
|
+
|
30
|
+
source_root File.expand_path('../templates', __FILE__)
|
31
|
+
|
32
|
+
def app_name
|
33
|
+
Rails::Application.subclasses.first.parent.to_s.underscore
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_map_reduce_files
|
37
|
+
template 'map.js', File.join('app', 'models', model_name, view_name, 'map.js')
|
38
|
+
template 'reduce.js', File.join('app', 'models', model_name, view_name, 'reduce.js')
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -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 Couchbase #: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
|
data/tasks/package.rake
ADDED
@@ -0,0 +1,27 @@
|
|
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
|
+
# require 'rubygems/package_task'
|
19
|
+
|
20
|
+
# def gemspec
|
21
|
+
# @clean_gemspec ||= eval(File.read(File.expand_path('../../couchbase-model.gemspec', __FILE__)))
|
22
|
+
# end
|
23
|
+
|
24
|
+
# Gem::PackageTask.new(gemspec) do |pkg|
|
25
|
+
# pkg.need_tar = true
|
26
|
+
# end
|
27
|
+
|
data/tasks/test.rake
ADDED
@@ -0,0 +1,34 @@
|
|
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
|
+
require 'rake/testtask'
|
19
|
+
require 'rake/clean'
|
20
|
+
|
21
|
+
rule 'test/CouchbaseMock.jar' do |task|
|
22
|
+
jar_path = "0.5-SNAPSHOT/CouchbaseMock-0.5-20120726.220757-19.jar"
|
23
|
+
sh %{wget -q -O test/CouchbaseMock.jar http://files.couchbase.com/maven2/org/couchbase/mock/CouchbaseMock/#{jar_path}}
|
24
|
+
end
|
25
|
+
|
26
|
+
CLOBBER << 'test/CouchbaseMock.jar'
|
27
|
+
|
28
|
+
Rake::TestTask.new do |test|
|
29
|
+
test.libs << "test" << "."
|
30
|
+
test.pattern = 'test/test_*.rb'
|
31
|
+
test.options = '--verbose'
|
32
|
+
end
|
33
|
+
|
34
|
+
Rake::Task['test'].prerequisites.unshift('test/CouchbaseMock.jar')
|
data/tasks/util.rake
ADDED
@@ -0,0 +1,21 @@
|
|
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
|
+
desc 'Start an irb session and load the library.'
|
19
|
+
task :console do
|
20
|
+
exec "irb -I lib -rcouchbase-model"
|
21
|
+
end
|
data/test/setup.rb
ADDED
@@ -0,0 +1,168 @@
|
|
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
|
+
require 'minitest/autorun'
|
19
|
+
require 'couchbase'
|
20
|
+
require 'couchbase/model'
|
21
|
+
|
22
|
+
require 'socket'
|
23
|
+
require 'open-uri'
|
24
|
+
|
25
|
+
class CouchbaseServer
|
26
|
+
attr_accessor :host, :port, :num_nodes, :buckets_spec
|
27
|
+
|
28
|
+
def real?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(params = {})
|
33
|
+
@host, @port = ['localhost', 8091] #ENV['COUCHBASE_SERVER'].split(':')
|
34
|
+
@port = @port.to_i
|
35
|
+
|
36
|
+
if @host.nil? || @host.empty? || @port == 0
|
37
|
+
raise ArgumentError, 'Check COUCHBASE_SERVER variable. It should be hostname:port'
|
38
|
+
end
|
39
|
+
|
40
|
+
@config = MultiJson.load(open("http://#{@host}:#{@port}/pools/default"))
|
41
|
+
@num_nodes = @config['nodes'].size
|
42
|
+
@buckets_spec = params[:buckets_spec] || 'default:' # "default:,protected:secret,cache::memcache"
|
43
|
+
end
|
44
|
+
|
45
|
+
def start
|
46
|
+
# flush all buckets
|
47
|
+
@buckets_spec.split(',') do |bucket|
|
48
|
+
name, password, _ = bucket.split(':')
|
49
|
+
connection = Couchbase.new(:hostname => @host,
|
50
|
+
:port => @port,
|
51
|
+
:username => name,
|
52
|
+
:bucket => name,
|
53
|
+
:password => password)
|
54
|
+
connection.flush
|
55
|
+
end
|
56
|
+
end
|
57
|
+
def stop; end
|
58
|
+
end
|
59
|
+
|
60
|
+
class CouchbaseMock
|
61
|
+
Monitor = Struct.new(:pid, :client, :socket, :port)
|
62
|
+
|
63
|
+
attr_accessor :host, :port, :buckets_spec, :num_nodes, :num_vbuckets
|
64
|
+
|
65
|
+
def real?
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
def initialize(params = {})
|
70
|
+
@host = '127.0.0.1'
|
71
|
+
@port = 0
|
72
|
+
@num_nodes = 10
|
73
|
+
@num_vbuckets = 4096
|
74
|
+
@buckets_spec = 'default:' # "default:,protected:secret,cache::memcache"
|
75
|
+
params.each do |key, value|
|
76
|
+
send("#{key}=", value)
|
77
|
+
end
|
78
|
+
yield self if block_given?
|
79
|
+
if @num_vbuckets < 1 || (@num_vbuckets & (@num_vbuckets - 1) != 0)
|
80
|
+
raise ArgumentError, 'Number of vbuckets should be a power of two and greater than zero'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def start
|
85
|
+
@monitor = Monitor.new
|
86
|
+
@monitor.socket = TCPServer.new(nil, 0)
|
87
|
+
@monitor.socket.listen(10)
|
88
|
+
_, @monitor.port, _, _ = @monitor.socket.addr
|
89
|
+
trap('CLD') do
|
90
|
+
puts 'CouchbaseMock.jar died unexpectedly during startup'
|
91
|
+
exit(1)
|
92
|
+
end
|
93
|
+
@monitor.pid = fork
|
94
|
+
if @monitor.pid.nil?
|
95
|
+
rc = exec(command_line("--harakiri-monitor=:#{@monitor.port}"))
|
96
|
+
else
|
97
|
+
trap('CLD', 'SIG_DFL')
|
98
|
+
@monitor.client, _ = @monitor.socket.accept
|
99
|
+
@port = @monitor.client.recv(100).to_i
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def stop
|
104
|
+
@monitor.client.close
|
105
|
+
@monitor.socket.close
|
106
|
+
Process.kill('TERM', @monitor.pid)
|
107
|
+
Process.wait(@monitor.pid)
|
108
|
+
end
|
109
|
+
|
110
|
+
def failover_node(index, bucket = 'default')
|
111
|
+
@monitor.client.send("failover,#{index},#{bucket}", 0)
|
112
|
+
end
|
113
|
+
|
114
|
+
def respawn_node(index, bucket = 'default')
|
115
|
+
@monitor.client.send("respawn,#{index},#{bucket}", 0)
|
116
|
+
end
|
117
|
+
|
118
|
+
protected
|
119
|
+
|
120
|
+
def command_line(extra = nil)
|
121
|
+
cmd = "java -jar #{File.dirname(__FILE__)}/CouchbaseMock.jar"
|
122
|
+
cmd << " --host #{@host}" if @host
|
123
|
+
cmd << " --port #{@port}" if @port
|
124
|
+
cmd << " --nodes #{@num_nodes}" if @num_nodes
|
125
|
+
cmd << " --vbuckets #{@num_vbuckets}" if @num_vbuckets
|
126
|
+
cmd << " --buckets #{@buckets_spec}" if @buckets_spec
|
127
|
+
cmd << " #{extra}"
|
128
|
+
cmd
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class MiniTest::Unit::TestCase
|
133
|
+
|
134
|
+
def start_mock(params = {})
|
135
|
+
mock = nil
|
136
|
+
if true # ENV['COUCHBASE_SERVER']
|
137
|
+
mock = CouchbaseServer.new(params)
|
138
|
+
if (params[:port] && mock.port != params[:port]) ||
|
139
|
+
(params[:host] && mock.host != params[:host]) ||
|
140
|
+
mock.buckets_spec != 'default:'
|
141
|
+
skip("Unable to configure real cluster. Requested config is: #{params.inspect}")
|
142
|
+
end
|
143
|
+
else
|
144
|
+
mock = CouchbaseMock.new(params)
|
145
|
+
end
|
146
|
+
mock.start
|
147
|
+
mock
|
148
|
+
end
|
149
|
+
|
150
|
+
def stop_mock(mock)
|
151
|
+
assert(mock)
|
152
|
+
mock.stop
|
153
|
+
end
|
154
|
+
|
155
|
+
def with_mock(params = {})
|
156
|
+
mock = nil
|
157
|
+
if block_given?
|
158
|
+
mock = start_mock(params)
|
159
|
+
yield mock
|
160
|
+
end
|
161
|
+
ensure
|
162
|
+
stop_mock(mock) if mock
|
163
|
+
end
|
164
|
+
|
165
|
+
def uniq_id(*suffixes)
|
166
|
+
[caller.first[/.*[` ](.*)'/, 1], suffixes].join('_')
|
167
|
+
end
|
168
|
+
end
|