elasticsearch-rails-dynamic-json-support 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 566cc9fe9bf6aa1283f82504a7827327076adaf9
4
- data.tar.gz: 1d6b9bfc94575e2d0be746d8ddf213e8e6da2335
3
+ metadata.gz: 116ff0923afb01ab10a9ad5f3eb9792439ccb93e
4
+ data.tar.gz: a7478fbbab3f9626369a734cef52c67344b3e6fa
5
5
  SHA512:
6
- metadata.gz: e007c4d66893a761c4bdda9a98ca0e2f969ba0f8a0447e7e08bc785e910e9ccc693b7cd7ebe07fcc453432dd74e1b9bde0cc90996e4af6bfa65ed1335b7d2abf
7
- data.tar.gz: 7e491753074c9b82dd1dfe576bd53d7f1c5354522f6ff9a5f03d2fa706adc5d84d664c3df4c22671d63434f1b5aa3632d6c8fcc7db598db1408f0a3be76e145e
6
+ metadata.gz: 7ff38c240e1395797a06ce9ef10d3ff2afb55a4fb56e0ebbe0a5330ca59586cc28e7964c6e9a05f2104eb22a748b35cd0aeed3278693db772c21e272acf2ec3a
7
+ data.tar.gz: 461b3a61dc3b270eab43211e7485ad6dccaee47e5b697addeea62305215877fcd73934bfb2f908746ec07a50fbfd17946f776357f5ee964fc13cac762931d174
data/Gemfile CHANGED
@@ -6,13 +6,21 @@ source "https://rubygems.org"
6
6
  # Add dependencies to develop your gem here.
7
7
  # Include everything needed to run rake, tests, features, etc.
8
8
 
9
+ gem 'elasticsearch-model', "~> 0.1.9"
9
10
  gem 'elasticsearch-rails', "~> 0.1.9"
10
11
 
11
12
  group :development do
12
- gem 'shoulda', '>= 0'
13
+ gem 'rspec', '>= 0'
13
14
  gem 'rdoc', '~> 3.12'
14
15
  gem 'bundler', '~> 1.0'
15
16
  gem 'jeweler', '~> 2.0.1'
16
17
  gem 'simplecov', '>= 0'
17
18
  gem 'concurrent-ruby'
19
+ gem 'activerecord'
20
+ gem 'activerecord-nulldb-adapter'
18
21
  end
22
+
23
+ group :test do
24
+ gem 'sqlite3'
25
+ end
26
+
data/Gemfile.lock CHANGED
@@ -1,18 +1,40 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- activesupport (5.0.0.1)
4
+ activemodel (5.0.0)
5
+ activesupport (= 5.0.0)
6
+ activerecord (5.0.0)
7
+ activemodel (= 5.0.0)
8
+ activesupport (= 5.0.0)
9
+ arel (~> 7.0)
10
+ activerecord-nulldb-adapter (0.3.4)
11
+ activerecord (>= 2.0.0)
12
+ activesupport (5.0.0)
5
13
  concurrent-ruby (~> 1.0, >= 1.0.2)
6
14
  i18n (~> 0.7)
7
15
  minitest (~> 5.1)
8
16
  tzinfo (~> 1.1)
9
17
  addressable (2.4.0)
18
+ arel (7.1.1)
10
19
  builder (3.2.2)
11
20
  concurrent-ruby (1.0.2)
12
21
  descendants_tracker (0.0.4)
13
22
  thread_safe (~> 0.3, >= 0.3.1)
23
+ diff-lcs (1.2.5)
14
24
  docile (1.1.5)
25
+ elasticsearch (2.0.0)
26
+ elasticsearch-api (= 2.0.0)
27
+ elasticsearch-transport (= 2.0.0)
28
+ elasticsearch-api (2.0.0)
29
+ multi_json
30
+ elasticsearch-model (0.1.9)
31
+ activesupport (> 3)
32
+ elasticsearch (> 0.4)
33
+ hashie
15
34
  elasticsearch-rails (0.1.9)
35
+ elasticsearch-transport (2.0.0)
36
+ faraday
37
+ multi_json
16
38
  faraday (0.9.2)
17
39
  multipart-post (>= 1.2, < 3)
18
40
  git (1.3.0)
@@ -55,17 +77,25 @@ GEM
55
77
  rake (11.2.2)
