UNPKG

@sehirapp/core-microservice

Version:

Modern mikroservis core paketi - MongoDB 6.7, Express API, Mongoose, PM2 cluster desteği

247 lines (215 loc) 8.17 kB
/** * Database Utilities - Core mikroservisler için ortak DB işlemleri * Modern Mongoose + native MongoDB desteği */ /** * Filtrelerle kayıt sayısı alma - tekrarlanan ensureConnection + getMongooseModel + countDocuments pattern'ini değiştirir * @param {CoreClass} modelInstance - Model instance'ı * @param {Object} filters - MongoDB filtreleri * @returns {Promise<number>} Toplam kayıt sayısı */ export const countWithFilters = async (modelInstance, filters = {}) => { try { await modelInstance.ensureConnection(); if (modelInstance._useMongoose) { const Model = modelInstance.getMongooseModel(); return await Model.countDocuments(filters); } else { return await modelInstance.dbManager.count(modelInstance.Collection(), filters); } } catch (error) { throw new Error(`Count operation failed: ${error.message}`); } }; /** * Pagination bilgilerini hesapla * @param {number} page - Sayfa numarası (1'den başlar) * @param {number} limit - Sayfa başına kayıt sayısı * @param {number} total - Toplam kayıt sayısı * @returns {Object} Pagination bilgileri */ export const paginateResults = (page, limit, total) => { const currentPage = parseInt(page) || 1; const pageLimit = parseInt(limit) || 20; const totalCount = parseInt(total) || 0; const pages = Math.ceil(totalCount / pageLimit); return { page: currentPage, limit: pageLimit, total: totalCount, pages: pages, hasNext: currentPage < pages, hasPrev: currentPage > 1, skip: (currentPage - 1) * pageLimit, // Ek bilgiler startRecord: totalCount > 0 ? ((currentPage - 1) * pageLimit) + 1 : 0, endRecord: Math.min(currentPage * pageLimit, totalCount), isEmpty: totalCount === 0 }; }; /** * Arama query'si oluşturucu - çoklu alan arama için * @param {string} searchTerm - Aranacak terim * @param {Array<string>} fields - Aranacak alanlar * @param {Object} options - Arama seçenekleri * @returns {Object} MongoDB $or query'si */ export const generateSearchQuery = (searchTerm, fields = [], options = {}) => { if (!searchTerm || !fields.length) { return {}; } const { caseSensitive = false, exactMatch = false, wordBoundary = false } = options; let searchPattern = searchTerm; // Özel karakterleri escape et searchPattern = searchPattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); if (exactMatch) { searchPattern = `^${searchPattern}$`; } else if (wordBoundary) { searchPattern = `\\b${searchPattern}\\b`; } const searchOptions = caseSensitive ? '' : 'i'; const searchRegex = new RegExp(searchPattern, searchOptions); return { $or: fields.map(field => ({ [field]: searchRegex })) }; }; /** * Gelişmiş filtreleme query'si oluşturucu * @param {Object} queryParams - Request query parametreleri * @param {Object} fieldMappings - Alan tipleri ve konfigürasyon * @returns {Object} MongoDB query objesi */ export const buildAdvancedFilter = (queryParams, fieldMappings = {}) => { const filters = {}; Object.keys(queryParams).forEach(key => { const value = queryParams[key]; if (value === undefined || value === null || value === '') return; const fieldConfig = fieldMappings[key] || { type: 'string' }; switch (fieldConfig.type) { case 'string': if (fieldConfig.exact) { filters[key] = value; } else { filters[key] = { $regex: value, $options: 'i' }; } break; case 'number': const numValue = Number(value); if (!isNaN(numValue)) { filters[key] = numValue; } break; case 'range': const rangeFilter = {}; if (queryParams[`${key}_min`]) { rangeFilter.$gte = Number(queryParams[`${key}_min`]); } if (queryParams[`${key}_max`]) { rangeFilter.$lte = Number(queryParams[`${key}_max`]); } if (Object.keys(rangeFilter).length > 0) { filters[key] = rangeFilter; } break; case 'date': if (queryParams[`${key}_from`]) { filters[key] = filters[key] || {}; filters[key].$gte = new Date(queryParams[`${key}_from`]).getTime(); } if (queryParams[`${key}_to`]) { filters[key] = filters[key] || {}; filters[key].$lte = new Date(queryParams[`${key}_to`]).getTime(); } break; case 'array': if (Array.isArray(value)) { filters[key] = { $in: value }; } else if (typeof value === 'string') { filters[key] = { $in: value.split(',') }; } break; case 'boolean': if (value === 'true' || value === '1') { filters[key] = true; } else if (value === 'false' || value === '0') { filters[key] = false; } break; } }); return filters; }; /** * Toplu güncelleme işlemi * @param {CoreClass} modelInstance - Model instance'ı * @param {Array} updates - Güncelleme listesi [{filter, data}, ...] * @param {Object} options - Seçenekler * @returns {Promise<Object>} İşlem sonuçları */ export const bulkUpdate = async (modelInstance, updates, options = {}) => { const { ordered = false, validateBeforeUpdate = true } = options; try { await modelInstance.ensureConnection(); if (modelInstance._useMongoose) { const Model = modelInstance.getMongooseModel(); const bulkOps = updates.map(update => ({ updateOne: { filter: update.filter, update: { ...update.data, updatedAt: Date.now() } } })); return await Model.bulkWrite(bulkOps, { ordered }); } else { // Native MongoDB bulk operations const results = { success: [], failed: [] }; for (const update of updates) { try { const result = await modelInstance.dbManager.update( modelInstance.Collection(), update.filter, { ...update.data, updatedAt: Date.now() } ); results.success.push({ filter: update.filter, result }); } catch (error) { results.failed.push({ filter: update.filter, error: error.message }); } } return results; } } catch (error) { throw new Error(`Bulk update failed: ${error.message}`); } }; /** * Aggregation pipeline yardımcısı * @param {CoreClass} modelInstance - Model instance'ı * @param {Array} pipeline - Aggregation pipeline * @returns {Promise<Array>} Aggregation sonuçları */ export const aggregateData = async (modelInstance, pipeline) => { try { await modelInstance.ensureConnection(); if (modelInstance._useMongoose) { const Model = modelInstance.getMongooseModel(); return await Model.aggregate(pipeline); } else { return await modelInstance.dbManager.aggregate(modelInstance.Collection(), pipeline); } } catch (error) { throw new Error(`Aggregation failed: ${error.message}`); } }; // Tüm utility fonksiyonları dışa aktar export const dbUtils = { countWithFilters, paginateResults, generateSearchQuery, buildAdvancedFilter, bulkUpdate, aggregateData }; export default dbUtils;