Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Alternate versioned implementation.
  • Loading branch information
dblock committed Feb 29, 2012
commit 3c229c0371915e80523e32e4ed59b943e42eb023
24 changes: 18 additions & 6 deletions lib/mongoid-cached-json/cached_json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module CachedJson

included do
class_attribute :all_json_properties
class_attribute :all_json_versions
class_attribute :cached_json_field_defs
class_attribute :cached_json_reference_defs
class_attribute :hide_as_child_json_when
Expand All @@ -16,13 +17,17 @@ module ClassMethods
#
# @param [ hash ] defs JSON field definition.
#
# @since 1.0.0
# @since 1.0
def json_fields(defs)
self.hide_as_child_json_when = defs.delete(:hide_as_child_json_when) || lambda { |a| false }
self.all_json_properties = [:short, :public, :all]
cached_json_defs = Hash[defs.map { |k,v| [k, { :type => :callable, :properties => :short, :definition => k }.merge(v)] }]
self.cached_json_field_defs = {}
self.cached_json_reference_defs = {}
# Collect all versions for clearing cache
self.all_json_versions = cached_json_defs.map do |field, definition|
[ Mongoid::CachedJson.config.default_version, definition[:version], Array(definition[:versions]) ]
end.flatten.compact.uniq
self.all_json_properties.each_with_index do |property, i|
self.cached_json_field_defs[property] = Hash[cached_json_defs.find_all do |field, definition|
self.all_json_properties.find_index(definition[:properties]) <= i and definition[:type] == :callable
Expand Down Expand Up @@ -62,6 +67,9 @@ def materialize_json(options, object_def)
nil
else
Hash[clazz.cached_json_field_defs[options[:properties]].map do |field, definition|
# version match
versions = ([definition[:version] ] | Array(definition[:versions])).compact
next unless versions.empty? or versions.include?(options[:version])
json_value = (definition[:definition].is_a?(Symbol) ? object_reference.send(definition[:definition]) : definition[:definition].call(object_reference))
Mongoid::CachedJson.config.transform.each do |t|
json_value = t.call(field, definition, json_value)
Expand All @@ -85,9 +93,9 @@ def materialize_json(options, object_def)

# Cache key.
def cached_json_key(options, cached_class, cached_id)
"as_json/#{cached_class}/#{cached_id}/#{options[:properties]}/#{!!options[:is_top_level_json]}"
"as_json/#{options[:version]}/#{cached_class}/#{cached_id}/#{options[:properties]}/#{!!options[:is_top_level_json]}"
end

# If the reference is a symbol, we may be lucky and be able to figure out the as_json
# representation by the (class, id) pair definition of the reference. That is, we may
# be able to load the as_json representation from the cache without even getting the
Expand Down Expand Up @@ -119,14 +127,18 @@ def resolve_json_reference(options, object, field, reference_def)
def as_json(options = { :properties => :short })
raise ArgumentError.new("Missing options[:properties]") if (options.nil? || options[:properties].nil?)
raise ArgumentError.new("Unknown properties option: #{options[:properties]}") if !self.all_json_properties.member?(options[:properties])
self.class.materialize_json({ :is_top_level_json => true }.merge(options), { :object => self })
self.class.materialize_json({ :is_top_level_json => true, :version => Mongoid::CachedJson.config.default_version }.merge(options), { :object => self })
end

# Expire all JSON entries for this class.
def expire_cached_json
self.all_json_properties.each do |properties|
[true, false].each do |is_top_level_json|
Mongoid::CachedJson.config.cache.delete(self.class.cached_json_key({:properties => properties, :is_top_level_json => is_top_level_json}, self.class, self.id))
self.all_json_versions.each do |version|
Mongoid::CachedJson.config.cache.delete(self.class.cached_json_key({
:properties => properties, :is_top_level_json => is_top_level_json, :version => version
}, self.class, self.id))
end
end
end
end
Expand All @@ -148,4 +160,4 @@ def configure
end

end
end
end
33 changes: 30 additions & 3 deletions lib/mongoid-cached-json/config.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# encoding: utf-8
module Mongoid
module CachedJson #:nodoc
module Mongoid
module CachedJson
module Config
extend self
include ActiveSupport::Callbacks

attr_accessor :settings, :defaults
# Current configuration settings.
attr_accessor :settings

# Default configuration settings.
attr_accessor :defaults

@settings = {}
@defaults = {}

Expand Down Expand Up @@ -36,8 +41,30 @@ def #{name}?
RUBY
end

# Disable caching.
option :disable_caching, { :default => false }

# Returns the default JSON version
#
# @example Get the default JSON version
# config.default_version
#
# @return [ Version ] The default JSON version.
def default_version
settings[:default_version] = :default unless settings.has_key?(:default_version)
settings[:default_version]
end

# Sets the default JSON version.
#
# @example Set the default version.
# config.default_version = :v2
#
# @return [ Version ] The newly set default version.
def default_version=(default_version)
settings[:default_version] = default_version
end

# Returns the default cache store, which is either a Rails logger of stdout logger
#
# @example Get the default cache store
Expand Down
33 changes: 21 additions & 12 deletions spec/cached_json_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,6 @@
value.upcase
end
end
after :each do
Mongoid::CachedJson.config.reset!
end
it "transforms every value in returned JSON" do
JsonFoobar.new({ :foo => "foo", :bar => "Bar", :baz => "BAZ" }).as_json.should == { "Baz" => "BAZ", :default_foo => "DEFAULT_FOO", :foo => "FOO" }
end
Expand All @@ -269,9 +266,6 @@
definition[:transform] ? value.send(definition[:transform].to_sym) : value
end
end
after :each do
Mongoid::CachedJson.config.reset!
end
it "transforms every value in returned JSON using the :transform attribute" do
JsonTransform.new({ :upcase => "upcase", :downcase => "DOWNCASE", :nochange => "eLiTe" }).as_json.should == { :upcase => "UPCASE", :downcase => "downcase", :nochange => "eLiTe" }
end
Expand All @@ -285,9 +279,6 @@
value.to_i / 2
end
end
after :each do
Mongoid::CachedJson.config.reset!
end
it "transforms every value in returned JSON using the :transform attribute" do
JsonMath.new({ :number => 9 }).as_json.should == { :number => 5 }
end
Expand All @@ -299,12 +290,30 @@
end
it "forces a cache miss" do
example = JsonFoobar.create({ :foo => "FOO", :baz => "BAZ", :bar => "BAR" })
Mongoid::CachedJson.config.cache.should_receive(:fetch).with("as_json/JsonFoobar/#{example.id}/short/true", { :force => true }).twice
Mongoid::CachedJson.config.cache.should_receive(:fetch).with("as_json/default/JsonFoobar/#{example.id}/short/true", { :force => true }).twice
example.as_json
example.as_json
end
after :each do
Mongoid::CachedJson.config.reset!
end
context "versioning" do
context "version 2" do
it "returns JSON for version 2" do
example = JsonFoobar.create(:foo => "FOO", :baz => "BAZ", :bar => "BAR")
example.as_json({ :properties => :short, :version => :v2 }).should == { :foo => "FOO", "Taz" => "BAZ", "Naz" => "BAZ", :default_foo => "DEFAULT_FOO" }
end
it "returns JSON for version 3" do
example = JsonFoobar.create(:foo => "FOO", :baz => "BAZ", :bar => "BAR")
example.as_json({ :properties => :short, :version => :v3 }).should == { :foo => "FOO", "Naz" => "BAZ", :default_foo => "DEFAULT_FOO" }
end
it "returns default JSON for version 4 that hasn't been declared" do
example = JsonFoobar.create(:foo => "FOO", :baz => "BAZ", :bar => "BAR")
example.as_json({ :properties => :short, :version => :v4 }).should == { :foo => "FOO", :default_foo => "DEFAULT_FOO" }
end
it "returns JSON for the default version" do
Mongoid::CachedJson.config.default_version = :v2
example = JsonFoobar.create(:foo => "FOO", :baz => "BAZ", :bar => "BAR")
example.as_json({ :properties => :short }).should == { :foo => "FOO", "Taz" => "BAZ", "Naz" => "BAZ", :default_foo => "DEFAULT_FOO" }
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

describe Mongoid::CachedJson::Config do
before :each do
@cache= Mongoid::CachedJson::Config.cache
@cache = Mongoid::CachedJson::Config.cache
end
after :each do
Mongoid::CachedJson::Config.cache = @cache
Expand Down
6 changes: 6 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,9 @@
config.master = Mongo::Connection.new.db("cached_json_test")
end

RSpec.configure do |config|
config.after :each do
Mongoid::CachedJson.config.reset!
end
end

6 changes: 4 additions & 2 deletions spec/support/json_foobar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ class JsonFoobar
json_fields \
:foo => { :properties => :short },
:bar => { :properties => :public },
"Baz" => { :definition => :baz },
"Baz" => { :definition => :baz, :versions => [ :default ] },
"Taz" => { :definition => :baz, :version => :v2 },
"Naz" => { :definition => :baz, :versions => [ :v2, :v3 ] },
:renamed_baz => { :properties => :all, :definition => :baz },
:default_foo => { }, # default value for properties is :short
:computed_field => { :properties => :all, :definition => lambda { |x| x.foo + x.bar } }

end