56
78
  rdoc (3.12.2)
57
79
  json (~> 1.4)
58
- shoulda (3.5.0)
59
- shoulda-context (~> 1.0, >= 1.0.1)
60
- shoulda-matchers (>= 1.4.1, < 3.0)
61
- shoulda-context (1.2.1)
62
- shoulda-matchers (2.8.0)
63
- activesupport (>= 3.0.0)
80
+ rspec (3.5.0)
81
+ rspec-core (~> 3.5.0)
82
+ rspec-expectations (~> 3.5.0)
83
+ rspec-mocks (~> 3.5.0)
84
+ rspec-core (3.5.3)
85
+ rspec-support (~> 3.5.0)
86
+ rspec-expectations (3.5.0)
87
+ diff-lcs (>= 1.2.0, < 2.0)
88
+ rspec-support (~> 3.5.0)
89
+ rspec-mocks (3.5.0)
90
+ diff-lcs (>= 1.2.0, < 2.0)
91
+ rspec-support (~> 3.5.0)
92
+ rspec-support (3.5.0)
64
93
  simplecov (0.12.0)
65
94
  docile (~> 1.1.0)
66
95
  json (>= 1.8, < 3)
67
96
  simplecov-html (~> 0.10.0)
68
97
  simplecov-html (0.10.0)
98
+ sqlite3 (1.3.11)
69
99
  thread_safe (0.3.5)
70
100
  tzinfo (1.2.2)
71
101
  thread_safe (~> 0.1)
@@ -74,10 +104,17 @@ PLATFORMS
74
104
  ruby
75
105
 
76
106
  DEPENDENCIES
107
+ activerecord
108
+ activerecord-nulldb-adapter
77
109
  bundler (~> 1.0)
78
110
  concurrent-ruby
111
+ elasticsearch-model (~> 0.1.9)
79
112
  elasticsearch-rails (~> 0.1.9)
80
113
  jeweler (~> 2.0.1)
81
114
  rdoc (~> 3.12)
82
- shoulda
115
+ rspec
83
116
  simplecov
117
+ sqlite3
118
+
119
+ BUNDLED WITH
120
+ 1.12.5
data/README.md CHANGED
@@ -6,30 +6,30 @@ ElasticsearchRails DynamicJsonSupport - Small little change to help your model u
6
6
 
7
7
  In ElasicSearch, if you define your model the following way:
8
8
 
9
- ```ruby
10
- # app/models/article.rb
11
- class Article < ActiveRecord::Base
12
- include Elasticsearch::Model
13
- include Elasticsearch::Model::Callbacks
14
-
15
- has_many :reviews
16
-
17
- def as_indexed_json options={}
18
- {
19
- id: id,
20
- title: title,
21
- article: content,
22
- created_at: created_at,
23
- updated_at: updated_at,
24
- reviews: reviews.map(&:as_json),
25
- }
26
- end
27
-
28
- # app/models/review.rb
29
- class Review < ActiveRecord::Base
30
- belongs_to :article
31
- end
32
- ```
9
+ ```ruby
10
+ # app/models/article.rb
11
+ class Article < ActiveRecord::Base
12
+ include Elasticsearch::Model
13
+ include Elasticsearch::Model::Callbacks
14
+
15
+ has_many :reviews
16
+
17
+ def as_indexed_json options={}
18
+ {
19
+ id: id,
20
+ title: title,
21
+ article: content,
22
+ created_at: created_at,
23
+ updated_at: updated_at,
24
+ reviews: reviews.map(&:as_json),
25
+ }
26
+ end
27
+
28
+ # app/models/review.rb
29
+ class Review < ActiveRecord::Base
30
+ belongs_to :article
31
+ end
32
+ ```
33
33
 
34
34
  There're 2 issues with the implementation above:
35
35
 
@@ -56,46 +56,63 @@ This library aims to solve these 2 issues, with the following convention:
56
56
 
57
57
  Example usage (which solves the 2 issues above) is as given below:
58
58
 
