fig-tree-evaluator 2.8.5 → 2.9.0
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/README.md +17 -3
- package/build/FigTreeEvaluator.d.ts +3 -0
- package/build/FigTreeEvaluator.js +6 -3
- package/build/cache.d.ts +16 -1
- package/build/cache.js +20 -5
- package/build/types.d.ts +2 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -115,9 +115,9 @@ A playground for building and testing expressions is available [here](https://ca
|
|
|
115
115
|
|
|
116
116
|
## Install
|
|
117
117
|
|
|
118
|
-
`npm install fig-tree`\
|
|
118
|
+
`npm install fig-tree-evaluator`\
|
|
119
119
|
or\
|
|
120
|
-
`yarn add fig-tree`
|
|
120
|
+
`yarn add fig-tree-evaluator`
|
|
121
121
|
|
|
122
122
|
## Usage
|
|
123
123
|
|
|
@@ -162,6 +162,7 @@ The `options` parameter is an object with the following available properties (al
|
|
|
162
162
|
- `excludeOperators` -- an array of operator names (or [aliases](#operator--property-aliases)) to prohibit from being used in expressions. You may wish to restrict (for example) database access via FigTree configurations, in which case these exclusions can be defined when instantiating the FigTree instance (or updated on the fly).
|
|
163
163
|
- `useCache` -- caches the results from certain operators to avoid repeated network requests with the same input values. By default, this is set to `true`, and it can be overridden for specific nodes. See [Memoization/Caching section](#caching-memoization) for more detail
|
|
164
164
|
- `maxCacheSize` -- the maximum number of results that will be held in the aforementioned cache (default: `50`)
|
|
165
|
+
- `maxCacheTime` -- the maximum time (in seconds) that a result will be cached since last access (default: `1800` (30 minutes))
|
|
165
166
|
- `noShorthand` -- there is a [shorthand syntax](#shorthand-syntax) available for writing expressions. Internally, this is pre-processed into the standard expression form before evaluation. If you have no use for this and you'd rather all expressions were written with full verbosity, set `noShorthand: true` to save a small amount in performance by skipping internal pre-processing.
|
|
166
167
|
|
|
167
168
|
As mentioned above, `options` can be provided as part of the constructor as part of each separate evaluation. You can also change the options permanently for a given evaluator instance with:
|
|
@@ -1527,7 +1528,7 @@ For more examples, see `23_shorthand.test.ts`, or have a play with the [demo app
|
|
|
1527
1528
|
|
|
1528
1529
|
## Caching (Memoization)
|
|
1529
1530
|
|
|
1530
|
-
FigTree Evaluator has basic [memoization](https://en.wikipedia.org/wiki/Memoization) functionality for certain nodes to speed up re-evaluation when the input parameters haven't changed. There is a single cache store per FigTree instance which persists for the lifetime of the instance. By default, it remembers the last 50 results, but
|
|
1531
|
+
FigTree Evaluator has basic [memoization](https://en.wikipedia.org/wiki/Memoization) functionality for certain nodes to speed up re-evaluation when the input parameters haven't changed. There is a single cache store per FigTree instance which persists for the lifetime of the instance. By default, it remembers the last 50 results with each result being valid for half and hour, but these values can be modified using the `maxCacheSize` and `maxCacheTime` [options](#available-options).
|
|
1531
1532
|
|
|
1532
1533
|
Currently, caching is only implemented for the following operators, since they perform requests to external resources, which are inherently slow:
|
|
1533
1534
|
|
|
@@ -1543,6 +1544,17 @@ This is different to the memoization provided by [Alias Nodes](#alias-nodes):
|
|
|
1543
1544
|
|
|
1544
1545
|
Caching is enabled by default for most of the above operators, but this can be overridden by setting `useCache: false` in [options](#available-options), either globally or per expression. If you're querying a database or API that is likely to have a different result for the same request (i.e. data has changed), then you probably want to turn the cache off.
|
|
1545
1546
|
|
|
1547
|
+
It's possible to manually set/get the cache store, which can be used (for example) to save the cache in local storage to persist it between page reloads or new FigTree instances.
|
|
1548
|
+
|
|
1549
|
+
Use the methods:
|
|
1550
|
+
|
|
1551
|
+
```js
|
|
1552
|
+
fig.getCache() // returns key-value store
|
|
1553
|
+
|
|
1554
|
+
fig.setCache(cache) // where "cache" is the object retrieved by .getCache()
|
|
1555
|
+
```
|
|
1556
|
+
|
|
1557
|
+
|
|
1546
1558
|
## Metadata
|
|
1547
1559
|
|
|
1548
1560
|
Evaluator expression can be configured by hand, with [aliases](#alias-nodes), [fragments](#fragments) and [shorthand](#shorthand-syntax) available to make the job easier.
|
|
@@ -1691,6 +1703,8 @@ Please open an issue: https://github.com/CarlosNZ/fig-tree-evaluator/issues
|
|
|
1691
1703
|
|
|
1692
1704
|
*Trivial upgrades (e.g. documentation, small re-factors, types, etc.) not included*
|
|
1693
1705
|
|
|
1706
|
+
- **v2.9.0**: Added ability to invalidate cache by time (#94)
|
|
1707
|
+
- **v2.8.6**: Small bug fix where `options` object would be mutated instead of replaced
|
|
1694
1708
|
- **v2.8.5**: Small bug fix in [COUNT](#count) operator
|
|
1695
1709
|
- **v2.8.4**: Refactor types, better compliance with [ESLint](https://eslint.org/) rules, add more tests
|
|
1696
1710
|
- **v2.8.0**:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EvaluatorNode, FigTreeOptions, OperatorMetadata, FragmentMetadata } from './types';
|
|
2
|
+
import { Store } from './cache';
|
|
2
3
|
declare class FigTreeEvaluator {
|
|
3
4
|
private options;
|
|
4
5
|
private operators;
|
|
@@ -9,6 +10,8 @@ declare class FigTreeEvaluator {
|
|
|
9
10
|
evaluate(expression: EvaluatorNode, options?: FigTreeOptions): Promise<import("./types").EvaluatorOutput>;
|
|
10
11
|
getOptions(): FigTreeOptions;
|
|
11
12
|
updateOptions(options: FigTreeOptions): void;
|
|
13
|
+
getCache: () => Store;
|
|
14
|
+
setCache: (cache: Store) => Store;
|
|
12
15
|
getOperators(): readonly OperatorMetadata[];
|
|
13
16
|
getFragments(): readonly (FragmentMetadata & {
|
|
14
17
|
name: string;
|
|
@@ -54,17 +54,21 @@ class FigTreeEvaluator {
|
|
|
54
54
|
return;
|
|
55
55
|
throw new Error(result);
|
|
56
56
|
};
|
|
57
|
+
this.getCache = () => this.cache.getCache();
|
|
58
|
+
this.setCache = (cache) => this.cache.setCache(cache);
|
|
57
59
|
this.getVersion = () => version_1.version;
|
|
58
60
|
this.options = standardiseOptionNames(options);
|
|
59
61
|
this.operators = (0, helpers_1.filterOperators)(operators, (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.excludeOperators) !== null && _b !== void 0 ? _b : [], operatorAliases);
|
|
60
62
|
this.operatorAliases = operatorAliases;
|
|
61
|
-
this.cache = new cache_1.default(options.maxCacheSize);
|
|
63
|
+
this.cache = new cache_1.default({ maxSize: options.maxCacheSize, maxTime: options.maxCacheTime });
|
|
62
64
|
}
|
|
63
65
|
evaluate(expression, options = {}) {
|
|
64
66
|
return __awaiter(this, void 0, void 0, function* () {
|
|
65
67
|
const currentOptions = (0, helpers_1.mergeOptions)(this.options, standardiseOptionNames(options));
|
|
66
68
|
if (currentOptions.maxCacheSize && currentOptions.maxCacheSize !== this.cache.getMax())
|
|
67
69
|
this.cache.setMax(currentOptions.maxCacheSize);
|
|
70
|
+
if (currentOptions.maxCacheTime && currentOptions.maxCacheTime !== this.cache.getMaxTime())
|
|
71
|
+
this.cache.setMaxTime(currentOptions.maxCacheTime);
|
|
68
72
|
return yield (0, evaluate_1.evaluatorFunction)(expression, {
|
|
69
73
|
options: currentOptions,
|
|
70
74
|
operators: options.excludeOperators
|
|
@@ -111,8 +115,7 @@ const evaluateExpression = (expression, options) => new FigTreeEvaluator(options
|
|
|
111
115
|
exports.evaluateExpression = evaluateExpression;
|
|
112
116
|
const standardiseOptionNames = (options) => {
|
|
113
117
|
if ('objects' in options) {
|
|
114
|
-
options
|
|
115
|
-
delete options.objects;
|
|
118
|
+
return Object.assign(Object.assign({}, options), { data: options.objects });
|
|
116
119
|
}
|
|
117
120
|
return options;
|
|
118
121
|
};
|
package/build/cache.d.ts
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
import { EvaluatorOutput, UnknownFunction } from './types';
|
|
2
|
+
interface CacheOptions {
|
|
3
|
+
maxSize?: number;
|
|
4
|
+
maxTime?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Store {
|
|
7
|
+
[key: string]: {
|
|
8
|
+
result: EvaluatorOutput;
|
|
9
|
+
timestamp: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
2
12
|
declare class FigTreeCache {
|
|
3
13
|
private store;
|
|
4
14
|
private queue;
|
|
5
15
|
private maxSize;
|
|
6
|
-
|
|
16
|
+
private maxTime;
|
|
17
|
+
constructor(options?: CacheOptions);
|
|
7
18
|
useCache: (shouldUseCache: boolean, action: UnknownFunction, ...args: unknown[]) => Promise<EvaluatorOutput>;
|
|
8
19
|
getMax: () => number;
|
|
9
20
|
setMax: (size: number) => void;
|
|
21
|
+
getMaxTime: () => number;
|
|
22
|
+
setMaxTime: (time: number) => void;
|
|
23
|
+
getCache: () => Store;
|
|
24
|
+
setCache: (cache: Store) => Store;
|
|
10
25
|
private resizeCache;
|
|
11
26
|
}
|
|
12
27
|
export default FigTreeCache;
|
package/build/cache.js
CHANGED
|
@@ -10,19 +10,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const MAX_CACHED_ITEMS = 50;
|
|
13
|
+
const MAX_CACHE_TIME = 1800;
|
|
13
14
|
class FigTreeCache {
|
|
14
|
-
constructor(
|
|
15
|
+
constructor(options) {
|
|
16
|
+
var _a, _b;
|
|
15
17
|
this.useCache = (shouldUseCache, action, ...args) => __awaiter(this, void 0, void 0, function* () {
|
|
16
18
|
if (!shouldUseCache)
|
|
17
19
|
return yield action(...args);
|
|
18
20
|
const key = stringifyInput(args);
|
|
19
|
-
|
|
21
|
+
const keyExists = key in this.store;
|
|
22
|
+
const newTimestamp = Date.now();
|
|
23
|
+
const isExpired = keyExists && newTimestamp - this.store[key].timestamp > this.maxTime * 1000;
|
|
24
|
+
if (keyExists) {
|
|
20
25
|
this.queue = this.queue.filter((val) => val !== key);
|
|
21
26
|
this.queue.unshift(key);
|
|
22
|
-
|
|
27
|
+
this.store[key].timestamp = newTimestamp;
|
|
28
|
+
if (isExpired)
|
|
29
|
+
this.store[key].result = yield action(...args);
|
|
30
|
+
return this.store[key].result;
|
|
23
31
|
}
|
|
24
32
|
const result = yield action(...args);
|
|
25
|
-
this.store[key] = result;
|
|
33
|
+
this.store[key] = { result, timestamp: newTimestamp };
|
|
26
34
|
this.queue.unshift(key);
|
|
27
35
|
this.resizeCache();
|
|
28
36
|
return result;
|
|
@@ -32,6 +40,12 @@ class FigTreeCache {
|
|
|
32
40
|
this.maxSize = size;
|
|
33
41
|
this.resizeCache();
|
|
34
42
|
};
|
|
43
|
+
this.getMaxTime = () => this.maxTime;
|
|
44
|
+
this.setMaxTime = (time) => {
|
|
45
|
+
this.maxTime = time;
|
|
46
|
+
};
|
|
47
|
+
this.getCache = () => this.store;
|
|
48
|
+
this.setCache = (cache) => (this.store = cache);
|
|
35
49
|
this.resizeCache = () => {
|
|
36
50
|
if (this.queue.length > this.maxSize) {
|
|
37
51
|
const keysToRemove = this.queue.slice(this.maxSize);
|
|
@@ -41,7 +55,8 @@ class FigTreeCache {
|
|
|
41
55
|
};
|
|
42
56
|
this.store = {};
|
|
43
57
|
this.queue = [];
|
|
44
|
-
this.maxSize = maxSize !== null &&
|
|
58
|
+
this.maxSize = (_a = options === null || options === void 0 ? void 0 : options.maxSize) !== null && _a !== void 0 ? _a : MAX_CACHED_ITEMS;
|
|
59
|
+
this.maxTime = (_b = options === null || options === void 0 ? void 0 : options.maxTime) !== null && _b !== void 0 ? _b : MAX_CACHE_TIME;
|
|
45
60
|
}
|
|
46
61
|
}
|
|
47
62
|
exports.default = FigTreeCache;
|
package/build/types.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { GraphQLConnection } from './operators';
|
|
|
4
4
|
import operatorAliases from './operators/_operatorAliases.json';
|
|
5
5
|
import { ExpectedType, TypeCheckInput } from './typeCheck';
|
|
6
6
|
export declare const Operators: readonly ["AND", "OR", "EQUAL", "NOT_EQUAL", "PLUS", "SUBTRACT", "MULTIPLY", "DIVIDE", "GREATER_THAN", "LESS_THAN", "CONDITIONAL", "REGEX", "OBJECT_PROPERTIES", "STRING_SUBSTITUTION", "SPLIT", "COUNT", "GET", "POST", "PG_SQL", "GRAPHQL", "BUILD_OBJECT", "MATCH", "CUSTOM_FUNCTIONS", "PASSTHRU"];
|
|
7
|
-
export type Operator = typeof Operators[number];
|
|
7
|
+
export type Operator = (typeof Operators)[number];
|
|
8
8
|
export type OperatorAlias = keyof typeof operatorAliases;
|
|
9
9
|
export type OperatorAliases = Record<OperatorAlias, Operator>;
|
|
10
10
|
export type Fragments = Record<string, Fragment>;
|
|
@@ -29,6 +29,7 @@ export interface FigTreeOptions {
|
|
|
29
29
|
excludeOperators?: OperatorAlias[];
|
|
30
30
|
useCache?: boolean;
|
|
31
31
|
maxCacheSize?: number;
|
|
32
|
+
maxCacheTime?: number;
|
|
32
33
|
supportDeprecatedValueNodes?: boolean;
|
|
33
34
|
}
|
|
34
35
|
export interface FigTreeConfig {
|
package/build/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.
|
|
1
|
+
export declare const version = "2.9.0";
|
package/build/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fig-tree-evaluator",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "Module to evaluate JSON-structured expression trees",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"@typescript-eslint/parser": "^5.57.0",
|
|
21
21
|
"dotenv": "^16.0.1",
|
|
22
22
|
"eslint": "^8.37.0",
|
|
23
|
-
"jest": "^
|
|
23
|
+
"jest": "^29.6.2",
|
|
24
24
|
"pg": "^8.7.3",
|
|
25
25
|
"rimraf": "^3.0.2",
|
|
26
|
-
"ts-jest": "^
|
|
26
|
+
"ts-jest": "^29.1.1",
|
|
27
27
|
"ts-node": "^10.8.0",
|
|
28
28
|
"typescript": "^4.7.2"
|
|
29
29
|
},
|