Skip to content

Commit

Permalink
feat: composition root for user subscriptions (#8649)
Browse files Browse the repository at this point in the history
Co-Authored-By: Tymoteusz Czech <[email protected]>
  • Loading branch information
kwasniew and Tymek authored Nov 5, 2024
1 parent b491d9e commit 6a8a75c
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/lib/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export const createStores = (
eventBus,
config.flagResolver,
),
userUnsubscribeStore: new UserUnsubscribeStore(db, getLogger),
userUnsubscribeStore: new UserUnsubscribeStore(db),
userSubscriptionsReadModel: new UserSubscriptionsReadModel(
db,
eventBus,
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
};
Original file line number Diff line number Diff line change
Expand Up @@ -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),
);
Expand Down
Original file line number Diff line number Diff line change
@@ -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: '[email protected]',
name: 'Sample Name',
});
});

afterAll(async () => {
await db.destroy();
});

test('Subscribe and unsubscribe', async () => {
const subscribers = await userSubscriptionsReadModel.getSubscribedUsers(
'productivity-report',
);
expect(subscribers).toMatchObject([
{ email: '[email protected]', 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([]);
});
17 changes: 2 additions & 15 deletions src/lib/features/user-subscriptions/user-unsubscribe-store.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 }) {
Expand Down

0 comments on commit 6a8a75c

Please sign in to comment.