function createSector()

in database-jones/Adapter/api/UserContext.js [708:908]


function createSector(outerLoopProjections, innerLoopProjections, sectors, index, offset) {
  if (udebug.is_debug()) {udebug.log('createSector ' + outerLoopProjections[0].name
      + ' for ' + outerLoopProjections[0].domainObject.name +
      ' inner: ' + innerLoopProjections[0].name + ' for ' + innerLoopProjections[0].domainObject.name +
      ' index: ' + index + ' offset: ' + offset);}
  var sector = new Sector();
  sector.index = index;

  var projection = innerLoopProjections.shift();
  var outerNestedProjection;
  var tableHandler;
  var keyFieldCount;
  var fieldNames, field, candidateField;
  var indexHandler;
  var parentFieldMapping, parentSectorIndex, parentTableHandler, parentSectorProjection;
  var parentTargetFieldName, parentTargetField;
  var thisFieldMapping;
  var joinTable, joinTableHandler;
  var foreignKey, foreignKeyName;
  var i;
  var projectionRelationshipName;

  sector.projection = projection;
  sector.offset = offset;
  tableHandler = projection.domainObject.prototype.jones.dbTableHandler;
  sector.tableHandler = tableHandler;

  // parentFieldMapping is the field mapping for the parent sector
  // it contains the field in the parent sector and mapping information including join columns
  parentFieldMapping = projection.parentFieldMapping;
  sector.parentFieldMapping = parentFieldMapping;
  if (udebug.is_detail()) {udebug.log_detail('createSector for table handler', tableHandler.dbTable.name,
      'thisDBTable name', tableHandler.dbTable.name);}
  if (parentFieldMapping && index !== 0) {
    // only perform related field mapping for nested projections
    // find the parent sector which will be somewhere between 0 and immediately to the left
    for (parentSectorIndex = 0; parentSectorIndex < index; ++parentSectorIndex) {
      parentSectorProjection = sectors[parentSectorIndex].projection;
      if (parentSectorProjection === projection.parentProjection) {
        // found it
        sector.parentSectorIndex = parentSectorIndex;
        sectors[parentSectorIndex].childSectorIndexes.push(index);
        break;
      }
    }
    if (parentSectorIndex == index) {
      projection.error += 'did not find parent sector for ' + projection.parentProjection.name;
    } else {
      parentTableHandler = projection.parentTableHandler;
      sector.parentTableHandler = parentTableHandler;
      // get this optional field mapping that corresponds to the parent field mapping
      // it may be needed to find the foreign key or join table
      parentTargetFieldName = parentFieldMapping.targetField;
      parentTargetField = sector.tableHandler.getFieldMapping(parentTargetFieldName);
      if (parentFieldMapping.toMany && parentFieldMapping.manyTo) {
        // this is a many-to-many relationship using a join table
        joinTable = parentFieldMapping.joinTable;
        // joinTableHandler is the DBTableHandler for the join table resolved during validateProjection
        if (joinTable) {
          // join table is defined on the related side
          joinTableHandler = parentFieldMapping.joinTableHandler;
        } else {
          // join table must be defined on this side
          thisFieldMapping = tableHandler.getFieldMapping(parentFieldMapping.targetField);
          joinTable = thisFieldMapping.joinTable;
          if (!joinTable) {
            // error; neither side defined the join table
            projection.error += '\nMappingError: ' + parentTableHandler.newObjectConstructor.name +
              ' field ' + parentFieldMapping.fieldName + ' neither side defined the join table.';
          }
          joinTableHandler = thisFieldMapping.joinTableHandler;
        }
        sector.joinTableHandler = joinTableHandler;
        // many to many relationship has a join table with at least two foreign keys;
        // one to each table mapped to the two domain objects
        if (joinTable) {
          joinTableHandler.getForeignKeyNames().forEach(function(foreignKeyName) {
            foreignKey = joinTableHandler.getForeignKey(foreignKeyName);
            // is this foreign key for this table?
            if (foreignKey.targetDatabase === tableHandler.dbTable.database &&
                foreignKey.targetTable === tableHandler.dbTable.name) {
              // this foreign key is for the other table
              parentFieldMapping.otherForeignKey = foreignKey;
            }
            if (foreignKey.targetDatabase === parentTableHandler.dbTable.database &&
                foreignKey.targetTable === parentTableHandler.dbTable.name) {
              parentFieldMapping.thisForeignKey = foreignKey;
            }
          });
          if (!(parentFieldMapping.thisForeignKey && parentFieldMapping.otherForeignKey)) {
            // error must have foreign keys to both this table and related table
            projection.error += '\nMappingError: ' + parentTableHandler.newObjectConstructor.name +
            ' field ' + parentFieldMapping.fieldName + ' join table must include foreign keys for both sides.';
          }
        }
      } else {
        // this is a relationship using a foreign key
        // resolve the columns involved in the join to the related field
        // there is either a foreign key or a target field that has a foreign key
        // the related field mapping is the field mapping on the other side
        // the field mapping on this side is not used in this projection
        foreignKeyName = parentFieldMapping.foreignKey;
        if (foreignKeyName) {
          // foreign key is defined on the other side
          foreignKey = parentTableHandler.getForeignKey(foreignKeyName);
          sector.thisJoinColumns = foreignKey.targetColumnNames;
          sector.otherJoinColumns = foreignKey.columnNames;
        } else {
          // foreign key is defined on this side
          // get the fieldMapping for this relationship field
          parentTargetField = sector.tableHandler.getFieldMapping(parentTargetFieldName);
          foreignKeyName = parentTargetField.foreignKey;
          if (foreignKeyName) {
          foreignKey = tableHandler.getForeignKey(foreignKeyName);
          sector.thisJoinColumns = foreignKey.columnNames;
          sector.otherJoinColumns = foreignKey.targetColumnNames;
          } else {
            // error: neither side defined the foreign key
            projection.error += 'MappingError: ' + parentTableHandler.newObjectConstructor.name +
              ' field ' + parentFieldMapping.fieldName + ' neither side defined the foreign key.';
          }
        }
      }
    }
  }

  // create relationship field list for object creation
  if (projection.relationships) {
    var relationship;
    // for each relationship add to either sector.toOneRelationships or sector.toManyRelationships
    for (projectionRelationshipName in projection.relationships) {
      if (projection.relationships.hasOwnProperty(projectionRelationshipName)) {
        relationship = projection.relationships[projectionRelationshipName];
        // add this relationship to the list of projections to create a sector for
        innerLoopProjections.push(relationship);
        if (outerLoopProjections.indexOf(relationship) == -1) {
          outerLoopProjections.push(relationship);
        }
        // find field for relationship
        for (i = 0; i < projection.mapping.fields.length; ++i) {
          candidateField = projection.mapping.fields[i];
          if (projectionRelationshipName === candidateField.fieldName) {
            if (candidateField.toMany) {
              sector.toManyRelationships.push(projectionRelationshipName);
            } else {
              sector.toOneRelationships.push(projectionRelationshipName);
            }
          }
        }
      }
    }
  }
  if (udebug.is_detail()) {
    udebug.log_detail('createSector for', projection.name, 'has toManyRelationships:', sector.toManyRelationships);
    udebug.log_detail('createSector for', projection.name, 'has toOneRelationships:', sector.toOneRelationships);
  }

  // create key fields from primary key index handler
  indexHandler = tableHandler.dbIndexHandlers[0];
  keyFieldCount = indexHandler.getNumberOfFields();
  sector.keyFieldCount = keyFieldCount;
  for (i = 0; i < keyFieldCount; ++i) {
    field = indexHandler.getField(i);
    sector.keyFields.push(field);
    sector.keyFieldNames.push(field.fieldName);
  }
  // create non-key fields from projection fields excluding key fields
  fieldNames = projection.fields;
  fieldNames.forEach(function(fieldName) {
    // is this field in key fields?
    if (sector.keyFieldNames.indexOf(fieldName) == -1) {
      // non-key field; add it to non-key fields
      field = tableHandler.getFieldMapping(fieldName);
      sector.nonKeyFields.push(field);
    }
  });
  sector.nonKeyFieldCount = sector.nonKeyFields.length;
  udebug.log_detail('createSector created new sector for index', index, 'sector', sector);
  
  // the sector is now complete
  sectors.push(sector);
  // innerLoopProjections contains the array of sectors to create
  if (innerLoopProjections.length > 0) {
    createSector(outerLoopProjections, innerLoopProjections,
        sectors, index + 1, offset + keyFieldCount + sector.nonKeyFieldCount);
  }
  // we are done at this outer projection level;
  if (udebug.is_debug() && outerLoopProjections[0] && outerLoopProjections[0].name) {
      udebug.log('createSector for ' + outerLoopProjections[0].name +
          ' created ' + outerLoopProjections[0].sectors.length +
          ' sectors for ' + outerLoopProjections[0].domainObject.name);
  }

  // now go to the outer projection next level down and do it all over again
  outerLoopProjections.shift(); // get rid of the projection we just finished
  if (outerLoopProjections.length > 0) {
    outerNestedProjection = outerLoopProjections[0];
    outerNestedProjection.sectors = [];
    createSector(outerLoopProjections, [outerNestedProjection], outerNestedProjection.sectors, 0, 0);
  }
}