@@ -72,6 +72,56 @@ def persistent(name, **opts, &block)
7272 end
7373 end
7474
75+ ##
76+ # Cache an ActiveRecord collection. Supports only a basic collection of one type of object. Column selections or
77+ # joins etc. will NOT be respected when the collection is read back out.
78+ # @param name [String] cache key name
79+ # @param value [ActiveRecord::Relation] collection to cache
80+ # @param opts [Hash] options hash - any unlisted options will be passed to the underlying cache
81+ # @option opts [Boolean] :include_community whether to include the community ID in the cache key
82+ def write_collection ( name , value , **opts )
83+ types = value . map ( &:class ) . uniq
84+ if types . size > 1
85+ raise TypeError , "Can't cache more than one type of object via write_collection"
86+ end
87+
88+ data = [ types [ 0 ] , ...value . map ( &:id ) ]
89+ namespaced = construct_ns_key ( name , include_community : include_community ( opts ) )
90+ @underlying . write ( namespaced , data , **opts )
91+ end
92+
93+ ##
94+ # Read an ActiveRecord collection from cache. Returns a basic collection of the records that were cached, with
95+ # no selects or joins applied.
96+ # @param name [String] cache key name
97+ # @param opts [Hash] options hash - any unlisted options will be passed to the underlying cache
98+ # @options opts [Boolean] :include_community whether to include the community ID in the cache key
99+ def read_collection ( name , **opts )
100+ namespaced = construct_ns_key ( name , include_community : include_community ( opts ) )
101+ data = @underlying . read ( namespaced , **opts )
102+ type = data . slice! ( 0 )
103+ type . constantize . where ( id : data )
104+ end
105+
106+ ##
107+ # Fetch an ActiveRecord collection from cache if it is present, otherwise cache the value returned by +block+.
108+ # @param name [String] cache key name
109+ # @param opts [Hash] options hash - any unlisted options will be passed to the underlying cache
110+ # @option opts [Boolean] :include_community whether to include the community ID in the cache key
111+ # @yieldreturn [ActiveRecord::Relation]
112+ def fetch_collection ( name , **opts , &block )
113+ if @underlying . exist? ( name )
114+ read_collection ( name , **opts )
115+ else
116+ unless block_given?
117+ raise ArgumentError , "Can't fetch collection without a block given"
118+ end
119+ data = block . call
120+ write_collection ( name , data , **opts )
121+ data
122+ end
123+ end
124+
75125 # We have to statically report that we support cache versioning even though this depends on the underlying class.
76126 # However, this is not really a problem since all cache stores provided by activesupport support the feature and
77127 # we only use the redis cache (by activesupport) for QPixel.
0 commit comments