Skip to content

Commit

Permalink
Built service for adding messages - worked on unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nsearls-bu committed Apr 21, 2024
1 parent a73a8ec commit 326fc7b
Show file tree
Hide file tree
Showing 28 changed files with 587 additions and 327 deletions.
Empty file added server/dev.db
Empty file.
420 changes: 350 additions & 70 deletions server/package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@
"@nestjs/core": "^10.0.0",
"@nestjs/graphql": "^12.1.1",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/typeorm": "^10.0.2",
"@prisma/client": "^5.12.1",
"graphql": "^16.8.1",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"sqlite": "^5.1.1",
"typeorm": "^0.3.20"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand Down
49 changes: 22 additions & 27 deletions server/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,29 @@ datasource db {
}

model User {
id String @id @default(uuid())
firstName String
lastName String
cell String
email String @unique
image String?
birthday DateTime?
username String @unique
password String
street String?
city String?
state String?
postalCode String?
conversations Conversation[]
}

model Conversation {
id String @id @default(uuid())
users User[]
name String
dateCreated DateTime
messages Message[]
id String @id @default(uuid())
firstName String
lastName String
cell String
email String @unique
image String?
birthday DateTime?
username String @unique
password String
street String?
city String?
state String?
postalCode String?
SentMessages Message[] @relation("SentMessages")
RecievedMessages Message[] @relation("RecievedMessages")
}

model Message {
id String @id @default(uuid())
senderID String
recipientID String
conversationID Conversation @relation(fields: [id], references: [id])
timeSend DateTime @default(now())
id String @id @default(uuid())
sender User @relation(name: "SentMessages", fields: [senderID], references: [id])
senderID String
recipient User @relation(name: "RecievedMessages", fields: [recipientID], references: [id])
recipientID String
timeSent DateTime @default(now())
messageContents String
}
61 changes: 30 additions & 31 deletions server/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""User entity representing a registered user"""
type User {
"""Unique identifier of the user"""
uid: ID!
id: ID!

"""First name of the user"""
firstName: String!
Expand Down Expand Up @@ -44,6 +44,9 @@ type User {

"""Postal code"""
postalCode: String

"""List of users conversations"""
conversations: [String!]
}

"""
Expand All @@ -52,22 +55,26 @@ A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date
scalar DateTime

type Chat {
"""Example field (placeholder)"""
exampleField: Int!
}
"""ID for each chat"""
id: ID!

"""ID of message sender"""
senderID: String!

"""ID of message recipient"""
recipientID: String!

"""Time message was sent"""
timeSent: DateTime!

type Conversation {
"""Example field (placeholder)"""
exampleField: Int!
"""Message contents"""
messageContents: String!
}

type Query {
users: [User!]!
user(username: ID!): User!
chats: [Chat!]!
chat(id: Int!): Chat!
conversations: [Conversation!]!
conversation(id: Int!): Conversation!
chats(recipientID: String!): [Chat!]!
}

type Mutation {
Expand All @@ -76,10 +83,7 @@ type Mutation {
removeUser(username: Int!): User!
createChat(createChatInput: CreateChatInput!): Chat!
updateChat(updateChatInput: UpdateChatInput!): Chat!
removeChat(id: Int!): Chat!
createConversation(createConversationInput: CreateConversationInput!): Conversation!
updateConversation(updateConversationInput: UpdateConversationInput!): Conversation!
removeConversation(id: Int!): Conversation!
removeChat(id: String!): Chat!
}

input CreateUser {
Expand Down Expand Up @@ -112,27 +116,22 @@ input UpdateUser {
postalCode: String

"""Create a user"""
uid: ID!
id: ID!
}

input CreateChatInput {
"""Example field (placeholder)"""
exampleField: Int!
}
"""ID of message sender"""
senderID: String!

input UpdateChatInput {
"""Example field (placeholder)"""
exampleField: Int
id: Int!
}
"""ID of message recipient"""
recipientID: String!

input CreateConversationInput {
"""Example field (placeholder)"""
exampleField: Int!
"""Contents of message"""
messageContents: String!
}

input UpdateConversationInput {
"""Example field (placeholder)"""
exampleField: Int
id: Int!
input UpdateChatInput {
"""Contents of message"""
messageContents: String
id: String!
}
34 changes: 32 additions & 2 deletions server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,46 @@ import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { UsersModule } from './users/users.module';
import { ChatsModule } from './chats/chats.module';
import { ConversationsModule } from './conversations/conversations.module';
import { ApolloServerErrorCode } from '@apollo/server/errors';
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: 'schema.gql',
formatError: (formattedError, error) => {
// Return a different error message

if (
formattedError.extensions.code ===
ApolloServerErrorCode.INTERNAL_SERVER_ERROR
) {
return {
...formattedError,

message: 'Request failed',
};
}

if (
formattedError.extensions.code ===
ApolloServerErrorCode.GRAPHQL_VALIDATION_FAILED
) {
return {
...formattedError,

message: error.toString(),
};
}

// Otherwise return the formatted error. This error can also

// be manipulated in other ways, as long as it's returned.

return formattedError;
},
}),
UsersModule,
ChatsModule,
ConversationsModule,
],
})
export class AppModule {}
3 changes: 2 additions & 1 deletion server/src/chats/chats.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Module } from '@nestjs/common';
import { ChatsService } from './chats.service';
import { ChatsResolver } from './chats.resolver';

