riagent 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/Gemfile +24 -0
- data/Gemfile.lock +73 -0
- data/LICENSE +202 -0
- data/README.md +230 -0
- data/Rakefile +47 -0
- data/lib/rails/generators/riagent/install/install_generator.rb +35 -0
- data/lib/rails/generators/riagent/install/templates/riak.yml +16 -0
- data/lib/riagent/active_document.rb +53 -0
- data/lib/riagent/associations.rb +119 -0
- data/lib/riagent/configuration.rb +73 -0
- data/lib/riagent/conversion.rb +83 -0
- data/lib/riagent/errors.rb +33 -0
- data/lib/riagent/persistence/riak_json_strategy.rb +62 -0
- data/lib/riagent/persistence.rb +166 -0
- data/lib/riagent/railtie.rb +35 -0
- data/lib/riagent/search_schema.rb +58 -0
- data/lib/riagent/version.rb +23 -0
- data/lib/riagent.rb +29 -0
- data/riagent.gemspec +51 -0
- data/test/config/riak.yml.example +19 -0
- data/test/examples/models/address_book.rb +32 -0
- data/test/examples/models/blog_post.rb +31 -0
- data/test/examples/models/contact.rb +29 -0
- data/test/examples/models/user.rb +41 -0
- data/test/integration/persistence_integration_test.rb +76 -0
- data/test/seeds.rb +30 -0
- data/test/test_helper.rb +33 -0
- data/test/unit/active_document_test.rb +41 -0
- data/test/unit/active_model_lint_test.rb +33 -0
- data/test/unit/associations_has_many_test.rb +32 -0
- data/test/unit/associations_has_one_test.rb +85 -0
- data/test/unit/config_test.rb +37 -0
- data/test/unit/embedded_test.rb +38 -0
- data/test/unit/persistence_riak_json_test.rb +118 -0
- data/test/unit/persistence_test.rb +57 -0
- data/test/unit/search_schema_test.rb +26 -0
- data/test/unit/validation_test.rb +39 -0
- metadata +227 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Copyright (c) "2014" Dmitri Zagidulin and Basho Technologies, Inc.
|
4
|
+
##
|
5
|
+
## This file is provided to you under the Apache License,
|
6
|
+
## Version 2.0 (the "License"); you may not use this file
|
7
|
+
## except in compliance with the License. You may obtain
|
8
|
+
## a copy of the License at
|
9
|
+
##
|
10
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
##
|
12
|
+
## Unless required by applicable law or agreed to in writing,
|
13
|
+
## software distributed under the License is distributed on an
|
14
|
+
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
## KIND, either express or implied. See the License for the
|
16
|
+
## specific language governing permissions and limitations
|
17
|
+
## under the License.
|
18
|
+
##
|
19
|
+
## -------------------------------------------------------------------
|
20
|
+
|
21
|
+
require 'active_support/concern'
|
22
|
+
require "active_model"
|
23
|
+
require "active_model/naming"
|
24
|
+
require 'riagent/document'
|
25
|
+
require 'riagent/conversion'
|
26
|
+
require 'riagent/persistence'
|
27
|
+
require 'riagent/associations'
|
28
|
+
require 'riagent/search_schema'
|
29
|
+
|
30
|
+
module Riagent
|
31
|
+
module ActiveDocument
|
32
|
+
extend ActiveSupport::Concern
|
33
|
+
extend ActiveModel::Naming
|
34
|
+
include ActiveModel::Validations
|
35
|
+
|
36
|
+
included do
|
37
|
+
include Riagent::Document
|
38
|
+
include Riagent::Conversion
|
39
|
+
include Riagent::Persistence
|
40
|
+
include Riagent::Associations
|
41
|
+
extend Riagent::SearchSchema
|
42
|
+
end
|
43
|
+
|
44
|
+
module ClassMethods
|
45
|
+
# Returns string representation for the collection name
|
46
|
+
# Used to determine the RiakJson::Collection name, or the Riak Bucket name
|
47
|
+
# Uses ActiveModel::Naming functionality to derive the name
|
48
|
+
def collection_name
|
49
|
+
self.model_name.plural
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Copyright (c) "2014" Dmitri Zagidulin and Basho Technologies, Inc.
|
4
|
+
##
|
5
|
+
## This file is provided to you under the Apache License,
|
6
|
+
## Version 2.0 (the "License"); you may not use this file
|
7
|
+
## except in compliance with the License. You may obtain
|
8
|
+
## a copy of the License at
|
9
|
+
##
|
10
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
##
|
12
|
+
## Unless required by applicable law or agreed to in writing,
|
13
|
+
## software distributed under the License is distributed on an
|
14
|
+
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
## KIND, either express or implied. See the License for the
|
16
|
+
## specific language governing permissions and limitations
|
17
|
+
## under the License.
|
18
|
+
##
|
19
|
+
## -------------------------------------------------------------------
|
20
|
+
|
21
|
+
require "active_support/concern"
|
22
|
+
|
23
|
+
module Riagent
|
24
|
+
module Associations
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def has_many(name, options={})
|
29
|
+
query_type = options[:using]
|
30
|
+
target_class = options[:class]
|
31
|
+
case query_type
|
32
|
+
when :solr
|
33
|
+
has_many_using_solr(name, target_class, query_type, options)
|
34
|
+
else
|
35
|
+
raise ArgumentError, ":using query type not supported"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Create a has_many association where the collection will be loaded
|
40
|
+
# via RiakJson Solr queries.
|
41
|
+
def has_many_using_solr(name, target_class, query_type, options)
|
42
|
+
target_getter_method = "#{name}".to_sym
|
43
|
+
|
44
|
+
# Create a <target name>_cache attribute accessors
|
45
|
+
# These will be used to store the actual loaded collection
|
46
|
+
target_cache_attribute = "#{name}_cache".to_sym
|
47
|
+
attr_accessor target_cache_attribute
|
48
|
+
|
49
|
+
# Create the getter method
|
50
|
+
define_method(target_getter_method) do
|
51
|
+
# First, check to see if the target collection has already been loaded/cached
|
52
|
+
# cached_collection = send(target_cache_attribute)
|
53
|
+
# if cached_collection.nil?
|
54
|
+
#
|
55
|
+
# source_key_value = send(:key) # Get the source (parent) id
|
56
|
+
# cached_collection = target_class.find(target_key)
|
57
|
+
# send(target_setter_method, cached_collection) # Cache the loaded target collection
|
58
|
+
# end
|
59
|
+
# cached_value
|
60
|
+
end
|
61
|
+
|
62
|
+
target_setter_method = "#{name}=".to_sym
|
63
|
+
|
64
|
+
# Create the setter method=
|
65
|
+
define_method(target_setter_method) do | target |
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def has_one(name, options={})
|
70
|
+
target_key_attribute = "#{name}_key"
|
71
|
+
target_class = options[:class]
|
72
|
+
|
73
|
+
# Create a <target name>_key attribute,
|
74
|
+
attribute target_key_attribute, String, default: ''
|
75
|
+
|
76
|
+
# Create a <target name>_cache attribute accessors
|
77
|
+
# These will be used to store the actual instance of the target
|
78
|
+
target_cache_attribute = "#{name}_cache".to_sym
|
79
|
+
attr_accessor target_cache_attribute
|
80
|
+
|
81
|
+
target_getter_method = "#{name}".to_sym
|
82
|
+
target_setter_method = "#{name}=".to_sym
|
83
|
+
|
84
|
+
# Create the setter method=
|
85
|
+
define_method(target_setter_method) do | target |
|
86
|
+
# Only assignments of the correct target class are allowed
|
87
|
+
unless target.kind_of? target_class
|
88
|
+
raise ArgumentError, "Invalid argument type #{target.class}, #{target_class} expected."
|
89
|
+
end
|
90
|
+
target_key = target ? target.key : nil
|
91
|
+
attribute_setter = "#{target_key_attribute}=".to_sym
|
92
|
+
send(attribute_setter, target_key)
|
93
|
+
attribute_cache_getter = "#{target_cache_attribute}="
|
94
|
+
send(attribute_cache_getter, target)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Create the getter method
|
98
|
+
define_method(target_getter_method) do
|
99
|
+
# First, check to see if the target instance has already been loaded/cached
|
100
|
+
cached_value = send(target_cache_attribute)
|
101
|
+
if cached_value.nil?
|
102
|
+
target_key = send(target_key_attribute)
|
103
|
+
cached_value = target_class.find(target_key)
|
104
|
+
send(target_setter_method, cached_value) # Cache the loaded target instance
|
105
|
+
end
|
106
|
+
cached_value
|
107
|
+
end
|
108
|
+
|
109
|
+
# Create build_<target> method
|
110
|
+
build_helper_method = "build_#{name}".to_sym
|
111
|
+
define_method(build_helper_method) do | attributes |
|
112
|
+
target_instance = target_class.new attributes
|
113
|
+
target_instance.key = self.key # The target object gets the source's key by default
|
114
|
+
send(target_setter_method, target_instance)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Copyright (c) "2014" Dmitri Zagidulin and Basho Technologies, Inc.
|
4
|
+
##
|
5
|
+
## This file is provided to you under the Apache License,
|
6
|
+
## Version 2.0 (the "License"); you may not use this file
|
7
|
+
## except in compliance with the License. You may obtain
|
8
|
+
## a copy of the License at
|
9
|
+
##
|
10
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
##
|
12
|
+
## Unless required by applicable law or agreed to in writing,
|
13
|
+
## software distributed under the License is distributed on an
|
14
|
+
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
## KIND, either express or implied. See the License for the
|
16
|
+
## specific language governing permissions and limitations
|
17
|
+
## under the License.
|
18
|
+
##
|
19
|
+
## -------------------------------------------------------------------
|
20
|
+
|
21
|
+
require "active_support/concern"
|
22
|
+
|
23
|
+
module Riagent
|
24
|
+
module Configuration
|
25
|
+
def config
|
26
|
+
@config ||= {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def config=(value)
|
30
|
+
@config = value
|
31
|
+
end
|
32
|
+
|
33
|
+
def config_for(environment=:development)
|
34
|
+
if self.config.present?
|
35
|
+
env_config = self.config[environment.to_s]
|
36
|
+
else
|
37
|
+
env_config = {
|
38
|
+
'host' => ENV['RIAK_HOST'],
|
39
|
+
'http_port' => ENV['RIAK_HTTP_PORT'],
|
40
|
+
'pb_port' => ENV['RIAK_PB_PORT']
|
41
|
+
}
|
42
|
+
end
|
43
|
+
env_config
|
44
|
+
end
|
45
|
+
|
46
|
+
def init_clients(environment=:development)
|
47
|
+
self.init_riak_json_client(environment)
|
48
|
+
end
|
49
|
+
|
50
|
+
def init_riak_json_client(environment=:development)
|
51
|
+
env_config = self.config_for(environment)
|
52
|
+
client = RiakJson::Client.new(env_config['host'], env_config['http_port'])
|
53
|
+
self.riak_json_client = client
|
54
|
+
end
|
55
|
+
|
56
|
+
def load_config_file(config_file_path)
|
57
|
+
config_file = File.expand_path(config_file_path)
|
58
|
+
config_hash = YAML.load(ERB.new(File.read(config_file)).result)
|
59
|
+
self.config = config_hash
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [RiakJson::Client] The client for the current thread.
|
63
|
+
def riak_json_client
|
64
|
+
Thread.current[:riak_json_client] ||= nil
|
65
|
+
end
|
66
|
+
|
67
|
+
# Sets the client for the current thread.
|
68
|
+
# @param [RiakJson::Client] value the client
|
69
|
+
def riak_json_client=(value)
|
70
|
+
Thread.current[:riak_json_client] = value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Copyright (c) "2014" Dmitri Zagidulin and Basho Technologies, Inc.
|
4
|
+
##
|
5
|
+
## This file is provided to you under the Apache License,
|
6
|
+
## Version 2.0 (the "License"); you may not use this file
|
7
|
+
## except in compliance with the License. You may obtain
|
8
|
+
## a copy of the License at
|
9
|
+
##
|
10
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
##
|
12
|
+
## Unless required by applicable law or agreed to in writing,
|
13
|
+
## software distributed under the License is distributed on an
|
14
|
+
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
## KIND, either express or implied. See the License for the
|
16
|
+
## specific language governing permissions and limitations
|
17
|
+
## under the License.
|
18
|
+
##
|
19
|
+
## -------------------------------------------------------------------
|
20
|
+
|
21
|
+
require 'active_model'
|
22
|
+
require 'active_model/conversion'
|
23
|
+
|
24
|
+
module Riagent
|
25
|
+
module Conversion
|
26
|
+
# Has this document been deleted?
|
27
|
+
# Required by ActiveModel::Conversion API
|
28
|
+
# @return [Boolean]
|
29
|
+
def destroyed?
|
30
|
+
@destroyed ||= false
|
31
|
+
end
|
32
|
+
|
33
|
+
# Is this a new, unsaved document?
|
34
|
+
# Required by ActiveModel::Conversion API
|
35
|
+
# @return [Boolean]
|
36
|
+
def new_record?
|
37
|
+
!persisted?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Mark the document as saved/persisted
|
41
|
+
# Called by +save+, and when instantiating query results (see ::Persistence)
|
42
|
+
def persist!
|
43
|
+
@persisted = true
|
44
|
+
end
|
45
|
+
|
46
|
+
# Has this document been saved to RiakJson?
|
47
|
+
# Required by ActiveModel::Conversion API
|
48
|
+
# @return [Boolean]
|
49
|
+
def persisted?
|
50
|
+
@persisted ||= false
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns an Enumerable of all key attributes if any is set, or +nil+ if
|
54
|
+
# the document is not persisted
|
55
|
+
# Required by ActiveModel::Conversion API
|
56
|
+
def to_key
|
57
|
+
self.new_record? ? nil : [self.key]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns an instance of an ActiveModel object (ie, itself)
|
61
|
+
# Required by ActiveModel::Conversion API
|
62
|
+
def to_model
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns a +string+ representing the object's key suitable for use in URLs,
|
67
|
+
# or +nil+ if <tt>persisted?</tt> is +false+.
|
68
|
+
# Required by ActiveModel::Conversion API
|
69
|
+
# @return [String, nil]
|
70
|
+
def to_param
|
71
|
+
self.key
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns a +string+ identifying the path associated with the object.
|
75
|
+
# ActionPack uses this to find a suitable partial to represent the object.
|
76
|
+
# Used in Rails helper methods such as +link_to+
|
77
|
+
# Required by ActiveModel::Conversion API
|
78
|
+
# @return [String]
|
79
|
+
def to_partial_path
|
80
|
+
"#{self.class.collection_name}/#{self.key}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Copyright (c) "2014" Dmitri Zagidulin and Basho Technologies, Inc.
|
4
|
+
##
|
5
|
+
## This file is provided to you under the Apache License,
|
6
|
+
## Version 2.0 (the "License"); you may not use this file
|
7
|
+
## except in compliance with the License. You may obtain
|
8
|
+
## a copy of the License at
|
9
|
+
##
|
10
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
##
|
12
|
+
## Unless required by applicable law or agreed to in writing,
|
13
|
+
## software distributed under the License is distributed on an
|
14
|
+
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
## KIND, either express or implied. See the License for the
|
16
|
+
## specific language governing permissions and limitations
|
17
|
+
## under the License.
|
18
|
+
##
|
19
|
+
## -------------------------------------------------------------------
|
20
|
+
|
21
|
+
module Riagent
|
22
|
+
# Generic Riagent exception class
|
23
|
+
class RiagentError < StandardError
|
24
|
+
end
|
25
|
+
|
26
|
+
# Raised by <tt>save!</tt> when a document does not pass validation
|
27
|
+
class InvalidDocumentError < RiagentError
|
28
|
+
attr_reader :document # :nodoc:
|
29
|
+
def initialize(document) # :nodoc:
|
30
|
+
@document = document
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Copyright (c) "2014" Dmitri Zagidulin and Basho Technologies, Inc.
|
4
|
+
##
|
5
|
+
## This file is provided to you under the Apache License,
|
6
|
+
## Version 2.0 (the "License"); you may not use this file
|
7
|
+
## except in compliance with the License. You may obtain
|
8
|
+
## a copy of the License at
|
9
|
+
##
|
10
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
##
|
12
|
+
## Unless required by applicable law or agreed to in writing,
|
13
|
+
## software distributed under the License is distributed on an
|
14
|
+
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
## KIND, either express or implied. See the License for the
|
16
|
+
## specific language governing permissions and limitations
|
17
|
+
## under the License.
|
18
|
+
##
|
19
|
+
## -------------------------------------------------------------------
|
20
|
+
|
21
|
+
require "riak_json"
|
22
|
+
require "active_support/concern"
|
23
|
+
|
24
|
+
module Riagent
|
25
|
+
module Persistence
|
26
|
+
module RiakJsonStrategy
|
27
|
+
extend ActiveSupport::Concern
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
def client
|
31
|
+
@client ||= Riagent.riak_json_client
|
32
|
+
end
|
33
|
+
|
34
|
+
def client=(client)
|
35
|
+
@client = client
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a RiakJson::Collection instance for this document
|
39
|
+
def collection
|
40
|
+
@collection ||= self.client.collection(self.collection_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Sets the RiakJson::Collection instance for this document
|
44
|
+
def collection=(collection_obj)
|
45
|
+
@collection = collection_obj
|
46
|
+
end
|
47
|
+
|
48
|
+
# Converts from a RiakJson::Document instance to an instance of ActiveDocument
|
49
|
+
# @return [ActiveDocument, nil] ActiveDocument instance, or nil if the Document is nil
|
50
|
+
def from_rj_document(doc, persisted=false)
|
51
|
+
return nil if doc.nil?
|
52
|
+
active_doc_instance = self.instantiate(doc.attributes)
|
53
|
+
active_doc_instance.key = doc.key
|
54
|
+
if persisted
|
55
|
+
active_doc_instance.persist! # Mark as persisted / not new
|
56
|
+
end
|
57
|
+
active_doc_instance
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Copyright (c) "2014" Dmitri Zagidulin and Basho Technologies, Inc.
|
4
|
+
##
|
5
|
+
## This file is provided to you under the Apache License,
|
6
|
+
## Version 2.0 (the "License"); you may not use this file
|
7
|
+
## except in compliance with the License. You may obtain
|
8
|
+
## a copy of the License at
|
9
|
+
##
|
10
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
##
|
12
|
+
## Unless required by applicable law or agreed to in writing,
|
13
|
+
## software distributed under the License is distributed on an
|
14
|
+
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
## KIND, either express or implied. See the License for the
|
16
|
+
## specific language governing permissions and limitations
|
17
|
+
## under the License.
|
18
|
+
##
|
19
|
+
## -------------------------------------------------------------------
|
20
|
+
|
21
|
+
require "active_support/concern"
|
22
|
+
require "riagent/persistence/riak_json_strategy"
|
23
|
+
|
24
|
+
module Riagent
|
25
|
+
module Persistence
|
26
|
+
extend ActiveSupport::Concern
|
27
|
+
|
28
|
+
included do
|
29
|
+
extend ActiveModel::Callbacks
|
30
|
+
define_model_callbacks :create, :update, :save, :destroy
|
31
|
+
end
|
32
|
+
|
33
|
+
# Delete the document from its collection
|
34
|
+
def destroy
|
35
|
+
run_callbacks(:destroy) do
|
36
|
+
self.class.collection.remove(self)
|
37
|
+
@destroyed = true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Performs validations and saves the document
|
42
|
+
# The validation process can be skipped by passing <tt>validate: false</tt>.
|
43
|
+
# Also triggers :before_create / :after_create type callbacks
|
44
|
+
# @return [String] Returns the key for the inserted document
|
45
|
+
def save(options={:validate => true})
|
46
|
+
context = new_record? ? :create : :update
|
47
|
+
return false if options[:validate] && !valid?(context)
|
48
|
+
|
49
|
+
run_callbacks(context) do
|
50
|
+
result = self.class.collection.insert(self)
|
51
|
+
self.persist!
|
52
|
+
result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Attempts to validate and save the document just like +save+ but will raise a +Riagent::InvalidDocumentError+
|
57
|
+
# exception instead of returning +false+ if the doc is not valid.
|
58
|
+
def save!(options={:validate => true})
|
59
|
+
unless save(options)
|
60
|
+
raise Riagent::InvalidDocumentError.new(self)
|
61
|
+
end
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
# Update an object's attributes and save it
|
66
|
+
def update(attrs)
|
67
|
+
run_callbacks(:update) do
|
68
|
+
self.attributes = attrs
|
69
|
+
self.save
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Perform an update(), raise an error if the doc is not valid
|
74
|
+
def update!(attrs)
|
75
|
+
unless update(attrs)
|
76
|
+
raise Riagent::InvalidDocumentError.new(self)
|
77
|
+
end
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
# Update attributes (alias for update() for Rails versions < 4)
|
82
|
+
def update_attributes(attrs)
|
83
|
+
self.update(attrs)
|
84
|
+
end
|
85
|
+
|
86
|
+
module ClassMethods
|
87
|
+
# Returns all documents (within results/pagination limit)
|
88
|
+
# from a collection.
|
89
|
+
# Implemented instead of all() to get around current RiakJson API limitations
|
90
|
+
# @param [String,Symbol] Name of a document field
|
91
|
+
# @param [Integer] Optional results limit
|
92
|
+
# @return [Array] of ActiveDocument instances
|
93
|
+
def all_for_field(field_name, results_limit=1000)
|
94
|
+
query = {
|
95
|
+
field_name => {'$regex' => "/.*/"},
|
96
|
+
'$per_page'=>results_limit
|
97
|
+
}.to_json
|
98
|
+
result = self.collection.find_all(query)
|
99
|
+
if result.present?
|
100
|
+
result.documents.map {|doc| self.from_rj_document(doc, persisted=true) }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Determines the document's persistence strategy
|
105
|
+
# Valid options: [:riak_json]
|
106
|
+
# Usage:
|
107
|
+
# <code>
|
108
|
+
# class SomeModel
|
109
|
+
# include Riagent::ActiveDocument
|
110
|
+
# collection_type :riak_json # persist to a RiakJson::Collection
|
111
|
+
# end
|
112
|
+
# </code>
|
113
|
+
def collection_type(coll_type)
|
114
|
+
@collection_type = coll_type
|
115
|
+
case @collection_type
|
116
|
+
when :riak_json
|
117
|
+
self.persistence_strategy = :riak_json
|
118
|
+
include Riagent::Persistence::RiakJsonStrategy
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Load a document by key.
|
123
|
+
def find(key)
|
124
|
+
return nil if key.nil? or key.empty?
|
125
|
+
doc = self.collection.find_by_key(key)
|
126
|
+
self.from_rj_document(doc, persisted=true)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Return the first document that matches the query
|
130
|
+
def find_one(query)
|
131
|
+
if query.kind_of? Hash
|
132
|
+
query = query.to_json
|
133
|
+
end
|
134
|
+
doc = self.collection.find_one(query)
|
135
|
+
if doc.present?
|
136
|
+
self.from_rj_document(doc, persisted=true)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def get_collection_type
|
141
|
+
@collection_type ||= nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def persistence_strategy
|
145
|
+
@persistence_strategy ||= nil
|
146
|
+
end
|
147
|
+
|
148
|
+
def persistence_strategy=(strategy)
|
149
|
+
@persistence_strategy = strategy
|
150
|
+
end
|
151
|
+
|
152
|
+
# Return all documents that match the query
|
153
|
+
def where(query)
|
154
|
+
if query.kind_of? Hash
|
155
|
+
query = query.to_json
|
156
|
+
end
|
157
|
+
result = self.collection.find_all(query)
|
158
|
+
if result.present?
|
159
|
+
result.documents.map do |doc|
|
160
|
+
self.from_rj_document(doc, persisted=true)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Copyright (c) "2014" Dmitri Zagidulin and Basho Technologies, Inc.
|
4
|
+
##
|
5
|
+
## This file is provided to you under the Apache License,
|
6
|
+
## Version 2.0 (the "License"); you may not use this file
|
7
|
+
## except in compliance with the License. You may obtain
|
8
|
+
## a copy of the License at
|
9
|
+
##
|
10
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
##
|
12
|
+
## Unless required by applicable law or agreed to in writing,
|
13
|
+
## software distributed under the License is distributed on an
|
14
|
+
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
## KIND, either express or implied. See the License for the
|
16
|
+
## specific language governing permissions and limitations
|
17
|
+
## under the License.
|
18
|
+
##
|
19
|
+
## -------------------------------------------------------------------
|
20
|
+
|
21
|
+
require 'rails/railtie'
|
22
|
+
require 'riak_json'
|
23
|
+
|
24
|
+
module Riagent
|
25
|
+
# Railtie for Rails integration and initialization
|
26
|
+
class Railtie < Rails::Railtie
|
27
|
+
initializer "riagent.configure_rails_initialization" do
|
28
|
+
config_file = Rails.root.join('config', 'riak.yml')
|
29
|
+
if File.exist?(config_file)
|
30
|
+
Riagent.load_config_file(config_file)
|
31
|
+
Riagent.init_clients(Rails.env) # Set up the client for the current environment
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
## -------------------------------------------------------------------
|
2
|
+
##
|
3
|
+
## Copyright (c) "2014" Dmitri Zagidulin and Basho Technologies, Inc.
|
4
|
+
##
|
5
|
+
## This file is provided to you under the Apache License,
|
6
|
+
## Version 2.0 (the "License"); you may not use this file
|
7
|
+
## except in compliance with the License. You may obtain
|
8
|
+
## a copy of the License at
|
9
|
+
##
|
10
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
##
|
12
|
+
## Unless required by applicable law or agreed to in writing,
|
13
|
+
## software distributed under the License is distributed on an
|
14
|
+
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
## KIND, either express or implied. See the License for the
|
16
|
+
## specific language governing permissions and limitations
|
17
|
+
## under the License.
|
18
|
+
##
|
19
|
+
## -------------------------------------------------------------------
|
20
|
+
|
21
|
+
module Riagent
|
22
|
+
# Generates RiakJson::CollectionSchema objects (translated into Solr schemas by RiakJson)
|
23
|
+
# from annotated document attributes.
|
24
|
+
# Usage:
|
25
|
+
# <code>
|
26
|
+
# class SampleModel
|
27
|
+
# include Riagent::ActiveDocument
|
28
|
+
# collection_type :riak_json
|
29
|
+
# attribute :name, required: true, search_index: { as: :text }
|
30
|
+
# end
|
31
|
+
# puts SampleModel.schema.inspect
|
32
|
+
# # => <RiakJson::CollectionSchema:0x000001050eef10 @fields=[{:name=>"name", :type=>"text", :require=>true}]>
|
33
|
+
#
|
34
|
+
# SampleModel.save_solr_schema() # sets that schema for the collection
|
35
|
+
# </code>
|
36
|
+
module SearchSchema
|
37
|
+
# Returns a CollectionSchema instance, derived from the document attributes
|
38
|
+
def schema
|
39
|
+
schema = RiakJson::CollectionSchema.new
|
40
|
+
self.attribute_set.each do | attribute |
|
41
|
+
if attribute.options.include? :search_index
|
42
|
+
field_type = attribute.options[:search_index][:as]
|
43
|
+
schema.add_field(field_type, attribute.options[:name], attribute.options[:required])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
schema
|
47
|
+
end
|
48
|
+
|
49
|
+
# Saves the generated Solr indexing schema to RiakJson.
|
50
|
+
# Usage:
|
51
|
+
# <code>
|
52
|
+
# SampleModel.save_solr_schema()
|
53
|
+
# </code>
|
54
|
+
def save_solr_schema
|
55
|
+
self.collection.set_schema(self.schema)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|