mongoid-cached-json 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
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