The evolution of the SMaps presented in the Postcard NoSQL thread is CSMaps.
SMap was about "sensing" when you set values. CSMap is the other way around: it adds an "acting when you get" values.
The idea is to "pull" computation: if you're getting values, it means you're curious about them, which means that work should be made around these values to enhance them, complete them, ...etc. It's exactly like focusing on something: when you direct your attention on something, you drive your "computations" on it.
The code is still super-small scale:
// Contributive Sensitive Maps
class CSMap extends Map {
sensors = {};
contributors = {};
constructor(content) {
super();
if (content)
for (let [k, v] of content) this.set(k, v);
}
sense(id) {
return this.sensors[id].solution;
}
removeContributor(id) {
delete this.contributors[id];
}
contributor(id, parameters, mapper) {
this.contributors[id] = { parameters, mapper };
}
removeSensor(id) {
delete this.sensors[id];
}
sensor(id, initial, reducer) {
this.sensors[id] = { reducer, solution: initial };
this.forEach((value, key) => {
this.sensors[id].solution =
this.sensors[id].reducer(
this.sensors[id].solution,
key,
value
)
});
}
touch(key, previous) {
for (let s in this.sensors)
this.sensors[s].solution =
this.sensors[s].reducer(
this.sensors[s].solution,
key,
super.get(key),
previous
);
}
get(...args) {
let result = super.get(...args);
for (let c in this.contributors)
this.contributors[c].mapper.call(
this,
args[0],
result,
this.contributors[c].parameters
);
return result;
}
set(...args) {
let previous = super.get(args[0]);
let result = super.set(...args);
this.touch(args[0], previous);
return result;
}
delete(...args) {
let previous = super.get(args[0]);
let result = super.delete(...args);
this.touch(args[0], previous);
return result;
}
}
Example usage:
let csmap = new CSMap();
csmap.set('i1', "foo");
csmap.set('i2', "bar");
csmap.sensor("string counter", 0, function (solution, key, newValue, oldValue) {
if (typeof oldValue != "string" && typeof newValue == "string") ++solution;
if (typeof oldValue == "string" && typeof newValue != "string") --solution;
return solution;
})
csmap.sensor("string selector", new Set(), function (solution, key, newValue, oldValue) {
if (typeof newValue == "string") solution.add(key);
else solution.delete(key);
return solution;
});
csmap.contributor("curious about numbers", { stuff: 55 }, function (key, value, parameters) {
if (typeof value == "number")
csmap.set("curious about", { what: key, myStuff: parameters.stuff });
});
csmap.set('i3', "baz");
console.log("counter:", csmap.sense("string counter"));
csmap.set('i3', 4);
console.log("counter:", csmap.sense("string counter"));
console.log("selector:", csmap.sense("string selector"));
console.log("getting i3:", csmap.get('i3'));
console.log("csmap:", csmap);
/* CONSOLE >>
counter: 3
counter: 2
selector: Set(2) { 'i1', 'i2' }
getting i3: 4
csmap: CSMap(4) [Map] {
'i1' => 'foo',
'i2' => 'bar',
'i3' => 4,
'curious about' => { what: 'i3', myStuff: 55 },
sensors: {
'string counter': { reducer: [Function (anonymous)], solution: 2 },
'string selector': { reducer: [Function (anonymous)], solution: [Set] }
},
contributors: {
'curious about numbers': { parameters: [Object], mapper: [Function (anonymous)] }
}
}
*/