import { PrismaModule } from '../prisma/prisma.module';
@Module({
imports: [PrismaModule],
providers: [ChatsResolver, ChatsService],
})
export class ChatsModule {}
3 changes: 2 additions & 1 deletion server/src/chats/chats.resolver.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ChatsResolver } from './chats.resolver';
import { ChatsService } from './chats.service';

import { PrismaModule } from '../prisma/prisma.module';
describe('ChatsResolver', () => {
let resolver: ChatsResolver;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [PrismaModule],
providers: [ChatsResolver, ChatsService],
}).compile();

Expand Down
12 changes: 6 additions & 6 deletions server/src/chats/chats.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ export class ChatsResolver {
}

@Query(() => [Chat], { name: 'chats' })
findAll() {
return this.chatsService.findAll();
findFrom(@Args('senderID') senderID: string) {
return this.chatsService.findFrom(senderID);
}

@Query(() => Chat, { name: 'chat' })
findOne(@Args('id', { type: () => Int }) id: number) {
return this.chatsService.findOne(id);
@Query(() => [Chat], { name: 'chats' })
findTo(@Args('recipientID') recipientID: string) {
return this.chatsService.findFrom(recipientID);
}

@Mutation(() => Chat)
Expand All @@ -29,7 +29,7 @@ export class ChatsResolver {
}

@Mutation(() => Chat)
removeChat(@Args('id', { type: () => Int }) id: number) {
removeChat(@Args('id') id: string) {
return this.chatsService.remove(id);
}
}
3 changes: 3 additions & 0 deletions server/src/chats/chats.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ChatsService } from './chats.service';
import { PrismaModule } from '../prisma/prisma.module';

describe('ChatsService', () => {
let service: ChatsService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [PrismaModule],

providers: [ChatsService],
}).compile();

Expand Down
67 changes: 56 additions & 11 deletions server/src/chats/chats.service.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,71 @@
import { Injectable } from '@nestjs/common';
import { CreateChatInput } from './dto/create-chat.input';
import { UpdateChatInput } from './dto/update-chat.input';

import { PrismaService } from '../prisma/prisma.service';
import { GraphQLError } from 'graphql';
import { Prisma } from '@prisma/client';
@Injectable()
export class ChatsService {
create(createChatInput: CreateChatInput) {
return 'This action adds a new chat';
constructor(private prisma: PrismaService) {}

// Method to create a new chat
async create(createChatInput: CreateChatInput) {
return this.prisma.message
.create({ data: createChatInput })
.catch((error) => {
// Handling unique constraint violation error
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new GraphQLError(
'Chat creation failed: Unique constraint violated.',
);
}
// Handling other errors
throw new GraphQLError('Chat creation failed.');
});
}

findAll() {
return `This action returns all chats`;
// Method to find chats sent from a specific user
async findFrom(id: string) {
return this.prisma.message
.findMany({ where: { senderID: id } })
.catch((error) => {
// Handling errors while fetching chats from sender
throw new GraphQLError(
'Error occurred while fetching chats from sender.',
);
});
}

findOne(id: number) {
return `This action returns a #${id} chat`;
// Method to find chats sent to a specific user
async findTo(id: string) {
return this.prisma.message
.findMany({ where: { recipientID: id } })
.catch((error) => {
// Handling errors while fetching chats to recipient
throw new GraphQLError(
'Error occurred while fetching chats to recipient.',
);
});
}

update(id: number, updateChatInput: UpdateChatInput) {
return `This action updates a #${id} chat`;
// Method to update a chat
async update(id: string, updateChatInput: UpdateChatInput) {
return this.prisma.message
.update({
where: { id: id },
data: { messageContents: updateChatInput.messageContents },
})
.catch((error) => {
// Handling errors while updating a chat
throw new GraphQLError('Error occurred while updating chat.');
});
}

remove(id: number) {
return `This action removes a #${id} chat`;
// Method to remove a chat
async remove(id: string) {
return this.prisma.message.delete({ where: { id: id } }).catch((error) => {
// Handling errors while deleting a chat
throw new GraphQLError('Error occurred while deleting chat.');
});
}
}
10 changes: 7 additions & 3 deletions server/src/chats/dto/create-chat.input.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { InputType, Int, Field } from '@nestjs/graphql';
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class CreateChatInput {
@Field(() => Int, { description: 'Example field (placeholder)' })
exampleField: number;
@Field({ description: 'ID of message sender' })
senderID: string;
@Field({ description: 'ID of message recipient' })
recipientID: string;
@Field({ description: 'Contents of message' })
messageContents: string;
}
Loading

0 comments on commit 326fc7b

Please sign in to comment.