59
- ```ruby
60
- # app/models/article.rb
61
- class Article < ActiveRecord::Base
62
- include Elasticsearch::Model
63
- include Elasticsearch::Model::Callbacks
64
- include Elasticsearch::Model::CascadeUpdate
65
-
66
- has_many :reviews
67
- es_register_attributes id: nil, title: nil, article: lambda {|rec| rec.content }, created_at: nil, updated_at: nil
68
- es_register_assoc(:reviews) { |review| review.as_indexed_json }
69
-
70
- def elasticsearch_json_changes(changed_attributes)
71
- keys_to_update = changed_attributes.keys.map {|k| key_map k}
72
- self.as_indexed_json.select { |k,_| keys_to_update.include? k.to_s }
73
- end
74
-
75
- private
76
- def key_map(key)
77
- key = key.to_s
78
- case key
79
- when 'content'
80
- 'article'
81
- else
82
- key
83
- end
84
- end
85
- end
86
-
87
- # app/models/review.rb
88
- class Review < ActiveRecord::Base
89
- # Make sure to register Article
90
- Article
91
-
92
- belongs_to :article
93
-
94
- def as_indexed_json(options = {})
95
- as_json
96
- end
97
- end
98
- ```
59
+ ```ruby
60
+ # app/models/article.rb
61
+ class Article < ActiveRecord::Base
62
+ include Elasticsearch::Model
63
+ include Elasticsearch::Model::Callbacks
64
+ include Elasticsearch::Model::CascadeUpdate
65
+
66
+ has_many :reviews
67
+ es_register_attributes :id, :title, article: lambda {|rec| rec.content }
68
+
69
+ # silent attribute would not be output by default
70
+ es_register_silent_attributes :created_at, :updated_at
71
+
72
+ # register association, with:
73
+ # - key_name = :reviews
74
+ # - get_assoc: default to be `#reviews` (the key_name)
75
+ # - &blk: the render_assoc, default to be: `object#as_indexed_json`.
76
+ # it would use a `map` by default for the has_many relationships
77
+ # - reverse_class: default to guess from the relationship
78
+ # - reverse_trigger: lambda {|obj, changes| do_things }
79
+ # the reverse_trigger, when the model change, to render the json
80
+ # document and update the objects. the returns is an array of the
81
+ # original object to be updated
82
+ es_register_assoc(:reviews) { |review| review.as_indexed_json }
83
+
84
+ # for the given changed_attributes, it would return the json to be fed
85
+ # into the `#update_document` method. What's given here is the default
86
+ # behaviour -- which is to find the keys, and do a matching
87
+ def elasticsearch_json_changes(changed_attributes)
88
+ keys_to_update = changed_attributes.keys.map {|k| key_map k}
89
+ self.as_indexed_json.select { |k,_| keys_to_update.include? k.to_s }
90
+ end
91
+
92
+ private
93
+ def key_map(key)
94
+ key = key.to_s
95
+ case key
96
+ when 'content'
97
+ 'article'
98
+ else
99
+ key
100
+ end
101
+ end
102
+ end
103
+
104
+ # app/models/review.rb
105
+ class Review < ActiveRecord::Base
106
+ # Make sure to register Article
107
+ Article
108
+
109
+ belongs_to :article
110
+
111
+ def as_indexed_json(options = {})
112
+ as_json
113
+ end
114
+ end
115
+ ```
99
116
 
100
117
  # More features
101
118
  - Exclusion of keys: simply call
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.6
1
+ 0.0.7
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: elasticsearch-rails-dynamic-json-support 0.0.6 ruby lib
5
+ # stub: elasticsearch-rails-dynamic-json-support 0.0.7 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "elasticsearch-rails-dynamic-json-support".freeze
9
- s.version = "0.0.6"
9
+ s.version = "0.0.7"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Song Yangyu".freeze]
14
- s.date = "2016-09-01"
14
+ s.date = "2016-09-20"
15
15
  s.description = "Enhance elasticsearch-rails with `elasticsearch_json_changes` to translate the attribute changes into document updates".freeze
16
16
  s.email = "flyfy1@gmail.com".freeze
17
17
  s.extra_rdoc_files = [
@@ -31,8 +31,9 @@ Gem::Specification.new do |s|
31
31
  "lib/elasticsearch/model/cascade_update.rb",
32
32
  "lib/elasticsearch/model/importing_decorator.rb",
33
33
  "lib/elasticsearch/model/indexing_decorator.rb",
34
- "test/helper.rb",
35
- "test/test_elasticsearch-rails-dynamic-json-support.rb"
34
+ "spec/cascade_update_spec.rb",
35
+ "spec/db.rb",
36
+ "spec/spec_helper.rb"
36
37
  ]
37
38
  s.homepage = "http://github.com/flyfy1/elasticsearch-rails-dynamic-json-support".freeze
38
39
  s.licenses = ["MIT".freeze]
@@ -43,30 +44,39 @@ Gem::Specification.new do |s|
43
44
  s.specification_version = 4
44
45
 
45
46
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
+ s.add_runtime_dependency(%q<elasticsearch-model>.freeze, ["~> 0.1.9"])
46
48
  s.add_runtime_dependency(%q<elasticsearch-rails>.freeze, ["~> 0.1.9"])
47
- s.add_development_dependency(%q<shoulda>.freeze, [">= 0"])
49
+ s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
48
50
  s.add_development_dependency(%q<rdoc>.freeze, ["~> 3.12"])
49
51
  s.add_development_dependency(%q<bundler>.freeze, ["~> 1.0"])
50
52
  s.add_development_dependency(%q<jeweler>.freeze, ["~> 2.0.1"])
51
53
  s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
52
54
  s.add_development_dependency(%q<concurrent-ruby>.freeze, [">= 0"])
55
+ s.add_development_dependency(%q<activerecord>.freeze, [">= 0"])
56
+ s.add_development_dependency(%q<activerecord-nulldb-adapter>.freeze, [">= 0"])
53
57
  else
58
+ s.add_dependency(%q<elasticsearch-model>.freeze, ["~> 0.1.9"])
54
59
  s.add_dependency(%q<elasticsearch-rails>.freeze, ["~> 0.1.9"])
55
- s.add_dependency(%q<shoulda>.freeze, [">= 0"])
60
+ s.add_dependency(%q<rspec>.freeze, [">= 0"])
56
61
  s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
57
62
  s.add_dependency(%q<bundler>.freeze, ["~> 1.0"])
58
63
  s.add_dependency(%q<jeweler>.freeze, ["~> 2.0.1"])
59
64
  s.add_dependency(%q<simplecov>.freeze, [">= 0"])
60
65
  s.add_dependency(%q<concurrent-ruby>.freeze, [">= 0"])
66
+ s.add_dependency(%q<activerecord>.freeze, [">= 0"])
67
+ s.add_dependency(%q<activerecord-nulldb-adapter>.freeze, [">= 0"])
61
68
  end
62
69
  else
70
+ s.add_dependency(%q<elasticsearch-model>.freeze, ["~> 0.1.9"])
63
71
  s.add_dependency(%q<elasticsearch-rails>.freeze, ["~> 0.1.9"])
64
- s.add_dependency(%q<shoulda>.freeze, [">= 0"])
72
+ s.add_dependency(%q<rspec>.freeze, [">= 0"])
65
73
  s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
66
74
  s.add_dependency(%q<bundler>.freeze, ["~> 1.0"])
67
75
  s.add_dependency(%q<jeweler>.freeze, ["~> 2.0.1"])
68
76
  s.add_dependency(%q<simplecov>.freeze, [">= 0"])
69
77
  s.add_dependency(%q<concurrent-ruby>.freeze, [">= 0"])
78
+ s.add_dependency(%q<activerecord>.freeze, [">= 0"])
79
+ s.add_dependency(%q<activerecord-nulldb-adapter>.freeze, [">= 0"])
70
80
  end
71
81
  end
72
82
 
@@ -1,25 +1,6 @@
1
1
  module Elasticsearch
2
2
  module Model
3
3
  module CascadeUpdate
4
-
5
- # Only for internal use. Holds the mapping from relationship, to the corresponding json
6
- class Actor
7
- def initialize(relationship_name, singularity, resource_to_json)
8
- @relationship_name = relationship_name
9
- @singularity = singularity.to_sym
10
- @resource_to_json = resource_to_json
11
- end
12
-
13
- def to_json(record)
14
- resource = record.public_send @relationship_name
15
- if(@singularity == :plural)
16
- resource.map {|record| @resource_to_json[record] }
17
- else # treat it as singular otherwise
18
- @resource_to_json[resource]
19
- end
20
- end
21
- end
22
-
23
4
  extend ActiveSupport::Concern
24
5
 
25
6
  # update, just for a specific key, or set of keys
@@ -28,7 +9,7 @@ module Elasticsearch
28
9
 
29
10
  res_json = {}
30
11
  keys.each do |key|
31
- res_json[key] = self.class.es_register_assoc(key).to_json(self)
12
+ res_json[key] = self.class.es_get_actor(key)[self]
32
13
  end
33
14
 
34
15
  self.__elasticsearch__.update_document_attributes res_json
@@ -40,91 +21,139 @@ module Elasticsearch
40
21
 
41
22
  class_methods do
42
23
  def es_to_json_when(scope_name, &condition_block)
43
- @@_es_condition_block = condition_block
44
- @@_es_scope_name = scope_name
24
+ instance_variable_set(:@_es_condition_block, condition_block)
25
+ instance_variable_set(:@_es_scope_name, scope_name)
26
+ end
27
+
28
+ def es_register_silent_attrs *attributes
29
+ __es_register_attrs __silent_attribute_registry, attributes
30
+ end
31
+
32
+ def es_get_actor(key, include_silent: true)
33
+ if include_silent
34
+ __load_attribute_registry[key] || __silent_attribute_registry[key]
35
+ else
36
+ __silent_attribute_registry[key]
37
+ end
45
38
  end
46
39
 
47
40
  # attributes is a pair of <key, block>
48
41
  def es_register_attrs *attributes
49
- hashed_attributes = attributes.extract_options!
42
+ __es_register_attrs __load_attribute_registry, attributes
43
+ end
50
44
 
51
- attributes.each do |k|
52
- json_attribute_registry[k] = lambda { |record| record.public_send k }
45
+ # register association, with:
46
+ # - key_name = the key name of the json object
47
+ # - relationship: can be nil, String or a Proc.
48
+ # - if nil or string, then default to the key_name. In that case,
49
+ # the listening_class can be guessed intelligently if not given
50
+ # - if lambda, then this is used to fetch the relationship
51
+ # - listening_class: default to guess from the relationship, to set the
52
+ # listener upon
53
+ # - reverse_trigger: lambda {|obj, changes| do_things }
54
+ # the reverse_trigger, when the model change, to render the json
55
+ # document and update the objects. the returns is an array of the
56
+ # original object to be updated
57
+ # - slient: default to false. If silent, then it's not exported by
58
+ # default
59
+ # - &blk: the render_assoc, default to be: `object#as_indexed_json`.
60
+ # it would use a `map` by default for the has_many relationships
61
+ def es_register_assoc key_name, relationship: nil, reverse_relationship: nil,
62
+ listening_class: nil, reverse_trigger: nil,
63
+ silent: false, &blk
64
+ key_name = key_name.to_s
65
+ relationship ||= key_name
66
+
67
+ relationship_getter = case relationship
68
+ when String, Symbol
69
+ lambda {|obj| obj.public_send relationship}
70
+ when Proc
71
+ relationship
72
+ else
73
+ fail "relationsihp can only be empty, String, or Proc, #{relationsihp} given."
74
+ end
75
+
76
+ single_to_json = blk || lambda do |r|
77
+ r.respond_to?(:as_indexed_json) ? r.as_indexed_json : r.as_json
53
78
  end
