Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse regular expression filter before storing to provenance graph #301

Merged
merged 4 commits into from
Feb 12, 2020
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 59 additions & 4 deletions src/lineup/internal/cmds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export async function setColumnImpl(inputs: IObjectRef<any>[], parameter: any) {
source.setMapping(createMappingFunction(parameter.value));
} else if (source) {
bak = source[`get${prop}`]();
source[`set${prop}`].call(source, parameter.value);
source[`set${prop}`].call(source, restoreRegExp(parameter.value)); // restore serialized regular expression before passing to LineUp
}

return waitForSorted({
Expand Down Expand Up @@ -322,26 +322,81 @@ function recordPropertyChange(source: Column | Ranking, provider: LocalDataProvi
if (ignore(`${property}Changed`, lineupViewWrapper)) {
return;
}
// console.log(source, property, old, newValue);

const newSerializedValue = stringifyRegExp(newValue); // serialize possible RegExp object to be properly stored as provenance graph

if (source instanceof Column) {
// assert ALineUpView and update the stats
lineupViewWrapper.value.getInstance().updateLineUpStats();

const rid = rankingId(provider, source.findMyRanker());
const path = source.fqpath;
graph.pushWithResult(setColumn(lineupViewWrapper, rid, path, property, newValue), {
graph.pushWithResult(setColumn(lineupViewWrapper, rid, path, property, newSerializedValue), {
inverse: setColumn(lineupViewWrapper, rid, path, property, old)
});
} else if (source instanceof Ranking) {
const rid = rankingId(provider, source);
graph.pushWithResult(setColumn(lineupViewWrapper, rid, null, property, newValue), {
graph.pushWithResult(setColumn(lineupViewWrapper, rid, null, property, newSerializedValue), {
inverse: setColumn(lineupViewWrapper, rid, null, property, old)
});
}
};
source.on(`${property}Changed.track`, delayed > 0 ? delayedCall(f, delayed) : f);
}

/**
* Serialize RegExp objects from LineUp string columns as plain object
* that can be stored in the provenance graph
*/
interface IRegExpFilter {
/**
* RegExp as string
*/
value: string;
/**
* Flag to indicate the value should be restored as RegExp
*/
isRegExp: boolean;
}

/**
* Serializes RegExp objects to an IRegexFilter object, which can be stored in the provenance graph.
* In case a string is passed to this function no serialization is applied.
*
* Background information:
* The serialization step is necessary, because RegExp objects are converted into an empty object `{}` on `JSON.stringify`.
* ```
* JSON.stringify(/^123$/gm); // result: {}
* ```
*
* @param value Input string or RegExp object
* @returns {string | IRegExpFilter} Returns the input string or a plain `IRegExpFilter` object
*/
function stringifyRegExp(value: string | RegExp): string | IRegExpFilter {
if (!(value instanceof RegExp)) {
return value;
}
return {value: value.toString(), isRegExp: true};
}

/**
* Restores a RegExp object from a given IRegExpFilter object.
* In case a string is passed to this function no deserialization is applied.
*
* @param filter Filter as string or plain object matching the IRegExpFilter
* @returns {string | RegExp| null} Returns the input string or the restored RegExp object
*/
function restoreRegExp(filter: string | IRegExpFilter): string | RegExp {
if (filter === null || !(<IRegExpFilter>filter).isRegExp) {
return <string | null>filter;
}

const serializedRegexParser = /^\/(.+)\/(\w+)?$/; // from https://gist.github.com/tenbits/ec7f0155b57b2d61a6cc90ef3d5f8b49
const matches = serializedRegexParser.exec((<IRegExpFilter>filter).value);
const [_full, regexString, regexFlags] = matches;
return new RegExp(regexString, regexFlags);
}

function trackColumn(provider: LocalDataProvider, lineup: IObjectRef<IViewProvider>, graph: ProvenanceGraph, col: Column) {
recordPropertyChange(col, provider, lineup, graph, 'metaData');
recordPropertyChange(col, provider, lineup, graph, 'filter');
Expand Down