function DBTableHandler()

in database-jones/Adapter/common/DBTableHandler.js [418:614]


function DBTableHandler(dbtable, tablemapping, ctor) {
  var i,               // an iterator
      field,           // a field
      col,             // a column
      id,              // a column id number
      index,           // a DBIndex
      columnNames,     // array of the mapped column names
      foreignKey,      // foreign key object from dbTable
      priv;            // our DBTableHandlerPrivate

  var dbTableHandler = this;
  var invalidateCallback;

  stats.constructor_calls++;

  if(! ( dbtable && dbtable.columns)) {
    stats.return_null++;
    return null;
  }

 if(stats.created[dbtable.name] === undefined) {
    stats.created[dbtable.name] = 1;
  } else {
    stats.created[dbtable.name]++;
  }
  
  /* Default properties */
  priv                        = new DBTableHandlerPrivate(this, dbtable.columns.length);
  this._private               = priv;
  this.dbTable                = dbtable;
  this.ValueObject            = null;
  this.errorMessages          = "";
  this.isValid                = true;
  this.autoIncFieldName       = null;
  this.autoIncColumnNumber    = null;
  this.numberOfLobColumns     = 0;
  this.newObjectConstructor   = ctor;
  this.dbIndexHandlers        = [];
  this.foreignKeyMap          = {};
  this.sparseContainer        = null;
  this.is1to1                 = true;
  this.relationshipFields     = [];
  if(tablemapping) {
    if(tablemapping.isValid()) {
      stats.explicit_mappings++;
    } else {
      this.errorMessages = tablemapping.error;
      this.isValid = false;
      return;
    }
  }
  else {                                          // Create a default mapping
    stats.default_mappings++;
    tablemapping          = new TableMapping(this.dbTable.name);
    tablemapping.database = this.dbTable.database;
  }

  /* Make a copy of the mapping and store it as the "resolved" mapping */
  this.resolvedMapping = new TableMapping(tablemapping);
  this.resolvedMapping.mapAllColumns = false;  // all fields will be present

  /* Build an array of column names.  This will establish column order. */
  columnNames = [];
  function addColumnName(name) {
    if(name && getColumnByName(dbtable, name) && columnNames.indexOf(name) === -1) {
      columnNames.push(name);
    }
  }

  if(tablemapping.mapAllColumns) {        // Use all columns from dictionary
    for(i = 0 ; i < dbtable.columns.length ; i++) {
      columnNames.push(dbtable.columns[i].name);
    }
  } else {        // Use all mapped columns plus any sparse container column
    for(i = 0 ; i < tablemapping.fields.length ; i++) {
      field = tablemapping.fields[i];
      if(field.persistent) {
        if(field.toManyColumns) {
          field.toManyColumns.forEach(addColumnName);
        } else {
          addColumnName(field.columnName || field.fieldName);
        }
      }
    }
    addColumnName(dbtable.sparseContainer);
  }
  udebug.log("DBTableHandler columns", columnNames);


  /* Build the array of columns.
  */
  for(id = 0 ; id < columnNames.length ; id++) {
    priv.addColumn(getColumnByName(dbtable, columnNames[id]),
                   tablemapping.columnConverterMap);
  }

  /* Build the array of mapped fields. */
  /* Start with persistent fields from the TableMapping */
  for(i = 0; i < this.resolvedMapping.fields.length ; i++) {
    field = this.resolvedMapping.fields[i];
    if(field.persistent) {
      priv.addField(field);
    }
  }
  /* Add a default field mapping for any yet-unmapped columns */
  if(tablemapping.mapAllColumns) {
    for(i = 0 ; i < priv.columns.length ; i++) {
      if(! priv.columns[i].isMapped) {
        field = priv.columnMetadata[i].name;
        if(priv.fields[field]) {
          priv.columns[i].setUnmappable();
        } else {
          this.resolvedMapping.mapField({"fieldName":field,"columnName":field});
          priv.addField(this.resolvedMapping.getFieldMapping(field));
        }
      }
    }
  }

  /* Iterate over all columns.
   * Set internal pointers for notable columns.
  */
  for(id = 0 ; id < columnNames.length ; id++) {
    col = columnNames[id];
    if(this.resolvedMapping.sparseContainer &&
       this.resolvedMapping.sparseContainer.columnName === col) {
      this.sparseContainer = col;
      priv.setSparseColumn(id, this.resolvedMapping);
    } else if(dbtable.sparseContainer === col && ! priv.columns[id].isMapped) {
      this.resolvedMapping.mapSparseFields(col);
      this.sparseContainer = col;
      priv.setSparseColumn(id, this.resolvedMapping);
    }
    if(priv.columnMetadata[id].isAutoincrement) {
      this.autoIncColumnNumber = i;
      this.autoIncFieldName = priv.columns[id].fieldNames[0];
    }
    if(priv.columnMetadata[id].isLob) {
      this.numberOfLobColumns++;
    }
    if(priv.columns[id].isShared || priv.columns[id].isPartial) {
      this.is1to1 = false;
    }
  }

  /* Iterate over all field mappings.
   * Build the array of relationshipFields.
   * For all persistent fields, resolve field.columnName.
   */
  for(i = 0 ; i < this.resolvedMapping.fields.length ; i++) {
    field = this.resolvedMapping.fields[i];
    if(field.relationship) {
      this.relationshipFields.push(field);
    } else if(field.persistent) {
      if(field.columnName) {
        if(! this._private.getColumnMappingByName(field.columnName)) {
          this.resolvedMapping.error += "Column " + field.columnName + " does not exist\n";
        }
      } else if(! field.toManyColumns) {
        if(this._private.getColumnMappingByName(field.fieldName)) {
          field.columnName = field.fieldName;
        } else if(this.sparseContainer) {
          field.columnName = this.sparseContainer;
        } else {
          this.resolvedMapping.error += "No column mapped for field " + field.fieldName + "\n";
        }
      }
    }
    if(field.columnName !== this.sparseContainer) {
      this.resolvedMapping.fieldIsNotSparse(field.fieldName);
    }
  }

  // build a dbIndexHandler for each usable dbIndex
  for (i = 0; i < this.dbTable.indexes.length; ++i) {
    index = this.dbTable.indexes[i];
    if(this.hasColumnsFromTable(index.columnNumbers)) {
      this.dbIndexHandlers.push(new DBIndexHandler(this, index));
    }
  }
  // build foreign key map
  for (i = 0; i < this.dbTable.foreignKeys.length; ++i) {
    foreignKey = this.dbTable.foreignKeys[i];
    this.foreignKeyMap[foreignKey.name] = foreignKey;
  }

  // set the invalidate callback if this db table handler is valid
  if (dbTableHandler.isValid) {
    invalidateCallback = function() {
      udebug.log('invalidateCallback called for dbTableHandler',
          ctor?'for constructor '+ctor.name:'default', 'for table', dbtable.database+'.'+dbtable.name);
      dbTableHandler.isValid = false;
    };
    dbtable.registerInvalidateCallback(invalidateCallback);
  }
  udebug.log("Constructor completed -- ", this);
}