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);
}
}