<commit_before>require 'active_model_serializers'

module Caprese
  module Adapter
    class JsonApi < ActiveModelSerializers::Adapter::Base
      extend ActiveSupport::Autoload
      autoload :Jsonapi
      autoload :ResourceIdentifier
      autoload :Relationship
      autoload :Link
      autoload :PaginationLinks
      autoload :Meta
      autoload :Error
      autoload :Deserialization

      def self.default_key_transform
        :dash
      end

      def self.fragment_cache(cached_hash, non_cached_hash, root = true)
        core_cached       = cached_hash.first
        core_non_cached   = non_cached_hash.first
        no_root_cache     = cached_hash.delete_if { |key, _value| key == core_cached[0] }
        no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] }
        cached_resource   = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
        hash = root ? { root => cached_resource } : cached_resource

        hash.deep_merge no_root_non_cache.deep_merge no_root_cache
      end

      def initialize(serializer, options = {})
        super

        begin
          @persistence_references = serializer.send(:instance_options).delete(:persistence_references).join(',')
        rescue NoMethodError
          @persistence_references = []
        end

        @include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
        @fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
      end

      # {http://jsonapi.org/format/#crud Requests are transactional, i.e. success or failure}
      # {http://jsonapi.org/format/#document-top-level data and errors MUST NOT coexist in the same document.}
      def serializable_hash(*)
        document = if serializer.success?
                     success_document
                   else
                     failure_document
                   end
        self.class.transform_key_casing!(document, instance_options)
      end

      def fragment_cache(cached_hash, non_cached_hash)
        root = !instance_options.include?(:include)
        self.class.fragment_cache(cached_hash, non_cached_hash, root)
      end

      # {http://jsonapi.org/format/#document-top-level Primary data}
      # definition:
      #   ☐ toplevel_data (required)
      #   ☐ toplevel_included
      #   ☑ toplevel_meta
      #   ☑ toplevel_links
      #   ☑ toplevel_jsonapi
      # structure:
      #  {
      #    data: toplevel_data,
      #    included: toplevel_included,
      #    meta: toplevel_meta,
      #    links: toplevel_links,
      #    jsonapi: toplevel_jsonapi
      #  }.reject! {|_,v| v.nil? }
      # rubocop:disable Metrics/CyclomaticComplexity
      def success_document
        is_collection = serializer.respond_to?(:each)
        serializers = is_collection ? serializer : [serializer]
        primary_data, included = resource_objects_for(serializers)

        hash = {}
        # toplevel_data
        # definition:
        #   oneOf
        #     resource
        #     array of unique items of type 'resource'
        #     null
        #
        # description:
        #   The document's "primary data" is a representation of the resource or collection of resources
        #   targeted by a request.
        #
        #   Singular: the resource object.
        #
        #   Collection: one of an array of resource objects, an array of resource identifier objects, or
        #   an empty array ([]), for requests that target resource collections.
        #
        #   None: null if the request is one that might correspond to a single resource, but doesn't currently.
        # structure:
        #  if serializable_resource.resource?
        #    resource
        #  elsif serializable_resource.collection?
        #    [
        #      resource,
        #      resource
        #    ]
        #  else
        #    nil
        #  end
        primary_data = primary_data.map { |d| d[1] }
        hash[:data] = is_collection ? primary_data : primary_data[0]
        # toplevel_included
        #   alias included
        # definition:
        #   array of unique items of type 'resource'
        #
        # description:
        #   To reduce the number of HTTP requests, servers **MAY** allow
        #   responses that include related resources along with the requested primary
        #   resources. Such responses are called "compound documents".
        # structure:
        #     [
        #       resource,
        #       resource
        #     ]
        if included.any?
          included = included.map { |d| d[1] }
          hash[:included] = included if included.any?
        end

        Jsonapi.add!(hash)

        if instance_options[:links]
          hash[:links] ||= {}
          hash[:links].update(instance_options[:links])
        end

        if is_collection && serializer.paginated?
          hash[:links] ||= {}
          hash[:links].update(pagination_links_for(serializer))
        end

        hash[:meta] = instance_options[:meta] unless instance_options[:meta].blank?

        hash
      end
      # rubocop:enable Metrics/CyclomaticComplexity

      # {http://jsonapi.org/format/#errors JSON API Errors}
      # TODO: look into caching
      # definition:
      #   ☑ toplevel_errors array (required)
      #   ☐ toplevel_meta
      #   ☐ toplevel_jsonapi
      # structure:
      #   {
      #     errors: toplevel_errors,
      #     meta: toplevel_meta,
      #     jsonapi: toplevel_jsonapi
      #   }.reject! {|_,v| v.nil? }
      # prs:
      #  https://github.com/rails-api/active_model_serializers/pull/1004
      def failure_document
        hash = {}
        # PR Please :)
        # Jsonapi.add!(hash)

        # toplevel_errors
        # definition:
        #   array of unique items of type 'error'
        # structure:
        #   [
        #     error,
        #     error
        #   ]
        if serializer.respond_to?(:each)
          hash[:errors] = serializer.flat_map do |error_serializer|
            Error.resource_errors(error_serializer, instance_options)
          end
        else
          hash[:errors] =
            if serializer.resource_errors?
              Error.resource_errors(serializer, instance_options)
            elsif serializer.document_errors?
              Error.document_errors(serializer, instance_options)
            else
              Error.param_errors(serializer, instance_options)
            end
        end
        hash
      end

      protected

      attr_reader :fieldset

      private

      # {http://jsonapi.org/format/#document-resource-objects Primary data}
      # resource
      # definition:
      #   JSON Object
      #
      # properties:
      #   type (required) : String
      #   id   (required) : String
      #   attributes
      #   relationships
      #   links
      #   meta
      #
      # description:
      #   "Resource objects" appear in a JSON API document to represent resources
      # structure:
      #   {
      #     type: 'admin--some-user',
      #     id: '1336',
      #     attributes: attributes,
      #     relationships: relationships,
      #     links: links,
      #     meta: meta,
      #   }.reject! {|_,v| v.nil? }
      # prs:
      #   type
      #     https://github.com/rails-api/active_model_serializers/pull/1122
      #     [x] https://github.com/rails-api/active_model_serializers/pull/1213
      #     https://github.com/rails-api/active_model_serializers/pull/1216
      #     https://github.com/rails-api/active_model_serializers/pull/1029
      #   links
      #     [x] https://github.com/rails-api/active_model_serializers/pull/1246
      #     [x] url helpers https://github.com/rails-api/active_model_serializers/issues/1269
      #   meta
      #     [x] https://github.com/rails-api/active_model_serializers/pull/1340
      def resource_objects_for(serializers)
        @primary = []
        @included = []
        @resource_identifiers = Set.new
        serializers.each { |serializer| process_resource(serializer, true, @include_directive) }
        serializers.each { |serializer| process_relationships(serializer, @include_directive) }

        [@primary, @included]
      end

      def process_resource(serializer, primary, included_associations)
        resource_identifier = ResourceIdentifier.new(serializer, instance_options).as_json
        exists = !@resource_identifiers.add?(resource_identifier)

        resource_object = resource_object_for(serializer, included_associations)
        if primary
          if exists
            @primary[@primary.find_index { |d| d[0] == resource_identifier }] = [resource_identifier, resource_object]
          else
            @primary << [resource_identifier, resource_object]
          end
        else
          if exists
            @included[@included.find_index { |d| d[0] == resource_identifier }] = [resource_identifier, resource_object]
          else
            @included << [resource_identifier, resource_object]
          end
        end

        true
      end

      def process_relationships(serializer, include_directive)
        serializer.associations(include_directive).each do |association|
          process_relationship(association.lazy_association.serializer, include_directive[association.key])
        end
      end

      def process_relationship(serializer, include_directive)
        if serializer.respond_to?(:each)
          serializer.each { |s| process_relationship(s, include_directive) }
          return
        end
        return unless serializer && serializer.object
        return unless process_resource(serializer, false, include_directive)

        process_relationships(serializer, include_directive)
      end
