Skip to content

Commit 2628901

Browse files
Fact Decorator Rough Sketch
This would introduce the concept of a FactDecorator to match the idea of a operator decorator. Fact Decorators could be used to do things like getting keysOf, valuesOf, or sizeOf facts. Additionally in order to Remove JSONPathPlus as such a dependency we could use the fact decorator pattern, even if we wanted to ship our own decorator that depended on JSON path we could move it to a peer dependency.
1 parent 9c9edd7 commit 2628901

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { JSONPath } from "jsonpath-plus";
2+
import FactDecorator from "./fact-decorator";
3+
4+
export const PathDecorator = new FactDecorator("path", (params, almanac, next) => {
5+
if (Object.prototype.hasOwnProperty.call(params, 'path')) {
6+
const path = params.path
7+
const paramCopy = Object.assign({}, params)
8+
delete paramCopy.path
9+
return Promise.resolve(next(paramCopy, almanac)).then(factValue => {
10+
if (factValue != null && typeof factValue === 'object') {
11+
const pathValue = JSONPath({ json: factValue, path, wrap: false })
12+
debug('condition::evaluate extracting object', { property: path, received: pathValue })
13+
return pathValue
14+
} else {
15+
debug('condition::evaluate could not compute object path of non-object', { path, factValue, type: typeof factValue })
16+
return factValue
17+
}
18+
})
19+
20+
} else {
21+
return next(params, almanac);
22+
}
23+
})
24+
25+
export const KeysOfDecorator = new FactDecorator("keysOf", (params, almanac, next) => {
26+
const n = next(params, almanac)
27+
if (n != null) {
28+
if (Object.prototype.hasOwnProperty.call(n, 'keys') && typeof n.keys === 'function') {
29+
return Array.from(n.keys())
30+
}
31+
return Object.keys(n)
32+
}
33+
return n;
34+
})
35+
36+
export const ValuesOfDecorator = new FactDecorator("valuesOf", (params, almanac, next) => {
37+
const n = next(params,almanac)
38+
if (n != null) {
39+
if (Object.prototype.hasOwnProperty(n, 'values') && typeof n.values === 'function') {
40+
return Array.from(n.values())
41+
}
42+
return Object.values(n)
43+
}
44+
return n
45+
})
46+
47+
export const SizeOfDecorator = new FactDecorator("sizeOf", (params, almanac, next) => {
48+
const n = next(params, almanac)
49+
if (n != null) {
50+
if (Object.prototype.hasOwnProperty(n, 'length')) {
51+
return n.length
52+
} else if (Object.prototype.hasOwnProperty(n, 'size') && typeof n.size === 'function') {
53+
return n.size()
54+
}
55+
}
56+
return 1
57+
})
58+
59+
/**
60+
* Options (arg 3) are merged onto fact options and override
61+
* This allows us to do things like create a noCache version of a fact
62+
* noCache:name for instance would access the name fact without hitting the cache
63+
*/
64+
export const NoCacheDecorator = new FactDecorator("noCache", (params, almanac, next) => next(params, almanac), { cache: false })

src/fact-decorator.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import Fact from "./fact";
2+
3+
class FactDecorator {
4+
5+
/**
6+
*
7+
* @param {string} id
8+
* @param {function} cb Function that computes the new fact value by invoking a 3rd argument
9+
* that is a function to produce the next value
10+
* @param {object} options options to override the defaults from the decorated fact
11+
*/
12+
constructor(id, cb, options) {
13+
this.id = id
14+
this.cb = cb
15+
if (options) {
16+
this.options = options
17+
} else {
18+
this.options = {}
19+
}
20+
}
21+
22+
/**
23+
*
24+
* @param {Fact} fact to decorate
25+
* @returns {Fact} the decorated fact
26+
*/
27+
decorate(fact) {
28+
const next = fact.calculate.bind(fact);
29+
return new Fact(
30+
`${this.id}:${fact.id}`,
31+
(params, almanac) => this.cb(params, almanac, next),
32+
Object.assign({}, this.options, fact.options)
33+
)
34+
}
35+
36+
}
37+
38+
39+
export default FactDecorator

0 commit comments

Comments
 (0)