simple-graph-query 2.1.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/simple-graph-query.bundle.js +77 -34
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare class SimpleGraphQueryEvaluator {
|
|
|
11
11
|
datum: IDataInstance;
|
|
12
12
|
forgeListener: ForgeListenerImpl;
|
|
13
13
|
walker: ParseTreeWalker;
|
|
14
|
+
private parseTreeCache;
|
|
14
15
|
constructor(datum: IDataInstance);
|
|
15
16
|
getExpressionParseTree(forgeExpr: string): import("./forge-antlr/ForgeParser").ParseExprContext;
|
|
16
17
|
evaluateExpression(forgeExpr: string): EvaluationResult;
|
|
@@ -48542,20 +48542,21 @@ function transitiveClosure(pairs) {
|
|
|
48542
48542
|
}
|
|
48543
48543
|
graph.get(from).add(to);
|
|
48544
48544
|
}
|
|
48545
|
-
//
|
|
48545
|
+
// Use more efficient BFS with index-based queue to avoid O(n) shift() operations
|
|
48546
48546
|
// NOTE: we use Set<string> instead of Set<[SingleValue, SingleValue]> since
|
|
48547
48547
|
// TS would compute equality over the object's reference instead of the value
|
|
48548
48548
|
// when the value is an array
|
|
48549
|
-
const
|
|
48549
|
+
const transitiveClosureSet = new Set();
|
|
48550
48550
|
for (const start of graph.keys()) {
|
|
48551
48551
|
const visited = new Set();
|
|
48552
48552
|
const queue = [...(graph.get(start) ?? [])];
|
|
48553
|
-
|
|
48554
|
-
|
|
48553
|
+
let queueIndex = 0; // Use index instead of shift() for O(1) access
|
|
48554
|
+
while (queueIndex < queue.length) {
|
|
48555
|
+
const current = queue[queueIndex++];
|
|
48555
48556
|
if (visited.has(current))
|
|
48556
48557
|
continue;
|
|
48557
48558
|
visited.add(current);
|
|
48558
|
-
|
|
48559
|
+
transitiveClosureSet.add(JSON.stringify([start, current]));
|
|
48559
48560
|
const neighbors = graph.get(current);
|
|
48560
48561
|
if (neighbors) {
|
|
48561
48562
|
for (const neighbor of neighbors) {
|
|
@@ -48567,7 +48568,7 @@ function transitiveClosure(pairs) {
|
|
|
48567
48568
|
}
|
|
48568
48569
|
}
|
|
48569
48570
|
// convert the result back to a Tuple[] and return
|
|
48570
|
-
return Array.from(
|
|
48571
|
+
return Array.from(transitiveClosureSet).map((pair) => JSON.parse(pair));
|
|
48571
48572
|
}
|
|
48572
48573
|
function dotJoin(left, right) {
|
|
48573
48574
|
const leftExpr = isSingleValue(left) ? [[left]] : left;
|
|
@@ -48685,11 +48686,23 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
48685
48686
|
}
|
|
48686
48687
|
// helper function to get the label as string (used for @: and @str: operators)
|
|
48687
48688
|
getLabelAsString(value) {
|
|
48689
|
+
// Optimization: for primitive types, convert directly
|
|
48690
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
48691
|
+
return String(value);
|
|
48692
|
+
}
|
|
48688
48693
|
const label = this.getLabelForValue(value);
|
|
48689
48694
|
return String(label);
|
|
48690
48695
|
}
|
|
48691
48696
|
// helper function to get the label as boolean (used for @bool: operator)
|
|
48692
48697
|
getLabelAsBoolean(value) {
|
|
48698
|
+
// Optimization: for boolean values, return directly
|
|
48699
|
+
if (typeof value === "boolean") {
|
|
48700
|
+
return value;
|
|
48701
|
+
}
|
|
48702
|
+
// Optimization: for number values, apply rule directly
|
|
48703
|
+
if (typeof value === "number") {
|
|
48704
|
+
return value !== 0;
|
|
48705
|
+
}
|
|
48693
48706
|
const label = this.getLabelForValue(value);
|
|
48694
48707
|
const labelStr = String(label).toLowerCase();
|
|
48695
48708
|
// Convert string representations to boolean
|
|
@@ -48707,6 +48720,10 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
48707
48720
|
}
|
|
48708
48721
|
// helper function to get the label as number (used for @num: operator)
|
|
48709
48722
|
getLabelAsNumber(value) {
|
|
48723
|
+
// Optimization: if value is already a number, return it directly
|
|
48724
|
+
if (typeof value === "number") {
|
|
48725
|
+
return value;
|
|
48726
|
+
}
|
|
48710
48727
|
const label = this.getLabelForValue(value);
|
|
48711
48728
|
const labelNum = Number(label);
|
|
48712
48729
|
if (isNaN(labelNum)) {
|
|
@@ -48884,6 +48901,12 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
48884
48901
|
const result = [];
|
|
48885
48902
|
let foundTrue = false;
|
|
48886
48903
|
let foundFalse = false;
|
|
48904
|
+
// Optimize: create environment once and reuse it
|
|
48905
|
+
const quantDeclEnv = {
|
|
48906
|
+
env: {},
|
|
48907
|
+
type: "quantDecl",
|
|
48908
|
+
};
|
|
48909
|
+
this.environmentStack.push(quantDeclEnv);
|
|
48887
48910
|
for (let i = 0; i < product.length; i++) {
|
|
48888
48911
|
const tuple = product[i];
|
|
48889
48912
|
if (isDisjoint) {
|
|
@@ -48901,16 +48924,10 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
48901
48924
|
continue;
|
|
48902
48925
|
}
|
|
48903
48926
|
}
|
|
48904
|
-
|
|
48905
|
-
env: {},
|
|
48906
|
-
type: "quantDecl",
|
|
48907
|
-
};
|
|
48927
|
+
// Update environment values in place
|
|
48908
48928
|
for (let j = 0; j < varNames.length; j++) {
|
|
48909
|
-
|
|
48910
|
-
const varValue = tuple[j];
|
|
48911
|
-
quantDeclEnv.env[varName] = varValue;
|
|
48929
|
+
quantDeclEnv.env[varNames[j]] = tuple[j];
|
|
48912
48930
|
}
|
|
48913
|
-
this.environmentStack.push(quantDeclEnv);
|
|
48914
48931
|
// now, we want to evaluate the barExpr
|
|
48915
48932
|
const barExprValue = this.visit(barExpr);
|
|
48916
48933
|
if (!isBoolean(barExprValue)) {
|
|
@@ -48923,14 +48940,15 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
48923
48940
|
else {
|
|
48924
48941
|
foundFalse = true;
|
|
48925
48942
|
}
|
|
48926
|
-
this.environmentStack.pop();
|
|
48927
48943
|
// short-circuit if possible
|
|
48928
48944
|
if (ctx.quant().ALL_TOK() && foundFalse) {
|
|
48945
|
+
this.environmentStack.pop();
|
|
48929
48946
|
const value = false;
|
|
48930
48947
|
this.cacheResult(ctx, freeVarsKey, value);
|
|
48931
48948
|
return value;
|
|
48932
48949
|
}
|
|
48933
48950
|
if (ctx.quant().NO_TOK() && foundTrue) {
|
|
48951
|
+
this.environmentStack.pop();
|
|
48934
48952
|
const value = false;
|
|
48935
48953
|
this.cacheResult(ctx, freeVarsKey, value);
|
|
48936
48954
|
return value;
|
|
@@ -48938,22 +48956,26 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
48938
48956
|
if (ctx.quant().mult()) {
|
|
48939
48957
|
const multExpr = ctx.quant().mult();
|
|
48940
48958
|
if (multExpr.LONE_TOK() && result.length > 1) {
|
|
48959
|
+
this.environmentStack.pop();
|
|
48941
48960
|
const value = false;
|
|
48942
48961
|
this.cacheResult(ctx, freeVarsKey, value);
|
|
48943
48962
|
return value;
|
|
48944
48963
|
}
|
|
48945
48964
|
if (multExpr.SOME_TOK() && foundTrue) {
|
|
48965
|
+
this.environmentStack.pop();
|
|
48946
48966
|
const value = true;
|
|
48947
48967
|
this.cacheResult(ctx, freeVarsKey, value);
|
|
48948
48968
|
return value;
|
|
48949
48969
|
}
|
|
48950
48970
|
if (multExpr.ONE_TOK() && result.length > 1) {
|
|
48971
|
+
this.environmentStack.pop();
|
|
48951
48972
|
const value = false;
|
|
48952
48973
|
this.cacheResult(ctx, freeVarsKey, value);
|
|
48953
48974
|
return value;
|
|
48954
48975
|
}
|
|
48955
48976
|
}
|
|
48956
48977
|
}
|
|
48978
|
+
this.environmentStack.pop();
|
|
48957
48979
|
if (ctx.quant().ALL_TOK()) {
|
|
48958
48980
|
const value = !foundFalse;
|
|
48959
48981
|
this.cacheResult(ctx, freeVarsKey, value);
|
|
@@ -49747,7 +49769,15 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
49747
49769
|
if (isTupleArray(childrenResults)) {
|
|
49748
49770
|
const transitiveClosureResult = transitiveClosure(childrenResults);
|
|
49749
49771
|
const idenResult = this.getIden();
|
|
49750
|
-
|
|
49772
|
+
// Optimize: Use Set for efficient deduplication instead of deduplicateTuples
|
|
49773
|
+
const resultSet = new Set();
|
|
49774
|
+
for (const tuple of idenResult) {
|
|
49775
|
+
resultSet.add(tupleToKey(tuple));
|
|
49776
|
+
}
|
|
49777
|
+
for (const tuple of transitiveClosureResult) {
|
|
49778
|
+
resultSet.add(tupleToKey(tuple));
|
|
49779
|
+
}
|
|
49780
|
+
return Array.from(resultSet).map(key => JSON.parse(key));
|
|
49751
49781
|
}
|
|
49752
49782
|
}
|
|
49753
49783
|
return childrenResults;
|
|
@@ -49872,18 +49902,18 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
49872
49902
|
}
|
|
49873
49903
|
const product = getCombinations(quantifiedSets);
|
|
49874
49904
|
const result = [];
|
|
49905
|
+
// Optimize: create environment once and reuse it
|
|
49906
|
+
const quantDeclEnv = {
|
|
49907
|
+
env: {},
|
|
49908
|
+
type: "quantDecl",
|
|
49909
|
+
};
|
|
49910
|
+
this.environmentStack.push(quantDeclEnv);
|
|
49875
49911
|
for (let i = 0; i < product.length; i++) {
|
|
49876
49912
|
const tuple = product[i];
|
|
49877
|
-
|
|
49878
|
-
env: {},
|
|
49879
|
-
type: "quantDecl",
|
|
49880
|
-
};
|
|
49913
|
+
// Update environment values in place
|
|
49881
49914
|
for (let j = 0; j < varNames.length; j++) {
|
|
49882
|
-
|
|
49883
|
-
const varValue = tuple[j];
|
|
49884
|
-
quantDeclEnv.env[varName] = varValue;
|
|
49915
|
+
quantDeclEnv.env[varNames[j]] = tuple[j];
|
|
49885
49916
|
}
|
|
49886
|
-
this.environmentStack.push(quantDeclEnv);
|
|
49887
49917
|
// now, we want to evaluate the barExpr
|
|
49888
49918
|
const barExprValue = this.visit(barExpr);
|
|
49889
49919
|
if (!isBoolean(barExprValue)) {
|
|
@@ -49893,9 +49923,10 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
49893
49923
|
// will error if not boolean val, which we want
|
|
49894
49924
|
result.push(tuple);
|
|
49895
49925
|
}
|
|
49896
|
-
this.environmentStack.pop();
|
|
49897
49926
|
}
|
|
49898
|
-
|
|
49927
|
+
this.environmentStack.pop();
|
|
49928
|
+
// Deduplicate results to ensure set semantics
|
|
49929
|
+
return deduplicateTuples(result);
|
|
49899
49930
|
}
|
|
49900
49931
|
if (ctx.LEFT_PAREN_TOK()) {
|
|
49901
49932
|
// NOTE: we just return the result of evaluating the expr that is inside
|
|
@@ -61164,6 +61195,8 @@ class SimpleGraphQueryEvaluator {
|
|
|
61164
61195
|
constructor(datum) {
|
|
61165
61196
|
this.forgeListener = new ForgeListenerImpl_1.ForgeListenerImpl();
|
|
61166
61197
|
this.walker = new ParseTreeWalker_1.ParseTreeWalker();
|
|
61198
|
+
// Cache for parsed expressions to avoid re-parsing the same expression
|
|
61199
|
+
this.parseTreeCache = new Map();
|
|
61167
61200
|
this.datum = datum;
|
|
61168
61201
|
}
|
|
61169
61202
|
getExpressionParseTree(forgeExpr) {
|
|
@@ -61177,18 +61210,28 @@ class SimpleGraphQueryEvaluator {
|
|
|
61177
61210
|
return tree;
|
|
61178
61211
|
}
|
|
61179
61212
|
evaluateExpression(forgeExpr) {
|
|
61180
|
-
|
|
61181
|
-
|
|
61213
|
+
// Check cache first
|
|
61214
|
+
let tree;
|
|
61215
|
+
if (this.parseTreeCache.has(forgeExpr)) {
|
|
61216
|
+
tree = this.parseTreeCache.get(forgeExpr);
|
|
61182
61217
|
}
|
|
61183
|
-
|
|
61184
|
-
//
|
|
61185
|
-
|
|
61186
|
-
|
|
61187
|
-
|
|
61218
|
+
else {
|
|
61219
|
+
try { // now, we can actually evaluate the expression
|
|
61220
|
+
const parsedTree = this.getExpressionParseTree(forgeExpr);
|
|
61221
|
+
tree = parsedTree instanceof ForgeParser_1.ExprContext ? parsedTree : parsedTree.getChild(0);
|
|
61222
|
+
// Cache the parsed tree
|
|
61223
|
+
this.parseTreeCache.set(forgeExpr, tree);
|
|
61224
|
+
}
|
|
61225
|
+
catch (e) {
|
|
61226
|
+
// if we can't parse the expression, we return an error
|
|
61227
|
+
return {
|
|
61228
|
+
error: new Error(`Error parsing expression "${forgeExpr}"`)
|
|
61229
|
+
};
|
|
61230
|
+
}
|
|
61188
61231
|
}
|
|
61189
61232
|
const evaluator = new ForgeExprEvaluator_1.ForgeExprEvaluator(this.datum);
|
|
61190
61233
|
try {
|
|
61191
|
-
let result = evaluator.visit(tree
|
|
61234
|
+
let result = evaluator.visit(tree);
|
|
61192
61235
|
// ensure we're visiting an ExprContext
|
|
61193
61236
|
return result;
|
|
61194
61237
|
}
|
package/package.json
CHANGED