<commit_msg>Fix bug in last commit<commit_after>require 'active_model_serializers'

module Caprese
  module Adapter
    class JsonApi < ActiveModelSerializers::Adapter::Base
      extend ActiveSupport::Autoload
      autoload :Jsonapi
      autoload :ResourceIdentifier
      autoload :Relationship
      autoload :Link
      autoload :PaginationLinks
      autoload :Meta
      autoload :Error
      autoload :Deserialization

      def self.default_key_transform
        :dash
      end

      def self.fragment_cache(cached_hash, non_cached_hash, root = true)
        core_cached       = cached_hash.first
        core_non_cached   = non_cached_hash.first
        no_root_cache     = cached_hash.delete_if { |key, _value| key == core_cached[0] }
        no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] }
        cached_resource   = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
        hash = root ? { root => cached_resource } : cached_resource

        hash.deep_merge no_root_non_cache.deep_merge no_root_cache
      end

      def initialize(serializer, options = {})
        super

        begin
          @persistence_references = serializer.send(:instance_options).delete(:persistence_references).join(',')
        rescue NoMethodError
          @persistence_references = []
        end

        @include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
        @fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
      end

      # {http://jsonapi.org/format/#crud Requests are transactional, i.e. success or failure}
      # {http://jsonapi.org/format/#document-top-level data and errors MUST NOT coexist in the same document.}
      def serializable_hash(*)
        document = if serializer.success?
                     success_document
                   else
                     failure_document
                   end
        self.class.transform_key_casing!(document, instance_options)
      end

      def fragment_cache(cached_hash, non_cached_hash)
        root = !instance_options.include?(:include)
        self.class.fragment_cache(cached_hash, non_cached_hash, root)
      end

      # {http://jsonapi.org/format/#document-top-level Primary data}
      # definition:
      #   ☐ toplevel_data (required)
      #   ☐ toplevel_included
      #   ☑ toplevel_meta
      #   ☑ toplevel_links
      #   ☑ toplevel_jsonapi
      # structure:
      #  {
      #    data: toplevel_data,
      #    included: toplevel_included,
      #    meta: toplevel_meta,
      #    links: toplevel_links,
      #    jsonapi: toplevel_jsonapi
      #  }.reject! {|_,v| v.nil? }
      # rubocop:disable Metrics/CyclomaticComplexity
      def success_document
        is_collection = serializer.respond_to?(:each)
        serializers = is_collection ? serializer : [serializer]
        primary_data, included = resource_objects_for(serializers)

        hash = {}
        # toplevel_data
        # definition:
        #   oneOf
        #     resource
        #     array of unique items of type 'resource'
        #     null
        #
        # description:
        #   The document's "primary data" is a representation of the resource or collection of resources
        #   targeted by a request.
        #
        #   Singular: the resource object.
        #
        #   Collection: one of an array of resource objects, an array of resource identifier objects, or
        #   an empty array ([]), for requests that target resource collections.
        #
        #   None: null if the request is one that might correspond to a single resource, but doesn't currently.
        # structure:
        #  if serializable_resource.resource?
        #    resource
        #  elsif serializable_resource.collection?
        #    [
        #      resource,
        #      resource
        #    ]
        #  else
        #    nil
        #  end
        primary_data = primary_data.map { |d| d[1] }
        hash[:data] = is_collection ? primary_data : primary_data[0]
        # toplevel_included
        #   alias included
        # definition:
        #   array of unique items of type 'resource'
        #
        # description:
        #   To reduce the number of HTTP requests, servers **MAY** allow
        #   responses that include related resources along with the requested primary
        #   resources. Such responses are called "compound documents".
        # structure:
        #     [
        #       resource,
        #       resource
        #     ]
        if included.any?
          included = included.map { |d| d[1] }
          hash[:included] = included if included.any?
        end

        Jsonapi.add!(hash)

        if instance_options[:links]
          hash[:links] ||= {}
          hash[:links].update(instance_options[:links])
        end

        if is_collection && serializer.paginated?
          hash[:links] ||= {}
          hash[:links].update(pagination_links_for(serializer))
        end

        hash[:meta] = instance_options[:meta] unless instance_options[:meta].blank?

        hash
      end
      # rubocop:enable Metrics/CyclomaticComplexity

      # {http://jsonapi.org/format/#errors JSON API Errors}
      # TODO: look into caching
      # definition:
      #   ☑ toplevel_errors array (required)
      #   ☐ toplevel_meta
      #   ☐ toplevel_jsonapi
      # structure:
      #   {
      #     errors: toplevel_errors,
      #     meta: toplevel_meta,
      #     jsonapi: toplevel_jsonapi
      #   }.reject! {|_,v| v.nil? }
      # prs:
      #  https://github.com/rails-api/active_model_serializers/pull/1004
      def failure_document
        hash = {}
        # PR Please :)
        # Jsonapi.add!(hash)

        # toplevel_errors
        # definition:
        #   array of unique items of type 'error'
        # structure:
        #   [
        #     error,
        #     error
        #   ]
        if serializer.respond_to?(:each)
          hash[:errors] = serializer.flat_map do |error_serializer|
            Error.resource_errors(error_serializer, instance_options)
          end
        else
          hash[:errors] =
            if serializer.resource_errors?
              Error.resource_errors(serializer, instance_options)
            elsif serializer.document_errors?
              Error.document_errors(serializer, instance_options)
            else
              Error.param_errors(serializer, instance_options)
            end
        end
        hash
      end

      protected

      attr_reader :fieldset

      private

      # {http://jsonapi.org/format/#document-resource-objects Primary data}
      # resource
      # definition:
      #   JSON Object
      #
      # properties:
      #   type (required) : String
      #   id   (required) : String
      #   attributes
      #   relationships
      #   links
      #   meta
      #
      # description:
      #   "Resource objects" appear in a JSON API document to represent resources
      # structure:
      #   {
      #     type: 'admin--some-user',
      #     id: '1336',
      #     attributes: attributes,
      #     relationships: relationships,
      #     links: links,
      #     meta: meta,
      #   }.reject! {|_,v| v.nil? }
      # prs:
      #   type
      #     https://github.com/rails-api/active_model_serializers/pull/1122
      #     [x] https://github.com/rails-api/active_model_serializers/pull/1213
      #     https://github.com/rails-api/active_model_serializers/pull/1216
      #     https://github.com/rails-api/active_model_serializers/pull/1029
      #   links
      #     [x] https://github.com/rails-api/active_model_serializers/pull/1246
      #     [x] url helpers https://github.com/rails-api/active_model_serializers/issues/1269
      #   meta
      #     [x] https://github.com/rails-api/active_model_serializers/pull/1340
      def resource_objects_for(serializers)
        @primary = []
        @included = []
        @resource_identifiers = Set.new
        serializers.each { |serializer| process_resource(serializer, true, @include_directive) }
        serializers.each { |serializer| process_relationships(serializer, @include_directive) }

        [@primary, @included]
      end

      def process_resource(serializer, primary, included_associations)
        resource_identifier = ResourceIdentifier.new(serializer, instance_options).as_json
        exists = !@resource_identifiers.add?(resource_identifier)

        resource_object = resource_object_for(serializer, included_associations)
        if primary
          if exists
            index = @primary.find_index { |d| d[0] == resource_identifier }
            @primary[index] = [resource_identifier, resource_object]
          else
            @primary << [resource_identifier, resource_object]
          end
        else
          if exists
            return if (index = @included.find_index { |d| d[0] == resource_identifier }).nil?
            @included[index] = [resource_identifier, resource_object]
          else
            @included << [resource_identifier, resource_object]
          end
        end

        true
      end

      def process_relationships(serializer, include_directive)
        serializer.associations(include_directive).each do |association|
          process_relationship(association.lazy_association.serializer, include_directive[association.key])
        end
      end

      def process_relationship(serializer, include_directive)
        if serializer.respond_to?(:each)
          serializer.each { |s| process_relationship(s, include_directive) }
          return
        end
        return unless serializer && serializer.object
        return unless process_resource(serializer, false, include_directive)

        process_relationships(serializer, include_directive)
      end

{'fraction_non_alphanumeric': 0.08899725693386162, 'fraction_numerical': 0.004774966981611298, 'mean_word_length': 2.0973882945248583, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 5, 'https://': 16, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4639241', 'n_tokens_mistral': 5650, 'n_tokens_neox': 5475, 'n_words': 1151}