Skip to content

Instantly share code, notes, and snippets.

@jherr
Created May 17, 2021 14:29
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jherr/23101f2cd7980a7839a76b6bdff45583 to your computer and use it in GitHub Desktop.
Save jherr/23101f2cd7980a7839a76b6bdff45583 to your computer and use it in GitHub Desktop.
Code for No BT TS - Challenge 3
class EventProcessor {
handleEvent(eventName: ..., data: ...): void {
}
addHandler(handler: ...) {
}
getProcessedEvents(): ...[] {
}
}
interface EventMap {
login: { user?: string; name?: string; hasSession?: boolean };
logout: { user?: string };
}
class UserEventProcessor extends EventProcessor<EventMap> {}
const uep = new UserEventProcessor();
uep.addHandler({
filterLogin: ({ user }) => Boolean(user),
mapLogin: (data) => ({
...data,
hasSession: Boolean(data.user && data.name),
}),
});
uep.handleEvent("login", {
user: null,
name: "jack",
});
uep.handleEvent("login", {
user: "tom",
name: "tomas",
});
uep.handleEvent("logout", {
user: "tom",
});
console.log(uep.getProcessedEvents());
/*
Result:
[
{
eventName: 'login',
data: { user: 'tom', name: 'tomas', hasSession: true }
},
{ eventName: 'logout', data: { user: 'tom' } }
]
*/
class EventProcessor {
handleEvent(eventName: ..., data: ...): void {
}
addFilter(
eventName: ...,
filter: (data: ...) => boolean
): void {
}
addMap(eventName: ..., map: (data: ...) => ...): void {
}
getProcessedEvents() {
}
}
interface EventMap {
login: { user?: string; name?: string; hasSession?: boolean };
logout: { user?: string };
}
class UserEventProcessor extends EventProcessor<EventMap> {}
const uep = new UserEventProcessor();
uep.addFilter("login", ({ user }) => Boolean(user));
uep.addMap("login", (data) => ({
...data,
hasSession: Boolean(data.user && data.name),
}));
uep.handleEvent("login", {
user: null,
name: "jack",
});
uep.handleEvent("login", {
user: "tom",
name: "tomas",
});
uep.handleEvent("logout", {
user: "tom",
});
console.log(uep.getProcessedEvents());
/*
Result:
[
{
eventName: 'login',
data: { user: 'tom', name: 'tomas', hasSession: true }
},
{ eventName: 'logout', data: { user: 'tom' } }
]
*/
@alexanderfanz
Copy link

In the basic solution, I'd like to remove these two lines this.maps[<keyof T>eventName] ||= []; (in addMap) and this.filters[<keyof T>eventName] ||= []; (in addFilter).
Is it possible to create a constructor that initializes both arrays inside the Record in this case?

@ryanzwe
Copy link

ryanzwe commented May 1, 2023

Here's the solution I came to

type EventLog<TInput> = Partial<{
  [K in keyof TInput]: TInput[K];
}>;

interface EventMap {
  login: { user?: string | null; name?: string; hasSession?: boolean };
  logout: { user?: string };
}

class EventProcessor<TInput> {
  private eventLog: EventLog<TInput>[] = [];
  private eventFilters: { [key in keyof TInput]?: (data: TInput[key]) => boolean } = {};
  private eventMaps: { [key in keyof TInput]?: (data: TInput[key]) => TInput[key] } = {};
  handleEvent(eventName: keyof TInput, data: TInput[keyof TInput]): void {
    const curEvent = {
      [eventName]: { ...data },
    } as EventLog<TInput>;
    this.eventLog.push(curEvent as EventLog<TInput>);
  }

  addFilter<U extends keyof TInput>(
    eventName: U,
    filter: (data: TInput[U]) => boolean
  ): void {
    this.eventFilters[eventName] = filter;
  }

  addMap<U extends keyof TInput, O>(
    eventName: U,
    map: (data: TInput[U]) => TInput[U]
  ): void {
    this.eventMaps[eventName] = map;
  }
  
  private runFilters(){
    return this.eventLog.filter((eventLog) => {
      const eventName = Object.keys(eventLog)[0] as keyof TInput;
      const eventData = eventLog[eventName];
      const filter = this.eventFilters[eventName];
      return !filter || filter(eventData);
    });
  }
  private runMaps(filteredObjs: Partial<{ [K in keyof TInput]: TInput[K]; }>[]){
    return filteredObjs.map((val,idx) => {
      const eventName = Object.keys(val)[0] as keyof TInput;
      const eventData = val[eventName]
      const curMapFunc = this.eventMaps[eventName]
      const mappedData = curMapFunc? curMapFunc(eventData) : eventData
      return {
        eventName,
        data:{
          ...mappedData
        }
      }
    })

  }

  getProcessedEvents() {
    return this.runMaps(this.runFilters());
  }
}




class UserEventProcessor extends EventProcessor<EventMap> {}

const uep = new UserEventProcessor();

uep.addFilter("login", ({ user }) => Boolean(user));

uep.addMap("login", (data) => ({
  ...data,
  hasSession: Boolean(data.user && data.name),
}));

uep.handleEvent("login", { user: null, name: "jack" });

uep.handleEvent("login", { user: "tom", name: "tomas" });

uep.handleEvent("logout", { user: "tom" });

console.log(uep.getProcessedEvents());

/*
Result:
[
  {
    eventName: 'login',
    data: { user: 'tom', name: 'tomas', hasSession: true }
  },
  { eventName: 'logout', data: { user: 'tom' } }
]
*/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment