Class: WCC::Contentful::Store::Base Abstract

Inherits:
Object
  • Object
show all
Includes:
Interface
Defined in:
lib/wcc/contentful/store/base.rb

Overview

This class is abstract.

At a minimum subclasses should override Interface#find, #execute, #set, and ##delete. As an alternative to overriding set and delete, the subclass can override #index. Index is called when a webhook triggers a sync, to update the store.

This is the base class for stores which implement #index, and therefore must be kept up-to-date via the Sync API. To implement a new store, you should include the rspec_examples in your rspec tests for the store. See spec/wcc/contentful/store/memory_store_spec.rb for an example.

Direct Known Subclasses

MemoryStore, PostgresStore

Constant Summary

Constants included from Interface

Interface::INTERFACE_METHODS

Instance Method Summary collapse

Methods included from Interface

#find

Constructor Details

#initialize(configuration = nil) ⇒ Base

Returns a new instance of Base.



20
21
22
# File 'lib/wcc/contentful/store/base.rb', line 20

def initialize(configuration = nil)
  @configuration = configuration || WCC::Contentful.configuration
end

Instance Method Details

#delete(_id) ⇒ Object

This method is abstract.

Removes the entry by ID from the store.

Raises:

  • (NotImplementedError)


32
33
34
# File 'lib/wcc/contentful/store/base.rb', line 32

def delete(_id)
  raise NotImplementedError, "#{self.class} does not implement #delete"
end

#ensure_hash(val) ⇒ Object

Raises:

  • (ArgumentError)


115
116
117
# File 'lib/wcc/contentful/store/base.rb', line 115

def ensure_hash(val)
  raise ArgumentError, 'Value must be a Hash' unless val.is_a?(Hash)
end

#execute(_query) ⇒ Object

This method is abstract.

Executes a WCC::Contentful::Store::Query object created by #find_all or #find_by. Implementations should override this to translate the query’s conditions into a query against the datastore.

For a very naiive implementation see WCC::Contentful::Store::MemoryStore#execute

Raises:

  • (NotImplementedError)


42
43
44
# File 'lib/wcc/contentful/store/base.rb', line 42

def execute(_query)
  raise NotImplementedError, "#{self.class} does not implement #execute"
end

#find_all(content_type:, options: nil) ⇒ Query

Finds all entries of the given content type. A content type is required.

Subclasses may override this to provide their own query implementation,

or else override #execute to run the query after it has been parsed.

Parameters:

  • content_type (String)

    The ID of the content type to search for.

  • options (Hash) (defaults to: nil)

    An optional set of additional parameters to the query defining for example include depth. Not all store implementations respect all options.

Returns:

  • (Query)

    A query object that exposes methods to apply filters



106
107
108
109
110
111
112
113
# File 'lib/wcc/contentful/store/base.rb', line 106

def find_all(content_type:, options: nil)
  Query.new(
    self,
    content_type: content_type,
    options: options,
    configuration: @configuration
  )
end

#find_by(content_type:, filter: nil, options: nil) ⇒ Object

Finds the first entry matching the given filter. A content type is required.

Parameters:

  • content_type (String)

    The ID of the content type to search for.

  • filter (Hash) (defaults to: nil)

    A set of key-value pairs defining filter operations. See WCC::Contentful::Store::Base::Query

  • options (Hash) (defaults to: nil)

    An optional set of additional parameters to the query defining for example include depth. Not all store implementations respect all options.



91
92
93
94
95
96
# File 'lib/wcc/contentful/store/base.rb', line 91

def find_by(content_type:, filter: nil, options: nil)
  # default implementation - can be overridden
  q = find_all(content_type: content_type, options: { limit: 1 }.merge!(options || {}))
  q = q.apply(filter) if filter
  q.first
end

#index(json) ⇒ Object

Processes a data point received via the Sync API. This can be a published entry or asset, or a ‘DeletedEntry’ or ‘DeletedAsset’. The default implementation calls into #set and #delete to perform the appropriate operations in the store.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/wcc/contentful/store/base.rb', line 56

def index(json)
  # This implementation assumes that #delete and #set are individually thread-safe.
  # No mutex is needed so long as the revisions are accurate.
  # Subclasses can override to do this in a more performant thread-safe way.
  # Example: postgres_store could do this in a stored procedure for speed
  prev =
    case type = json.dig('sys', 'type')
    when 'DeletedEntry', 'DeletedAsset'
      delete(json.dig('sys', 'id'))
    else
      set(json.dig('sys', 'id'), json)
    end

  if (prev_rev = prev&.dig('sys', 'revision')) &&
      (next_rev = json.dig('sys', 'revision')) &&
      (next_rev < prev_rev)
    # Uh oh! we overwrote an entry with a prior revision.  Put the previous back.
    return index(prev)
  end

  case type
  when 'DeletedEntry', 'DeletedAsset'
    nil
  else
    json
  end
end

#index?Boolean

Returns true if this store can persist entries and assets which are retrieved from the sync API.

Returns:

  • (Boolean)


48
49
50
# File 'lib/wcc/contentful/store/base.rb', line 48

def index?
  true
end

#set(_id, _value) ⇒ Object

This method is abstract.

Sets the value of the entry with the given ID in the store.

Raises:

  • (NotImplementedError)


26
27
28
# File 'lib/wcc/contentful/store/base.rb', line 26

def set(_id, _value)
  raise NotImplementedError, "#{self.class} does not implement #set"
end