couchbase-orm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cc28632e30fe3d518b6fb10fe892a9a51fae2229
4
+ data.tar.gz: c794c256004e9550f88dd2e760df80d0e35ad6b6
5
+ SHA512:
6
+ metadata.gz: 8cfd1a37baac0d5ff3045165d6a723b1d91814fe20790511e1a242839917de1b04de3806af038f2bcb34ea90445bfd73d0869bea2b0eb77ab12cf326b7f722dc
7
+ data.tar.gz: eaa78cf644bb41f50b4e465931308174394589c89ca46b6569e485d7311a17ee27c6a4a42071fa1bd499a4a09ffaec9e7c37913af9fd2e3f8707af441d3f189c
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ html
6
+ pkg
7
+ doc
8
+ tmp
9
+ rerun.txt
10
+ Gemfile.lock
11
+ .bundle
12
+ .idea
13
+ *.rbc
14
+ .yardoc
15
+ bin
16
+ Gemfile-custom
17
+
18
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,34 @@
1
+ language: ruby
2
+ rvm:
3
+ - ruby-2.3.1
4
+ - ruby-2.2.5
5
+ - ruby-head
6
+ - rubinius-3.62
7
+ - rubinius
8
+ - jruby-9.1.5.0
9
+ - jruby-head
10
+ branches:
11
+ only:
12
+ - master
13
+ before_install:
14
+ - git submodule update --init --recursive
15
+ - gem install ffi
16
+ - sudo apt-get install libev-dev
17
+ - sudo wget http://packages.couchbase.com/releases/4.5.1/couchbase-server-enterprise_4.5.1-ubuntu14.04_amd64.deb
18
+ - sudo dpkg -i couchbase-server-enterprise_4.5.1-ubuntu14.04_amd64.deb
19
+ - sleep 4
20
+ - sudo service couchbase-server status
21
+ - /opt/couchbase/bin/couchbase-cli cluster-init -c 127.0.0.1:8091 --cluster-username=admin --cluster-password=password --cluster-ramsize=320 --cluster-index-ramsize=256 --cluster-fts-ramsize=256 --services=data,index,query,fts
22
+ - sleep 4
23
+ - /opt/couchbase/bin/couchbase-cli server-info -c 127.0.0.1:8091 -u admin -p password
24
+ - /opt/couchbase/bin/couchbase-cli bucket-create -c 127.0.0.1:8091 -u admin -p password --bucket=default --bucket-type=couchbase --bucket-ramsize=160 --bucket-replica=0 --wait
25
+ before_script:
26
+ - rake compile
27
+ matrix:
28
+ allow_failures:
29
+ - rvm: jruby-head
30
+ - rvm: ruby-head
31
+ - rvm: rubinius
32
+ - rvm: rubinius-3.62
33
+ sudo: required
34
+ dist: trusty
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+
4
+ gem "rubysl", :platform => :rbx
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2016 ACAProjects
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is furnished
8
+ to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
20
+
21
+ ===
22
+
23
+ This license applies to all parts of the libcouchbase gem (Ruby FFI bindings for libcouchbase only)
24
+ Libcouchbase itself [is using the Couchbase license](https://github.com/couchbase/libcouchbase/blob/master/LICENSE)
data/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # Couchbase ORM for Rails
2
+
3
+ ## Rails integration
4
+
5
+ To generate config you can use `rails generate couchbase_orm:config`:
6
+
7
+ $ rails generate couchbase_orm:config
8
+ create config/couchbase.yml
9
+
10
+ It will generate this `config/couchbase.yml` for you:
11
+
12
+ common: &common
13
+ hosts: localhost
14
+ password:
15
+
16
+ development:
17
+ <<: *common
18
+ bucket: default
19
+
20
+ test:
21
+ <<: *common
22
+ bucket: app_name_test
23
+ password: for_test_bucket
24
+
25
+ # set these environment variables on your production server
26
+ production:
27
+ hosts: <%= ENV['COUCHBASE_HOST'] || ENV['COUCHBASE_HOSTS'] %>
28
+ bucket: <%= ENV['COUCHBASE_BUCKET'] %>
29
+ password: <%= ENV['COUCHBASE_PASSWORD'] %>
30
+
31
+
32
+ ## Examples
33
+
34
+ ```ruby
35
+ require 'couchbase-orm'
36
+
37
+ class Post < CouchbaseOrm::Base
38
+ attribute :title, type: String
39
+ attribute :body, type: String
40
+ attribute :draft, type: Boolean
41
+ end
42
+
43
+ p = Post.new(id: 'hello-world',
44
+ title: 'Hello world',
45
+ draft: true)
46
+ p.save
47
+ p = Post.find('hello-world')
48
+ p.body = "Once upon the times...."
49
+ p.save
50
+ p.update(draft: false)
51
+ Post.bucket.get('hello-world') #=> {"title"=>"Hello world", "draft"=>false,
52
+ # "body"=>"Once upon the times...."}
53
+ ```
54
+
55
+ You can also let the library generate the unique identifier for you:
56
+
57
+ ```ruby
58
+ p = Post.create(title: 'How to generate ID',
59
+ body: 'Open up the editor...')
60
+ p.id #=> "post-abcDE34"
61
+ ```
62
+
63
+ You can define connection options on per model basis:
64
+
65
+ ```ruby
66
+ class Post < CouchbaseOrm::Base
67
+ attribute :title, type: String
68
+ attribute :body, type: String
69
+ attribute :draft, type: Boolean
70
+
71
+ connect bucket: 'blog', password: ENV['BLOG_BUCKET_PASSWORD']
72
+ end
73
+ ```
74
+
75
+ ## Validations
76
+
77
+ There are all methods from ActiveModel::Validations accessible in
78
+ context of rails application. You can also enforce types using ruby
79
+ [conversion methods](http://www.virtuouscode.com/2012/05/07/a-ruby-conversion-idiom/)
80
+
81
+ ```ruby
82
+ class Comment < Couchbase::Model
83
+ attribute :author, :body, type: String
84
+
85
+ validates_presence_of :author, :body
86
+ end
87
+ ```
88
+
89
+ ## Views (aka Map/Reduce indexes)
90
+
91
+ Views are defined in the model and typically just emit an attribute that
92
+ can then be used for filtering results or ordering.
93
+
94
+ ```ruby
95
+ class Comment < CouchbaseOrm::Base
96
+ attribute :author, :body, type: String
97
+ view :all # => emits :id and will return all comments
98
+ view :by_author, emit_key: :author
99
+
100
+ # Generates two functions:
101
+ # * the by_author view above
102
+ # * def find_by_author(author); end
103
+ index_view :author
104
+
105
+ validates_presence_of :author, :body
106
+ end
107
+ ```
108
+
109
+ You can use `Comment.find_by_author('name')` to obtain all the comments by
110
+ a particular author. The same thing, using the view directly would be:
111
+ `Comment.by_author(key: 'name')`
112
+
113
+ ## Associations and Indexes
114
+
115
+ There are common active record helpers available for use `belongs_to` and `has_many`
116
+
117
+ ```ruby
118
+ class Comment < CouchbaseOrm::Base
119
+ belongs_to :author
120
+ end
121
+
122
+ class Author < CouchbaseOrm::Base
123
+ has_many :comments, dependent: :destroy
124
+
125
+ # You can ensure an attribute is unique for this model
126
+ attribute :email, type: String
127
+ ensure_unique :email
128
+ end
129
+ ```
130
+
131
+
data/Rakefile ADDED
@@ -0,0 +1,75 @@
1
+ require 'rubygems'
2
+ require 'rspec/core/rake_task' # testing framework
3
+ require 'yard' # yard documentation
4
+ require 'ffi' # loads the extension
5
+ require 'rake/clean' # for the :clobber rake task
6
+ require File.expand_path('../lib/libcouchbase/ext/tasks', __FILE__) # platform specific rake tasks used by compile
7
+
8
+
9
+
10
+ # By default we don't run network tests
11
+ task :default => :limited_spec
12
+ RSpec::Core::RakeTask.new(:limited_spec) do |t|
13
+ # Exclude full text search tests until we can automate index creation
14
+ t.rspec_opts = "--tag ~full_text_search --tag ~n1ql_query"
15
+ end
16
+ RSpec::Core::RakeTask.new(:spec)
17
+
18
+
19
+ desc 'Run all tests'
20
+ task :test => [:spec]
21
+
22
+
23
+ YARD::Rake::YardocTask.new do |t|
24
+ t.files = ['lib/**/*.rb', '-', 'ext/README.md', 'README.md']
25
+ end
26
+
27
+
28
+ desc 'Compile libcouchbase from submodule'
29
+ if FFI::Platform.windows?
30
+ task :compile => ["ext/bin/libcouchbase.#{FFI::Platform::LIBSUFFIX}"]
31
+ CLOBBER.include("ext/bin/libcouchbase.#{FFI::Platform::LIBSUFFIX}")
32
+ else
33
+ task :compile => ["ext/libcouchbase/build/lib/libcouchbase_libuv.#{FFI::Platform::LIBSUFFIX}"]
34
+ CLOBBER.include("ext/libcouchbase/build/lib/libcouchbase_libuv.#{FFI::Platform::LIBSUFFIX}")
35
+ end
36
+
37
+
38
+ # NOTE:: Generated on OSX
39
+ desc 'Generate the FFI bindings'
40
+ task :generate_bindings do
41
+ require "ffi/gen"
42
+
43
+ # NOTE:: you must export the include dir:
44
+ # export CPATH=./ext/libcouchbase/include/
45
+ #
46
+ # Once generated we need to:
47
+ # * adjust the ffi_lib path:
48
+ # ffi_lib ::File.expand_path("../../../../ext/libcouchbase/build/lib/libcouchbase_libuv.#{FFI::Platform::LIBSUFFIX}", __FILE__)
49
+ # * Rename some structs strings to pointers
50
+ # create_st3.rb -> connstr, username, passwd
51
+ # cmdhttp.rb -> body, reqhandle, content_type, username, password, host
52
+ # cmdfts.rb -> query
53
+ # respfts.rb -> row
54
+ # respviewquery.rb -> value, geometry, docid
55
+ # respn1ql.rb -> row
56
+
57
+ FFI::Gen.generate(
58
+ module_name: "Libcouchbase::Ext",
59
+ ffi_lib: "libcouchbase",
60
+ require_path: "libcouchbase/ext/libcouchbase",
61
+ headers: [
62
+ "./ext/libcouchbase/include/libcouchbase/couchbase.h",
63
+ "./ext/libcouchbase/include/libcouchbase/error.h",
64
+ "./ext/libcouchbase/include/libcouchbase/views.h",
65
+ "./ext/libcouchbase/include/libcouchbase/subdoc.h",
66
+ "./ext/libcouchbase/include/libcouchbase/n1ql.h",
67
+ "./ext/libcouchbase/include/libcouchbase/cbft.h",
68
+ "./ext/libcouchbase/include/libcouchbase/kvbuf.h"
69
+ ],
70
+ # Searching for stdarg.h
71
+ cflags: ["-I/System/Library/Frameworks/Kernel.framework/Versions/A/Headers"],
72
+ prefixes: ["LCB_", "lcb_"],
73
+ output: "libcouchbase.rb"
74
+ )
75
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path("../lib/couchbase-orm/version", __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "couchbase-orm"
5
+ gem.version = CouchbaseOrm::VERSION
6
+ gem.license = 'MIT'
7
+ gem.authors = ["Stephen von Takach"]
8
+ gem.email = ["steve@cotag.me"]
9
+ gem.homepage = "https://github.com/cotag/couchbase-orm"
10
+ gem.summary = "Couchbase ORM for Rails"
11
+ gem.description = "A Couchbase ORM for Rails"
12
+
13
+ gem.required_ruby_version = '>= 2.1.0'
14
+ gem.require_paths = ["lib"]
15
+
16
+ gem.add_runtime_dependency 'libcouchbase', '~> 0.0'
17
+ gem.add_runtime_dependency 'activemodel', '~> 5.0'
18
+ gem.add_runtime_dependency 'radix', '~> 2.2' # converting numbers to and from any base
19
+
20
+ gem.add_development_dependency 'rake', '~> 11.2'
21
+ gem.add_development_dependency 'rspec', '~> 3.5'
22
+ gem.add_development_dependency 'yard', '~> 0.9'
23
+ gem.add_development_dependency 'minitest', '~> 5.9'
24
+
25
+ gem.files = `git ls-files`.split("\n")
26
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
27
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ require 'libcouchbase'
4
+
5
+ module CouchbaseOrm
6
+ autoload :Error, 'couchbase-orm/error'
7
+ autoload :Connection, 'couchbase-orm/connection'
8
+ autoload :IdGenerator, 'couchbase-orm/id_generator'
9
+ autoload :Base, 'couchbase-orm/base'
10
+ end
11
+
12
+ # Provide Boolean conversion function
13
+ # See: http://www.virtuouscode.com/2012/05/07/a-ruby-conversion-idiom/
14
+ module Conversions
15
+ private
16
+
17
+ def Boolean(value)
18
+ case value
19
+ when String, Symbol
20
+ case value.to_s.strip.downcase
21
+ when 'true'
22
+ return true
23
+ when 'false'
24
+ return false
25
+ end
26
+ when Integer
27
+ return value != 0
28
+ when false, nil
29
+ return false
30
+ when true
31
+ return true
32
+ end
33
+
34
+ raise ArgumentError, "invalid value for Boolean(): \"#{value.inspect}\""
35
+ end
36
+ end
37
+ class Boolean < TrueClass; end
38
+
39
+ # If we are using Rails then we will include the Couchbase railtie.
40
+ if defined?(Rails)
41
+ require 'couchbase-orm/railtie'
42
+ end
43
+
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ require 'active_model'
4
+
5
+ module CouchbaseOrm
6
+ module Associations
7
+ extend ActiveSupport::Concern
8
+
9
+
10
+ module ClassMethods
11
+ # Defines a belongs_to association for the model
12
+ def belongs_to(name, **options)
13
+ @associations ||= []
14
+ @associations << [name.to_sym, options[:dependent]]
15
+
16
+ ref = options[:foreign_key] || :"#{name}_id"
17
+ ref_ass = :"#{ref}="
18
+ instance_var = :"@__assoc_#{name}"
19
+
20
+ # Class reference
21
+ assoc = (options[:class_name] || name.to_s.camelize).to_s
22
+
23
+ # Create the local setter / getter
24
+ attribute(ref) { |value|
25
+ remove_instance_variable(instance_var) if instance_variable_defined?(instance_var)
26
+ value
27
+ }
28
+
29
+ # Define reader
30
+ define_method(name) do
31
+ return instance_variable_get(instance_var) if instance_variable_defined?(instance_var)
32
+ val = assoc.constantize.find(self.send(ref), quiet: true)
33
+ instance_variable_set(instance_var, val)
34
+ val
35
+ end
36
+
37
+ # Define writer
38
+ attr_writer name
39
+ define_method(:"#{name}=") do |value|
40
+ if value
41
+ self.send(ref_ass, value.id)
42
+ else
43
+ self.send(ref_ass, nil)
44
+ end
45
+
46
+ instance_variable_set(instance_var, value)
47
+ end
48
+ end
49
+
50
+ def associations
51
+ @associations || []
52
+ end
53
+ end
54
+
55
+
56
+ def destroy_associations!
57
+ assoc = self.class.associations
58
+ assoc.each do |name, dependent|
59
+ next unless dependent
60
+
61
+ model = self.__send__(name)
62
+ if model.present?
63
+ case dependent
64
+ when :destroy, :delete
65
+ if model.respond_to?(:stream)
66
+ model.stream { |mod| mod.__send__(dependent) }
67
+ else
68
+ model.__send__(dependent)
69
+ end
70
+ when :restrict_with_exception
71
+ raise RecordExists.new("#{self.class.name} instance maintains a restricted reference to #{name}", self)
72
+ when :restrict_with_error
73
+ # TODO::
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ def reset_associations
80
+ assoc = self.class.associations
81
+ assoc.each do |name, _|
82
+ instance_var = :"@__assoc_#{name}"
83
+ remove_instance_variable(instance_var) if instance_variable_defined?(instance_var)
84
+ end
85
+ end
86
+ end
87
+ end