class WCC::Contentful::Store::Factory

This factory presents a DSL for configuring the store stack. The store stack sits in between the Model layer and the datastore, which can be Contentful or something else like Postgres.

A set of “presets” are available to get pre-configured stacks based on what we've found most useful.

Attributes

config[R]
options[R]
preset[R]
store[RW]

Set the base store instance.

Public Class Methods

new(config = WCC::Contentful.configuration, preset = :direct, options = nil) click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 27
def initialize(config = WCC::Contentful.configuration, preset = :direct, options = nil)
  @config = config
  @preset = preset || :custom
  @options = [*options] || []

  # Infer whether they passed in a store implementation object or class
  if class_implements_store_interface?(@preset) ||
      object_implements_store_interface?(@preset)
    @options.unshift(@preset)
    @preset = :custom
  end

  configure_preset(@preset)
end

Private Class Methods

default_middleware() click to toggle source

The middleware that by default lives at the top of the middleware stack.

# File lib/wcc/contentful/store/factory.rb, line 179
def default_middleware
  [
    [WCC::Contentful::Store::InstrumentationMiddleware]
  ].freeze
end

Public Instance Methods

build(services = WCC::Contentful::Services.instance) click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 64
def build(services = WCC::Contentful::Services.instance)
  store_instance = build_store(services)
  options = {
    config: config,
    services: services
  }
  middleware.reverse
    .reduce(store_instance) do |memo, middleware_config|
      # May have added a middleware with `middleware << MyMiddleware.new`
      middleware_config = [middleware_config] unless middleware_config.is_a? Array

      middleware, params, configure_proc = middleware_config
      middleware_options = options.merge((params || []).extract_options!)
      middleware = middleware.call(memo, *params, **middleware_options)
      middleware&.instance_exec(&configure_proc) if configure_proc
      middleware || memo
    end
end
middleware() click to toggle source

An array of tuples that set up and configure a Store middleware.

# File lib/wcc/contentful/store/factory.rb, line 23
def middleware
  @middleware ||= self.class.default_middleware.dup
end
preset_custom() click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 119
def preset_custom
  self.store = options.shift
end
preset_direct() click to toggle source

Configures the default “direct” preset which passes everything through to Contentful CDN

# File lib/wcc/contentful/store/factory.rb, line 115
def preset_direct
  self.store = CDNAdapter.new(preview: options.include?(:preview))
end
preset_eager_sync() click to toggle source

Sets the “eager sync” preset using one of the preregistered stores like :postgres

# File lib/wcc/contentful/store/factory.rb, line 99
def preset_eager_sync
  store = options.shift || :memory
  store = SYNC_STORES[store]&.call(config, *options) if store.is_a?(Symbol)
  self.store = store
end
preset_lazy_sync() click to toggle source

Configures a “lazy sync” preset which caches direct lookups but hits Contentful for any missing information. The cache is kept up to date by the sync engine.

# File lib/wcc/contentful/store/factory.rb, line 107
def preset_lazy_sync
  preset_direct
  use(WCC::Contentful::Middleware::Store::CachingMiddleware,
    ActiveSupport::Cache.lookup_store(*options))
end
replace(middleware, *middleware_params, &block) click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 49
def replace(middleware, *middleware_params, &block)
  idx = self.middleware.find_index { |m| m[0] == middleware }
  raise ArgumentError, "Middleware #{middleware} not present" if idx.nil?

  configure_proc = block_given? ? Proc.new(&block) : nil
  self.middleware[idx] = [middleware, middleware_params, configure_proc]
end
unuse(middleware) click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 57
def unuse(middleware)
  idx = self.middleware.find_index { |m| m[0] == middleware }
  return if idx.nil?

  self.middleware.delete_at idx
end
use(middleware, *middleware_params, &block) click to toggle source

Adds a middleware to the chain. Use a block here to configure the middleware after it has been created.

# File lib/wcc/contentful/store/factory.rb, line 44
def use(middleware, *middleware_params, &block)
  configure_proc = block_given? ? Proc.new(&block) : nil
  self.middleware << [middleware, middleware_params, configure_proc]
end
validate!() click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 83
def validate!
  unless preset.nil? || PRESETS.include?(preset)
    raise ArgumentError, "Please use one of #{PRESETS} instead of #{preset}"
  end

  middleware.each do |m|
    next if m[0].respond_to?(:call)

    raise ArgumentError, "The middleware '#{m[0]&.try(:name) || m[0]}' cannot be applied!  " \
      'It must respond to :call'
  end

  validate_store!(store)
end

Private Instance Methods

build_store(services) click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 147
def build_store(services)
  store_class = store
  store =
    if object_implements_store_interface?(store_class)
      store_class
    else
      store_class.new(config, *options - [store_class])
    end

  # Inject services into the custom store class
  (WCC::Contentful::SERVICES - %i[store preview_store]).each do |s|
    next unless store.respond_to?("#{s}=")

    store.public_send("#{s}=",
      services.public_send(s))
  end

  store
end
class_implements_store_interface?(klass) click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 167
def class_implements_store_interface?(klass)
  (WCC::Contentful::Store::Interface::INTERFACE_METHODS -
      (klass.try(:instance_methods) || [])).empty?
end
configure_preset(preset) click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 139
def configure_preset(preset)
  unless respond_to?("preset_#{preset}")
    raise ArgumentError, "Don't know how to build content delivery method '#{preset}'"
  end

  public_send("preset_#{preset}")
end
object_implements_store_interface?(object) click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 172
def object_implements_store_interface?(object)
  (WCC::Contentful::Store::Interface::INTERFACE_METHODS -
      (object.try(:methods) || [])).empty?
end
validate_store!(store) click to toggle source
# File lib/wcc/contentful/store/factory.rb, line 125
def validate_store!(store)
  raise ArgumentError, 'No store provided' unless store

  return true if class_implements_store_interface?(store) ||
    object_implements_store_interface?(store)

  methods = [*store.try(:instance_methods), *store.try(:methods)]
  WCC::Contentful::Store::Interface::INTERFACE_METHODS.each do |method|
    next if methods.include?(method)

    raise ArgumentError, "Custom store '#{store}' must respond to the #{method} method"
  end
end