Skip to content

Commit

Permalink
Add support for pattern_sources in domain_filter (#1003)
Browse files Browse the repository at this point in the history
* add new domain-filter APIs

* make sure pattern_sources support same syntax as vis-col
  • Loading branch information
RFSH authored Feb 22, 2024
1 parent d77072b commit e806b78
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 51 deletions.
34 changes: 28 additions & 6 deletions docs/dev-docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ to use for ERMrest JavaScript agents.
* [.getAggregates(aggregateList)](#ERMrest.Reference+getAggregates) ⇒ <code>Promise</code>
* [.setSamePaging(page)](#ERMrest.Reference+setSamePaging)[<code>Reference</code>](#ERMrest.Reference)
* [.getColumnByName(name)](#ERMrest.Reference+getColumnByName)[<code>ReferenceColumn</code>](#ERMrest.ReferenceColumn)
* [.generateColumnsList(tuple)](#ERMrest.Reference+generateColumnsList)[<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.generateColumnsList(tuple, columnsList, dontChangeReference, skipLog)](#ERMrest.Reference+generateColumnsList)[<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.generateActiveList([tuple])](#ERMrest.Reference+generateActiveList) ⇒ <code>Object</code>
* [._getReadPath(useEntity, getTRS, getTCRS, getUnlinkTRS)](#ERMrest.Reference+_getReadPath) : <code>Object</code>
* [~processSortObject()](#ERMrest.Reference+_getReadPath..processSortObject)
Expand Down Expand Up @@ -540,6 +540,8 @@ to use for ERMrest JavaScript agents.
* [.reference](#ERMrest.ForeignKeyPseudoColumn+reference) : [<code>Reference</code>](#ERMrest.Reference)
* [.foreignKey](#ERMrest.ForeignKeyPseudoColumn+foreignKey) : [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
* [.hasDomainFilter](#ERMrest.ForeignKeyPseudoColumn+hasDomainFilter) : <code>Boolean</code>
* [.domainFilterUsedColumns](#ERMrest.ForeignKeyPseudoColumn+domainFilterUsedColumns) : [<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.domainFilterRawString](#ERMrest.ForeignKeyPseudoColumn+domainFilterRawString) : <code>string</code>
* [.defaultValues](#ERMrest.ForeignKeyPseudoColumn+defaultValues) : <code>Object</code>
* [.defaultReference](#ERMrest.ForeignKeyPseudoColumn+defaultReference) : <code>ERMrest.Refernece</code>
* [.displayname](#ERMrest.ForeignKeyPseudoColumn+displayname) : <code>Object</code>
Expand Down Expand Up @@ -781,7 +783,7 @@ to use for ERMrest JavaScript agents.
* [.getAggregates(aggregateList)](#ERMrest.Reference+getAggregates) ⇒ <code>Promise</code>
* [.setSamePaging(page)](#ERMrest.Reference+setSamePaging)[<code>Reference</code>](#ERMrest.Reference)
* [.getColumnByName(name)](#ERMrest.Reference+getColumnByName)[<code>ReferenceColumn</code>](#ERMrest.ReferenceColumn)
* [.generateColumnsList(tuple)](#ERMrest.Reference+generateColumnsList)[<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.generateColumnsList(tuple, columnsList, dontChangeReference, skipLog)](#ERMrest.Reference+generateColumnsList)[<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.generateActiveList([tuple])](#ERMrest.Reference+generateActiveList) ⇒ <code>Object</code>
* [._getReadPath(useEntity, getTRS, getTCRS, getUnlinkTRS)](#ERMrest.Reference+_getReadPath) : <code>Object</code>
* [~processSortObject()](#ERMrest.Reference+_getReadPath..processSortObject)
Expand Down Expand Up @@ -3196,7 +3198,7 @@ Constructor for a ParsedFilter.
* [.getAggregates(aggregateList)](#ERMrest.Reference+getAggregates) ⇒ <code>Promise</code>
* [.setSamePaging(page)](#ERMrest.Reference+setSamePaging)[<code>Reference</code>](#ERMrest.Reference)
* [.getColumnByName(name)](#ERMrest.Reference+getColumnByName)[<code>ReferenceColumn</code>](#ERMrest.ReferenceColumn)
* [.generateColumnsList(tuple)](#ERMrest.Reference+generateColumnsList)[<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.generateColumnsList(tuple, columnsList, dontChangeReference, skipLog)](#ERMrest.Reference+generateColumnsList)[<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.generateActiveList([tuple])](#ERMrest.Reference+generateActiveList) ⇒ <code>Object</code>
* [._getReadPath(useEntity, getTRS, getTCRS, getUnlinkTRS)](#ERMrest.Reference+_getReadPath) : <code>Object</code>
* [~processSortObject()](#ERMrest.Reference+_getReadPath..processSortObject)
Expand Down Expand Up @@ -3908,7 +3910,7 @@ Will throw an error if

<a name="ERMrest.Reference+generateColumnsList"></a>

#### reference.generateColumnsList(tuple) ⇒ [<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
#### reference.generateColumnsList(tuple, columnsList, dontChangeReference, skipLog) ⇒ [<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
Generates the list of visible columns
The logic is as follows:

Expand Down Expand Up @@ -3961,6 +3963,9 @@ NOTE:
| Param | Type | Description |
| --- | --- | --- |
| tuple | [<code>Tuple</code>](#ERMrest.Tuple) | the data for the current refe |
| columnsList | <code>Array.&lt;Object&gt;</code> | if passed, we will skip the annotation and heuristics and use this list instead. |
| dontChangeReference | <code>boolean</code> | whether we should mutate the reference or just return the generated list. |
| skipLog | <code>boolean</code> | whether we should skip logging the warning messages |

<a name="ERMrest.Reference+generateActiveList"></a>

Expand Down Expand Up @@ -4935,6 +4940,8 @@ In other cases, the returned data will only include the scalar value.
* [.reference](#ERMrest.ForeignKeyPseudoColumn+reference) : [<code>Reference</code>](#ERMrest.Reference)
* [.foreignKey](#ERMrest.ForeignKeyPseudoColumn+foreignKey) : [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
* [.hasDomainFilter](#ERMrest.ForeignKeyPseudoColumn+hasDomainFilter) : <code>Boolean</code>
* [.domainFilterUsedColumns](#ERMrest.ForeignKeyPseudoColumn+domainFilterUsedColumns) : [<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.domainFilterRawString](#ERMrest.ForeignKeyPseudoColumn+domainFilterRawString) : <code>string</code>
* [.defaultValues](#ERMrest.ForeignKeyPseudoColumn+defaultValues) : <code>Object</code>
* [.defaultReference](#ERMrest.ForeignKeyPseudoColumn+defaultReference) : <code>ERMrest.Refernece</code>
* [.displayname](#ERMrest.ForeignKeyPseudoColumn+displayname) : <code>Object</code>
Expand Down Expand Up @@ -4981,6 +4988,18 @@ The Foreign key object that this PseudoColumn is created based on
#### foreignKeyPseudoColumn.hasDomainFilter : <code>Boolean</code>
Whether this column has domain-filter annotation

**Kind**: instance property of [<code>ForeignKeyPseudoColumn</code>](#ERMrest.ForeignKeyPseudoColumn)
<a name="ERMrest.ForeignKeyPseudoColumn+domainFilterUsedColumns"></a>

#### foreignKeyPseudoColumn.domainFilterUsedColumns : [<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
The visible columns that are used as part of the domain-filter

**Kind**: instance property of [<code>ForeignKeyPseudoColumn</code>](#ERMrest.ForeignKeyPseudoColumn)
<a name="ERMrest.ForeignKeyPseudoColumn+domainFilterRawString"></a>

#### foreignKeyPseudoColumn.domainFilterRawString : <code>string</code>
The raw string value of the ermerst_path_pattern used in domain filter

**Kind**: instance property of [<code>ForeignKeyPseudoColumn</code>](#ERMrest.ForeignKeyPseudoColumn)
<a name="ERMrest.ForeignKeyPseudoColumn+defaultValues"></a>

Expand Down Expand Up @@ -7030,7 +7049,7 @@ get PathColumn object by column name
* [.getAggregates(aggregateList)](#ERMrest.Reference+getAggregates) ⇒ <code>Promise</code>
* [.setSamePaging(page)](#ERMrest.Reference+setSamePaging)[<code>Reference</code>](#ERMrest.Reference)
* [.getColumnByName(name)](#ERMrest.Reference+getColumnByName)[<code>ReferenceColumn</code>](#ERMrest.ReferenceColumn)
* [.generateColumnsList(tuple)](#ERMrest.Reference+generateColumnsList)[<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.generateColumnsList(tuple, columnsList, dontChangeReference, skipLog)](#ERMrest.Reference+generateColumnsList)[<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
* [.generateActiveList([tuple])](#ERMrest.Reference+generateActiveList) ⇒ <code>Object</code>
* [._getReadPath(useEntity, getTRS, getTCRS, getUnlinkTRS)](#ERMrest.Reference+_getReadPath) : <code>Object</code>
* [~processSortObject()](#ERMrest.Reference+_getReadPath..processSortObject)
Expand Down Expand Up @@ -7742,7 +7761,7 @@ Will throw an error if

<a name="ERMrest.Reference+generateColumnsList"></a>

#### reference.generateColumnsList(tuple) ⇒ [<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
#### reference.generateColumnsList(tuple, columnsList, dontChangeReference, skipLog) ⇒ [<code>Array.&lt;ReferenceColumn&gt;</code>](#ERMrest.ReferenceColumn)
Generates the list of visible columns
The logic is as follows:

Expand Down Expand Up @@ -7795,6 +7814,9 @@ NOTE:
| Param | Type | Description |
| --- | --- | --- |
| tuple | [<code>Tuple</code>](#ERMrest.Tuple) | the data for the current refe |
| columnsList | <code>Array.&lt;Object&gt;</code> | if passed, we will skip the annotation and heuristics and use this list instead. |
| dontChangeReference | <code>boolean</code> | whether we should mutate the reference or just return the generated list. |
| skipLog | <code>boolean</code> | whether we should skip logging the warning messages |

<a name="ERMrest.Reference+generateActiveList"></a>

Expand Down
6 changes: 6 additions & 0 deletions docs/user-docs/annotation.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,14 @@ Supported _columnorder_key_ syntax:

Supported _domainfilter_ syntax:
- `{ "ermrest_path_pattern":` _pathpattern_ `}`: The _pathpattern_ yields a _filter_ via [Pattern Expansion](#pattern-expansion). With this syntax, the applied filter will be hidden from the user.
- `{ "ermrest_path_pattern":` _pathpattern_ `, "pattern_sources":` _columnlist_ `}`: The added `pattern_sources` allows the client to proceed more meaningful errors to users.
- `{ "ermrest_path_pattern":` _pathpattern_ `, "display_markdown_pattern":` _displaypattern_ `}`: The _pathpattern_ yields a _filter_ via [Pattern Expansion](#pattern-expansion). _displaypattern_ will provide the visual presentation of the filter which will be computed by performing [Pattern Expansion](#pattern-expansion) to obtain a markdown-formatted text value which MAY be rendered using a markdown-aware renderer.
- If the computed _filter_ is an empty string, the _domain_filter_ will be ignored, and the client behaves as if this annotation is not even defined. Therefore, while rendering the list of allowed foreign key rows in recordedit, users will see the whole list.
- `{ "ermrest_path_pattern":` _pathpattern_ `, "display_markdown_pattern":` _displaypattern_ `, "pattern_sources":` _columnlist_ `}`: The added `pattern_sources` allows the client to proceed more meaningful errors to users.

Supported _columnlist_ patterns:

- `[` ... _columndirective_ `,` ... `]`: The list of [columns directives](#column-directive) that are used in the `ermrest_path_pattern`. Make sure to use the same column directive as visible columns. For example if you've used column named `fk_col` in the pattern, but the foreign key that this column is part of visible, you should include the foreign key column here (and not the `fk_col` itself).

Supported _filter_ syntax:

Expand Down
47 changes: 45 additions & 2 deletions js/column.js
Original file line number Diff line number Diff line change
Expand Up @@ -1915,31 +1915,74 @@ ForeignKeyPseudoColumn.prototype._determineSortable = function () {
Object.defineProperty(ForeignKeyPseudoColumn.prototype, "hasDomainFilter", {
get: function () {
if (this._hasDomainFilter === undefined) {
var checkDomainFilter = function (self) {
var populateDomainFilterProps = function (self) {
// the annotaion didn't exist
if (!self.foreignKey.annotations.contains(module._annotations.FOREIGN_KEY)) {
self._domainFilterRawString = '';
self._domainFilterUsedColumns = [];
return false;
}

var content = self.foreignKey.annotations.get(module._annotations.FOREIGN_KEY).content;

// the annotation is properly defined
if (isObjectAndNotNull(content.domain_filter) && isStringAndNotEmpty(content.domain_filter.ermrest_path_pattern)) {
self._domainFilterRawString = content.domain_filter.ermrest_path_pattern;

var usedColumns = [];
if (Array.isArray(content.domain_filter.pattern_sources)) {
usedColumns = self._baseReference.generateColumnsList(undefined, content.domain_filter.pattern_sources, true, true);
}
self._domainFilterUsedColumns = usedColumns;

return true;
}
// backward compatibility
else if (typeof content.domain_filter_pattern === "string") {
self._domainFilterRawString = content.domain_filter_pattern;
self._domainFilterUsedColumns = [];
return true;
}

self._domainFilterRawString = '';
self._domainFilterUsedColumns = [];
return false;
};

this._hasDomainFilter = checkDomainFilter(this);
this._hasDomainFilter = populateDomainFilterProps(this);
}
return this._hasDomainFilter;
}
});
/**
* The visible columns that are used as part of the domain-filter
* @member {ERMrest.ReferenceColumn[]} domainFilterUsedColumns
* @memberof ERMrest.ForeignKeyPseudoColumn#
*/
Object.defineProperty(ForeignKeyPseudoColumn.prototype, 'domainFilterUsedColumns', {
get: function () {
if (this._domainFilterUsedColumns === undefined) {
// this will popuplate _domainFilterUsedColumns too
var temp = this.hasDomainFilter;
}
return this._domainFilterUsedColumns;
}
});
/**
* The raw string value of the ermerst_path_pattern used in domain filter
* @member {string} domainFilterRawString
* @memberof ERMrest.ForeignKeyPseudoColumn#
*/
Object.defineProperty(ForeignKeyPseudoColumn.prototype, 'domainFilterRawString', {
get: function () {
if (this._domainFilterRawString === undefined) {
// this will popuplate _domainFilterRawString too
var temp = this.hasDomainFilter;
}
return this._domainFilterRawString;
}
});


/**
* returns the raw default values of the constituent columns.
Expand Down
Loading

0 comments on commit e806b78

Please sign in to comment.