mongoid-cached-json 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -3,7 +3,7 @@ Mongoid::CachedJson [![Build Status](https://secure.travis-ci.org/dblock/mongoid
3
3
 
4
4
  Typical *as_json* definitions may involve lots of database point queries and method calls. When returning collections of objects, a single call may yield hundreds of database queries that can take seconds. This library mitigates the problem by implementing a module called *CachedJson*.
5
5
 
6
- CachedJson enables returning multiple JSON formats from a single class and provides some rules for returning embedded or referenced data. It then uses a scheme where fragments of JSON are cached for a particular (class, id) pair containing only the data that doesn't involve references/embedded documents. To get the full JSON for an instance, CachedJson will combine fragments of JSON from the instance with fragments representing the JSON for its references. In the best case, when all of these fragments are cached, this falls through to a few cache lookups followed by a couple Ruby hash merges to create the JSON.
6
+ CachedJson enables returning multiple JSON formats and versions from a single class and provides some rules for returning embedded or referenced data. It then uses a scheme where fragments of JSON are cached for a particular (class, id) pair containing only the data that doesn't involve references/embedded documents. To get the full JSON for an instance, CachedJson will combine fragments of JSON from the instance with fragments representing the JSON for its references. In the best case, when all of these fragments are cached, this falls through to a few cache lookups followed by a couple Ruby hash merges to create the JSON.
7
7
 
8
8
  Using Mongoid::CachedJson we were able to cut our JSON API average response time by about a factor of 10.
9
9
 
@@ -78,8 +78,16 @@ Mongoid::CachedJson.configure do |config|
78
78
  end
79
79
  ```
80
80
 
81
- Definining Fields
82
- -----------------
81
+ The default JSON version returned from `as_json` is `:unspecified`. If you wish to redefine this, set `Mongoid::CachedJson.config.default_version`.
82
+
83
+ ``` ruby
84
+ Mongoid::CachedJson.configure do |config|
85
+ config.default_version = :v2
86
+ end
87
+ ```
88
+
89
+ Defining Fields
90
+ ---------------
83
91
 
84
92
  Mongoid::CachedJson supports the following options.
85
93
 
@@ -90,6 +98,42 @@ Mongoid::CachedJson field definitions support the following options.
90
98
  * `:definition` can be a symbol or an anonymous function, eg. `:description => { :definition => :name }` or `:description => { :definition => lambda { |instance| instance.name } }`
91
99
  * `:type` can be `:reference`, required for referenced objects
92
100
  * `:properties` can be one of `:short`, `:public`, `:all`, in this order
101
+ * `:version` can be a single version for this field to appear in
102
+ * `:versions` can be an array of versions for this field to appear in
103
+
104
+ Versioning
105
+ ----------
106
+
107
+ You can set an optional `version` or `versions` attribute on JSON fields. Consider the following definition where the first version defined `:name`, then split it into `:first`, `:middle` and `:last` in version `:v2` and introduced a date of birth in `:v3`.
108
+
109
+ ``` ruby
110
+ class Person
111
+ include Mongoid::Document
112
+ include Mongoid::CachedJson
113
+
114
+ field :first
115
+ field :last
116
+
117
+ def name
118
+ [ first, middle, last ].compact.join(" ")
119
+ end
120
+
121
+ json_fields \
122
+ :first => { :versions => [ :v2, :v3 ] },
123
+ :last => { :versions => [ :v2, :v3 ] },
124
+ :middle => { :versions => [ :v2, :v3 ] },
125
+ :born => { :versions => :v3 },
126
+ :name => { :definition => :name }
127
+
128
+ end
129
+ ```
130
+
131
+ ``` ruby
132
+ person = Person.create({ :first => "John", :middle => "F.", :last => "Kennedy", :born => "May 29, 1917" })
133
+ person.as_json # { :name => "John F. Kennedy" }
134
+ person.as_json({ :version => :v2 }) # { :first => "John", :middle => "F.", :last => "Kennedy", :name => "John F. Kennedy" }
135
+ person.as_json({ :version => :v3 }) # { :first => "John", :middle => "F.", :last => "Kennedy", :name => "John F. Kennedy", :born => "May 29, 1917" }
136
+ ```
93
137
 
94
138
  Transformations
95
139
  ---------------
@@ -98,6 +142,7 @@ You can define global transformations on all JSON values with `Mongoid::CachedJs
98
142
 
99
143
  ``` ruby
100
144
  class Widget
145
+ include Mongoid::Document
101
146
  include Mongoid::CachedJson
102
147
 
103
148
  field :name
@@ -128,11 +173,11 @@ You can set `Mongoid::CachedJson.config.disable_caching = true`. It may be a goo
128
173
  Contributing
129
174
  ------------
130
175
 
131
- Fork the project. Make your feature addition or bug fix with tests. Send a pull request. Bonus points for topical branches.
176
+ Fork the project. Make your feature addition or bug fix with tests. Send a pull request. Bonus points for topic branches.
132
177
 
133
178
  Copyright and License
134
179
  ---------------------
135
180
 
136
- MIT License, see [LICENSE](LICENSE.md) for details.
181
+ MIT License, see [LICENSE](https://github.com/dblock/mongoid-cached-json/blob/master/LICENSE.md) for details.
137
182
 
138
- (c) 2012 [Art.sy Inc.](http://artsy.github.com) and [Contributors](HISTORY.md)
183
+ (c) 2012 [Art.sy Inc.](http://artsy.github.com) and [Contributors](https://github.com/dblock/mongoid-cached-json/blob/master/HISTORY.md)
@@ -5,6 +5,7 @@ module Mongoid
5
5
 
6
6
  included do
7
7
  class_attribute :all_json_properties
8
+ class_attribute :all_json_versions
8
9
  class_attribute :cached_json_field_defs
9
10
  class_attribute :cached_json_reference_defs
10
11
  class_attribute :hide_as_child_json_when
@@ -16,13 +17,17 @@ module Mongoid
16
17
  #
17
18
  # @param [ hash ] defs JSON field definition.
18
19
  #
19
- # @since 1.0.0
20
+ # @since 1.0
20
21
  def json_fields(defs)
21
22
  self.hide_as_child_json_when = defs.delete(:hide_as_child_json_when) || lambda { |a| false }
22
23
  self.all_json_properties = [:short, :public, :all]
23
24
  cached_json_defs = Hash[defs.map { |k,v| [k, { :type => :callable, :properties => :short, :definition => k }.merge(v)] }]
24
25
  self.cached_json_field_defs = {}
25
26
  self.cached_json_reference_defs = {}
27
+ # Collect all versions for clearing cache
28
+ self.all_json_versions = cached_json_defs.map do |field, definition|
29
+ [ :unspecified, definition[:version], Array(definition[:versions]) ]
30
+ end.flatten.compact.uniq
26
31
  self.all_json_properties.each_with_index do |property, i|
27
32
  self.cached_json_field_defs[property] = Hash[cached_json_defs.find_all do |field, definition|
28
33
  self.all_json_properties.find_index(definition[:properties]) <= i and definition[:type] == :callable
@@ -62,6 +67,9 @@ module Mongoid
62
67
  nil
63
68
  else
64
69
  Hash[clazz.cached_json_field_defs[options[:properties]].map do |field, definition|
70
+ # version match
71
+ versions = ([definition[:version] ] | Array(definition[:versions])).compact
72
+ next unless versions.empty? or versions.include?(options[:version])
65
73
  json_value = (definition[:definition].is_a?(Symbol) ? object_reference.send(definition[:definition]) : definition[:definition].call(object_reference))
66
74
  Mongoid::CachedJson.config.transform.each do |t|
67
75
  json_value = t.call(field, definition, json_value)
@@ -85,9 +93,9 @@ module Mongoid
85
93
 
86
94
  # Cache key.
87
95
  def cached_json_key(options, cached_class, cached_id)
88
- "as_json/#{cached_class}/#{cached_id}/#{options[:properties]}/#{!!options[:is_top_level_json]}"
96
+ "as_json/#{options[:version]}/#{cached_class}/#{cached_id}/#{options[:properties]}/#{!!options[:is_top_level_json]}"
89
97
  end
90
-
98
+
91
99
  # If the reference is a symbol, we may be lucky and be able to figure out the as_json
92
100
  # representation by the (class, id) pair definition of the reference. That is, we may
93
101
  # be able to load the as_json representation from the cache without even getting the
@@ -116,17 +124,24 @@ module Mongoid
116
124
 
117
125
  end
118
126
 
119
- def as_json(options = { :properties => :short })
120
- raise ArgumentError.new("Missing options[:properties]") if (options.nil? || options[:properties].nil?)
121
- raise ArgumentError.new("Unknown properties option: #{options[:properties]}") if !self.all_json_properties.member?(options[:properties])
122
- self.class.materialize_json({ :is_top_level_json => true }.merge(options), { :object => self })
127
+ def as_json(options = {})
128
+ if options[:properties] and ! self.all_json_properties.member?(options[:properties])
129
+ raise ArgumentError.new("Unknown properties option: #{options[:properties]}")
130
+ end
131
+ self.class.materialize_json({
132
+ :properties => :short, :is_top_level_json => true, :version => Mongoid::CachedJson.config.default_version
133
+ }.merge(options), { :object => self })
123
134
  end
124
135
 
125
136
  # Expire all JSON entries for this class.
126
137
  def expire_cached_json
127
138
  self.all_json_properties.each do |properties|
128
139
  [true, false].each do |is_top_level_json|
129
- Mongoid::CachedJson.config.cache.delete(self.class.cached_json_key({:properties => properties, :is_top_level_json => is_top_level_json}, self.class, self.id))
140
+ self.all_json_versions.each do |version|
141
+ Mongoid::CachedJson.config.cache.delete(self.class.cached_json_key({
142
+ :properties => properties, :is_top_level_json => is_top_level_json, :version => version
143
+ }, self.class, self.id))
144
+ end
130
145
  end
131
146
  end
132
147
  end
@@ -148,4 +163,4 @@ module Mongoid
148
163
  end
149
164
 
150
165
  end
151
- end
166
+ end
@@ -1,11 +1,16 @@
1
1
  # encoding: utf-8
2
- module Mongoid
3
- module CachedJson #:nodoc
2
+ module Mongoid
3
+ module CachedJson
4
4
  module Config
5
5
  extend self
6
6
  include ActiveSupport::Callbacks
7
7
 
8
- attr_accessor :settings, :defaults
8
+ # Current configuration settings.
9
+ attr_accessor :settings
10
+
11
+ # Default configuration settings.
12
+ attr_accessor :defaults
13
+
9
14
  @settings = {}
10
15
  @defaults = {}
11
16
 
@@ -36,8 +41,30 @@ module Mongoid
36
41
  RUBY
37
42
  end
38
43
 
44
+ # Disable caching.
39
45
  option :disable_caching, { :default => false }
40
46
 
47
+ # Returns the default JSON version
48
+ #
49
+ # @example Get the default JSON version
50
+ # config.default_version
51
+ #
52
+ # @return [ Version ] The default JSON version.
53
+ def default_version
54
+ settings[:default_version] = :unspecified unless settings.has_key?(:default_version)
55
+ settings[:default_version]
56
+ end
57
+
58
+ # Sets the default JSON version.
59
+ #
60
+ # @example Set the default version.
61
+ # config.default_version = :v2
62
+ #
63
+ # @return [ Version ] The newly set default version.
64
+ def default_version=(default_version)
65
+ settings[:default_version] = default_version
66
+ end
67
+
41
68
  # Returns the default cache store, which is either a Rails logger of stdout logger
42
69
  #
43
70
  # @example Get the default cache store
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid
3
3
  module CachedJson
4
- VERSION = '1.0'
4
+ VERSION = '1.1'
5
5
  end
6
6
  end
7
7
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-cached-json
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.0'
4
+ version: '1.1'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,11 +11,11 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-02-20 00:00:00.000000000Z
14
+ date: 2012-03-13 00:00:00.000000000Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
18
- requirement: &70215312132660 !ruby/object:Gem::Requirement
18
+ requirement: &82900940 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
21
  - - ! '>='
@@ -23,10 +23,10 @@ dependencies:
23
23
  version: '0'
24
24
  type: :runtime
25
25
  prerelease: false
26
- version_requirements: *70215312132660
26
+ version_requirements: *82900940
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: mongoid
29
- requirement: &70215312131960 !ruby/object:Gem::Requirement
29
+ requirement: &82886650 !ruby/object:Gem::Requirement
30
30
  none: false
31
31
  requirements:
32
32
  - - ! '>='
@@ -34,10 +34,10 @@ dependencies:
34
34
  version: '0'
35
35
  type: :runtime
36
36
  prerelease: false
37
- version_requirements: *70215312131960
37
+ version_requirements: *82886650
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: bson_ext
40
- requirement: &70215312120160 !ruby/object:Gem::Requirement
40
+ requirement: &82886190 !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
43
  - - ! '>='
@@ -45,10 +45,10 @@ dependencies:
45
45
  version: '0'
46
46
  type: :runtime
47
47
  prerelease: false
48
- version_requirements: *70215312120160
48
+ version_requirements: *82886190
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: hpricot
51
- requirement: &70215312118740 !ruby/object:Gem::Requirement
51
+ requirement: &82885630 !ruby/object:Gem::Requirement
52
52
  none: false
53
53
  requirements:
54
54
  - - ! '>='
@@ -56,10 +56,10 @@ dependencies:
56
56
  version: '0'
57
57
  type: :runtime
58
58
  prerelease: false
59
- version_requirements: *70215312118740
59
+ version_requirements: *82885630
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: rspec
62
- requirement: &70215312117220 !ruby/object:Gem::Requirement
62
+ requirement: &82885050 !ruby/object:Gem::Requirement
63
63
  none: false
64
64
  requirements:
65
65
  - - ~>
@@ -67,10 +67,10 @@ dependencies:
67
67
  version: '2.5'
68
68
  type: :development
69
69
  prerelease: false
70
- version_requirements: *70215312117220
70
+ version_requirements: *82885050
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: bundler
73
- requirement: &70215312116260 !ruby/object:Gem::Requirement
73
+ requirement: &82884260 !ruby/object:Gem::Requirement
74
74
  none: false
75
75
  requirements:
76
76
  - - ~>
@@ -78,10 +78,10 @@ dependencies:
78
78
  version: '1.0'
79
79
  type: :development
80
80
  prerelease: false
81
- version_requirements: *70215312116260
81
+ version_requirements: *82884260
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: jeweler
84
- requirement: &70215312115520 !ruby/object:Gem::Requirement
84
+ requirement: &82883690 !ruby/object:Gem::Requirement
85
85
  none: false
86
86
  requirements:
87
87
  - - ~>
@@ -89,10 +89,10 @@ dependencies:
89
89
  version: '1.6'
90
90
  type: :development
91
91
  prerelease: false
92
- version_requirements: *70215312115520
92
+ version_requirements: *82883690
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: yard
95
- requirement: &70215312114460 !ruby/object:Gem::Requirement
95
+ requirement: &82883090 !ruby/object:Gem::Requirement
96
96
  none: false
97
97
  requirements:
98
98
  - - ~>
@@ -100,7 +100,7 @@ dependencies:
100
100
  version: '0.6'
101
101
  type: :development
102
102
  prerelease: false
103
- version_requirements: *70215312114460
103
+ version_requirements: *82883090
104
104
  description: Cached-json is a DSL for describing JSON representations of Mongoid models.
105
105
  email: dblock@dblock.org
106
106
  executables: []
@@ -130,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
130
130
  version: '0'
131
131
  segments:
132
132
  - 0
133
- hash: 2087512391400708959
133
+ hash: -206724813
134
134
  required_rubygems_version: !ruby/object:Gem::Requirement
135
135
  none: false
136
136
  requirements: