- 
                Notifications
    You must be signed in to change notification settings 
- Fork 0
Implement Database models #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| WalkthroughAdds Mongoose-backed Event and Booking models with schemas, validations, pre-save hooks, indexes, and timestamps; a cached MongoDB connection utility; a barrel export for models; and adds mongoose and slugify dependencies. Changes
 Sequence Diagram(s)sequenceDiagram
    participant App
    participant connectDB
    participant Cache as Global Cache
    participant Mongoose as mongoose.connect()
    participant MongoDB
    App->>connectDB: call connectDB()
    alt cached.conn exists
        connectDB->>Cache: return cached.conn
        connectDB-->>App: connection
    else
        connectDB->>Cache: check cached.promise
        alt promise pending
            Cache-->>connectDB: return cached.promise
            connectDB-->>App: promise
        else
            connectDB->>Mongoose: mongoose.connect(MONGODB_URI, {bufferCommands:false})
            Mongoose->>MongoDB: establish connection
            Mongoose-->>Cache: store conn & promise
            Mongoose-->>App: connection
        end
    end
sequenceDiagram
    participant Client
    participant BookingModel as Booking.create()
    participant PreSaveHook as Booking pre-save
    participant EventModel as Event.findById()
    participant DB
    Client->>BookingModel: create booking with eventId
    BookingModel->>PreSaveHook: trigger pre-save
    PreSaveHook->>EventModel: findById(eventId)
    EventModel->>DB: query by id
    alt event found
        DB-->>EventModel: event
        EventModel-->>PreSaveHook: exists
        PreSaveHook-->>BookingModel: allow save
    else not found
        DB-->>EventModel: null
        EventModel-->>PreSaveHook: throw "Event not found"
        PreSaveHook-->>Client: validation error
    end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 
 Poem
 Pre-merge checks and finishing touches❌ Failed checks (1 warning)
 ✅ Passed checks (2 passed)
 ✨ Finishing touches
 🧪 Generate unit tests (beta)
 📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
 🚧 Files skipped from review as they are similar to previous changes (1)
 Comment  | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (5)
