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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/.rubocop.yml +6 -0
- data/.rubocop_todo.yml +80 -0
- data/.travis.yml +16 -0
- data/CHANGELOG.md +85 -0
- data/CONTRIBUTING.md +118 -0
- data/Gemfile +21 -0
- data/README.md +49 -52
- data/Rakefile +34 -0
- data/lib/mongoid-cached-json.rb +0 -1
- data/lib/mongoid-cached-json/array.rb +1 -3
- data/lib/mongoid-cached-json/cached_json.rb +52 -50
- data/lib/mongoid-cached-json/config.rb +20 -21
- data/lib/mongoid-cached-json/hash.rb +1 -3
- data/lib/mongoid-cached-json/key_references.rb +0 -3
- data/lib/mongoid-cached-json/mongoid_criteria.rb +1 -3
- data/lib/mongoid-cached-json/version.rb +1 -2
- data/mongoid-cached-json.gemspec +17 -0
- data/spec/array_spec.rb +48 -0
- data/spec/benchmark_spec.rb +115 -0
- data/spec/cached_json_spec.rb +501 -0
- data/spec/config_spec.rb +21 -0
- data/spec/dalli_spec.rb +37 -0
- data/spec/hash_spec.rb +66 -0
- data/spec/mongoid_criteria_spec.rb +78 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/awesome_artwork.rb +11 -0
- data/spec/support/awesome_image.rb +14 -0
- data/spec/support/fast_json_artwork.rb +15 -0
- data/spec/support/fast_json_image.rb +12 -0
- data/spec/support/fast_json_url.rb +12 -0
- data/spec/support/json_embedded_foobar.rb +5 -0
- data/spec/support/json_employee.rb +12 -0
- data/spec/support/json_foobar.rb +19 -0
- data/spec/support/json_manager.rb +14 -0
- data/spec/support/json_math.rb +9 -0
- data/spec/support/json_parent_foobar.rb +11 -0
- data/spec/support/json_polymorphic_embedded_foobar.rb +9 -0
- data/spec/support/json_polymorphic_referenced_foobar.rb +9 -0
- data/spec/support/json_referenced_foobar.rb +5 -0
- data/spec/support/json_supervisor.rb +13 -0
- data/spec/support/json_transform.rb +13 -0
- data/spec/support/matchers/invalidate.rb +22 -0
- data/spec/support/person.rb +20 -0
- data/spec/support/poly_company.rb +10 -0
- data/spec/support/poly_person.rb +10 -0
- data/spec/support/poly_post.rb +9 -0
- data/spec/support/prison_cell.rb +11 -0
- data/spec/support/prison_inmate.rb +12 -0
- data/spec/support/secret_parent.rb +11 -0
- data/spec/support/sometimes_secret.rb +11 -0
- data/spec/support/tool.rb +11 -0
- data/spec/support/tool_box.rb +10 -0
- metadata +62 -137
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
require File.expand_path('../lib/mongoid-cached-json/version', __FILE__)
|
5
|
+
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
|
+
|
9
|
+
require 'rake'
|
10
|
+
|
11
|
+
require 'rspec/core'
|
12
|
+
require 'rspec/core/rake_task'
|
13
|
+
|
14
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
15
|
+
files = FileList['spec/**/*_spec.rb']
|
16
|
+
files = files.exclude 'spec/benchmark_spec.rb'
|
17
|
+
spec.pattern = files
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rdoc/task'
|
21
|
+
Rake::RDocTask.new do |rdoc|
|
22
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ''
|
23
|
+
|
24
|
+
rdoc.rdoc_dir = 'rdoc'
|
25
|
+
rdoc.title = "mongoid-cached-json #{version}"
|
26
|
+
rdoc.rdoc_files.include('README*')
|
27
|
+
rdoc.rdoc_files.include('LICENSE*')
|
28
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'rubocop/rake_task'
|
32
|
+
RuboCop::RakeTask.new
|
33
|
+
|
34
|
+
task default: [:rubocop, :spec]
|
data/lib/mongoid-cached-json.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
class Array
|
2
|
-
|
3
2
|
def as_json_partial(options = {})
|
4
3
|
json_keys = nil
|
5
4
|
json = map do |i|
|
@@ -11,12 +10,11 @@ class Array
|
|
11
10
|
i.as_json(options)
|
12
11
|
end
|
13
12
|
end
|
14
|
-
[
|
13
|
+
[json_keys, json]
|
15
14
|
end
|
16
15
|
|
17
16
|
def as_json(options = {})
|
18
17
|
json_keys, json = as_json_partial(options)
|
19
18
|
Mongoid::CachedJson.materialize_json_references_with_read_multi(json_keys, json)
|
20
19
|
end
|
21
|
-
|
22
20
|
end
|
@@ -12,33 +12,32 @@ module Mongoid
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module ClassMethods
|
15
|
-
|
16
15
|
# Define JSON fields for a class.
|
17
16
|
#
|
18
17
|
# @param [ hash ] defs JSON field definition.
|
19
18
|
#
|
20
19
|
# @since 1.0
|
21
20
|
def json_fields(defs)
|
22
|
-
self.hide_as_child_json_when = defs.delete(:hide_as_child_json_when) || lambda { |
|
23
|
-
self.all_json_properties = [
|
24
|
-
cached_json_defs = Hash[defs.map { |k,v| [k, { :
|
21
|
+
self.hide_as_child_json_when = defs.delete(:hide_as_child_json_when) || lambda { |_a| false }
|
22
|
+
self.all_json_properties = [:short, :public, :all]
|
23
|
+
cached_json_defs = Hash[defs.map { |k, v| [k, { type: :callable, properties: :short, definition: k }.merge(v)] }]
|
25
24
|
self.cached_json_field_defs = {}
|
26
25
|
self.cached_json_reference_defs = {}
|
27
26
|
# Collect all versions for clearing cache
|
28
|
-
self.all_json_versions = cached_json_defs.map do |
|
29
|
-
[
|
27
|
+
self.all_json_versions = cached_json_defs.map do |_field, definition|
|
28
|
+
[:unspecified, definition[:version], Array(definition[:versions])]
|
30
29
|
end.flatten.compact.uniq
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
all_json_properties.each_with_index do |property, i|
|
31
|
+
cached_json_field_defs[property] = Hash[cached_json_defs.find_all do |_field, definition|
|
32
|
+
all_json_properties.find_index(definition[:properties]) <= i && definition[:type] == :callable
|
34
33
|
end]
|
35
|
-
|
36
|
-
|
34
|
+
cached_json_reference_defs[property] = Hash[cached_json_defs.find_all do |_field, definition|
|
35
|
+
all_json_properties.find_index(definition[:properties]) <= i && definition[:type] == :reference
|
37
36
|
end]
|
38
37
|
# If the field is a reference and is just specified as a symbol, reflect on it to get metadata
|
39
|
-
|
38
|
+
cached_json_reference_defs[property].to_a.each do |field, definition|
|
40
39
|
if definition[:definition].is_a?(Symbol)
|
41
|
-
|
40
|
+
cached_json_reference_defs[property][field][:metadata] = reflect_on_association(definition[:definition])
|
42
41
|
end
|
43
42
|
end
|
44
43
|
end
|
@@ -49,20 +48,20 @@ module Mongoid
|
|
49
48
|
# Materialize a cached JSON within a cache block.
|
50
49
|
def materialize_cached_json(clazz, id, object_reference, options)
|
51
50
|
is_top_level_json = options[:is_top_level_json] || false
|
52
|
-
object_reference = clazz.where(
|
51
|
+
object_reference = clazz.where(_id: id).first unless object_reference
|
53
52
|
if !object_reference || (!is_top_level_json && options[:properties] != :all && clazz.hide_as_child_json_when.call(object_reference))
|
54
53
|
nil
|
55
54
|
else
|
56
55
|
Hash[clazz.cached_json_field_defs[options[:properties]].map do |field, definition|
|
57
56
|
# version match
|
58
|
-
versions = ([definition[:version]
|
59
|
-
next unless versions.empty?
|
57
|
+
versions = ([definition[:version]] | Array(definition[:versions])).compact
|
58
|
+
next unless versions.empty? || versions.include?(options[:version])
|
60
59
|
json_value = (definition[:definition].is_a?(Symbol) ? object_reference.send(definition[:definition]) : definition[:definition].call(object_reference))
|
61
60
|
Mongoid::CachedJson.config.transform.each do |t|
|
62
61
|
json_value = t.call(field, definition, json_value)
|
63
62
|
end
|
64
63
|
[field, json_value]
|
65
|
-
end]
|
64
|
+
end.compact]
|
66
65
|
end
|
67
66
|
end
|
68
67
|
|
@@ -73,7 +72,7 @@ module Mongoid
|
|
73
72
|
# the JSON by calling resolve_json_reference on each of them (which may, in turn,
|
74
73
|
# call materialize_json)
|
75
74
|
def materialize_json(options, object_def)
|
76
|
-
return nil if !object_def[:object]
|
75
|
+
return nil if !object_def[:object] && !object_def[:id]
|
77
76
|
is_top_level_json = options[:is_top_level_json] || false
|
78
77
|
if object_def[:object]
|
79
78
|
object_reference = object_def[:object]
|
@@ -82,18 +81,18 @@ module Mongoid
|
|
82
81
|
object_reference = nil
|
83
82
|
clazz, id = object_def[:clazz], object_def[:id]
|
84
83
|
end
|
85
|
-
key =
|
86
|
-
json = { :
|
84
|
+
key = cached_json_key(options, clazz, id)
|
85
|
+
json = { _ref: { _clazz: self, _key: key, _materialize_cached_json: [clazz, id, object_reference, options] } }
|
87
86
|
keys = KeyReferences.new
|
88
87
|
keys.set_and_add(key, json)
|
89
88
|
reference_defs = clazz.cached_json_reference_defs[options[:properties]]
|
90
|
-
|
91
|
-
object_reference = clazz.where(
|
89
|
+
unless reference_defs.empty?
|
90
|
+
object_reference = clazz.where(_id: id).first unless object_reference
|
92
91
|
if object_reference && (is_top_level_json || options[:properties] == :all || !clazz.hide_as_child_json_when.call(object_reference))
|
93
92
|
json.merge!(Hash[reference_defs.map do |field, definition|
|
94
93
|
json_properties_type = definition[:reference_properties] || ((options[:properties] == :all) ? :all : :short)
|
95
|
-
reference_keys, reference = clazz.resolve_json_reference(options.merge(
|
96
|
-
if
|
94
|
+
reference_keys, reference = clazz.resolve_json_reference(options.merge(properties: json_properties_type, is_top_level_json: false), object_reference, field, definition)
|
95
|
+
if reference.is_a?(Hash) && ref = reference[:_ref]
|
97
96
|
ref[:_parent] = json
|
98
97
|
ref[:_field] = field
|
99
98
|
end
|
@@ -102,7 +101,7 @@ module Mongoid
|
|
102
101
|
end])
|
103
102
|
end
|
104
103
|
end
|
105
|
-
[
|
104
|
+
[keys, json]
|
106
105
|
end
|
107
106
|
|
108
107
|
# Cache key.
|
@@ -115,7 +114,7 @@ module Mongoid
|
|
115
114
|
# representation by the (class, id) pair definition of the reference. That is, we may
|
116
115
|
# be able to load the as_json representation from the cache without even getting the
|
117
116
|
# model from the database and materializing it through Mongoid. We'll try to do this first.
|
118
|
-
def resolve_json_reference(options, object,
|
117
|
+
def resolve_json_reference(options, object, _field, reference_def)
|
119
118
|
keys = nil
|
120
119
|
reference_json = nil
|
121
120
|
if reference_def[:metadata]
|
@@ -127,16 +126,20 @@ module Mongoid
|
|
127
126
|
end
|
128
127
|
if reference_def[:metadata].relation == Mongoid::Relations::Referenced::ManyToMany
|
129
128
|
object_ids = object.send(key)
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
129
|
+
if object_ids
|
130
|
+
reference_json = object_ids.map do |id|
|
131
|
+
materialize_keys, json = materialize_json(options, clazz: clazz, id: id)
|
132
|
+
keys = keys ? keys.merge_set(materialize_keys) : materialize_keys
|
133
|
+
json
|
134
|
+
end.compact
|
135
|
+
else
|
136
|
+
object_ids = []
|
137
|
+
end
|
135
138
|
end
|
136
139
|
end
|
137
140
|
# If we get to this point and reference_json is still nil, there's no chance we can
|
138
141
|
# load the JSON from cache so we go ahead and call as_json on the object.
|
139
|
-
|
142
|
+
unless reference_json
|
140
143
|
reference_def_definition = reference_def[:definition]
|
141
144
|
reference = reference_def_definition.is_a?(Symbol) ? object.send(reference_def_definition) : reference_def_definition.call(object)
|
142
145
|
reference_json = nil
|
@@ -149,9 +152,8 @@ module Mongoid
|
|
149
152
|
end
|
150
153
|
end
|
151
154
|
end
|
152
|
-
[
|
155
|
+
[keys, reference_json]
|
153
156
|
end
|
154
|
-
|
155
157
|
end
|
156
158
|
|
157
159
|
# Check whether the cache supports :read_multi and prefetch the data if it does.
|
@@ -169,15 +171,15 @@ module Mongoid
|
|
169
171
|
refs.each do |ref|
|
170
172
|
_ref = ref.delete(:_ref)
|
171
173
|
key = _ref[:_key]
|
172
|
-
fetched_json = local_cache[key] if local_cache.
|
173
|
-
|
174
|
+
fetched_json = local_cache[key] if local_cache.key?(key)
|
175
|
+
unless fetched_json
|
174
176
|
if read_multi
|
175
177
|
# no value in cache, materialize and write
|
176
178
|
fetched_json = (local_cache[key] = _ref[:_clazz].materialize_cached_json(* _ref[:_materialize_cached_json]))
|
177
|
-
Mongoid::CachedJson.config.cache.write(key, fetched_json) unless
|
179
|
+
Mongoid::CachedJson.config.cache.write(key, fetched_json) unless Mongoid::CachedJson.config.disable_caching
|
178
180
|
else
|
179
181
|
# fetch/write from cache
|
180
|
-
fetched_json = (local_cache[key] = Mongoid::CachedJson.config.cache.fetch(key,
|
182
|
+
fetched_json = (local_cache[key] = Mongoid::CachedJson.config.cache.fetch(key, force: !!Mongoid::CachedJson.config.disable_caching) do
|
181
183
|
_ref[:_clazz].materialize_cached_json(* _ref[:_materialize_cached_json])
|
182
184
|
end)
|
183
185
|
end
|
@@ -195,14 +197,14 @@ module Mongoid
|
|
195
197
|
# Return a partial JSON without resolved references and all the keys.
|
196
198
|
def as_json_partial(options = {})
|
197
199
|
options ||= {}
|
198
|
-
if options[:properties]
|
199
|
-
|
200
|
+
if options[:properties] && !all_json_properties.member?(options[:properties])
|
201
|
+
fail ArgumentError.new("Unknown properties option: #{options[:properties]}")
|
200
202
|
end
|
201
203
|
# partial, unmaterialized JSON
|
202
204
|
keys, partial_json = self.class.materialize_json({
|
203
|
-
:
|
204
|
-
}.merge(options),
|
205
|
-
[
|
205
|
+
properties: :short, is_top_level_json: true, version: Mongoid::CachedJson.config.default_version
|
206
|
+
}.merge(options), object: self)
|
207
|
+
[keys, partial_json]
|
206
208
|
end
|
207
209
|
|
208
210
|
# Fetch the partial JSON and materialize all JSON references.
|
@@ -218,19 +220,20 @@ module Mongoid
|
|
218
220
|
|
219
221
|
# Expire all JSON entries for this class.
|
220
222
|
def expire_cached_json
|
221
|
-
|
223
|
+
all_json_properties.each do |properties|
|
222
224
|
[true, false].each do |is_top_level_json|
|
223
|
-
|
225
|
+
all_json_versions.each do |version|
|
224
226
|
Mongoid::CachedJson.config.cache.delete(self.class.cached_json_key({
|
225
|
-
|
226
|
-
|
227
|
+
properties: properties,
|
228
|
+
is_top_level_json: is_top_level_json,
|
229
|
+
version: version
|
230
|
+
}, self.class, id))
|
227
231
|
end
|
228
232
|
end
|
229
233
|
end
|
230
234
|
end
|
231
235
|
|
232
236
|
class << self
|
233
|
-
|
234
237
|
# Set the configuration options. Best used by passing a block.
|
235
238
|
#
|
236
239
|
# @example Set up configuration options.
|
@@ -242,8 +245,7 @@ module Mongoid
|
|
242
245
|
def configure
|
243
246
|
block_given? ? yield(Mongoid::CachedJson::Config) : Mongoid::CachedJson::Config
|
244
247
|
end
|
245
|
-
|
248
|
+
alias_method :config, :configure
|
246
249
|
end
|
247
|
-
|
248
250
|
end
|
249
251
|
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
module Mongoid
|
3
|
-
module CachedJson
|
2
|
+
module Mongoid
|
3
|
+
module CachedJson
|
4
4
|
module Config
|
5
5
|
extend self
|
6
6
|
include ActiveSupport::Callbacks
|
7
|
-
|
7
|
+
|
8
8
|
# Current configuration settings.
|
9
9
|
attr_accessor :settings
|
10
|
-
|
10
|
+
|
11
11
|
# Default configuration settings.
|
12
12
|
attr_accessor :defaults
|
13
|
-
|
13
|
+
|
14
14
|
@settings = {}
|
15
15
|
@defaults = {}
|
16
|
-
|
16
|
+
|
17
17
|
# Define a configuration option with a default.
|
18
18
|
#
|
19
19
|
# @example Define the option.
|
@@ -25,25 +25,25 @@ module Mongoid
|
|
25
25
|
# @option options [ Object ] :default The default value.
|
26
26
|
def option(name, options = {})
|
27
27
|
defaults[name] = settings[name] = options[:default]
|
28
|
-
|
28
|
+
|
29
29
|
class_eval <<-RUBY
|
30
30
|
def #{name}
|
31
31
|
settings[#{name.inspect}]
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
def #{name}=(value)
|
35
35
|
settings[#{name.inspect}] = value
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
def #{name}?
|
39
39
|
#{name}
|
40
40
|
end
|
41
41
|
RUBY
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
# Disable caching.
|
45
|
-
option :disable_caching,
|
46
|
-
|
45
|
+
option :disable_caching, default: false
|
46
|
+
|
47
47
|
# Returns the default JSON version
|
48
48
|
#
|
49
49
|
# @example Get the default JSON version
|
@@ -51,7 +51,7 @@ module Mongoid
|
|
51
51
|
#
|
52
52
|
# @return [ Version ] The default JSON version.
|
53
53
|
def default_version
|
54
|
-
settings[:default_version] = :unspecified unless settings.
|
54
|
+
settings[:default_version] = :unspecified unless settings.key?(:default_version)
|
55
55
|
settings[:default_version]
|
56
56
|
end
|
57
57
|
|
@@ -64,7 +64,7 @@ module Mongoid
|
|
64
64
|
def default_version=(default_version)
|
65
65
|
settings[:default_version] = default_version
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
# Returns the default cache store, for example Rails cache or an instance of ActiveSupport::Cache::MemoryStore.
|
69
69
|
#
|
70
70
|
# @example Get the default cache store
|
@@ -74,7 +74,7 @@ module Mongoid
|
|
74
74
|
def default_cache
|
75
75
|
defined?(Rails) && Rails.respond_to?(:cache) ? Rails.cache : ::ActiveSupport::Cache::MemoryStore.new
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
# Returns the cache, or defaults to Rails cache when running under Rails or ActiveSupport::Cache::MemoryStore.
|
79
79
|
#
|
80
80
|
# @example Get the cache.
|
@@ -82,10 +82,10 @@ module Mongoid
|
|
82
82
|
#
|
83
83
|
# @return [ Cache ] The configured cache or a default cache instance.
|
84
84
|
def cache
|
85
|
-
settings[:cache] = default_cache unless settings.
|
85
|
+
settings[:cache] = default_cache unless settings.key?(:cache)
|
86
86
|
settings[:cache]
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
# Sets the cache to use.
|
90
90
|
#
|
91
91
|
# @example Set the cache.
|
@@ -95,7 +95,7 @@ module Mongoid
|
|
95
95
|
def cache=(cache)
|
96
96
|
settings[:cache] = cache
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
# Reset the configuration options to the defaults.
|
100
100
|
#
|
101
101
|
# @example Reset the configuration options.
|
@@ -103,7 +103,7 @@ module Mongoid
|
|
103
103
|
def reset!
|
104
104
|
settings.replace(defaults)
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
# Define a transformation on JSON data.
|
108
108
|
#
|
109
109
|
# @example Convert every string in materialized JSON to upper-case.
|
@@ -111,11 +111,10 @@ module Mongoid
|
|
111
111
|
# value.upcase
|
112
112
|
# end
|
113
113
|
def transform(& block)
|
114
|
-
settings[:transform] = [] unless settings.
|
114
|
+
settings[:transform] = [] unless settings.key?(:transform)
|
115
115
|
settings[:transform] << block if block_given?
|
116
116
|
settings[:transform]
|
117
117
|
end
|
118
|
-
|
119
118
|
end
|
120
119
|
end
|
121
120
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class Hash
|
2
|
-
|
3
2
|
def as_json_partial(options = {})
|
4
3
|
json_keys = nil
|
5
4
|
json = inject({}) do |h, (k, v)|
|
@@ -12,12 +11,11 @@ class Hash
|
|
12
11
|
end
|
13
12
|
h
|
14
13
|
end
|
15
|
-
[
|
14
|
+
[json_keys, json]
|
16
15
|
end
|
17
16
|
|
18
17
|
def as_json(options = {})
|
19
18
|
json_keys, json = as_json_partial(options)
|
20
19
|
Mongoid::CachedJson.materialize_json_references_with_read_multi(json_keys, json)
|
21
20
|
end
|
22
|
-
|
23
21
|
end
|