From d453d97df341c5b62fea1f13758bfded97df1ccf Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Fri, 4 Dec 2020 18:05:56 +1100 Subject: [PATCH] Add custom-wizard-specific caching system Initially for use with registered custom fields --- coverage/.last_run.json | 2 +- extensions/custom_field/preloader.rb | 2 +- extensions/custom_field/serializer.rb | 4 +- lib/custom_wizard/action.rb | 6 +-- lib/custom_wizard/cache.rb | 39 +++++++++++++++++++ lib/custom_wizard/custom_field.rb | 38 ++++++++++-------- lib/custom_wizard/engine.rb | 6 ++- lib/custom_wizard/template.rb | 8 ++-- plugin.rb | 3 +- spec/components/custom_wizard/cache_spec.rb | 35 +++++++++++++++++ .../custom_wizard/custom_field_spec.rb | 5 ++- 11 files changed, 118 insertions(+), 30 deletions(-) create mode 100644 lib/custom_wizard/cache.rb create mode 100644 spec/components/custom_wizard/cache_spec.rb diff --git a/coverage/.last_run.json b/coverage/.last_run.json index e9894915..375f0421 100644 --- a/coverage/.last_run.json +++ b/coverage/.last_run.json @@ -1,5 +1,5 @@ { "result": { - "covered_percent": 89.25 + "covered_percent": 89.41 } } diff --git a/extensions/custom_field/preloader.rb b/extensions/custom_field/preloader.rb index 6478199f..ff3a8d61 100644 --- a/extensions/custom_field/preloader.rb +++ b/extensions/custom_field/preloader.rb @@ -4,7 +4,7 @@ module CustomWizardCustomFieldPreloader @cw_klass = objects.first.class.name.underscore if cw_fields.any? cw_fields.each do |field| - fields << field.name + fields << field[:name] end end end diff --git a/extensions/custom_field/serializer.rb b/extensions/custom_field/serializer.rb index d7f3b10c..75f140d4 100644 --- a/extensions/custom_field/serializer.rb +++ b/extensions/custom_field/serializer.rb @@ -8,9 +8,9 @@ module CustomWizardCustomFieldSerializer if cw_fields.any? cw_fields.each do |field| if @cw_klass == "topic_view" - hash[field.name.to_sym] = object.topic.custom_fields["#{field.name}"] + hash[field[:name].to_sym] = object.topic.custom_fields["#{field[:name]}"] else - hash[field.name.to_sym] = object.custom_fields["#{field.name}"] + hash[field[:name].to_sym] = object.custom_fields["#{field[:name]}"] end end end diff --git a/lib/custom_wizard/action.rb b/lib/custom_wizard/action.rb index bb569a7e..50063759 100644 --- a/lib/custom_wizard/action.rb +++ b/lib/custom_wizard/action.rb @@ -454,7 +454,7 @@ class CustomWizard::Action user: user ).perform - registered_fields = CustomWizard::CustomField.list + registered_fields = CustomWizard::CustomField.cached_list field_map.each do |field| keyArr = field[:key].split('.') @@ -468,9 +468,9 @@ class CustomWizard::Action end - registered = registered_fields.select { |f| f.name == name } + registered = registered_fields.select { |f| f[:name] == name } if registered.first.present? - klass = registered.first.klass + klass = registered.first[:klass] end if klass === 'topic' diff --git a/lib/custom_wizard/cache.rb b/lib/custom_wizard/cache.rb new file mode 100644 index 00000000..dea98e00 --- /dev/null +++ b/lib/custom_wizard/cache.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +class ::CustomWizard::Cache + def initialize(key) + @key = "#{CustomWizard::PLUGIN_NAME}_#{key}" + end + + def read + cache.read(@key) + end + + def write(data) + synchronize { cache.write(@key, data) } + end + + def delete + synchronize { cache.delete(@key) } + end + + def synchronize + DistributedMutex.synchronize(@key) { yield } + end + + def cache + @cache ||= Discourse.cache + end + + def self.wrap(key, &block) + c = new(key) + + if cached = c.read + cached + else + result = block.call() + c.write(result) + result + end + end +end \ No newline at end of file diff --git a/lib/custom_wizard/custom_field.rb b/lib/custom_wizard/custom_field.rb index 0fd82f1e..0f806bbc 100644 --- a/lib/custom_wizard/custom_field.rb +++ b/lib/custom_wizard/custom_field.rb @@ -18,6 +18,7 @@ class ::CustomWizard::CustomField post: ["post"] } TYPES ||= ["string", "boolean", "integer", "json"] + LIST_CACHE_KEY ||= 'custom_field_list' def self.serializers CLASSES.values.flatten.uniq @@ -120,22 +121,29 @@ class ::CustomWizard::CustomField errors.blank? end - def self.reset - @list = nil - @any = nil - end - def self.list - @list ||= PluginStoreRow.where(plugin_name: NAMESPACE) - .map { |record| create_from_store(record) } + PluginStoreRow.where(plugin_name: NAMESPACE).map do |record| + create_from_store(record) + end end - def self.list_by(attr, value) - self.list.select do |cf| + def self.cached_list + ::CustomWizard::Cache.wrap(LIST_CACHE_KEY) do + PluginStoreRow.where(plugin_name: NAMESPACE).map do |record| + create_from_store(record).as_json.with_indifferent_access + end + end + end + + def self.list_by(attr, value, cached: true) + attr = attr.to_sym + fields = cached ? cached_list : list + + fields.select do |cf| if attr == :serializers - cf.send(attr).include?(value) + cf[attr].include?(value) else - cf.send(attr) == value + cf[attr] == value end end end @@ -196,17 +204,13 @@ class ::CustomWizard::CustomField end def self.invalidate_cache - self.reset + CustomWizard::Cache.new(LIST_CACHE_KEY).delete Discourse.clear_readonly! Discourse.request_refresh! end def self.any? - if @any.nil? - @any = PluginStoreRow.where(plugin_name: NAMESPACE).exists? - else - @any - end + cached_list.length > 0 end def self.enabled? diff --git a/lib/custom_wizard/engine.rb b/lib/custom_wizard/engine.rb index 80681bee..70e3d18a 100644 --- a/lib/custom_wizard/engine.rb +++ b/lib/custom_wizard/engine.rb @@ -1,6 +1,10 @@ +# frozen_string_literal: true + module ::CustomWizard + PLUGIN_NAME ||= 'custom_wizard' + class Engine < ::Rails::Engine - engine_name 'custom_wizard' + engine_name PLUGIN_NAME isolate_namespace CustomWizard end end \ No newline at end of file diff --git a/lib/custom_wizard/template.rb b/lib/custom_wizard/template.rb index f3e43f17..8329ea61 100644 --- a/lib/custom_wizard/template.rb +++ b/lib/custom_wizard/template.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CustomWizard::Template include HasErrors @@ -19,7 +21,7 @@ class CustomWizard::Template ActiveRecord::Base.transaction do schedule_save_jobs unless opts[:skip_jobs] - PluginStore.set('custom_wizard', @data[:id], @data) + PluginStore.set(CustomWizard::PLUGIN_NAME, @data[:id], @data) end @data[:id] @@ -30,7 +32,7 @@ class CustomWizard::Template end def self.find(wizard_id) - PluginStore.get('custom_wizard', wizard_id) + PluginStore.get(CustomWizard::PLUGIN_NAME, wizard_id) end def self.remove(wizard_id) @@ -39,7 +41,7 @@ class CustomWizard::Template return false if !wizard ActiveRecord::Base.transaction do - PluginStore.remove('custom_wizard', wizard.id) + PluginStore.remove(CustomWizard::PLUGIN_NAME, wizard.id) if wizard.after_time Jobs.cancel_scheduled_job(:set_after_time_wizard) diff --git a/plugin.rb b/plugin.rb index f7220e64..52b8348c 100644 --- a/plugin.rb +++ b/plugin.rb @@ -55,6 +55,7 @@ after_initialize do ../lib/custom_wizard/action_result.rb ../lib/custom_wizard/action.rb ../lib/custom_wizard/builder.rb + ../lib/custom_wizard/cache.rb ../lib/custom_wizard/custom_field.rb ../lib/custom_wizard/field.rb ../lib/custom_wizard/mapper.rb @@ -178,7 +179,7 @@ after_initialize do klass.to_s .classify .constantize - .register_custom_field_type(field.name, field.type.to_sym) + .register_custom_field_type(field[:name], field[:type].to_sym) end end end diff --git a/spec/components/custom_wizard/cache_spec.rb b/spec/components/custom_wizard/cache_spec.rb new file mode 100644 index 00000000..13f6a782 --- /dev/null +++ b/spec/components/custom_wizard/cache_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require_relative '../../plugin_helper.rb' + +describe CustomWizard::Cache do + it "writes and reads values to the cache" do + CustomWizard::Cache.new('list').write([1,2,3]) + expect(CustomWizard::Cache.new('list').read).to eq([1,2,3]) + end + + it "deletes values from the cache" do + CustomWizard::Cache.new('list').delete + expect(CustomWizard::Cache.new('list').read).to eq(nil) + end + + describe "#wrap" do + before do + @raw = [1,2,3] + end + + def list + CustomWizard::Cache.wrap('list') { @raw } + end + + it "returns value from passed block" do + expect(list).to eq([1,2,3]) + end + + it "returns cached value" do + cached = list + @raw = [3,2,1] + expect(list).to eq(cached) + end + end +end diff --git a/spec/components/custom_wizard/custom_field_spec.rb b/spec/components/custom_wizard/custom_field_spec.rb index eadb37b0..bbedb514 100644 --- a/spec/components/custom_wizard/custom_field_spec.rb +++ b/spec/components/custom_wizard/custom_field_spec.rb @@ -10,6 +10,10 @@ describe CustomWizard::CustomField do ).read) } + before do + CustomWizard::CustomField.invalidate_cache + end + it "saves custom field records" do custom_field_json['custom_fields'].each do |field_json| custom_field = CustomWizard::CustomField.new(nil, field_json) @@ -184,7 +188,6 @@ describe CustomWizard::CustomField do end it "is not enabled if there are no custom fields" do - CustomWizard::CustomField.invalidate_cache expect(CustomWizard::CustomField.enabled?).to eq(false) end end \ No newline at end of file