<commit_before>// dependencies
import _ from 'lodash';
import inflect from 'i';

// serializer utilities
import baseUrl from './utils/base-url';

// general utilities
import parseModelName from '../utils/parse-model-name';
import hasAttribute from '../utils/has-attribute';
import getRelationship from '../utils/get-relationship';
import hasRelationship from '../utils/has-relationship';

export default class Serializer {
  constructor(options = {}) {
    // setup the options
    this.origin = options.origin || 'http://localhost';
    this.port = options.port || 3000;
    this.namespace = options.namespace || '/';
  }

  /**
   * Loop through the raw Mongo document.
   *
   * ```js
   * {
   *   _id: '55---------------',
   *   name: 'Bob',
   *   age: 22
   * }
   * ```
   *
   * TODO: add how it's transformed
   */
  serializeResource(router, type, response, document) {
    const fields = router.fields;
    const i = inflect();
    let id = document._id;

    // build resource object
    let resource = {
      links: {
        self: baseUrl(router.origin, router.port, router.namespace, type, id),
      },
      id: id,
      type: parseModelName(type),
    };

    // loop through the raw Mongo object
    _.forOwn(document, (value, field) => {
      let isFieldAttribute = hasAttribute(fields, type, field);
      let isFieldRelationship = hasRelationship(fields, type, field);

      // if the field is not an attribute or relationship, stop processing
      if (!(isFieldAttribute || isFieldRelationship)) return;

      // if the field is an attribute, simply add the value to `attributes`
      if (isFieldAttribute) {
        // initialize the resource `attributes` hash
        if (!resource.attributes) {
          resource.attributes = {};
        }

        resource.attributes[field] = value;
        return;
      }

      // the field must be a relationship, more complex processing
      let relationship = value;

      // initialize the relationship attributes and relationships
      let relationshipAttributes = {};
      let relationshipRelationships = {};

      let relationshipDefinition = getRelationship(fields, type, field);
      let relationshipType = relationshipDefinition.type;
      let relationshipIsMany = relationshipDefinition.isMany;

      // initialize `relationships` hash and `included` array
      if (!resource.relationships) {
        resource.relationships = {};
        response.included = [];
      }

      // add the proper relationship links
      resource.relationships[field] = {
        links: {
          self: `${router.origin}:${router.port}${router.namespace}/${i.pluralize(type)}/${id}/relationships/${field}`,
          related: `${router.origin}:${router.port}${router.namespace}/${i.pluralize(type)}/${id}/${field}`,
        },
      };

      // process the has many relationship
      if (relationshipIsMany) {
        // initialize the data array for this particular relationship
        resource.relationships[field].data = [];

        // loop through all the embedded relationship documents
        _.each(relationship, relatedDocument => {
          const relatedDocumentId = relatedDocument._id;
          // append to the relationship data array with proper type and id
          resource.relationships[field].data.push({
            type: relationshipType,
            id: relatedDocumentId,
          });

          // check if the `included` array doesn't include the related document
          if (!_.find(response.included, { id: relatedDocumentId })) {
            // loop through the related document keys
            _.forOwn(relatedDocument, (relatedDocumentValue, relatedDocumentField) => {
              const isRelatedDocumentFieldRelationship = hasRelationship(fields, relationshipType, relatedDocumentField);
              const isRelatedDocumentFieldAttribute = hasAttribute(fields, relationshipType, relatedDocumentField);

              // if the related document field is not an attribute or relationship, stop processing
              if (!(isRelatedDocumentFieldAttribute || isRelatedDocumentFieldRelationship)) return;

              // the related document field is a relationship
              if (isRelatedDocumentFieldRelationship) {
                relationshipRelationships[relatedDocumentField] = relatedDocumentValue;
                return;
              }

              // the related document field is an attribute
              relationshipAttributes[relatedDocumentField] = relatedDocumentValue;
            });

            // push the document to the `included` array
            response.included.push({
              type: relationshipType,
              id: relatedDocumentId,
              links: {
                self: baseUrl(router.origin, router.port, router.namespace, fields[parseModelName(type)].relationships[field].type, relatedDocumentId),
              },
              attributes: relationshipAttributes,
              relationships: relationshipRelationships,
            });
          }
        });
      } else if (relationship) {
        const relationshipId = relationship._id;
        // the relationship is a to-one, so add a single hash to `data`
        resource.relationships[field].data = {
          type: relationshipType,
          id: relationshipId,
        };

        // check if the `included` array doesn't include the related document
        if (!_.find(response.included, { id: relationshipId })) {
          // loop through the relationship document keys
          _.forOwn(relationship, (relatedDocumentValue, relatedDocumentField) => {
            const isRelatedDocumentFieldRelationship = hasRelationship(fields, relationshipType, relatedDocumentField);
            const isRelatedDocumentFieldAttribute = hasAttribute(fields, relationshipType, relatedDocumentField);

            // if the related document field is not an attribute or relationship, stop processing
            if (!(isRelatedDocumentFieldAttribute || isRelatedDocumentFieldRelationship)) return;

            // the related document field is a relationship
            if (isRelatedDocumentFieldRelationship) {
              relationshipRelationships[relatedDocumentField] = relatedDocumentValue;
              return;
            }<commit_msg>Add data and type objects to related documents<commit_after>// dependencies
import _ from 'lodash';
import inflect from 'i';

// serializer utilities
import baseUrl from './utils/base-url';

// general utilities
import parseModelName from '../utils/parse-model-name';
import hasAttribute from '../utils/has-attribute';
import getRelationship from '../utils/get-relationship';
import hasRelationship from '../utils/has-relationship';

export default class Serializer {
  constructor(options = {}) {
    // setup the options
    this.origin = options.origin || 'http://localhost';
    this.port = options.port || 3000;
    this.namespace = options.namespace || '/';
  }

  /**
   * Loop through the raw Mongo document.
   *
   * ```js
   * {
   *   _id: '55---------------',
   *   name: 'Bob',
   *   age: 22
   * }
   * ```
   *
   * TODO: add how it's transformed
   */
  serializeResource(router, type, response, document) {
    const fields = router.fields;
    const i = inflect();
    let id = document._id;

    // build resource object
    let resource = {
      links: {
        self: baseUrl(router.origin, router.port, router.namespace, type, id),
      },
      id: id,
      type: parseModelName(type),
    };

    // loop through the raw Mongo object
    _.forOwn(document, (value, field) => {
      let isFieldAttribute = hasAttribute(fields, type, field);
      let isFieldRelationship = hasRelationship(fields, type, field);

      // if the field is not an attribute or relationship, stop processing
      if (!(isFieldAttribute || isFieldRelationship)) return;

      // if the field is an attribute, simply add the value to `attributes`
      if (isFieldAttribute) {
        // initialize the resource `attributes` hash
        if (!resource.attributes) {
          resource.attributes = {};
        }

        resource.attributes[field] = value;
        return;
      }

      // the field must be a relationship, more complex processing
      let relationship = value;

      // initialize the relationship attributes and relationships
      let relationshipAttributes = {};
      let relationshipRelationships = {};

      let relationshipDefinition = getRelationship(fields, type, field);
      let relationshipType = relationshipDefinition.type;
      let relationshipIsMany = relationshipDefinition.isMany;

      // initialize `relationships` hash and `included` array
      if (!resource.relationships) {
        resource.relationships = {};
        response.included = [];
      }

      // add the proper relationship links
      resource.relationships[field] = {
        links: {
          self: `${router.origin}:${router.port}${router.namespace}/${i.pluralize(type)}/${id}/relationships/${field}`,
          related: `${router.origin}:${router.port}${router.namespace}/${i.pluralize(type)}/${id}/${field}`,
        },
      };

      // process the has many relationship
      if (relationshipIsMany) {
        // initialize the data array for this particular relationship
        resource.relationships[field].data = [];

        // loop through all the embedded relationship documents
        _.each(relationship, relatedDocument => {
          const relatedDocumentId = relatedDocument._id;
          // append to the relationship data array with proper type and id
          resource.relationships[field].data.push({
            type: relationshipType,
            id: relatedDocumentId,
          });

          // check if the `included` array doesn't include the related document
          if (!_.find(response.included, { id: relatedDocumentId })) {
            // loop through the related document keys
            _.forOwn(relatedDocument, (relatedDocumentValue, relatedDocumentField) => {
              const isRelatedDocumentFieldRelationship = hasRelationship(fields, relationshipType, relatedDocumentField);
              const isRelatedDocumentFieldAttribute = hasAttribute(fields, relationshipType, relatedDocumentField);

              // if the related document field is not an attribute or relationship, stop processing
              if (!(isRelatedDocumentFieldAttribute || isRelatedDocumentFieldRelationship)) return;

              // the related document field is a relationship
              if (isRelatedDocumentFieldRelationship) {
                // relationshipRelationships[relatedDocumentField] = relatedDocumentValue;
                console.log('Mother fucker!!! is many');
                console.log(relatedDocumentValue);
                console.log(_.isArray(relatedDocumentValue));

                if (_.isArray(relatedDocumentValue)) {
                  relationshipRelationships[relatedDocumentField] = _.map(relatedDocumentValue, relatedDocumentValueId => {
                    return {
                      type: 'something',
                      id: relatedDocumentValueId,
                    };
                  });
                } else {
                  relationshipRelationships[relatedDocumentField] = {
                    type: 'something',
                    id: relatedDocumentValue,
                  };
                }

                return;
              }

              // the related document field is an attribute
              relationshipAttributes[relatedDocumentField] = relatedDocumentValue;
            });

            // push the document to the `included` array
            response.included.push({
              type: relationshipType,
              id: relatedDocumentId,
              links: {
                self: baseUrl(router.origin, router.port, router.namespace, fields[parseModelName(type)].relationships[field].type, relatedDocumentId),
              },
              attributes: relationshipAttributes,
              relationships: relationshipRelationships,
            });
          }
        });
      } else if (relationship) {
        const relationshipId = relationship._id;
        // the relationship is a to-one, so add a single hash to `data`
        resource.relationships[field].data = {
          type: relationshipType,
          id: relationshipId,
        };

        // check if the `included` array doesn't include the related document
        if (!_.find(response.included, { id: relationshipId })) {
          // loop through the relationship document keys
          _.forOwn(relationship, (relatedDocumentValue, relatedDocumentField) => {
            const isRelatedDocumentFieldRelationship = hasRelationship(fields, relationshipType, relatedDocumentField);
            const isRelatedDocumentFieldAttribute = hasAttribute(fields, relationshipType, relatedDocumentField);

            // if the related document field is not an attribute or relationship, stop processing
            if (!(isRelatedDocumentFieldAttribute || isRelatedDocumentFieldRelationship)) return;

            // the related document field is a relationship
            if (isRelatedDocumentFieldRelationship) {
              // relationshipRelationships[relatedDocumentField] = relatedDocumentValue;
              // TODO: change type of something to the real type

              if (_.isArray(relatedDocumentValue)) {
                relationshipRelationships[relatedDocumentField] = _.map(relatedDocumentValue, relatedDocumentValueId => {
                  return {
                    type: 'something',
                    id: relatedDocumentValueId,
                  };
                });
              } else {
                relationshipRelationships[relatedDocumentField] = {
                  type: 'something',
                  id: relatedDocumentValue,
                };
              }
              return;
            }
{'fraction_non_alphanumeric': 0.09720926895760097, 'fraction_numerical': 0.0011478585264366166, 'mean_word_length': 2.3072360616844603, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, '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': '6475930', 'n_tokens_mistral': 3309, 'n_tokens_neox': 3134, 'n_words': 918}