54
79
 
55
- hashed_attributes.each do |k, v|
56
- k = k.to_s
57
- json_attribute_registry[k] = v || lambda { |record| record.public_send k }
80
+ resource_to_json = lambda do |resource|
81
+ resource.respond_to?(:map) ? resource.map(&single_to_json) : single_to_json[resource]
58
82
  end
59
- end
60
83
 
61
- # default `reverse_relationship_name` to be singular case if not given
62
- def es_register_assoc key_name, relationship_name: nil, reverse_relationship_name: nil, &blk
63
- key_name = key_name.to_s
64
- return json_relationship_registry[key_name] unless blk
84
+ (silent ? __silent_attribute_registry : __load_attribute_registry )[key_name] = lambda do |record|
85
+ resource = relationship_getter[record]
86
+ resource_to_json[resource]
87
+ end
65
88
 
66
- relationship_name = key_name unless relationship_name
67
- relationship_name = relationship_name.to_s
89
+ reflection = nil
90
+ unless listening_class
91
+ # try to guess reverse class if not given
92
+ reflection = reflect_on_association relationship
93
+ listening_class = reflection.class_name.constantize
94
+ end
68
95
 
69
- reverse_relationship_name = self.name.demodulize.downcase unless reverse_relationship_name
70
- reverse_relationship_name = reverse_relationship_name.to_s
96
+ reverse_relationship = self.name.demodulize.downcase unless reverse_relationship
71
97
 
