<commit_before>
/**
 * Module dependencies
 */

var _ = require('lodash'),
    utils = require('./utils'),
    hasOwnProperty = utils.object.hasOwnProperty;

/**
 * Expose JoinTables
 */

module.exports = JoinTables;

/**
 * Insert Join/Junction Tables where needed whenever two collections
 * point to each other. Also replaces the references to point to the new join table.
 *
 * @param {Object} collections
 * @return {Object}
 * @api private
 */

function JoinTables(collections) {
  collections = collections || {};
  this.collections = _.cloneDeep(collections);
  this.tables = {};

  // Build Up Join Tables
  for(var collection in collections) {
    var joinTables = this.buildJoins(collection);
    this.uniqueTables(joinTables);

    // Mark hasManyThrough tables as junction tables with select all set to true
    this.markCustomJoinTables(collection);
  }

  // Update Collection Attributes to point to the join table
  this.linkAttributes();

  return _.extend(this.collections, this.tables);
}

/**
 * Build A Set of Join Tables
 *
 * @param {String} collection
 * @api private
 * @return {Array}
 */

JoinTables.prototype.buildJoins = function(collection) {
  var attributes = this.collections[collection].attributes,
      collectionAttributes = this.mapCollections(attributes),
      tables = [];

  // If there are no collection attributes return an empty array
  if(Object.keys(collectionAttributes).length === 0) return [];

  // For each collection attribute, inspect it to build up a join table if needed.
  for(var attribute in collectionAttributes) {

    // Check the collection it references to see if this is a one-to-many or many-to-many
    // relationship. If it's a one-to-many we don't need to build up a join table.
    var attr = collectionAttributes[attribute];

    // Ensure the attribute has a `via` property
    if(!hasOwnProperty(attr, 'via')) {
      throw new Error('Collection ' + collection + ' has an association attribute that is missing a '+
        '`via` property. Any associations with a `collection` attribute must specify a `via` option ' +
        'that points to another attribute. Update the attribute: ' + attribute + ' and add a `via` property');
    }

    // Check if this is a hasManyThrough attribute, if so a join table doesn't need to be created
    if(hasOwnProperty(attr, 'through')) continue;

    var child = this.collections[attr.collection.toLowerCase()];

    // Ensure the `via` exists on the child.
    if(!hasOwnProperty(child.attributes, attr.via)) {
      throw new Error('Collection ' + collection + ' has a `via` attribute which is missing from the ' +
        'collection ' + attr.collection);
    }

    // If the associated attribute is a foreign key, ignore it
    if(hasOwnProperty(child.attributes[attr.via], 'foreignKey')) continue;

    // Build up an object that can be used to build a join table
    var tableAttributes = {
      column_one: {
        collection: collection,
        attribute: attribute,
        via: attr.via
      },

      column_two: {
        collection: attr.collection,
        attribute: attr.via,
        via: attribute
      }
    };

    // Build join tables
    tables = tables.concat(this.buildTable(tableAttributes));
  }

  return tables;
};

/**
 * Find Has Many attributes for a given set of attributes.<commit_msg>normalize collection name in one spot<commit_after>
/**
 * Module dependencies
 */

var _ = require('lodash'),
    utils = require('./utils'),
    hasOwnProperty = utils.object.hasOwnProperty;

/**
 * Expose JoinTables
 */

module.exports = JoinTables;

/**
 * Insert Join/Junction Tables where needed whenever two collections
 * point to each other. Also replaces the references to point to the new join table.
 *
 * @param {Object} collections
 * @return {Object}
 * @api private
 */

function JoinTables(collections) {
  collections = collections || {};
  this.collections = _.cloneDeep(collections);
  this.tables = {};

  // Build Up Join Tables
  for(var collection in collections) {
    var joinTables = this.buildJoins(collection);
    this.uniqueTables(joinTables);

    // Mark hasManyThrough tables as junction tables with select all set to true
    this.markCustomJoinTables(collection);
  }

  // Update Collection Attributes to point to the join table
  this.linkAttributes();

  return _.extend(this.collections, this.tables);
}

/**
 * Build A Set of Join Tables
 *
 * @param {String} collection
 * @api private
 * @return {Array}
 */

JoinTables.prototype.buildJoins = function(collection) {
  var attributes = this.collections[collection].attributes,
      collectionAttributes = this.mapCollections(attributes),
      tables = [];

  // If there are no collection attributes return an empty array
  if(Object.keys(collectionAttributes).length === 0) return [];

  // For each collection attribute, inspect it to build up a join table if needed.
  for(var attribute in collectionAttributes) {

    // Check the collection it references to see if this is a one-to-many or many-to-many
    // relationship. If it's a one-to-many we don't need to build up a join table.
    var attr = collectionAttributes[attribute];

    // Ensure the attribute has a `via` property
    if(!hasOwnProperty(attr, 'via')) {
      throw new Error('Collection ' + collection + ' has an association attribute that is missing a '+
        '`via` property. Any associations with a `collection` attribute must specify a `via` option ' +
        'that points to another attribute. Update the attribute: ' + attribute + ' and add a `via` property');
    }

    // Check if this is a hasManyThrough attribute, if so a join table doesn't need to be created
    if(hasOwnProperty(attr, 'through')) continue;

    // Normalize `collection` property name to lowercased version
    attr.collection = attr.collection.toLowerCase();

    var child = this.collections[attr.collection];

    // Ensure the `via` exists on the child.
    if(!hasOwnProperty(child.attributes, attr.via)) {
      throw new Error('Collection ' + collection + ' has a `via` attribute which is missing from the ' +
        'collection ' + attr.collection);
    }

    // If the associated attribute is a foreign key, ignore it
    if(hasOwnProperty(child.attributes[attr.via], 'foreignKey')) continue;

    // Build up an object that can be used to build a join table
    var tableAttributes = {
      column_one: {
        collection: collection.toLowerCase(),
        attribute: attribute,
        via: attr.via
      },

      column_two: {
        collection: attr.collection,
        attribute: attr.via,
        via: attribute
      }
    };

    // Build join tables
    tables = tables.concat(this.buildTable(tableAttributes));
  }

  return tables;
};

/**
 * Find Has Many attributes for a given set of attributes.
{'fraction_non_alphanumeric': 0.10281607509533587, 'fraction_numerical': 0.0002933411557641537, 'mean_word_length': 3.1808706315144084, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '4804161', 'n_tokens_mistral': 1823, 'n_tokens_neox': 1787, 'n_words': 663}