Skip to content

Commit

Permalink
check for annotation values to use for bulk create foreign key APIs. …
Browse files Browse the repository at this point in the history
…Test cases added
  • Loading branch information
jrchudy committed Oct 22, 2024
1 parent 16373ea commit 4db0b7c
Show file tree
Hide file tree
Showing 17 changed files with 1,584 additions and 52 deletions.
3 changes: 2 additions & 1 deletion js/column.js
Original file line number Diff line number Diff line change
Expand Up @@ -2166,7 +2166,8 @@ Object.defineProperty(ForeignKeyPseudoColumn.prototype, "display", {
}

// check visible-columns annotation display property and set to override property from fk annotation or display annotation
if (displ.bulk_create_foreign_key) {
// make sure `false` is not ignored since that turns this feature off
if (displ.bulk_create_foreign_key !== null) {
sourceDisplay.bulkForeignKeyCreateConstraintName = displ.bulk_create_foreign_key;
}
}
Expand Down
30 changes: 20 additions & 10 deletions js/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -1105,18 +1105,20 @@
}
}

// no match was found, turn off the feature
if (value === -1) value = false;
return value;
};

var showSavedQueryAnnoVal = _getHierarchicalDisplayAnnotationValue(this, "show_saved_query");
/**
* if showSavedQueryAnnoVal is -1, turn off the feature
* @type {boolean}
*/
this._showSavedQuery = _getHierarchicalDisplayAnnotationValue(this, "show_saved_query");
this._showSavedQuery = showSavedQueryAnnoVal === -1 ? false : showSavedQueryAnnoVal;

// if false, turn off the feature
// if null or not defined, allow the heuristics to be used
this._shouldUseBulkCreateForeignKey = _getHierarchicalDisplayAnnotationValue(this, "bulk_create_foreign_key") === false ? false : true;
var bulkCreateAnnoVal = _getHierarchicalDisplayAnnotationValue(this, "bulk_create_foreign_key");
this._shouldUseBulkCreateForeignKey = bulkCreateAnnoVal === false ? false : true;

/**
* @desc The path to the table where the favorite terms are stored
Expand Down Expand Up @@ -4790,18 +4792,26 @@
* bulkForeignKeyCreate column is set based on the following rules:
* 1. defined on display property in visible-columns
* 2. foreign key annotation
* 3. table-display annotation when defined on the leaf table of the fkey relationship
* 4. default heuristics used when computeBulkCreateForeignKeyObject is called
*
*
* 3. table-display annotation
* 4. display annotation on table, schema, then catalog
* 5. default heuristics used when computeBulkCreateForeignKeyObject is called
*/
// check display annotation on table/schema/catalog
// if true, don't set anything and let the heuristics be used
// if false, set to false to turn off heuristics
if (toCol.table._shouldUseBulkCreateForeignKey === false) bulkCreateConstraintName = false;
if (this.table._shouldUseBulkCreateForeignKey === false) bulkCreateConstraintName = false;

if (this.table.annotations.contains(module._annotations.TABLE_DISPLAY)) {
var tableAnnotation = module._getRecursiveAnnotationValue(context, this.table.annotations.get(module._annotations.TABLE_DISPLAY).content);

if (tableAnnotation.bulk_create_foreign_key_candidates !== null) {
bulkCreateConstraintName = tableAnnotation.bulk_create_foreign_key_candidates;
}
}