72
- reflection = reflect_on_association relationship_name
98
+ listening_class.class_eval do
99
+ # include Elasticsearch::Model unless include? Elasticsearch::Model
100
+ before_save do |instance|
101
+ self.instance_variable_set(:@__changed_attributes__, instance.changes)
102
+ end
73
103
 
74
- reflected_class = reflection.class_name.constantize
104
+ after_commit do |instance|
105
+ changes = instance.instance_variable_get(:@__changed_attributes__)
75
106
 
76
- actor = Actor.new relationship_name, get_singularity(reflection), blk
77
- json_relationship_registry[key_name] = actor
107
+ Array.wrap(self.public_send reverse_relationship).each do |record|
108
+ record.es_partial_update(key_name)
109
+ end if !reverse_trigger || reverse_trigger[instance, changes]
78
110
 
79
- reflected_class.class_eval do
80
- after_commit do
81
- Array.wrap(self.public_send reverse_relationship_name).each do |record|
82
- record.es_partial_update(key_name)
83
- end
111
+ instance.remove_instance_variable(:@__changed_attributes__)
84
112
  end
85
113
  end
86
114
  end
87
115
 
88
116
  def to_indexed_json(record, options = {})
89
117
  result = {}
90
- exclude_keys = options[:exclude_keys]
91
- exclude_keys = [] unless exclude_keys
92
- exclude_keys = exclude_keys.map(&:to_s)
118
+ exclude_keys = (options[:exclude] || []).map(&:to_s)
119
+ include_keys = (options[:include] || []).map(&:to_s)
93
120
 
