src/database/schemas.ts (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
import { type Document, Schema, model } from "mongoose";
import { z } from "zod";
// zod schemas for validation
export const guildSchema = z.object({
guild_id: z.string(),
suggestion_forum: z.string().optional(),
bug_channel: z.string().optional(),
commands_channel: z.string().optional(),
highlights_channel: z.string().optional(),
manager_roles: z.array(z.string()).default([]),
});
export const userSchema = z.object({
user_id: z.string(),
guild_id: z.string(),
});
const CounterSchema = new Schema({
_id: String,
sequence_value: { type: Number, default: 0 },
});
export const bugSchema = z.object({
bug_id: z.number(),
user_id: z.string(),
status: z.enum(["open", "closed"]).default("open"),
game: z.enum(["wft", "gw", "ab"]),
title: z.string(),
description: z.string(),
sent: z.boolean().default(false),
message_id: z.string().optional(),
thread_id: z.string().optional(),
});
export const mediaSchema = z.object({
media_type: z.enum(["image", "video"]),
data: z.instanceof(Buffer),
user_id: z.string(),
bug_id: z.string().optional(),
});
// ts types
export type GuildType = z.infer<typeof guildSchema> & Document;
export type UserType = z.infer<typeof userSchema> & Document;
export type BugType = z.infer<typeof bugSchema> & Document;
export type MediaType = z.infer<typeof mediaSchema> & Document;
// mongoose schemas
const GuildSchema = new Schema(
{
guild_id: { type: String, required: true, unique: true },
suggestion_forum: String,
bug_channel: String,
commands_channel: String,
highlights_channel: String,
manager_roles: [String],
},
{ timestamps: true },
);
const UserSchema = new Schema(
{
user_id: { type: String, required: true },
guild_id: { type: String, required: true, ref: "Guild" },
},
{ timestamps: true },
);
const BugSchema = new Schema(
{
bug_id: { type: Number, required: true, unique: true },
user_id: { type: String, required: true, ref: "User" },
status: { type: String, enum: ["open", "closed"], default: "open" },
title: { type: String, required: true },
game: { type: String, enum: ["wft", "gw", "ab"], required: true },
description: { type: String, required: true },
sent: { type: Boolean, default: false },
message_id: String,
thread_id: String,
},
{ timestamps: true },
);
const MediaSchema = new Schema(
{
media_type: { type: String, enum: ["image", "video"], required: true },
data: { type: Buffer, required: true },
user_id: { type: String, required: true, ref: "User" },
bug_id: { type: String, ref: "Bug" },
},
{ timestamps: true },
);
// compound indexes for better perf
UserSchema.index({ user_id: 1, guild_id: 1 }, { unique: true });
// models
export const GuildModel = model<GuildType>("Guild", GuildSchema);
export const UserModel = model<UserType>("User", UserSchema);
export const BugModel = model<BugType>("Bug", BugSchema);
export const MediaModel = model<MediaType>("Media", MediaSchema);
export const CounterModel = model("Counter", CounterSchema);
// funcs
export async function getNextBugId(): Promise<number> {
const counter = await CounterModel.findByIdAndUpdate(
"bug_id",
{ $inc: { sequence_value: 1 } },
{ new: true, upsert: true },
);
return counter.sequence_value;
}
|