mongoid-cached-json 1.5.1 → 1.5.2

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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +6 -0
  5. data/.rubocop_todo.yml +80 -0
  6. data/.travis.yml +16 -0
  7. data/CHANGELOG.md +85 -0
  8. data/CONTRIBUTING.md +118 -0
  9. data/Gemfile +21 -0
  10. data/README.md +49 -52
  11. data/Rakefile +34 -0
  12. data/lib/mongoid-cached-json.rb +0 -1
  13. data/lib/mongoid-cached-json/array.rb +1 -3
  14. data/lib/mongoid-cached-json/cached_json.rb +52 -50
  15. data/lib/mongoid-cached-json/config.rb +20 -21
  16. data/lib/mongoid-cached-json/hash.rb +1 -3
  17. data/lib/mongoid-cached-json/key_references.rb +0 -3
  18. data/lib/mongoid-cached-json/mongoid_criteria.rb +1 -3
  19. data/lib/mongoid-cached-json/version.rb +1 -2
  20. data/mongoid-cached-json.gemspec +17 -0
  21. data/spec/array_spec.rb +48 -0
  22. data/spec/benchmark_spec.rb +115 -0
  23. data/spec/cached_json_spec.rb +501 -0
  24. data/spec/config_spec.rb +21 -0
  25. data/spec/dalli_spec.rb +37 -0
  26. data/spec/hash_spec.rb +66 -0
  27. data/spec/mongoid_criteria_spec.rb +78 -0
  28. data/spec/spec_helper.rb +20 -0
  29. data/spec/support/awesome_artwork.rb +11 -0
  30. data/spec/support/awesome_image.rb +14 -0
  31. data/spec/support/fast_json_artwork.rb +15 -0
  32. data/spec/support/fast_json_image.rb +12 -0
  33. data/spec/support/fast_json_url.rb +12 -0
  34. data/spec/support/json_embedded_foobar.rb +5 -0
  35. data/spec/support/json_employee.rb +12 -0
  36. data/spec/support/json_foobar.rb +19 -0
  37. data/spec/support/json_manager.rb +14 -0
  38. data/spec/support/json_math.rb +9 -0
  39. data/spec/support/json_parent_foobar.rb +11 -0
  40. data/spec/support/json_polymorphic_embedded_foobar.rb +9 -0
  41. data/spec/support/json_polymorphic_referenced_foobar.rb +9 -0
  42. data/spec/support/json_referenced_foobar.rb +5 -0
  43. data/spec/support/json_supervisor.rb +13 -0
  44. data/spec/support/json_transform.rb +13 -0
  45. data/spec/support/matchers/invalidate.rb +22 -0
  46. data/spec/support/person.rb +20 -0
  47. data/spec/support/poly_company.rb +10 -0
  48. data/spec/support/poly_person.rb +10 -0
  49. data/spec/support/poly_post.rb +9 -0
  50. data/spec/support/prison_cell.rb +11 -0
  51. data/spec/support/prison_inmate.rb +12 -0
  52. data/spec/support/secret_parent.rb +11 -0
  53. data/spec/support/sometimes_secret.rb +11 -0
  54. data/spec/support/tool.rb +11 -0
  55. data/spec/support/tool_box.rb +10 -0
  56. metadata +62 -137
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::CachedJson::Config do
4
+ before :each do
5
+ @cache = Mongoid::CachedJson::Config.cache
6
+ end
7
+ after :each do
8
+ Mongoid::CachedJson::Config.cache = @cache
9
+ end
10
+ it 'configures a cache store' do
11
+ cache = Class.new
12
+ Mongoid::CachedJson.configure do |config|
13
+ config.cache = cache
14
+ end
15
+ expect(cache).to receive(:fetch).once
16
+ JsonFoobar.new.as_json
17
+ end
18
+ it 'sets disable_caching to false' do
19
+ expect(Mongoid::CachedJson.config.disable_caching).to be_falsey
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'active_support/cache/dalli_store'
3
+
4
+ describe ActiveSupport::Cache::DalliStore do
5
+ before :each do
6
+ @cache = Mongoid::CachedJson::Config.cache
7
+ Mongoid::CachedJson.configure do |config|
8
+ config.cache = ActiveSupport::Cache.lookup_store(:dalli_store)
9
+ end
10
+ end
11
+ after :each do
12
+ Mongoid::CachedJson::Config.cache = @cache
13
+ end
14
+ it 'uses dalli_store' do
15
+ expect(Mongoid::CachedJson.config.cache).to be_a ActiveSupport::Cache::DalliStore
16
+ end
17
+ context 'read_multi' do
18
+ context 'array' do
19
+ it 'uses a local cache to fetch repeated objects' do
20
+ options = { properties: :all, is_top_level_json: true, version: :unspecified }
21
+ tool1 = Tool.create!(name: 'hammer')
22
+ tool1_key = Tool.cached_json_key(options, Tool, tool1.id)
23
+ tool2 = Tool.create!(name: 'screwdriver')
24
+ tool2_key = Tool.cached_json_key(options, Tool, tool2.id)
25
+ expect(Mongoid::CachedJson.config.cache).not_to receive(:fetch)
26
+ expect(Mongoid::CachedJson.config.cache).to receive(:read_multi).with(tool1_key, tool2_key).once.and_return(
27
+ tool1_key => { _id: tool1.id.to_s },
28
+ tool2_key => { _id: tool2.id.to_s }
29
+ )
30
+ expect([tool1, tool2].as_json(properties: :all)).to eq([
31
+ { tool_box: nil, _id: tool1.id.to_s },
32
+ { tool_box: nil, _id: tool2.id.to_s }
33
+ ])
34
+ end
35
+ end
36
+ end
37
+ end
data/spec/hash_spec.rb ADDED
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hash do
4
+ it 'hash' do
5
+ expect({ x: 'x', y: 'y' }.as_json).to eq(x: 'x', y: 'y')
6
+ end
7
+ it 'materializes multiple objects that may or may not respond to as_json_partial' do
8
+ foobar1 = JsonFoobar.create(foo: 'FOO1', baz: 'BAZ', bar: 'BAR')
9
+ foobar2 = JsonFoobar.create(foo: 'FOO2', baz: 'BAZ', bar: 'BAR')
10
+ expect({
11
+ :x => :y,
12
+ :foobar1 => foobar1,
13
+ :foobar2 => foobar2,
14
+ :z => {
15
+ foobar1: foobar1
16
+ },
17
+ :t => [foobar1, :y],
18
+ 'empty' => []
19
+ }.as_json).to eq(
20
+ :x => 'y',
21
+ :foobar1 => { :foo => 'FOO1', 'Baz' => 'BAZ', :default_foo => 'DEFAULT_FOO' },
22
+ :foobar2 => { :foo => 'FOO2', 'Baz' => 'BAZ', :default_foo => 'DEFAULT_FOO' },
23
+ :z => { foobar1: { :foo => 'FOO1', 'Baz' => 'BAZ', :default_foo => 'DEFAULT_FOO' } },
24
+ :t => [{ :foo => 'FOO1', 'Baz' => 'BAZ', :default_foo => 'DEFAULT_FOO' }, 'y'],
25
+ 'empty' => []
26
+ )
27
+ end
28
+ context 'without read_multi' do
29
+ before :each do
30
+ Mongoid::CachedJson.config.cache.instance_eval { undef :read_multi }
31
+ end
32
+ it 'uses a local cache to fetch repeated objects' do
33
+ tool = Tool.create!(name: 'hammer')
34
+ expect(Mongoid::CachedJson.config.cache).to receive(:fetch).once.and_return(
35
+ x: :y
36
+ )
37
+ expect({
38
+ t1: tool,
39
+ t2: tool,
40
+ t3: tool
41
+ }.as_json(properties: :all)).to eq(
42
+ t1: { tool_box: nil, x: :y },
43
+ t2: { tool_box: nil, x: :y },
44
+ t3: { tool_box: nil, x: :y }
45
+ )
46
+ end
47
+ end
48
+ context 'with read_multi' do
49
+ it 'uses a local cache to fetch repeated objects' do
50
+ tool = Tool.create!(name: 'hammer')
51
+ tool_key = "as_json/unspecified/Tool/#{tool.id}/all/true"
52
+ expect(Mongoid::CachedJson.config.cache).to receive(:read_multi).once.with(tool_key).and_return(
53
+ tool_key => { x: :y }
54
+ )
55
+ expect({
56
+ t1: tool,
57
+ t2: tool,
58
+ t3: tool
59
+ }.as_json(properties: :all)).to eq(
60
+ t1: { tool_box: nil, x: :y },
61
+ t2: { tool_box: nil, x: :y },
62
+ t3: { tool_box: nil, x: :y }
63
+ )
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Criteria do
4
+ it 'mongoid_criteria' do
5
+ tool_box = ToolBox.create!(color: 'red')
6
+ Tool.create!(name: 'hammer', tool_box: tool_box)
7
+ Tool.create!(name: 'screwdriver', tool_box: tool_box)
8
+ expect(Tool.where(tool_box_id: tool_box.id).as_json(properties: :all)).to eq([
9
+ { tool_box: { color: 'red' }, name: 'hammer' },
10
+ { tool_box: { color: 'red' }, name: 'screwdriver' }
11
+ ])
12
+ end
13
+ context 'without read_multi' do
14
+ before :each do
15
+ Mongoid::CachedJson.config.cache.instance_eval { undef :read_multi }
16
+ end
17
+ it 'materializes multiple objects using a single partial' do
18
+ tool_box = ToolBox.create!(color: 'red')
19
+ Tool.create!(name: 'hammer', tool_box: tool_box)
20
+ Tool.create!(name: 'screwdriver', tool_box: tool_box)
21
+ # once per tool and once for the tool box
22
+ expect(Mongoid::CachedJson.config.cache).to receive(:fetch).exactly(3).times.and_return(
23
+ x: :y
24
+ )
25
+ expect(tool_box.tools.as_json(properties: :all)).to eq([
26
+ { tool_box: { x: :y }, x: :y },
27
+ { tool_box: { x: :y }, x: :y }
28
+ ])
29
+ end
30
+ end
31
+ context 'with read_multi' do
32
+ it 'responds to read_multi' do
33
+ expect(Mongoid::CachedJson.config.cache).to respond_to :read_multi
34
+ end
35
+ it 'materializes multiple objects using a single partial' do
36
+ tool_box = ToolBox.create!(color: 'red')
37
+ tool1 = Tool.create!(name: 'hammer', tool_box: tool_box)
38
+ tool2 = Tool.create!(name: 'screwdriver', tool_box: tool_box)
39
+ # once per tool and once for the tool box
40
+ keys = [
41
+ "as_json/unspecified/Tool/#{tool1.id}/all/true",
42
+ "as_json/unspecified/ToolBox/#{tool_box.id}/all/false",
43
+ "as_json/unspecified/Tool/#{tool2.id}/all/true"
44
+ ]
45
+ expect(Mongoid::CachedJson.config.cache).to receive(:read_multi).once.with(*keys).and_return(
46
+ keys[0] => { x: :y },
47
+ keys[1] => { x: :y },
48
+ keys[2] => { x: :y }
49
+ )
50
+ expect(tool_box.tools.as_json(properties: :all)).to eq([
51
+ { tool_box: { x: :y }, x: :y },
52
+ { tool_box: { x: :y }, x: :y }
53
+ ])
54
+ end
55
+ it 'does not call fetch for missing objects, only write' do
56
+ tool_box = ToolBox.create!(color: 'red')
57
+ tool1 = Tool.create!(name: 'hammer', tool_box: tool_box)
58
+ tool2 = Tool.create!(name: 'screwdriver', tool_box: tool_box)
59
+ # once per tool and once for the tool box
60
+ keys = [
61
+ "as_json/unspecified/Tool/#{tool1.id}/all/true",
62
+ "as_json/unspecified/ToolBox/#{tool_box.id}/all/false",
63
+ "as_json/unspecified/Tool/#{tool2.id}/all/true"
64
+ ]
65
+ expect(Mongoid::CachedJson.config.cache).to receive(:read_multi).once.with(*keys).and_return(
66
+ keys[0] => { x: :y },
67
+ keys[1] => { x: :y }
68
+ )
69
+ # read_multi returned only 2 of 3 things, don't call fetch, just store the third value
70
+ expect(Mongoid::CachedJson.config.cache).not_to receive(:fetch)
71
+ expect(Mongoid::CachedJson.config.cache).to receive(:write).with("as_json/unspecified/Tool/#{tool2.id}/all/true", name: 'screwdriver')
72
+ expect(tool_box.tools.as_json(properties: :all)).to eq([
73
+ { tool_box: { x: :y }, x: :y },
74
+ { tool_box: { x: :y }, name: 'screwdriver' }
75
+ ])
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,20 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'rspec'
5
+ require 'mongoid-cached-json'
6
+
7
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |f|
8
+ require f
9
+ end
10
+
11
+ Mongoid.configure do |config|
12
+ config.connect_to('cached_json_test')
13
+ end
14
+
15
+ RSpec.configure do |config|
16
+ config.raise_errors_for_deprecations!
17
+ config.after :each do
18
+ Mongoid::CachedJson.config.reset!
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ class AwesomeArtwork
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :name
6
+ has_one :awesome_image
7
+
8
+ json_fields \
9
+ name: {},
10
+ image: { type: :reference, definition: :awesome_image }
11
+ end
@@ -0,0 +1,14 @@
1
+ class AwesomeImage
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :name
6
+ field :nickname, default: 'Mona'
7
+ field :url, default: 'http://example.com/404.html'
8
+ belongs_to :awesome_artwork
9
+
10
+ json_fields \
11
+ name: {},
12
+ nickname: {},
13
+ url: { properties: :public }
14
+ end
@@ -0,0 +1,15 @@
1
+ class FastJsonArtwork
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :name, default: 'Artwork'
6
+ field :display_name, default: 'Awesome Artwork'
7
+ field :price, default: 1000
8
+ has_one :fast_json_image
9
+
10
+ json_fields \
11
+ name: {},
12
+ display_name: { properties: :public },
13
+ price: { properties: :all },
14
+ image: { type: :reference, definition: :fast_json_image }
15
+ end
@@ -0,0 +1,12 @@
1
+ class FastJsonImage
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :name, default: 'Image'
6
+ belongs_to :fast_json_artwork
7
+ has_and_belongs_to_many :fast_json_urls
8
+
9
+ json_fields \
10
+ name: {},
11
+ urls: { type: :reference, definition: :fast_json_urls }
12
+ end
@@ -0,0 +1,12 @@
1
+ class FastJsonUrl
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :url, default: 'http://art.sy/omg.jpeg'
6
+ field :is_public, default: false
7
+ has_and_belongs_to_many :fast_json_image
8
+
9
+ json_fields \
10
+ url: {},
11
+ is_public: { properties: :all }
12
+ end
@@ -0,0 +1,5 @@
1
+ require File.join(File.dirname(__FILE__), 'json_polymorphic_embedded_foobar')
2
+
3
+ class JsonEmbeddedFoobar < JsonPolymorphicEmbeddedFoobar
4
+ field :foo, type: String
5
+ end
@@ -0,0 +1,12 @@
1
+ class JsonEmployee
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :name
6
+ field :nickname, default: 'My Favorite'
7
+ belongs_to :json_manager
8
+
9
+ json_fields \
10
+ name: {},
11
+ nickname: { properties: :all }
12
+ end
@@ -0,0 +1,19 @@
1
+ class JsonFoobar
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :foo
6
+ field :bar
7
+ field :baz
8
+ field :default_foo, default: 'DEFAULT_FOO'
9
+
10
+ json_fields \
11
+ :foo => { properties: :short },
12
+ :bar => { properties: :public },
13
+ 'Baz' => { definition: :baz, version: :unspecified },
14
+ 'Taz' => { definition: :baz, version: :v2 },
15
+ 'Naz' => { definition: :baz, versions: [:v2, :v3] },
16
+ :renamed_baz => { properties: :all, definition: :baz },
17
+ :default_foo => {}, # default value for properties is :short
18
+ :computed_field => { properties: :all, definition: lambda { |x| "#{x.foo}#{x.bar}" } }
19
+ end
@@ -0,0 +1,14 @@
1
+ class JsonManager
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :name
6
+ field :ssn, default: '123-45-6789'
7
+ has_many :json_employees
8
+ belongs_to :supervisor, class_name: 'JsonSupervisor'
9
+
10
+ json_fields \
11
+ name: {},
12
+ ssn: { properties: :all },
13
+ employees: { type: :reference, definition: :json_employees }
14
+ end
@@ -0,0 +1,9 @@
1
+ class JsonMath
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :number
6
+
7
+ json_fields \
8
+ number: {}
9
+ end
@@ -0,0 +1,11 @@
1
+ class JsonParentFoobar
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ belongs_to :json_polymorphic_referenced_foobar
6
+ embeds_one :json_polymorphic_embedded_foobar
7
+
8
+ json_fields \
9
+ json_polymorphic_referenced_foobar: { type: :reference },
10
+ json_polymorphic_embedded_foobar: { type: :reference }
11
+ end
@@ -0,0 +1,9 @@
1
+ class JsonPolymorphicEmbeddedFoobar
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ embedded_in :json_parent_foobar
6
+
7
+ json_fields \
8
+ foo: { properties: :short }
9
+ end
@@ -0,0 +1,9 @@
1
+ class JsonPolymorphicReferencedFoobar
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ has_one :json_parent_foobar
6
+
7
+ json_fields \
8
+ foo: { properties: :short }
9
+ end
@@ -0,0 +1,5 @@
1
+ require File.join(File.dirname(__FILE__), 'json_polymorphic_referenced_foobar')
2
+
3
+ class JsonReferencedFoobar < JsonPolymorphicReferencedFoobar
4
+ field :foo, type: String
5
+ end
@@ -0,0 +1,13 @@
1
+ class JsonSupervisor
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :name
6
+ field :ssn, default: '123-45-6789'
7
+ has_many :json_managers
8
+
9
+ json_fields \
10
+ name: {},
11
+ ssn: { properties: :all },
12
+ managers: { type: :reference, definition: :json_managers, properties: :all, reference_properties: :short }
13
+ end
@@ -0,0 +1,13 @@
1
+ class JsonTransform
2
+ include Mongoid::Document
3
+ include Mongoid::CachedJson
4
+
5
+ field :upcase
6
+ field :downcase
7
+ field :nochange
8
+
9
+ json_fields \
10
+ upcase: { transform: :upcase },
11
+ downcase: { transform: :downcase },
12
+ nochange: {}
13
+ end