Skip to content

Instantly share code, notes, and snippets.

@tengla
Last active November 1, 2024 09:03
Show Gist options
  • Save tengla/a856940c324a96c3a952e9457fd57f3f to your computer and use it in GitHub Desktop.
Save tengla/a856940c324a96c3a952e9457fd57f3f to your computer and use it in GitHub Desktop.
interface User {
id: string;
name: string;
roles: string[];
}
function withRoles(roles: string[]) {
return function (_target: Selector, _propertyName: string, propertyDescriptor: PropertyDescriptor) {
let originalMethod = propertyDescriptor.value!;
propertyDescriptor.value = function () {
const ctx = this as Selector;
console.log('Checking roles...');
if(roles.some(role => ctx.user.roles.includes(role))) {
return originalMethod.apply(this, arguments);
}
throw new Error('Unauthorized', {
cause: `User does not have the required roles. ${roles.join(', ')} required. Was ${ctx.user.roles.join(', ')}`,
});
}
}
}
class Selector {
user: User
constructor(user: User) {
this.user = user;
}
select() {
return `SELECT * FROM "appointments"`;
}
}
class AdminSelector extends Selector {
@withRoles(['admin'])
select() {
return super.select();
}
}
class UserSelector extends Selector {
@withRoles(['user'])
select() {
return super.select() + ` WHERE "user_id" = ${this.user.id}`;
}
}
class SelectorDelegate {
private selector: Selector;
constructor(user: User) {
switch (true) {
case user.roles.includes('admin'):
this.selector = new AdminSelector(user);
break;
case user.roles.includes('user'):
this.selector = new UserSelector(user);
break;
default:
throw new Error('Unauthorized', {
cause: 'User does not have any roles assigned'
});
}
}
select() {
return this.selector.select();
}
}
const selector = new SelectorDelegate({ id: '1', name: 'John Doe', roles: ['user'] });
try {
console.log(selector.select());
} catch (e: unknown) {
const error = e as Error;
console.error(error.message, error.cause);
}
@tengla
Copy link
Author

tengla commented Nov 1, 2024

remb to put "experimentalDecorators": true to your compilerOptions of tsconfig.json

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