1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-12 01:17:04 +02:00

feat: composition root for user subscriptions (#8649)

Co-Authored-By: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com>
This commit is contained in:
Mateusz Kwasniewski 2024-11-05 10:50:31 +01:00 committed by GitHub
parent b491d9eb8b
commit 6a8a75ce71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 111 additions and 17 deletions

View File

@ -189,7 +189,7 @@ export const createStores = (
eventBus,
config.flagResolver,
),
userUnsubscribeStore: new UserUnsubscribeStore(db, getLogger),
userUnsubscribeStore: new UserUnsubscribeStore(db),
userSubscriptionsReadModel: new UserSubscriptionsReadModel(
db,
eventBus,

View File

@ -0,0 +1,36 @@
import type { Db, IUnleashConfig } from '../../server-impl';
import UserSubscriptionService from './user-subscriptions-service';
import { UserUnsubscribeStore } from './user-unsubscribe-store';
import {
createEventsService,
createFakeEventsService,
} from '../events/createEventsService';
import { FakeUserUnsubscribeStore } from './fake-user-unsubscribe-store';
export const createUserSubscriptionsService =
(config: IUnleashConfig) =>
(db: Db): UserSubscriptionService => {
const userUnsubscribeStore = new UserUnsubscribeStore(db);
const eventService = createEventsService(db, config);
const userSubscriptionsService = new UserSubscriptionService(
{ userUnsubscribeStore },
config,
eventService,
);
return userSubscriptionsService;
};
export const createFakeUserSubscriptionsService = (config: IUnleashConfig) => {
const userUnsubscribeStore = new FakeUserUnsubscribeStore();
const eventService = createFakeEventsService(config);
const userSubscriptionsService = new UserSubscriptionService(
{ userUnsubscribeStore },
config,
eventService,
);
return userSubscriptionsService;
};

View File

@ -45,10 +45,14 @@ export class UserSubscriptionsReadModel implements IUserSubscriptionsReadModel {
}
async getUserSubscriptions(userId: number) {
const unsubscriptions = await this.db(UNSUBSCRIPTION_TABLE)
const unsubscriptionsList = await this.db(UNSUBSCRIPTION_TABLE)
.select('subscription')
.where('user_id', userId);
const unsubscriptions: string[] = unsubscriptionsList.map(
(item) => item.subscription,
);
return SUBSCRIPTION_TYPES.filter(
(subscription) => !unsubscriptions.includes(subscription),
);

View File

@ -0,0 +1,67 @@
import {
type IUnleashConfig,
type IUnleashStores,
type IUser,
TEST_AUDIT_USER,
} from '../../types';
import type UserSubscriptionService from './user-subscriptions-service';
import dbInit, { type ITestDb } from '../../../test/e2e/helpers/database-init';
import { createTestConfig } from '../../../test/config/test-config';
import getLogger from '../../../test/fixtures/no-logger';
import { createUserSubscriptionsService } from './createUserSubscriptionsService';
import type { IUserSubscriptionsReadModel } from './user-subscriptions-read-model-type';
let stores: IUnleashStores;
let db: ITestDb;
let userSubscriptionService: UserSubscriptionService;
let userSubscriptionsReadModel: IUserSubscriptionsReadModel;
let config: IUnleashConfig;
let user: IUser;
beforeAll(async () => {
db = await dbInit('user_subscriptions', getLogger);
stores = db.stores;
config = createTestConfig({});
userSubscriptionService = createUserSubscriptionsService(config)(
db.rawDatabase,
);
userSubscriptionsReadModel = db.stores.userSubscriptionsReadModel;
user = await stores.userStore.insert({
email: 'test@getunleash.io',
name: 'Sample Name',
});
});
afterAll(async () => {
await db.destroy();
});
test('Subscribe and unsubscribe', async () => {
const subscribers = await userSubscriptionsReadModel.getSubscribedUsers(
'productivity-report',
);
expect(subscribers).toMatchObject([
{ email: 'test@getunleash.io', name: 'Sample Name' },
]);
const userSubscriptions =
await userSubscriptionsReadModel.getUserSubscriptions(user.id);
expect(userSubscriptions).toMatchObject(['productivity-report']);
await userSubscriptionService.unsubscribe(
user.id,
'productivity-report',
TEST_AUDIT_USER,
);
const noSubscribers = await userSubscriptionsReadModel.getSubscribedUsers(
'productivity-report',
);
expect(noSubscribers).toMatchObject([]);
const noUserSubscriptions =
await userSubscriptionsReadModel.getUserSubscriptions(user.id);
expect(noUserSubscriptions).toMatchObject([]);
});

View File

@ -1,9 +1,5 @@
import type { Logger, LogProvider } from '../../logger';
import type { Db } from '../../db/db';
import type {
UnsubscribeEntry,
IUserUnsubscribeStore,
} from './user-unsubscribe-store-type';
import type { IUserUnsubscribeStore } from './user-unsubscribe-store-type';
const COLUMNS = ['user_id', 'subscription', 'created_at'];
export const TABLE = 'user_unsubscription';
@ -14,20 +10,11 @@ interface IUserUnsubscribeTable {
created_at?: Date;
}
const rowToField = (row: IUserUnsubscribeTable): UnsubscribeEntry => ({
userId: row.user_id,
subscription: row.subscription,
createdAt: row.created_at,
});
export class UserUnsubscribeStore implements IUserUnsubscribeStore {
private db: Db;
private logger: Logger;
constructor(db: Db, getLogger: LogProvider) {
constructor(db: Db) {
this.db = db;
this.logger = getLogger('user-unsubscribe-store.ts');
}
async insert({ userId, subscription }) {