Skip to content

Instantly share code, notes, and snippets.

@matheusmv
Last active April 27, 2023 15:50
Show Gist options
  • Save matheusmv/e3765a43bb1916b5b028c3099068daa2 to your computer and use it in GitHub Desktop.
Save matheusmv/e3765a43bb1916b5b028c3099068daa2 to your computer and use it in GitHub Desktop.
dummy decorator method for cache
class User {
createdAt: Date = new Date();
constructor(
public id: number,
public username: string,
public password: string,
public email: string
) { }
}
interface Repository<K, T> {
findById(id: K): T | null;
findAll(): T[];
save(getId: (o: T) => K, o: T): void;
saveAll(getId: (o: T) => K, ...o: T[]): void;
update(getId: (o: T) => K, o: T): void;
deleteById(id: K): void;
}
interface ICache<K, V> {
putObject(k: K, o: V): void;
getObject(k: K, dbQueryCmd: () => V): V | null;
deleteObject(k: K): void;
}
class MemDB<K, T> implements Repository<K, T> {
private db: Map<K, T> = new Map();
findById(id: K): T | null {
const entity = this.db.get(id);
return entity || null;
}
findAll(): T[] {
const entities = [...this.db.values()];
return entities;
}
save(getId: (o: T) => K, o: T): void {
this.db.set(getId(o), o);
}
saveAll(getId: (o: T) => K, ...o: T[]): void {
o.forEach((entity) => this.db.set(getId(entity), entity));
}
update(getId: (o: T) => K, o: T): void {
this.db.set(getId(o), o);
}
deleteById(id: K): void {
this.db.delete(id);
}
}
class MemCache<K, V> implements ICache<K, V> {
private cache: Map<K, { value: V, et: number }> = new Map();
constructor(private readonly expiryTimeInMinutes: number) { }
private addMinutes(minutes: number): number {
return Date.now() + minutes * 60000;
}
private buildValueWithExpiryTime(v: V): { value: V, et: number } {
return {
value: v,
et: this.addMinutes(this.expiryTimeInMinutes)
};
}
putObject(k: K, o: V): void {
this.cache.set(k, this.buildValueWithExpiryTime(o));
}
getObject(k: K, dbQueryCmd: () => V): V | null {
const obj = this.cache.get(k);
if (obj && obj.et > Date.now()) {
console.log("get from cache");
return obj.value;
}
const entityFromDB = dbQueryCmd();
if (entityFromDB)
this.putObject(k, entityFromDB);
return entityFromDB;
}
deleteObject(k: K): void {
this.cache.delete(k);
}
}
const globalCache = new MemCache<number, User>(5);
function cacheable(action: 'SAVE' | 'UPDATE' | 'DELETE') {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const method = descriptor.value;
descriptor.value = function (...args: any[]) {
switch (action) {
case 'SAVE': {
const [id] = args;
return globalCache.getObject(id, () => method.apply(this, args));
}
case 'UPDATE': {
const [obj] = args;
globalCache.putObject(obj['id'], obj);
return method.apply(this, args);
}
case 'DELETE': {
const [id] = args;
globalCache.deleteObject(id);
return method.apply(this, args);
}
}
}
}
}
class UserService {
constructor(private repository: Repository<number, User>) { }
findAllUsers(): User[] {
return this.repository.findAll();
}
@cacheable("SAVE")
findUserById(id: number): User | null {
return this.repository.findById(id);
}
createUser(user: User): void {
this.repository.save((u: User) => u.id, user);
}
createUsers(...users: User[]): void {
this.repository.saveAll((u: User) => u.id, ...users);
}
@cacheable("UPDATE")
updateUser(user: User): void {
this.repository.update((u: User) => u.id, user);
}
@cacheable("DELETE")
deleteUserById(id: number): void {
this.repository.deleteById(id);
}
}
const userService = new UserService(new MemDB<number, User>());
userService.createUsers(
new User(1, 'jhon', '12345', 'jhon@email.com'),
new User(2, 'alex', '12345', 'alex@email.com'),
new User(3, 'mary', '12345', 'mary@email.com'),
new User(4, 'carl', '12345', 'carl@email.com'),
);
console.log(userService.findUserById(3));
let test = userService.findUserById(3) as User;
test.email = 'new-email@email.com';
userService.updateUser(test);
console.log(userService.findUserById(3));
console.log(userService.findUserById(3));
console.log(userService.findUserById(3));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment