UNPKG

maggie-api

Version:

🧙‍♀️ A magical Express middleware to auto-generate CRUD APIs for Mongoose models with validation, unique keys, and middlewares.

184 lines (183 loc) 8.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.insertMany = exports.getById = exports.getAll = exports.deleteById = exports.updateDoc = exports.createDoc = void 0; const qs_1 = require("qs"); const url_1 = require("url"); const common_1 = require("../utils/common"); const createDoc = (model, data) => __awaiter(void 0, void 0, void 0, function* () { return yield model.create(data); }); exports.createDoc = createDoc; const updateDoc = (model, data) => __awaiter(void 0, void 0, void 0, function* () { if (!data._id) throw new Error("Missing _id for update"); return yield model.findByIdAndUpdate(data._id, data, { new: true }); }); exports.updateDoc = updateDoc; const deleteById = (model, id) => __awaiter(void 0, void 0, void 0, function* () { return yield model.findByIdAndDelete(id); }); exports.deleteById = deleteById; const getAll = (model, settings, req) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f, _g, _h, _j; try { let query = model.find(); // Use qs to parse nested query params like filter[price][gte] const url = new url_1.URL(req.originalUrl, `http://${req.headers.host}`); const queryParams = (0, qs_1.parse)(url.searchParams.toString()); // 1️⃣ FIELD SELECTION if ((_a = settings.getKeys) === null || _a === void 0 ? void 0 : _a.length) { query = query.select(settings.getKeys.join(" ")); } // 2️⃣ FILTERING const rawFilter = queryParams.filter; const allowedFilterFields = ((_c = (_b = settings.get) === null || _b === void 0 ? void 0 : _b.filter) === null || _c === void 0 ? void 0 : _c.allowedFields) || []; if (rawFilter && typeof rawFilter === "object") { const filterConditions = {}; for (const [field, value] of Object.entries(rawFilter)) { if (!allowedFilterFields.includes(field)) continue; if (typeof value === "object" && !Array.isArray(value)) { const rangeQuery = {}; for (const [op, val] of Object.entries(value)) { if (["gte", "lte", "gt", "lt"].includes(op)) { rangeQuery[`$${op}`] = val; } } filterConditions[field] = rangeQuery; } else if (Array.isArray(value)) { filterConditions[field] = { $in: value }; } else { filterConditions[field] = value; } } if (Object.keys(filterConditions).length > 0) { query = query.find(filterConditions); } } // 3️⃣ SEARCH const searchKeyword = queryParams.search; const caseSensitive = queryParams.caseSensitive === "true"; const searchFieldsFromQuery = (_d = queryParams.searchFields) === null || _d === void 0 ? void 0 : _d.split(",").map((f) => f.trim()); const searchConfig = (_e = settings.get) === null || _e === void 0 ? void 0 : _e.search; const isSearchDisabled = (searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.disabled) === true; if (!isSearchDisabled && typeof searchKeyword === "string" && searchKeyword.trim()) { let finalSearchFields = []; if (searchFieldsFromQuery === null || searchFieldsFromQuery === void 0 ? void 0 : searchFieldsFromQuery.length) { finalSearchFields = ((_f = searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.allowedFields) === null || _f === void 0 ? void 0 : _f.length) ? searchFieldsFromQuery.filter((field) => searchConfig.allowedFields.includes(field)) : searchFieldsFromQuery; } if (!finalSearchFields.length && ((_g = searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.allowedFields) === null || _g === void 0 ? void 0 : _g.length)) { finalSearchFields = searchConfig.allowedFields; } if (finalSearchFields.length) { const regex = new RegExp(searchKeyword, caseSensitive ? "" : "i"); const searchConditions = finalSearchFields.map((field) => ({ [field]: regex, })); query = query.find({ $or: searchConditions }); } else { console.warn("⚠️ Search skipped: No valid searchable fields found."); } } // 4️⃣ POPULATE if ((_j = (_h = settings.get) === null || _h === void 0 ? void 0 : _h.populate) === null || _j === void 0 ? void 0 : _j.length) { for (const pop of settings.get.populate) { query = query.populate(pop); } } // 5️⃣ SORTING const sortParam = queryParams.sort; if (sortParam) { const sortFields = sortParam .split(",") .map((field) => field.trim()) .filter((field) => field.length > 0) .reduce((acc, field) => { if (field.startsWith("-")) { acc[field.slice(1)] = -1; } else { acc[field] = 1; } return acc; }, {}); query = query.sort(sortFields); } let results; let pagination = null; const limit = parseInt(queryParams.limit); const page = parseInt(queryParams.page); const isPaginate = !isNaN(limit) && limit > 0 && !isNaN(page) && page > 0; if (isPaginate) { const skip = (page - 1) * limit; query = query.skip(skip).limit(limit); const totalDocs = yield model.countDocuments(query.getQuery()); results = yield query.exec(); pagination = { total: totalDocs, page, limit, totalPages: Math.ceil(totalDocs / limit), }; } else { results = yield query.exec(); } const responseKeyName = (0, common_1.singularToPlural)(model.modelName.toLowerCase()); return pagination ? { [responseKeyName]: results, pagination } : { [responseKeyName]: results }; } catch (error) { console.error("Error in getAll:", error); throw error; } }); exports.getAll = getAll; const getById = (model, id, settings) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b, _c; try { let query = model.findById(id); // Select specific fields if ((_a = settings.getByIdKeys) === null || _a === void 0 ? void 0 : _a.length) { query = query.select(settings.getByIdKeys.join(" ")); } // Populate fields if defined if ((_c = (_b = settings.getById) === null || _b === void 0 ? void 0 : _b.populate) === null || _c === void 0 ? void 0 : _c.length) { for (const pop of settings.getById.populate) { query = query.populate(pop); } } const result = yield query.exec(); return result; } catch (error) { console.error("Error in getById:", error); throw error; } }); exports.getById = getById; // 🔹 insertMany service const insertMany = (model, docs) => __awaiter(void 0, void 0, void 0, function* () { if (!Array.isArray(docs)) { throw new Error("insertMany expects an array of documents"); } return yield model.insertMany(docs); }); exports.insertMany = insertMany;