Popular
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
import { Evt, ToNonPostableEvt } from "../lib/index.ts";import { assert } from "https://deno.land/x/tsafe@v1.1.1/assert.ts";import { id } from "https://deno.land/x/tsafe@v1.1.1/id.ts";
type Person = { name: string; age: number;};
type PersonChange = Readonly<{ eventType: "NEW" | "DELETE"; person: Person;} | { eventType: "UPDATE"; field: "name" | "age"; person: Person;}>;
let acc = "";
const startUi = (() => {
const createPersonLogger = <T extends string>( { person, evtFieldChange }: { person: Readonly<Person>; evtFieldChange: ToNonPostableEvt<Evt<T>>; } ) => evtFieldChange.attach( field => acc += `${person.name} ${field} changed\n` );
return ({ evtPersonChange }: { evtPersonChange: ToNonPostableEvt<Evt<PersonChange>> }) => {
const ctx = Evt.newCtx();
evtPersonChange.$attach( personChange => personChange.eventType === "NEW" ? [personChange.person] : null, ctx, person => createPersonLogger({ person, "evtFieldChange": (() => {
const ctx = Evt.newCtx();
return evtPersonChange.pipe( ctx, (personChange, registerSideEffect) => personChange.person !== person ? null : (() => { switch (personChange.eventType) { case "NEW": return null; case "UPDATE": return [personChange.field] as const; case "DELETE": return (registerSideEffect(() => ctx.done()), null); } })() );
})()
}) );
};
})();
const updateModelFactory = ( { postPersonChange, handlerHandlingEventCount }: { postPersonChange(personChange: PersonChange): void; handlerHandlingEventCount(personsChange: PersonChange): number; }) => {
const sleep = (ms: number) => new Promise<void>(resolve => setTimeout(() => resolve(), ms));
const updateModel = async (person: Person): Promise<void> => {
{
const personChange: PersonChange = { "eventType": "NEW", person };
assert(handlerHandlingEventCount(personChange) === 1);
postPersonChange(personChange);
assert(handlerHandlingEventCount(personChange) === 1);
}
await sleep(30);
{
person.age++;
const personChange: PersonChange = { "eventType": "UPDATE", "field": "age", person };
assert(handlerHandlingEventCount(personChange) === 1);
postPersonChange(personChange);
assert(handlerHandlingEventCount(personChange) === 1);
}
await sleep(20);
{
person.name += " (verified)";
const personChange: PersonChange = { "eventType": "UPDATE", "field": "name", person };
assert(handlerHandlingEventCount(personChange) === 1);
postPersonChange(personChange);
assert(handlerHandlingEventCount(personChange) === 1);
}
await sleep(40);
{
const personChange: PersonChange = { "eventType": "DELETE", person };
assert(handlerHandlingEventCount(personChange) === 1);
postPersonChange(personChange);
assert(handlerHandlingEventCount(personChange) === 0);
}
};
return { updateModel };
};
(function main() {
const evtPersonChange = new Evt<PersonChange>();
startUi({ evtPersonChange });
const { updateModel } = updateModelFactory({ "postPersonChange": personChange => evtPersonChange.post(personChange), "handlerHandlingEventCount": personChange => evtPersonChange .getHandlers() .filter(({ op }) => evtPersonChange.isHandledByOp(op, personChange)) .length });
Promise.all( id<[string, number][]>([ ["Alice", 55], ["Bob", 12], ["Louis", 15], ["John", 44], ["Paul", 33] ]).map(([name, age]) => updateModel({ name, age })) ).then(() => {
//The only remaining handler is the one listening for new person. assert(evtPersonChange.getHandlers().length === 1);
assert( acc === [ "Alice age changed", "Bob age changed", "Louis age changed", "John age changed", "Paul age changed", "Alice (verified) name changed", "Bob (verified) name changed", "Louis (verified) name changed", "John (verified) name changed", "Paul (verified) name changed", "" ].join("\n") );
console.log("PASS");
});
})();