// check foreign key annotation
if (displayAnnot.bulk_create_foreign_key) {
// make sure `false` is not ignored since that turns this feature off
if (displayAnnot.bulk_create_foreign_key !== undefined && displayAnnot.bulk_create_foreign_key !== null) {
bulkCreateConstraintName = displayAnnot.bulk_create_foreign_key;
}

Expand Down
91 changes: 66 additions & 25 deletions js/reference.js
Original file line number Diff line number Diff line change
Expand Up @@ -4077,62 +4077,103 @@

// set of foreignkey columns (they might be overlapping so we're not using array)
var fkCols = {};
var mainColumn = null;
nonSystemColumnFks.forEach(function(fk) {
fk.colset.columns.forEach(function(col) {
fkCols[col] = true;

if (prefillObject.fkColumnNames.indexOf(col.name) !== -1) {
// mainColumn is the column being prefilled, this should ALWAYS be in the visible columns list
mainColumn = col;
}
});
});

var mainColumn = null;
// find main column in the visible columns list
self.columns.forEach(function(column) {
// column should be a foreignkey pseudo column
if (!column.isForeignKey) return;
if (prefillObject.fkColumnNames.indexOf(column.name) !== -1) {
// mainColumn is the column being prefilled, this should ALWAYS be in the visible columns list
mainColumn = column;
}
});

/**
* Using the given constraintName, determines the leaf column to be used for bulk foreign key create from the annotation value.
* If no constraintName is provided, uses the other foreign key found on the table as the leaf
* NOTE: when no constraintName, this is only called if there are 2 foreign keys and we know the main column
*
* @param {string} constraintName name of the foreingkey from annotation
* @param {string[][] | string[]} constraintNameProp constraint name of the foreingkey from annotation or array of constraint names
* @returns BulkCreateForeignKeyObject if leaf column can be found, null otherwise
*/
var findLeafColumnAndSetBulkCreate = function(constraintName) {
var leafCol = null;
self.columns.forEach(function(column) {
// column should be a foreignkey pseudo column
if (!column.isForeignKey) return;
var findLeafColumnAndSetBulkCreate = function(constraintNameProp) {
/**
*
* @param {ERMRest.Column} col foreign key column to check if it's in the list of visible columns and matches the constraint name
* @param {string[]} constraintName
* @returns the foreign key column that represents the leaf table
*/
var findLeafColumn = function(col, constraintName) {
var foundColumn = null;

nonSystemColumnFks.forEach(function(fk) {
for (k = 0; k < nonSystemColumnFks.length; k++) {
var fk = nonSystemColumnFks[k];
// make sure column is in visible columns and is in foreign key list
// column and foreign key `.name` property is a hash value
if (column.name === fk.name) {
if (constraintName && constraintName === column.constraint_names[0]) {
if (col.name === fk.name) {
if (constraintName && constraintName === col._constraintName) {
// use the constraint name to check each column and ensure it's the one we want from annotation
leafCol = column;
} else if (!constraintName && column.name !== mainColumn.name) {
foundColumn = col;
} else if (!constraintName && col.name !== mainColumn.name) {
// make sure the current column is the NOT the main column
// assume there are only 2 foreign keys and we know mainColumn already
leafCol = column;
foundColumn = col;
}

if (foundColumn) break;
}
});
});
};

return foundColumn;
}

var leafCol = null;
// use for loop so we can break if we find the leaf column
for (i = 0; i < self.columns.length; i++) {
var column = self.columns[i];

// column should be a foreignkey pseudo column
if (!column.isForeignKey) continue;

// if constraintNameProp is string[][], it's from bulk_create_foreign_key_candidates
// we need to iterate over the set to find the first matching column
if (Array.isArray(constraintNameProp) && Array.isArray(constraintNameProp[0])) {
for (j = 0; j < constraintNameProp.length; j++) {
leafCol = findLeafColumn(column, constraintNameProp[j].join("_"));

if (leafCol) break;
}
} else if (Array.isArray(constraintNameProp)) {
// constraintNameProp should be a string[]
leafCol = findLeafColumn(column, constraintNameProp.join("_"));
} else {
// no constraintName
leafCol = findLeafColumn(column);
}

if (leafCol) break;
};

if (!leafCol) return null;
return new BulkCreateForeignKeyObject(this, prefillObject, fkCols, mainColumn, leafCol);
return new BulkCreateForeignKeyObject(self, prefillObject, fkCols, mainColumn, leafCol);
}

if (!mainColumn) {
// if no mainColumn, this API can't be used
this._bulkCreateForeignKeyObject = null;
} else if (mainColumn.leafColumnConstrainName === false) {
} else if (mainColumn.display.bulkForeignKeyCreateConstraintName === false) {
// don't use heuristics
this._bulkCreateForeignKeyObject = null;
} else if (mainColumn.leafColumnConstrainName) {
// see if the leaf column to use is determined by an annotation by seeting `true`
} else if (mainColumn.display.bulkForeignKeyCreateConstraintName) {
// see if the leaf column to use is determined by an annotation by setting `true`
// if a leaf column is determined, call BulkCreateForeignKeyObject constructor and set the generated value
this._bulkCreateForeignKeyObject = findLeafColumnAndSetBulkCreate(mainColumn.leafColumnConstrainName);
this._bulkCreateForeignKeyObject = findLeafColumnAndSetBulkCreate(mainColumn.display.bulkForeignKeyCreateConstraintName);
} else {
// use heuristics instead
// There have to be 2 foreign key columns
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit 4db0b7c

Please sign in to comment.