94
- json_attribute_registry.each do |k, blk|
95
- k = k.to_s
121
+ __load_attribute_registry.each do |k, blk|
96
122
  next if exclude_keys.include? k
97
123
  result[k] = blk[record]
98
124
  end
99
125
 
100
- json_relationship_registry.each do |k, actor|
101
- k = k.to_s
102
- next if exclude_keys.include? k
103
- result[k] = actor.to_json(record)
126
+ __silent_attribute_registry.each do |k, blk|
127
+ next unless include_keys.include? k
128
+ result[k] = blk[record]
104
129
  end
105
130
 
106
131
  result
107
132
  end
108
133
 
109
134
  private
110
- def json_relationship_registry
111
- @@__json_actor_registry_ ||= {}
135
+ def __load_attribute_registry
136
+ instance_variable_set :@__json_attribute_registry, {} unless instance_variable_defined? :@__json_attribute_registry
137
+ instance_variable_get :@__json_attribute_registry
112
138
  end
113
-
114
- def json_attribute_registry
115
- @@__json_attribute_registry ||= {}
139
+ def __silent_attribute_registry
140
+ instance_variable_set :@__json_silent_attr_registry, {} unless instance_variable_defined? :@__json_silent_attr_registry
141
+ instance_variable_get :@__json_silent_attr_registry
116
142
  end
117
143
 
118
- def get_singularity(reflection)
119
- case reflection
120
- when ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::ThroughReflection,
121
- ActiveRecord::Reflection::HasAndBelongsToManyReflection
122
- :plural
123
- else
124
- :singular
144
+ # attributes is a pair of <key, block>
145
+ def __es_register_attrs register_hash, attributes
146
+ hashed_attributes = attributes.extract_options!
147
+
148
+ attributes.each do |k|
149
+ register_hash[k.to_s] = lambda { |record| record.public_send k }
150
+ end
151
+
152
+ hashed_attributes.each do |k, v|
153
+ register_hash[k.to_s] = v || lambda { |record| record.public_send k }
125
154
  end
126
155
  end
127
156
  end
128
157
  end
129
158
  end
