@everytravel/shared
Version:
A comprehensive shared package for Everytravel containing Mongoose models and CRUD operations for hotel booking, user management, and transaction handling. Updated with improved model syntax and enhanced error handling.
103 lines (95 loc) • 5.03 kB
JavaScript
import mongoose from "mongoose";
const { Schema } = mongoose;
import {
arrayOfStringsSanitizer,
trimIfString,
} from '../validation/index.js';
/**
* Suite model for hotel properties.
*
* @typedef {Object} Suite
* @property {ObjectId} property - Reference to the Property.
* @property {String} roomType - Type of room (e.g., "suite", "apartment", "room").
* @property {Number} stars - Number of stars for the property.
* @property {Number} rating - Average rating of the suite.
* @property {ObjectId[]} reviews - References to Review documents.
* @property {Object} location - Location details (address, city, country, zipCode, coordinates).
* @property {Object} pricePerNight - Price per night details (from, to, currency).
* @property {Number} sizeSqMeters - Size of the suite in square meters.
* @property {Number} numBeds - Number of beds in the suite.
* @property {String} bedType - Type of bed (e.g., "king", "queen", "twin").
* @property {Number} availabilityCount - Number of available suites.
* @property {Number} sleeps - Number of people the suite can sleep.
* @property {Number} numBathrooms - Number of bathrooms in the suite.
* @property {String[]} features - Array of features (e.g., "wifi", "pool").
* @property {String[]} metaTags - Array of meta tags (e.g., "luxury", "budget").
*/
const SuiteSchema = new Schema({
property: { type: Schema.Types.ObjectId, ref: 'Property' },
roomType: {
type: String,
enum: ['suite', 'room'],
required: true,
},
stars: { type: Number, min: 0, max: 5 },// 1-5 stars will programmatically be set based on reviews
rating: { type: Number, min: 0, max: 5 },// 1-5 stars will programmatically be set based on reviews
reviews: [{ type: Schema.Types.ObjectId, ref: 'Review' }],
roomNumber: { type: String, set: trimIfString },// e.g. "101", "102", "103"
pricePerNight: {
from: { type: Number, min: 0 },// Minimum price per night
to: { type: Number, min: 0, validate: { validator(value) { return value == null || this.pricePerNight?.from == null || value >= this.pricePerNight.from; }, message: 'pricePerNight.to must be >= pricePerNight.from' } },// Maximum price per night
currency: { type: String, default: 'NGN' }// Currency of the price
},
sizeSqMeters: { type: Number, min: 0 },// Size of the suite in square meters
numBeds: { type: Number, min: 0 },// Number of beds in the suite
bedType: { type: String, set: trimIfString },// Type of bed (e.g., "king", "queen", "twin")
quantity: { type: Number, min: 0 },// Number of this particular suite in the property
availabilityCount: { type: Number, min: 0 },// Number of this particular suite that is available for booking
sleeps: { type: Number, min: 0 }, // should be compatible with guests number in Booking
numBathrooms: { type: Number, min: 0 },// Number of bathrooms in the suite
show: { type: Boolean, default: true },// Whether the suite is visible to the public
softDeleted: { type: Boolean, default: false },// Whether the suite is deleted (soft delete)
deletedAt: Date,// When the suite was deleted (for soft delete)
features: { type: [String], set: arrayOfStringsSanitizer },
metaTags: { type: [String], set: arrayOfStringsSanitizer },
refundPolicy: {
zero: {
name: { type: String, required: true },
description: String,
refundPercentage: { type: Number, default: 0 }
},
full: {
name: { type: String, required: true },
description: String,
refundPercentage: { type: Number, default: 100 }
},
partial: {
name: { type: String, required: true },
description: String,
refundPercentage: { type: Number, default: 75 }
}
},
images: [{
url: { type: String, set: trimIfString, validate: { validator: (v) => v === undefined || v === null || isNonEmptyString(v), message: 'images.url must be a non-empty string' } },
tags: { type: [String], set: arrayOfStringsSanitizer },
order: { type: Number, min: 0 },
isCover: { type: Boolean, default: false },
}],
});
// Indexes to optimize common queries
// - Public visibility filters
SuiteSchema.index({ show: 1, softDeleted: 1 });
// - Property scoping and soft-deletion checks
SuiteSchema.index({ property: 1, softDeleted: 1 });
// - Common filters and sorting keys
SuiteSchema.index({ roomType: 1 });
SuiteSchema.index({ 'pricePerNight.from': 1 });
SuiteSchema.index({ sizeSqMeters: 1 });
SuiteSchema.index({ numBeds: 1 });
SuiteSchema.index({ numBathrooms: 1 });
SuiteSchema.index({ sleeps: 1 });
SuiteSchema.index({ availabilityCount: 1 });
SuiteSchema.index({ metaTags: 1 }); // multikey
SuiteSchema.index({ features: 1 }); // multikey
const Suite = mongoose.model('Suite', SuiteSchema);
export default Suite;