UNPKG

@mnaufalhamdani/cores-backend

Version:

Shared core module with ESM for Node.js backend applications, providing utilities for MySQL operations with a focus on clean architecture principles.

228 lines (200 loc) 7.96 kB
import { DateTime } from 'luxon'; /** * Insert Data * @param {import('mysql2/promise').Connection} conn - koneksi mysql * @param {string} table - nama tabel * @param {Object} data - data {key-value} * @returns {Promise<import('mysql2/promise').OkPacket>} - hasil eksekusi query * @throws {Error} - jika terjadi kesalahan */ export const insertData = async (conn, table, data) => { try { const dateTimeUtc = DateTime.utc().toFormat('yyyy-MM-dd HH:mm:ss'); const payload = { ...data, created_at: dateTimeUtc, updated_at: dateTimeUtc }; const columns = Object.keys(payload).join(', '); const values = Object.values(payload).map(val => val === undefined ? null : val);; const placeholders = Object.keys(payload).map(() => '?').join(', '); const updateClause = Object.keys(payload) .filter(element => element !== 'created_at') .map(element => `${element} = VALUES(${element})`) .join(', '); const sql = `INSERT INTO ${table} (${columns}) VALUES (${placeholders}) ON DUPLICATE KEY UPDATE ${updateClause}`; const [result] = await conn.execute(sql, values); // @ts-ignore return result; }catch (error) { console.error('Error in insertData:', error); throw error; } }; /** * Update Data * @param {import('mysql2/promise').Connection} conn - koneksi mysql * @param {string} table - nama tabel * @param {Object} whereClause - kondisi untuk update {key-value} * @param {Object} data - data {key-value} * @returns {Promise<import('mysql2/promise').OkPacket>} - hasil eksekusi query * @throws {Error} - jika terjadi kesalahan */ export const updateData = async (conn, table, whereClause, data) => { try { const dateTimeUtc = DateTime.utc().toFormat('yyyy-MM-dd HH:mm:ss'); const payload = { ...data, updated_at: dateTimeUtc }; const safeValues = arr => arr.map(v => (typeof v === 'undefined' ? null : v)); const setClause = Object.keys(payload).map(col => `${col} = ?`).join(', '); const whereStr = Object.keys(whereClause).map(col => `${col} = ?`).join(' AND '); const sql = `UPDATE ${table} SET ${setClause} WHERE ${whereStr}`; const params = safeValues([...Object.values(payload), ...Object.values(whereClause)]); const [result] = await conn.execute(sql, params); // @ts-ignore return result.affectedRows; }catch (error) { console.error('Error in updateData:', error); throw error; } }; /** * Update Data with WHERE IN * @param {import('mysql2/promise').Connection} conn * @param {string} table * @param {{ [key: string]: Array<any> }} whereIn * @param {Object} data * @param {Object} [extraWhere] * @returns {Promise<number>} affected rows */ export const updateDataWhereIn = async ( conn, table, whereIn, data, extraWhere = {} ) => { try { const dateTimeUtc = DateTime.utc().toFormat('yyyy-MM-dd HH:mm:ss'); const payload = { ...data, updated_at: dateTimeUtc }; const safeValues = arr => arr.map(v => (typeof v === 'undefined' ? null : v)); /* ======================= * SET CLAUSE * ======================= */ const setClause = Object.keys(payload) .map(col => `${col} = ?`) .join(', '); /* ======================= * WHERE IN CLAUSE * ======================= */ const whereInEntries = Object.entries(whereIn); if (!whereInEntries.length) { throw new Error('whereIn tidak boleh kosong'); } const whereInClause = whereInEntries .map(([col, values]) => { if (!Array.isArray(values) || !values.length) { throw new Error(`whereIn.${col} harus berupa array dan tidak kosong`); } const placeholders = values.map(() => '?').join(', '); return `${col} IN (${placeholders})`; }) .join(' AND '); /* ======================= * EXTRA WHERE (=) * ======================= */ const extraClause = Object.keys(extraWhere) .map(col => `${col} = ?`) .join(' AND '); const whereClause = [ whereInClause, extraClause ].filter(Boolean).join(' AND '); const sql = `UPDATE ${table} SET ${setClause} WHERE ${whereClause}`; /* ======================= * PARAMS ORDER * ======================= */ const params = safeValues([ ...Object.values(payload), ...whereInEntries.flatMap(([, values]) => values), ...Object.values(extraWhere) ]); const [result] = await conn.execute(sql, params); // @ts-ignore return result.affectedRows; } catch (error) { console.error('Error in updateDataWhereIn:', error); throw error; } }; /** * Delete Data * @param {import('mysql2/promise').Connection} conn - koneksi mysql * @param {string} table - nama tabel * @param {Object} whereClause - kondisi untuk update {key-value} * @returns {Promise<import('mysql2/promise').OkPacket>} - hasil eksekusi query * @throws {Error} - jika terjadi kesalahan */ export const deleteData = async (conn, table, whereClause) => { try { // Cek kolom mana yang undefined const undefinedKeys = Object.entries(whereClause) .filter(([_, value]) => value === undefined) .map(([key]) => key); if (undefinedKeys.length > 0) { throw { status: 403, message: `Invalid column [${undefinedKeys.join(', ')}]` }; } const whereStr = Object.keys(whereClause).map(col => `${col} = ?`).join(' AND '); const sql = `DELETE FROM ${table} WHERE ${whereStr}`; const [result] = await conn.execute(sql, Object.values(whereClause)); // @ts-ignore return result.affectedRows; }catch (error) { console.error('Error in deleteData:', error); throw error; } }; /** * Generate kode unik berdasarkan pengecekan data yang sudah ada * @param {import('mysql2/promise').Connection} db - koneksi mysql * @param {string} tableName - nama tabel * @param {Object} [options] - nama kolom yang digunakan untuk pengecekan {key} * @returns {Promise<import('mysql2/promise').OkPacket>} - hasil eksekusi query * @throws {Error} - jika terjadi kesalahan */ export const generateCode = async (db, tableName, options = {}) => { const { id = 'id' } = options; const date = DateTime.utc().toFormat('yyMMdd'); // 'yymmdd' const datePart = date; // misal: '250620' let total = 0; // Hitung jumlah data yang mengandung awalan tanggal (misalnya '250620') let [rows] = await db.query( `SELECT COALESCE(COUNT(${id}), 0) AS count FROM ${tableName} WHERE ${id} LIKE ? LIMIT 1`, [`${datePart}%`] ); if (rows[0].count > 0) { // Ambil ID terakhir (terbesar) yang mengandung tanggal hari ini const [lastRow] = await db.query( `SELECT ${id} FROM ${tableName} WHERE ${id} LIKE ? ORDER BY ${id} DESC LIMIT 1`, [`${datePart}%`] ); const lastId = lastRow[0][id].toString(); total = parseInt(lastId.slice(-4), 10); // ambil 4 digit terakhir } const newCode = `${datePart}${String(total + 1).padStart(4, '0')}`; // @ts-ignore return newCode; }; /** * Generate urutan angka berdasarkan pengecekan data yang sudah ada * @param {import('mysql2/promise').Connection} db - koneksi mysql * @param {string} tableName - nama tabel * @param {string} columnName - nama kolom yang digunakan untuk pengecekan * @param {string} id - nilai ID yang digunakan untuk pengecekan * @returns {Promise<import('mysql2/promise').OkPacket>} - hasil eksekusi query * @throws {Error} - jika terjadi kesalahan */ export const generateUrutan = async (db, tableName, columnName, id) => { const [rows] = await db.query(` SELECT COALESCE(COUNT(${columnName}), 0) AS count FROM ${tableName} WHERE ${columnName} = ? FOR UPDATE `, [id]); const urutan = (rows[0]?.count || 0) + 1; return urutan; };