130
- end
159
+ end
@@ -0,0 +1,157 @@
1
+ require_relative './spec_helper.rb'
2
+
3
+ RSpec.describe Elasticsearch::Model::CascadeUpdate, type: :model do
4
+ @@counter = 0
5
+
6
+ before do
7
+ @clz = Article.dup
8
+ eval("ArticleD#{@@counter} = @clz")
9
+ @clz.table_name = 'articles'
10
+
11
+ @dep_clz = Review.dup
12
+ eval("ReviewD#{@@counter} = @dep_clz")
13
+ @dep_clz.table_name = 'reviews'
14
+
15
+ @@counter += 1
16
+
17
+ review_class = @dep_clz
18
+ @clz.class_eval do
19
+ has_many :reviews, class_name: review_class.name, foreign_key: 'article_id', inverse_of: :article
20
+ end
21
+
22
+ article_class = @clz
23
+ @dep_clz.class_eval do
24
+ belongs_to :article, class_name: article_class.name, foreign_key: 'article_id', inverse_of: :reviews
25
+ end
26
+
27
+ @clz.__send__ :include, Elasticsearch::Model
28
+ @clz.__send__ :include, Elasticsearch::Model::Callbacks
29
+ @clz.__send__ :include, Elasticsearch::Model::CascadeUpdate
30
+ end
31
+
32
+ context 'attrs' do
33
+ describe 'load' do
34
+ before do
35
+ @clz.class_eval do
36
+ es_register_attrs :title, :content
37
+ end
38
+
39
+ @article = @clz.new(title: 'nani', content: 'oops')
40
+ end
41
+
42
+ it { expect(@article.as_indexed_json).to eq({"title"=>"nani", "content"=>"oops"}) }
43
+ end
44
+
45
+ describe 'silent' do
46
+ before do
47
+ @clz.class_eval do
48
+ es_register_silent_attrs :title
49
+ es_register_attrs :content, explicit_title: lambda {|o| o.title}
50
+ end
51
+
52
+ @article = @clz.new(title: 'nani', content: 'oops')
53
+ end
54
+
55
+ it { expect(@article.as_indexed_json(include: [:title])).to eq({
56
+ "explicit_title"=>"nani", "content"=>"oops", "title" => "nani"
57
+ }) }
58
+ end
59
+ end
60
+
61
+ context 'assoc' do
62
+ before do
63
+ @article = @clz.create!(title: 'nani', content: 'oops')
64
+ @article.reviews.create!(content: 'review 1')
65
+ @article.reviews.create!(content: 'review 2')
66
+ end
67
+
68
+ describe 'basis' do
69
+ before do
70
+ @clz.class_eval do
71
+ es_register_assoc :reviews, reverse_relationship: 'article'
72
+ end
73
+ end
74
+
75
+ it { expect(@article.as_indexed_json).to eq({
76
+ "reviews"=>[{"id"=>1, "article_id"=>1, "content"=>"review 1", "nonsense"=>nil},
77
+ {"id"=>2, "article_id"=>1, "content"=>"review 2", "nonsense"=>nil}]
78
+ }) }
79
+ end
80
+
81
+ describe 'blk passed in' do
82
+ before do
83
+ @clz.class_eval do
84
+ es_register_assoc :reviews, reverse_relationship: 'article' do |review|
85
+ review.as_json(only: [:content])
86
+ end
87
+ end
88
+ end
89
+
90
+ it { expect(@article.as_indexed_json).to eq({
91
+ "reviews"=>[ {"content"=>"review 1"},
92
+ {"content"=>"review 2"}]
93
+ }) }
94
+ end
95
+
96
+ describe 'reverse' do
97
+ context '#reverse_relationship' do
98
+ before do
99
+ @clz.class_eval do
100
+ es_register_attrs :title
101
+ es_register_assoc :reviews, reverse_relationship: 'article' do |review|
102
+ review.as_json(only: [:content])
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ it do
109
+ expect(@article.__elasticsearch__).to receive(:update_document_attributes).with(
110
+ "reviews"=>[ {"content"=>"review 1"},
111
+ {"content"=>"review 2 changed"}]
112
+ )
113
+
114
+ @review = @article.reviews[1]
115
+ @review.content = 'review 2 changed'
116
+ @review.save!
117
+ end
118
+ end
119
+
120
+ context '#reverse_trigger' do
121
+ before do
122
+ @clz.class_eval do
123
+ es_register_attrs :title
124
+ es_register_assoc(:reviews, reverse_relationship: 'article',
125
+ reverse_trigger: lambda {|review, changes| changes.has_key? :content }
126
+ ) do |review|
127
+ review.as_json(only: [:content])
128
+ end
129
+ end
130
+ end
131
+
132
+ describe 'include changed key' do
133
+ it do
134
+ expect(@article.__elasticsearch__).to receive(:update_document_attributes).with(
135
+ "reviews"=>[ {"content"=>"review 1"},
136
+ {"content"=>"review 2 changed"}]
137
+ )
138
+
139
+ @review = @article.reviews[1]
140
+ @review.content = 'review 2 changed'
141
+ @review.save!
142
+ end
143
+ end
144
+
145
+ describe 'exclude changed key' do
146
+ it do
147
+ expect(@article.__elasticsearch__).to receive(:update_document_attributes).never
148
+
149
+ @review = @article.reviews[1]
150
+ @review.nonsense = 'change does not matter much'
151
+ @review.save!
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
data/spec/db.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'active_record'
2
+ require 'elasticsearch-rails-dynamic-json-support'
3
+
4
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
5
+ ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ":memory:" )
6
+ ActiveRecord::Schema.define(version: 1) do
7
+ create_table :articles do |t|
8
+ t.string :title, null: false
9
+ t.string :content, null: false
10
+ end
11
+
12
+ create_table :reviews do |t|
13
+ t.integer :article_id, null: false
14
+ t.string :content, null: false
15
+ t.string :nonsense
16
+ end
17
+
18
+ add_index :reviews, :article_id
19
+ end
20
+
21
+ class Article < ActiveRecord::Base
22
+ validates_presence_of :title
23
+ validates_presence_of :content
24
+ end
25
+
26
+ class Review < ActiveRecord::Base
27
+ validates_presence_of :content
28
+ end
@@ -14,21 +14,17 @@ end
14
14
  ENV["COVERAGE"] && SimpleCov.start do