package.json (1)
15-15: Mongoose/slugify additions look fine; verify TS types and Node engine.
- Check that slugify ships types in 1.6.6 in your toolchain; if not, add @types/slugify.
- Consider adding "engines": { "node": ">=18" } to reflect Next 16 + Mongoose 8 runtime expectations.
Also applies to: 22-22
lib/mongodb.ts (1)
36-53: Annotate return type and add a conservative serverSelection timeout.Small hardening and clarity:
-async function connectDB() { +async function connectDB(): Promise<Mongoose> { @@ - const opts = { - bufferCommands: false, - }; + const opts = { + bufferCommands: false, + serverSelectionTimeoutMS: 5000, + } as const;If you run on any Edge runtime, ensure routes using this import specify runtime: "nodejs".
database/booking.model.ts (1)
1-1: Tighten typing and uniqueness on bookings.
- Use Types.ObjectId for stronger typing.
- Normalize email and prevent duplicate bookings per event/email with a compound unique index.
Apply this diff:
-import { Schema, model, models, Document } from "mongoose"; +import { Schema, model, models, Document, Types } from "mongoose"; @@ export interface IBooking extends Document { - eventId: Schema.Types.ObjectId; + eventId: Types.ObjectId; email: string; createdAt: Date; updatedAt: Date; } @@ - eventId: { - type: Schema.Types.ObjectId, + eventId: { + type: Types.ObjectId, ref: "Event", required: [true, "Event ID is required"], }, email: { type: String, required: [true, "Email is required"], - match: [/.+\@.+\..+/, "Please enter a valid email address"], + match: [/.+\@.+\..+/, "Please enter a valid email address"], + lowercase: true, + trim: true, }, @@ -// Add an index on eventId for faster queries -bookingSchema.index({ eventId: 1 }); +// Prevent duplicate bookings for the same event/email +bookingSchema.index({ eventId: 1, email: 1 }, { unique: true });Also applies to: 6-7, 14-23, 41-42
database/event.model.ts (1)
51-55: Consider handling slug collisions and non‑latin titles.Optional improvements:
- If slugify yields an empty string, fall back to a safe token.
- Ensure uniqueness by appending a counter when a slug already exists.
I can provide a concise async pre hook snippet to handle collisions if you want it in this PR.
database/index.ts (1)
1-4: LGTM; optionally re‑export model types for ergonomics.Add type exports so consumers can import from a single barrel.
export { Event, Booking }; +export type { IEvent } from "./event.model"; +export type { IBooking } from "./booking.model";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
- package-lock.jsonis excluded by- !**/package-lock.json
📒 Files selected for processing (5)
- database/booking.model.ts(1 hunks)
- database/event.model.ts(1 hunks)
- database/index.ts(1 hunks)
- lib/mongodb.ts(1 hunks)
- package.json(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
database/event.model.ts (1)
database/index.ts (1)
Event(4-4)
database/booking.model.ts (1)
database/index.ts (2)
Event(4-4)
Booking(4-4)
🪛 Biome (2.1.2)
lib/mongodb.ts
[error] 24-24: Shouldn't redeclare 'mongoose'. Consider to delete it or rename it.
'mongoose' is defined here:
(lint/suspicious/noRedeclare)
| const eventSchema = new Schema<IEvent>( | ||
| { | ||
| title: { type: String, required: [true, "Title is required"] }, | ||
| slug: { type: String, unique: true }, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate/conflicting slug index (will error at index build).
You already define slug with unique: true. Adding a separate non‑unique index with the same key conflicts and may fail deployment.
Apply this diff:
-// Add a unique index to the slug field for faster queries
-eventSchema.index({ slug: 1 });Also applies to: 66-67
🤖 Prompt for AI Agents
In database/event.model.ts around lines 27 and 66-67, a duplicate/conflicting
index for the slug field is being created: slug is already defined with unique:
true on the schema property and a separate non-unique index is also added, which
will conflict at index build. Remove the separate index declaration (the
additional index call for slug at lines 66-67) so the schema relies on the
unique: true property only, or alternatively remove unique: true and keep a
single index declaration — ensure only one index definition for slug remains to
avoid index conflicts.
| // Validate and normalize the date to ISO format | ||
| if (this.date) { | ||
| const isoDate = new Date(this.date).toISOString(); | ||
| this.date = isoDate; | ||
| } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard against invalid dates and only normalize when modified.
-  // Validate and normalize the date to ISO format
-  if (this.date) {
-    const isoDate = new Date(this.date).toISOString();
-    this.date = isoDate;
-  }
+  // Validate and normalize the date to ISO format
+  if (this.isModified("date") && this.date) {
+    const d = new Date(this.date);
+    if (Number.isNaN(d.getTime())) {
+      return next(new Error("Invalid date"));
+    }
+    this.date = d.toISOString();
+  }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In database/event.model.ts around lines 57 to 61, the code always converts
this.date to ISO without checking validity or whether the field was modified;
change it to first check that the document's date field was modified (e.g.,
this.isModified('date')) and only then attempt normalization, and before
assigning run a validity check (e.g., create a Date and ensure
!isNaN(date.getTime()) or use Date.parse) so you only set this.date = isoString
when the input is a valid date; if invalid, leave the field unchanged or set a
validation error as appropriate.
| // Extend NodeJS.Global to include mongoose property | ||
| declare global { | ||
| // eslint-disable-next-line no-var | ||
| var mongoose: MongooseCache | undefined; | ||
| } | ||
|  | ||
| let cached: MongooseCache = global.mongoose ?? { conn: null, promise: null }; | ||
|  | ||
| if (!cached) { | ||
| cached = (global as typeof globalThis).mongoose = { | ||
| conn: null, | ||
| promise: null, | ||
| }; | ||
| } | ||
|  | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix global cache name and ensure it’s actually persisted across reloads.
- noRedeclare: global var name ‘mongoose’ collides with the imported symbol.
- Bug: when global.mongoose is undefined, you create a local object but never attach it back to global, so hot‑reload caching won’t work.
Apply this diff:
-// Extend NodeJS.Global to include mongoose property
-declare global {
-  // eslint-disable-next-line no-var
-  var mongoose: MongooseCache | undefined;
-}
-
-let cached: MongooseCache = global.mongoose ?? { conn: null, promise: null };
-
-if (!cached) {
-  cached = (global as typeof globalThis).mongoose = {
-    conn: null,
-    promise: null,
-  };
-}
+// Extend global to include a dedicated mongoose cache property
+declare global {
+  // eslint-disable-next-line no-var
+  var mongooseCache: MongooseCache | undefined;
+}
+
+const globalForMongoose = global as unknown as { mongooseCache?: MongooseCache };
+if (!globalForMongoose.mongooseCache) {
+  globalForMongoose.mongooseCache = { conn: null, promise: null };
+}
+const cached = globalForMongoose.mongooseCache!;🧰 Tools
🪛 Biome (2.1.2)
[error] 24-24: Shouldn't redeclare 'mongoose'. Consider to delete it or rename it.
'mongoose' is defined here:
(lint/suspicious/noRedeclare)
| Note Docstrings generation - SUCCESS | 
Docstrings generation was requested by @ailearningguy. * #3 (comment) The following files were modified: * `lib/mongodb.ts`
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Summary by CodeRabbit
New Features
Chores