Skip to content

Commit

Permalink
Improve discriminator setup
Browse files Browse the repository at this point in the history
  • Loading branch information
JessicaMulein committed Nov 27, 2024
1 parent 3d4dad8 commit e3caba4
Show file tree
Hide file tree
Showing 16 changed files with 240 additions and 199 deletions.
2 changes: 1 addition & 1 deletion chili-and-cilantro-api/src/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export class App implements IApplication {

// init all middlewares and routes
Middlewares.init(this.expressApp);
this._apiRouter = new ApiRouter(this.getModel, this.db.connection);
this._apiRouter = new ApiRouter(this);
this._appRouter = new AppRouter(this._apiRouter);
this._appRouter.init(this.expressApp, debug);
// if none of the above handle the request, pass it to error handler
Expand Down
19 changes: 10 additions & 9 deletions chili-and-cilantro-api/src/controllers/api/game.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import {

Check failure on line 1 in chili-and-cilantro-api/src/controllers/api/game.ts

View workflow job for this annotation

GitHub Actions / Qodana for JS

ESLint

ESLint: Install the 'eslint' package
CardType,
GetModelFunction,
IUserDocument,
ModelName,
TurnAction,
UserNotFoundError,
ValidationError,
} from '@chili-and-cilantro/chili-and-cilantro-lib';
import { RouteConfig } from 'chili-and-cilantro-api/src/interfaces/route-config';
import {
IApplication,
RouteConfig,
} from '@chili-and-cilantro/chili-and-cilantro-node-lib';
import { Request, Response } from 'express';
import { InvalidTokenError } from 'express-oauth2-jwt-bearer';
import { body } from 'express-validator';
import { Connection } from 'mongoose';
import { ActionService } from '../../services/action';
import { ChefService } from '../../services/chef';
import { GameService } from '../../services/game';
Expand All @@ -24,13 +25,13 @@ export class GameController extends BaseController {
private readonly playerService;
private readonly gameService;

constructor(getModel: GetModelFunction, connection: Connection) {
super(getModel);
this.actionService = new ActionService(getModel, connection);
this.chefService = new ChefService(getModel);
this.playerService = new PlayerService(getModel);
constructor(application: IApplication) {
super(application.getModel);
this.actionService = new ActionService(application);
this.chefService = new ChefService(application.getModel);
this.playerService = new PlayerService(application.getModel);
this.gameService = new GameService(
getModel,
application.getModel,
this.actionService,
this.chefService,
this.playerService,
Expand Down
2 changes: 1 addition & 1 deletion chili-and-cilantro-api/src/controllers/api/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import {
IUserResponse,
ModelName,
} from '@chili-and-cilantro/chili-and-cilantro-lib';
import { RouteConfig } from '@chili-and-cilantro/chili-and-cilantro-node-lib';
import { Request, Response } from 'express';
import { body, query } from 'express-validator';
import { MongooseValidationError } from '../../errors/mongoose-validation-error';
import { RouteConfig } from '../../interfaces/route-config';
import { findAuthToken } from '../../middlewares/authenticate-token';
import { JwtService } from '../../services/jwt';
import { RequestUserService } from '../../services/request-user';
Expand Down
2 changes: 1 addition & 1 deletion chili-and-cilantro-api/src/controllers/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import {
IMongoErrors,
IRequestUser,
} from '@chili-and-cilantro/chili-and-cilantro-lib';
import { RouteConfig } from '@chili-and-cilantro/chili-and-cilantro-node-lib';
import { NextFunction, Request, Response, Router } from 'express';
import {
matchedData,
ValidationChain,
ValidationError,
validationResult,
} from 'express-validator';
import { RouteConfig } from '../interfaces/route-config';
import { authenticateToken } from '../middlewares/authenticate-token';

export abstract class BaseController {
Expand Down
11 changes: 5 additions & 6 deletions chili-and-cilantro-api/src/routers/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { GetModelFunction } from '@chili-and-cilantro/chili-and-cilantro-lib';
import { Connection } from 'mongoose';
import { IApplication } from '@chili-and-cilantro/chili-and-cilantro-node-lib';

Check failure on line 1 in chili-and-cilantro-api/src/routers/api.ts

View workflow job for this annotation

GitHub Actions / Qodana for JS

ESLint

ESLint: Install the 'eslint' package
import { GameController } from '../controllers/api/game';
import { UserController } from '../controllers/api/user';
import { BaseRouter } from './base';
Expand All @@ -10,10 +9,10 @@ import { BaseRouter } from './base';
export class ApiRouter extends BaseRouter {
private readonly userController: UserController;
private readonly gameController: GameController;
constructor(getModel: GetModelFunction, connnection: Connection) {
super(getModel);
this.userController = new UserController(getModel);
this.gameController = new GameController(getModel, connnection);
constructor(application: IApplication) {
super(application.getModel);
this.userController = new UserController(application.getModel);
this.gameController = new GameController(application);
this.router.use('/user', this.userController.router);
this.router.use('/game', this.gameController.router);
}
Expand Down
208 changes: 123 additions & 85 deletions chili-and-cilantro-api/src/services/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,28 @@ import {
IUserDocument,
ModelName,
} from '@chili-and-cilantro/chili-and-cilantro-lib';
import { ActionDiscriminatorsByActionType } from '@chili-and-cilantro/chili-and-cilantro-node-lib';
import { Connection, Model } from 'mongoose';
import { IApplication } from '@chili-and-cilantro/chili-and-cilantro-node-lib';
import { Model } from 'mongoose';

export class ActionService {
private readonly getModel: GetModelFunction;
private readonly actionDiscriminators: { [key in ActionType]: Model<any> };
private readonly actionDiscriminatorsByType: Record<
ActionType,
Model<IActionDocument>
>;

constructor(getModel: GetModelFunction, connection: Connection) {
this.getModel = getModel;
this.actionDiscriminators = ActionDiscriminatorsByActionType(connection);
constructor(application: IApplication) {
this.getModel = application.getModel;
this.actionDiscriminatorsByType = application.schemaMap.Action
.discriminators.byType as Record<ActionType, Model<IActionDocument>>;
}
private async createAction<T extends IActionDocument, U extends IAction>(
action: ActionType,
data: U,
): Promise<T> {
return this.actionDiscriminatorsByType[action].create(data) as Promise<T>;
}

public async getGameHistoryAsync(game: IGameDocument): Promise<IAction[]> {
const ActionModel = this.getModel<IActionDocument>(ModelName.Action);
return ActionModel.find({ gameId: game._id }).sort({
Expand All @@ -59,128 +70,155 @@ export class ActionService {
chef: IChefDocument,
user: IUserDocument,
): Promise<ICreateGameActionDocument> {
return this.actionDiscriminators.CREATE_GAME.create({
gameId: game._id,
chefId: chef._id,
userId: user._id,
type: ActionType.CREATE_GAME,
details: {} as ICreateGameDetails,
round: constants.NONE,
} as ICreateGameAction);
return this.createAction<ICreateGameActionDocument, ICreateGameAction>(
ActionType.CREATE_GAME,
{
gameId: game._id,
chefId: chef._id,
userId: user._id,
type: ActionType.CREATE_GAME,
details: {} as ICreateGameDetails,
round: constants.NONE,
} as ICreateGameAction,
);
}
public async joinGameAsync(
game: IGameDocument,
chef: IChefDocument,
user: IUserDocument,
): Promise<IJoinGameActionDocument> {
return this.actionDiscriminators.JOIN_GAME.create({
gameId: game._id,
chefId: chef._id,
userId: user._id,
type: ActionType.JOIN_GAME,
details: {} as IJoinGameDetails,
round: constants.NONE,
} as IJoinGameAction);
return this.createAction<IJoinGameActionDocument, IJoinGameAction>(
ActionType.JOIN_GAME,
{
gameId: game._id,
chefId: chef._id,
userId: user._id,
type: ActionType.JOIN_GAME,
details: {} as IJoinGameDetails,
round: constants.NONE,
} as IJoinGameAction,
);
}
public async startGameAsync(
game: IGameDocument,
): Promise<IStartGameActionDocument> {
return this.actionDiscriminators.START_GAME.create({
gameId: game._id,
chefId: game.hostChefId,
userId: game.hostUserId,
type: ActionType.START_GAME,
details: {} as IStartGameDetails,
round: game.currentRound,
} as IStartGameAction);
return this.createAction<IStartGameActionDocument, IStartGameAction>(
ActionType.START_GAME,
{
gameId: game._id,
chefId: game.hostChefId,
userId: game.hostUserId,
type: ActionType.START_GAME,
details: {} as IStartGameDetails,
round: game.currentRound,
} as IStartGameAction,
);
}
public async expireGameAsync(
game: IGameDocument,
): Promise<IExpireGameActionDocument> {
return this.actionDiscriminators.EXPIRE_GAME.create({
gameId: game._id,
chefId: game.hostChefId,
userId: game.hostUserId,
type: ActionType.EXPIRE_GAME,
details: {} as IExpireGameDetails,
round: game.currentRound,
} as IExpireGameAction);
return this.createAction<IExpireGameActionDocument, IExpireGameAction>(
ActionType.EXPIRE_GAME,
{
gameId: game._id,
chefId: game.hostChefId,
userId: game.hostUserId,
type: ActionType.EXPIRE_GAME,
details: {} as IExpireGameDetails,
round: game.currentRound,
} as IExpireGameAction,
);
}
public async sendMessageAsync(
game: IGameDocument,
chef: IChefDocument,
message: string,
): Promise<IMessageActionDocument> {
return this.actionDiscriminators.MESSAGE.create({
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.MESSAGE,
details: {
message: message,
} as IMessageDetails,
round: game.currentRound,
} as IMessageAction);
return this.createAction<IMessageActionDocument, IMessageAction>(
ActionType.MESSAGE,
{
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.MESSAGE,
details: {
message: message,
} as IMessageDetails,
round: game.currentRound,
} as IMessageAction,
);
}
public async startBiddingAsync(
game: IGameDocument,
chef: IChefDocument,
bid: number,
): Promise<IStartBiddingActionDocument> {
return this.actionDiscriminators.START_BIDDING.create({
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.START_BIDDING,
details: {
bid: bid,
} as IStartBiddingDetails,
round: game.currentRound,
} as IStartBiddingAction);
return this.createAction<IStartBiddingActionDocument, IStartBiddingAction>(
ActionType.START_BIDDING,
{
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.START_BIDDING,
details: {
bid: bid,
} as IStartBiddingDetails,
round: game.currentRound,
} as IStartBiddingAction,
);
}
public async passAsync(
game: IGameDocument,
chef: IChefDocument,
): Promise<IPassActionDocument> {
return this.actionDiscriminators.PASS.create({
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.PASS,
details: {} as IPassDetails,
round: game.currentRound,
} as IPassAction);
return this.createAction<IPassActionDocument, IPassAction>(
ActionType.PASS,
{
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.PASS,
details: {} as IPassDetails,
round: game.currentRound,
} as IPassAction,
);
}
public async placeCardAsync(
game: IGameDocument,
chef: IChefDocument,
cardType: CardType,
position: number,
): Promise<IPlaceCardActionDocument> {
return this.actionDiscriminators.PLACE_CARD.create({
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.PLACE_CARD,
details: {
cardType: cardType,
position: position,
} as IPlaceCardDetails,
round: game.currentRound,
} as IPlaceCardAction);
return this.createAction<IPlaceCardActionDocument, IPlaceCardAction>(
ActionType.PLACE_CARD,
{
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.PLACE_CARD,
details: {
cardType: cardType,
position: position,
} as IPlaceCardDetails,
round: game.currentRound,
} as IPlaceCardAction,
);
}

public async quitGameAsync(
game: IGameDocument,
chef: IChefDocument,
): Promise<IQuitGameActionDocument> {
return this.actionDiscriminators.QUIT_GAME.create({
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.QUIT_GAME,
details: {} as IQuitGameDetails,
round: game.currentRound,
} as IQuitGameAction);
return this.createAction<IQuitGameActionDocument, IQuitGameAction>(
ActionType.QUIT_GAME,
{
gameId: game._id,
chefId: chef._id,
userId: chef.userId,
type: ActionType.QUIT_GAME,
details: {} as IQuitGameDetails,
round: game.currentRound,
} as IQuitGameAction,
);
}
}
6 changes: 5 additions & 1 deletion chili-and-cilantro-api/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@
"types": ["node"]
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts", "src/types/express.d.ts"]
"include": [
"src/**/*.ts",
"src/types/express.d.ts",
"../chili-and-cilantro-node-lib/src/lib/interfaces/route-config.ts"
]
}
2 changes: 2 additions & 0 deletions chili-and-cilantro-node-lib/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export * from './lib/action-schema-map';

Check failure on line 1 in chili-and-cilantro-node-lib/src/index.ts

View workflow job for this annotation

GitHub Actions / Qodana for JS

ESLint

ESLint: Install the 'eslint' package
export * from './lib/discriminators/action';
export * from './lib/interfaces/application';
export * from './lib/interfaces/discriminator-collections';
export * from './lib/interfaces/route-config';
export * from './lib/interfaces/schema-data';
export * from './lib/interfaces/schema-model-data';
export * from './lib/models/action';
Expand Down
Loading

0 comments on commit e3caba4

Please sign in to comment.