15
15
  add_filter "/.rvm/"
16
16
  end
17
- require 'rubygems'
18
- require 'bundler'
19
- begin
20
- Bundler.setup(:default, :development)
21
- rescue Bundler::BundlerError => e
22
- $stderr.puts e.message
23
- $stderr.puts "Run `bundle install` to install missing gems"
24
- exit e.status_code
25
- end
26
- require 'test/unit'
27
- require 'shoulda'
28
-
29
17
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
30
18
  $LOAD_PATH.unshift(File.dirname(__FILE__))
31
- require 'elasticsearch-rails-dynamic-json-support'
32
19
 
33
- class Test::Unit::TestCase
20
+ require 'rspec'
21
+
22
+ # Requires supporting files with custom matchers and macros, etc,
23
+ # in ./support/ and its subdirectories.
24
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
25
+
26
+ RSpec.configure do |config|
27
+
34
28
  end
29
+
30
+ require_relative './db'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticsearch-rails-dynamic-json-support
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Song Yangyu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-01 00:00:00.000000000 Z
11
+ date: 2016-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: elasticsearch-model
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.9
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.9
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: elasticsearch-rails
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -25,7 +39,7 @@ dependencies:
25
39
  - !ruby/object:Gem::Version
26
40
  version: 0.1.9
27
41
  - !ruby/object:Gem::Dependency
28
- name: shoulda
42
+ name: rspec
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - ">="
@@ -108,6 +122,34 @@ dependencies:
108
122
  - - ">="
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: activerecord
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: activerecord-nulldb-adapter
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
111
153
  description: Enhance elasticsearch-rails with `elasticsearch_json_changes` to translate
112
154
  the attribute changes into document updates
113
155
  email: flyfy1@gmail.com
@@ -129,8 +171,9 @@ files:
129
171
  - lib/elasticsearch/model/cascade_update.rb
130
172
  - lib/elasticsearch/model/importing_decorator.rb
131
173
  - lib/elasticsearch/model/indexing_decorator.rb
132
- - test/helper.rb
133
- - test/test_elasticsearch-rails-dynamic-json-support.rb
174
+ - spec/cascade_update_spec.rb
175
+ - spec/db.rb
176
+ - spec/spec_helper.rb
134
177
  homepage: http://github.com/flyfy1/elasticsearch-rails-dynamic-json-support
135
178
  licenses:
136
179
  - MIT
@@ -1,7 +0,0 @@
1
- require 'helper'
2
-
3
- class TestElasticsearchRailsDynamicJsonSupport < Test::Unit::TestCase
4
- should "probably rename this file and start testing for real" do
5
- flunk "hey buddy, you should probably rename this file and start testing for real"
6
- end
7
- end