feat(db): add lobbies and lobby_players tables + model
- Add lobbies and lobby_players tables with camelCase TS aliases
- Add LOBBY_STATUSES constant in shared
- Add lobbyModel with atomic addPlayer and transactional finishGame
- Enable Drizzle relational query API via { schema } option
This commit is contained in:
parent
47a68c0315
commit
cf56399a5e
2 changed files with 101 additions and 0 deletions
|
|
@ -1,2 +1,3 @@
|
|||
export * from "./constants.js";
|
||||
export * from "./schemas/game.js";
|
||||
export * from "./schemas/lobby.js";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import * as z from "zod";
|
||||
|
||||
import { LOBBY_STATUSES } from "../constants.js";
|
||||
import { GameQuestionSchema } from "./game.js";
|
||||
|
||||
export const LobbyPlayerSchema = z.object({
|
||||
lobbyId: z.uuid(),
|
||||
|
|
@ -19,4 +20,103 @@ export const LobbySchema = z.object({
|
|||
createdAt: z.iso.datetime(),
|
||||
players: z.array(LobbyPlayerSchema),
|
||||
});
|
||||
|
||||
export type Lobby = z.infer<typeof LobbySchema>;
|
||||
|
||||
export const JoinLobbyResponseSchema = LobbySchema;
|
||||
|
||||
export type JoinLobbyResponse = z.infer<typeof JoinLobbyResponseSchema>;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// WebSocket: Client → Server
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
export const WsLobbyJoinSchema = z.object({
|
||||
type: z.literal("lobby:join"),
|
||||
code: z.string().min(1).max(10),
|
||||
});
|
||||
|
||||
export type WsLobbyJoin = z.infer<typeof WsLobbyJoinSchema>;
|
||||
|
||||
export const WsLobbyLeaveSchema = z.object({
|
||||
type: z.literal("lobby:leave"),
|
||||
lobbyId: z.uuid(),
|
||||
});
|
||||
|
||||
export type WsLobbyLeave = z.infer<typeof WsLobbyLeaveSchema>;
|
||||
|
||||
export const WsLobbyStartSchema = z.object({
|
||||
type: z.literal("lobby:start"),
|
||||
lobbyId: z.uuid(),
|
||||
});
|
||||
|
||||
export type WsLobbyStart = z.infer<typeof WsLobbyStartSchema>;
|
||||
|
||||
export const WsGameAnswerSchema = z.object({
|
||||
type: z.literal("game:answer"),
|
||||
lobbyId: z.uuid(),
|
||||
questionId: z.uuid(),
|
||||
selectedOptionId: z.number().int().min(0).max(3),
|
||||
});
|
||||
|
||||
export type WsGameAnswer = z.infer<typeof WsGameAnswerSchema>;
|
||||
|
||||
export const WsClientMessageSchema = z.discriminatedUnion("type", [
|
||||
WsLobbyJoinSchema,
|
||||
WsLobbyLeaveSchema,
|
||||
WsLobbyStartSchema,
|
||||
WsGameAnswerSchema,
|
||||
]);
|
||||
export type WsClientMessage = z.infer<typeof WsClientMessageSchema>;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// WebSocket: Server → Client
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
export const WsLobbyStateSchema = z.object({
|
||||
type: z.literal("lobby:state"),
|
||||
lobby: LobbySchema,
|
||||
});
|
||||
|
||||
export type WsLobbyState = z.infer<typeof WsLobbyStateSchema>;
|
||||
|
||||
export const WsGameQuestionSchema = z.object({
|
||||
type: z.literal("game:question"),
|
||||
question: GameQuestionSchema,
|
||||
questionNumber: z.number().int().min(1),
|
||||
totalQuestions: z.number().int().min(1),
|
||||
});
|
||||
|
||||
export type WsGameQuestion = z.infer<typeof WsGameQuestionSchema>;
|
||||
|
||||
export const WsGameAnswerResultSchema = z.object({
|
||||
type: z.literal("game:answer_result"),
|
||||
correctOptionId: z.number().int().min(0).max(3),
|
||||
results: z.array(
|
||||
z.object({
|
||||
userId: z.string(),
|
||||
selectedOptionId: z.number().int().min(0).max(3).nullable(),
|
||||
isCorrect: z.boolean(),
|
||||
}),
|
||||
),
|
||||
players: z.array(LobbyPlayerSchema),
|
||||
});
|
||||
|
||||
export type WsGameAnswerResult = z.infer<typeof WsGameAnswerResultSchema>;
|
||||
|
||||
export const WsGameFinishedSchema = z.object({
|
||||
type: z.literal("game:finished"),
|
||||
players: z.array(LobbyPlayerSchema),
|
||||
winnerIds: z.array(z.string()),
|
||||
});
|
||||
|
||||
export type WsGameFinished = z.infer<typeof WsGameFinishedSchema>;
|
||||
|
||||
export const WsServerMessageSchema = z.discriminatedUnion("type", [
|
||||
WsLobbyStateSchema,
|
||||
WsGameQuestionSchema,
|
||||
WsGameAnswerResultSchema,
|
||||
WsGameFinishedSchema,
|
||||
]);
|
||||
|
||||
export type WsServerMessage = z.infer<typeof WsServerMessageSchema>;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue