Skip to content

Commit

Permalink
Merge pull request #132 from jbrunton/refactor-message-types
Browse files Browse the repository at this point in the history
refactor: message types
  • Loading branch information
jbrunton authored Aug 15, 2024
2 parents 87d0ed9 + 7b8e0d8 commit 1fb3d42
Show file tree
Hide file tree
Showing 40 changed files with 113 additions and 92 deletions.
2 changes: 1 addition & 1 deletion services/api/src/app/dispatcher/dispatcher.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Dispatcher } from '@entities/message.entity';
import { Dispatcher } from '@entities/messages';
import { Module } from '@nestjs/common';
import { EventEmitter } from 'stream';
import { DispatcherService } from './dispatcher.service';
Expand Down
6 changes: 3 additions & 3 deletions services/api/src/app/dispatcher/dispatcher.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { TestRoomsRepository } from '@fixtures/data/test.rooms.repository';
import { DispatcherService } from './dispatcher.service';
import { TestMessagesRepository } from '@fixtures/data/test.messages.repository';
import { TestAuthService } from '@fixtures/auth/test-auth-service';
import { DraftMessage, Message } from '@entities/message.entity';
import { DraftMessage, SentMessage } from '@entities/messages';
import { RoomFactory } from '@fixtures/messages/room.factory';
import { UserFactory } from '@fixtures/messages/user.factory';
import { MockProxy, mock } from 'jest-mock-extended';
Expand Down Expand Up @@ -53,7 +53,7 @@ describe('DispatcherService', () => {

await dispatcher.send(draft);

const expectedMessage: Message = {
const expectedMessage: SentMessage = {
id: `message:${now.getTime()}`,
time: now.getTime(),
...draft,
Expand All @@ -74,7 +74,7 @@ describe('DispatcherService', () => {

await dispatcher.send(draft);

const expectedMessage: Message = {
const expectedMessage: SentMessage = {
id: `message:${now.getTime()}`,
time: now.getTime(),
...draft,
Expand Down
4 changes: 2 additions & 2 deletions services/api/src/app/dispatcher/dispatcher.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dispatcher, DraftMessage, isPrivate } from '@entities/message.entity';
import { MessagesRepository } from '@entities/messages.repository';
import { Dispatcher, DraftMessage, isPrivate } from '@entities/messages';
import { MessagesRepository } from '@entities/messages';
import { RoomsRepository } from '@entities/rooms.repository';
import { User } from '@entities/user.entity';
import { ConsoleLogger, Injectable } from '@nestjs/common';
Expand Down
2 changes: 1 addition & 1 deletion services/api/src/app/messages/command.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Injectable } from '@nestjs/common';
import { HelpCommandUseCase } from '@usecases/commands/help';
import { RenameRoomUseCase } from '@usecases/rooms/rename';
import { RenameUserUseCase } from '@usecases/users/rename';
import { Dispatcher } from '@entities/message.entity';
import { Dispatcher } from '@entities/messages';
import { LoremCommandUseCase } from '@usecases/commands/lorem';
import { ParseCommandUseCase } from '@usecases/commands/parse';

Expand Down
2 changes: 1 addition & 1 deletion services/api/src/app/messages/messages.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '@fixtures/auth/FakeAuth';
import { MessageFactory } from '@fixtures/messages/message.factory';
import { UsersRepository } from '@entities/users.repository';
import { MessagesRepository } from '@entities/messages.repository';
import { MessagesRepository } from '@entities/messages';
import { TestDataModule } from '@fixtures/data/test.data.module';
import { TestUsersRepository } from '@fixtures/data/test.users.repository';
import { TestMessagesRepository } from '@fixtures/data/test.messages.repository';
Expand Down
2 changes: 1 addition & 1 deletion services/api/src/app/messages/messages.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CreateMessageDto } from './dto/create-message.dto';
import { Auth } from '@app/auth/auth.decorator';
import { Identify } from '@app/auth/auth0/identify.decorator';
import { User } from '@entities/user.entity';
import { Dispatcher } from '@entities/message.entity';
import { Dispatcher } from '@entities/messages';
import { GetMessagesUseCase } from '@usecases/messages/get-messages';

@Auth()
Expand Down
2 changes: 1 addition & 1 deletion services/api/src/data/data.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Global, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MessagesRepository } from '@entities/messages.repository';
import { MessagesRepository } from '@entities/messages';
import databaseConfig from '@config/database.config';
import { DynamoDBMessagesRepository } from './repositories/dynamodb.messages.repository';
import { RoomsRepository } from '@entities/rooms.repository';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DynamoDBMessagesRepository } from '@data/repositories/dynamodb.messages.repository';
import { DraftMessage } from '@entities/message.entity';
import { DraftMessage } from '@entities/messages';
import { TestMessagesRepository } from '@fixtures/data/test.messages.repository';
import { RoomFactory } from '@fixtures/messages/room.factory';
import { UserFactory } from '@fixtures/messages/user.factory';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DraftMessage, Message } from '@entities/message.entity';
import { MessagesRepository } from '@entities/messages.repository';
import { DraftMessage, SentMessage } from '@entities/messages';
import { MessagesRepository } from '@entities/messages';
import { Injectable } from '@nestjs/common';
import { pick } from 'rambda';
import { DynamoDBAdapter } from '../adapters/dynamodb.adapter';
Expand All @@ -11,7 +11,7 @@ export class DynamoDBMessagesRepository extends MessagesRepository {
super();
}

override async saveMessage(params: DraftMessage): Promise<Message> {
override async saveMessage(params: DraftMessage): Promise<SentMessage> {
const message = await this.adapter.Message.create(
{
...params,
Expand All @@ -22,15 +22,15 @@ export class DynamoDBMessagesRepository extends MessagesRepository {
return messageFromRecord(message);
}

override async getMessagesForRoom(roomId: string): Promise<Message[]> {
override async getMessagesForRoom(roomId: string): Promise<SentMessage[]> {
const messages = await this.adapter.Message.find(
{ Id: roomId },
{ hidden: true },
);
return messages.map(messageFromRecord);
}

override async getAuthorHistory(authorId: string): Promise<Message[]> {
override async getAuthorHistory(authorId: string): Promise<SentMessage[]> {
const messages = await this.adapter.Message.scan(
{},
{
Expand All @@ -45,7 +45,7 @@ export class DynamoDBMessagesRepository extends MessagesRepository {
}
}

const messageFromRecord = (record: DbMessage): Message => ({
const messageFromRecord = (record: DbMessage): SentMessage => ({
id: record.Sort,
...pick(
['roomId', 'content', 'authorId', 'recipientId', 'time', 'updatedEntities'],
Expand Down
9 changes: 0 additions & 9 deletions services/api/src/domain/entities/command.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,3 @@ export class Command {
roomId: string;
canonicalInput: string;
}

export type ParsedCommand =
| { tag: 'help'; params: null }
| { tag: 'renameRoom'; params: { newName: string } }
| { tag: 'renameUser'; params: { newName: string } }
| {
tag: 'lorem';
params: { count: number; typeToken: 'words' | 'paragraphs' };
};
7 changes: 0 additions & 7 deletions services/api/src/domain/entities/messages.repository.ts

This file was deleted.

3 changes: 3 additions & 0 deletions services/api/src/domain/entities/messages/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './message';
export * from './system';
export * from './messages.repository';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Observable } from 'rxjs';
import { User } from './user.entity';
import { User } from '../user.entity';

export type Message = {
export type SentMessage = {
id: string;
time: number;
content: string;
Expand All @@ -11,15 +11,15 @@ export type Message = {
updatedEntities?: string[];
};

export type PrivateMessage = Message & {
export type PrivateMessage = SentMessage & {
recipientId: string;
};

export const isPrivate = (message: Message): message is PrivateMessage => {
export const isPrivate = (message: SentMessage): message is PrivateMessage => {
return (message as PrivateMessage).recipientId !== undefined;
};

export type DraftMessage = Omit<Message, 'id' | 'time'>;
export type DraftMessage = Omit<SentMessage, 'id' | 'time'>;

export abstract class Dispatcher {
abstract subscribe(roomId: string, user: User): Promise<Observable<unknown>>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { DraftMessage, SentMessage } from './message';

export abstract class MessagesRepository {
abstract saveMessage(params: DraftMessage): Promise<SentMessage>;
abstract getMessagesForRoom(roomId: string): Promise<SentMessage[]>;
abstract getAuthorHistory(authorId: string): Promise<SentMessage[]>;
}
18 changes: 18 additions & 0 deletions services/api/src/domain/entities/messages/system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { SentMessage, DraftMessage } from './message';

export const systemUser = 'system';

export const isSystemMessage = (message: SentMessage): boolean => {
return message.authorId === systemUser;
};

export const buildSystemMessage = ({
content,
roomId,
}: Omit<DraftMessage, 'authorId'>) => {
return {
content,
roomId,
authorId: systemUser,
};
};
2 changes: 1 addition & 1 deletion services/api/src/domain/usecases/commands/help.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HelpCommandUseCase } from './help';
import { MockProxy, mock } from 'jest-mock-extended';
import { Dispatcher } from '@entities/message.entity';
import { Dispatcher } from '@entities/messages';
import { User } from '@entities/user.entity';
import { UserFactory } from '@fixtures/messages/user.factory';
import { RoomFactory } from '@fixtures/messages/room.factory';
Expand Down
2 changes: 1 addition & 1 deletion services/api/src/domain/usecases/commands/help.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Dispatcher } from '@entities/message.entity';
import { Dispatcher } from '@entities/messages';
import { User } from '@entities/user.entity';
import { Injectable } from '@nestjs/common';
import { parsers } from './parse/parsers';
Expand Down
2 changes: 1 addition & 1 deletion services/api/src/domain/usecases/commands/lorem.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LoremCommandUseCase, LoremGenerator, LoremParams } from './lorem';
import { MockProxy, mock } from 'jest-mock-extended';
import { Dispatcher } from '@entities/message.entity';
import { Dispatcher } from '@entities/messages';
import { User } from '@entities/user.entity';
import { RoomFactory } from '@fixtures/messages/room.factory';
import { UserFactory } from '@fixtures/messages/user.factory';
Expand Down
2 changes: 1 addition & 1 deletion services/api/src/domain/usecases/commands/lorem.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Dispatcher, DraftMessage } from '@entities/message.entity';
import { Dispatcher, DraftMessage } from '@entities/messages';
import { User } from '@entities/user.entity';
import { Injectable } from '@nestjs/common';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { Command, ParsedCommand } from '@entities/command.entity';
import { Command } from '@entities/command.entity';
import { BadRequestException } from '@nestjs/common';
import { equals } from 'rambda';
import { z, ZodIssue, ZodType } from 'zod';

export type ParsedCommand =
| { tag: 'help'; params: null }
| { tag: 'renameRoom'; params: { newName: string } }
| { tag: 'renameUser'; params: { newName: string } }
| {
tag: 'lorem';
params: { count: number; typeToken: 'words' | 'paragraphs' };
};

export type ParseResult =
| {
match: true;
Expand Down
3 changes: 2 additions & 1 deletion services/api/src/domain/usecases/commands/parse/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Command, ParsedCommand } from '@entities/command.entity';
import { Command } from '@entities/command.entity';
import { BadRequestException, Injectable } from '@nestjs/common';
import { parsers } from './parsers';
import { ParsedCommand } from './command.parser';

@Injectable()
export class ParseCommandUseCase {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Command, ParsedCommand } from '@entities/command.entity';
import { Command } from '@entities/command.entity';
import { BadRequestException } from '@nestjs/common';
import { ParseCommandUseCase } from './parse';
import { ParseCommandUseCase } from '.';
import { ParsedCommand } from './command.parser';

describe('ParseCommandUseCase', () => {
let parse: ParseCommandUseCase;
Expand All @@ -9,7 +10,7 @@ describe('ParseCommandUseCase', () => {
parse = new ParseCommandUseCase();
});

const expectCommand = (command: string) => {
const withMessage = (command: string) => {
const tokens = command.slice(1).split(' ');
const parsedCommand: Command = {
roomId: 'my-room',
Expand All @@ -18,12 +19,12 @@ describe('ParseCommandUseCase', () => {
};
const parse = new ParseCommandUseCase();
return {
toReturn: (expected: ParsedCommand) => {
expectCommand: (expected: ParsedCommand) => {
const result = parse.exec(parsedCommand);
expect(result).toEqual(expected);
},

toErrorWith: (...expectedMessage: string[]) => {
expectError: (...expectedMessage: string[]) => {
expect(() => parse.exec(parsedCommand)).toThrow(
new BadRequestException(expectedMessage.join('\n')),
);
Expand All @@ -33,14 +34,14 @@ describe('ParseCommandUseCase', () => {

describe('/help', () => {
it('parses the command', () => {
expectCommand('/help').toReturn({
withMessage('/help').expectCommand({
tag: 'help',
params: null,
});
});

it('validates the number of arguments', () => {
expectCommand('/help me').toErrorWith(
withMessage('/help me').expectError(
'Error in command `/help me`:',
'* Received too many arguments. Expected: `/help`',
);
Expand All @@ -49,7 +50,7 @@ describe('ParseCommandUseCase', () => {

describe('/lorem', () => {
it('parses valid commands', () => {
expectCommand('/lorem 3 words').toReturn({
withMessage('/lorem 3 words').expectCommand({
tag: 'lorem',
params: {
count: 3,
Expand All @@ -59,22 +60,22 @@ describe('ParseCommandUseCase', () => {
});

it('validates the number of arguments', () => {
expectCommand('/lorem').toErrorWith(
withMessage('/lorem').expectError(
'Error in command `/lorem`:',
`* Received too few arguments. Expected: \`/lorem {count} {'words' | 'paragraphs'}\``,
);
expectCommand('/lorem 3 words paragraphs').toErrorWith(
withMessage('/lorem 3 words paragraphs').expectError(
'Error in command `/lorem 3 words paragraphs`:',
`* Received too many arguments. Expected: \`/lorem {count} {'words' | 'paragraphs'}\``,
);
});

it('validates the arguments', () => {
expectCommand('/lorem three words').toErrorWith(
withMessage('/lorem three words').expectError(
'Error in command `/lorem three words`:',
'* Argument 1 (`three`): Expected number, received nan',
);
expectCommand('/lorem 3 chars').toErrorWith(
withMessage('/lorem 3 chars').expectError(
'Error in command `/lorem 3 chars`:',
`* Argument 2 (\`chars\`): Invalid enum value. Expected 'words' | 'paragraphs', received 'chars'`,
);
Expand All @@ -83,7 +84,7 @@ describe('ParseCommandUseCase', () => {

describe('/rename room', () => {
it('parses valid commands', () => {
expectCommand('/rename room My Room').toReturn({
withMessage('/rename room My Room').expectCommand({
tag: 'renameRoom',
params: {
newName: 'My Room',
Expand All @@ -92,7 +93,7 @@ describe('ParseCommandUseCase', () => {
});

it('validates the number of arguments', () => {
expectCommand('/rename room').toErrorWith(
withMessage('/rename room').expectError(
'Error in command `/rename room`:',
`* Received too few arguments. Expected: \`/rename room {name}\``,
);
Expand All @@ -101,7 +102,7 @@ describe('ParseCommandUseCase', () => {

describe('/rename user', () => {
it('parses valid commands', () => {
expectCommand('/rename user My User').toReturn({
withMessage('/rename user My User').expectCommand({
tag: 'renameUser',
params: {
newName: 'My User',
Expand All @@ -110,7 +111,7 @@ describe('ParseCommandUseCase', () => {
});

it('validates the number of arguments', () => {
expectCommand('/rename user').toErrorWith(
withMessage('/rename user').expectError(
'Error in command `/rename user`:',
`* Received too few arguments. Expected: \`/rename user {name}\``,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ParsedCommand } from '@entities/command.entity';
import { z } from 'zod';
import { CommandParser } from '../command.parser';
import { CommandParser, ParsedCommand } from '../command.parser';

const schema = z.tuple([z.literal('help')]).transform<ParsedCommand>(() => ({
tag: 'help',
Expand Down
Loading

0 comments on commit 1fb3d42

Please sign in to comment.