lib/wcc/contentful/model_methods.rb in wcc-contentful-0.4.0.pre.rc vs lib/wcc/contentful/model_methods.rb in wcc-contentful-1.0.0.pre.rc1

- old
+ new

@@ -3,10 +3,19 @@ # This module is included by all {WCC::Contentful::Model models} and defines instance # methods that are not dynamically generated. # # @api Model module WCC::Contentful::ModelMethods + include WCC::Contentful::Instrumentation + + # The set of options keys that are specific to the Model layer and shouldn't + # be passed down to the Store layer. + MODEL_LAYER_CONTEXT_KEYS = %i[ + preview + backlinks + ].freeze + # Resolves all links in an entry to the specified depth. # # Each link in the entry is recursively retrieved from the store until the given # depth is satisfied. Depth resolution is unlimited, circular references will # be resolved to the same object. @@ -20,34 +29,40 @@ # @param [Hash] options The remaining optional parameters, defined below # @option options [Symbol] circular_reference Determines how circular references are # handled. `:raise` causes a {WCC::Contentful::CircularReferenceError} to be raised, # `:ignore` will cause the field to remain unresolved, and any other value (or nil) # will cause the field to point to the previously resolved ruby object for that ID. - def resolve(depth: 1, fields: nil, context: {}, **options) + def resolve(depth: 1, fields: nil, context: sys.context.to_h, **options) raise ArgumentError, "Depth must be > 0 (was #{depth})" unless depth && depth > 0 return self if resolved?(depth: depth, fields: fields) fields = fields.map { |f| f.to_s.camelize(:lower) } if fields.present? fields ||= self.class::FIELDS typedef = self.class.content_type_definition links = fields.select { |f| %i[Asset Link].include?(typedef.fields[f].type) } - raw_links = - links.any? do |field_name| - raw_value = raw.dig('fields', field_name, sys.locale) - if raw_value&.is_a? Array - raw_value.any? { |v| v&.dig('sys', 'type') == 'Link' } - elsif raw_value - raw_value.dig('sys', 'type') == 'Link' + raw_link_ids = + links.map { |field_name| raw.dig('fields', field_name, sys.locale) } + .flat_map do |raw_value| + _try_map(raw_value) { |v| v.dig('sys', 'id') if v.dig('sys', 'type') == 'Link' } end - end - if raw_links - # use include param to do resolution - raw = self.class.store.find_by(content_type: self.class.content_type, - filter: { 'sys.id' => id }, - options: { include: [depth, 10].min }) + raw_link_ids = raw_link_ids.compact + backlinked_ids = (context[:backlinks]&.map { |m| m.id } || []) + + has_unresolved_raw_links = (raw_link_ids - backlinked_ids).any? + if has_unresolved_raw_links + raw = + _instrument 'resolve', id: id, depth: depth, backlinks: backlinked_ids do + # use include param to do resolution + self.class.store(context[:preview]) + .find_by(content_type: self.class.content_type, + filter: { 'sys.id' => id }, + options: context.except(*MODEL_LAYER_CONTEXT_KEYS).merge!({ + include: [depth, 10].min + })) + end unless raw raise WCC::Contentful::ResolveError, "Cannot find #{self.class.content_type} with ID #{id}" end @raw = raw.freeze @@ -116,10 +131,16 @@ } end delegate :to_json, to: :to_h + protected + + def _instrumentation_event_prefix + '.model.contentful.wcc' + end + private def _resolve_field(field_name, depth = 1, context = {}, options = {}) return if depth <= 0 @@ -145,20 +166,24 @@ # Use the already resolved circular reference, or resolve a link, or # instantiate from already resolved raw entry data. m = already_resolved || if raw.dig('sys', 'type') == 'Link' - WCC::Contentful::Model.find(id, new_context) + _instrument 'resolve', + id: self.id, depth: depth, backlinks: context[:backlinks]&.map(&:id) do + WCC::Contentful::Model.find(id, options: new_context) + end else WCC::Contentful::Model.new_from_raw(raw, new_context) end m.resolve(depth: depth - 1, context: new_context, **options) if m && depth > 1 m } begin val = _try_map(val) { |v| load.call(v) } + val = val.compact if val.is_a? Array instance_variable_set(var_name + '_resolved', val) rescue WCC::Contentful::CircularReferenceError raise unless options[:circular_reference] == :ignore end