nagasql
v1.0.3
Published
Lightweight SQL Loader & Query Manager for Node.js
Maintainers
Readme
🐉 NagaSQL
Lightweight SQL Loader & Query Manager for Node.js
โหลดไฟล์ .sql มาใช้งานแบบ dynamic พร้อม parameter, condition และ callback logic
🚀 Basic Usage
const mysql = require('mysql2');
const NagaSQL = require('nagasql');
const db = new NagaSQL({
mysql,
config: {
host: 'localhost',
user: 'root',
password: '',
database: 'test'
},
path: __dirname + '/sql',
debug: true,
log: true
});📂 Folder Structure
project/
│
├── sql/
│ ├── getUser.sql
│ ├── listUsers.sql
│ └── createUser.sql
│
└── app.js🧾 Writing SQL Files
1. Basic Query
SELECT * FROM users WHERE id = :id;Usage
await db.use('getUser', { id: 1 });2. Array Parameter
SELECT * FROM users WHERE id IN (:[ids]);await db.use('listUsers', { ids: [1,2,3] });3. Conditional SQL
SELECT * FROM users
WHERE 1=1
$role{ AND role = :role }{ }await db.use('listUsers', { role: 'admin' });- ถ้ามี
role→ จะเพิ่มเงื่อนไข - ถ้าไม่มี → จะไม่เพิ่ม
4. Choice SQL
ใช้ $name{key:{value}, $:{default}} เพื่อเลือก SQL fragment จากค่าที่ส่งเข้ามา เหมาะกับค่าที่ bind parameter ไม่ได้ เช่น column name หรือ ORDER BY
SELECT * FROM `store`
ORDER BY $order_key{id:{id}, name:{`name`}, user:{user}, $:{id}}
$order_type{$:{ASC}, asc:{ASC}, desc:{DESC}}await db.use('listStore', {
order_key: 'name',
order_type: 'asc'
});จะได้ SQL:
SELECT * FROM `store` ORDER BY `name` ASCถ้าไม่ส่งค่า และมี $:{...} จะใช้ default:
await db.use('listStore', {});SELECT * FROM `store` ORDER BY id ASCถ้าไม่มี $:{...} และค่าที่ส่งมาไม่ตรงกับ key ใดเลย จะคืน false และไม่ส่ง SQL ไปที่ server
value ใน {...} รองรับช่องว่างและ SQL expression ได้ เช่น:
SELECT * FROM `users`
ORDER BY $order_by{id:{ `users`.`id` ASC }, name:{ `users`.`name` DESC }, $:{ `users`.`id` ASC }}5. Join SQL
ใช้ $(separator)[key:{sql},key:{sql}] เพื่อประกอบ SQL หลายเงื่อนไขจาก key ที่มีใน data แล้ว join ด้วย separator ที่กำหนด
ใส่ $:{sql} เพื่อเป็น default fragment เมื่อไม่มี key ไหนตรงกับ data
SELECT * FROM `users`
WHERE $( AND )[id:{id = :id}, user:{`user` LIKE :user}, status:{status = :status}]await db.use('listUsers', { id: 1 });จะได้ SQL:
SELECT * FROM `users` WHERE id = 1await db.use('listUsers', { id: 1, user: 'a' });จะได้ SQL:
SELECT * FROM `users` WHERE id = 1 AND `user` LIKE 'a'ถ้าไม่มี key ที่ตรงกัน ระบบจะลบ WHERE ท้าย query ออก:
await db.use('listUsers', {});SELECT * FROM `users`ถ้าต้องการ default ตอน data ว่าง:
SELECT * FROM `users`
WHERE $( AND )[id:{id = :id}, user:{`user` LIKE :user}, status:{status = :status}, $:{id = 1}]await db.use('listUsers', {});SELECT * FROM `users` WHERE id = 1ใช้กับ SET ได้เหมือนกัน:
UPDATE `users`
SET $(,)[id:{id = :id}, status:{status = :status}]await db.use('updateUser', { id: 1, status: 1 });จะได้ SQL:
UPDATE `users` SET id = 1,status = 1🧠 Special Comments (Magic Directives)
ใช้ comment แบบพิเศษเพื่อควบคุมผลลัพธ์ของ query
Supported Compare Operators
ใช้กับ directive ที่ต้องตรวจค่า เช่น length, affectedRows, changedRows, serverStatus
| Syntax | Meaning |
|--------|---------|
| {=1} | เท่ากับ 1 |
| {>0} | มากกว่า 0 |
| {<5} | น้อยกว่า 5 |
| {[5} | น้อยกว่าหรือเท่ากับ 5 |
| {]1} | มากกว่าหรือเท่ากับ 1 |
| {!0} | ไม่เท่ากับ 0 |
🔹 Return Only One Row
/* [R938.one] {} */
SELECT * FROM users WHERE id = :id;const user = await db.use('getUser', { id: 1 });🔹 Check Length
/* [R938.length] {>0} */
SELECT * FROM users;>0→ ต้องมีข้อมูลอย่างน้อย 1 row=1→ ต้องมี 1 row เท่านั้น
🔹 Check affectedRows / affect
/* [R938.affectedRows] {>0} */
INSERT INTO users(name) VALUES(:name);const success = await db.use('createUser', { name: 'John' });ใช้ alias ได้:
/* [R938.affect] {>0} */
INSERT INTO users(name) VALUES(:name);คืนค่า true เมื่อ affectedRows ผ่านเงื่อนไข ไม่ผ่านจะคืน false
🔹 Check changedRows / change
/* [R938.changedRows] {>0} */
UPDATE users SET name = :name WHERE id = :id;const changed = await db.use('updateUser', { id: 1, name: 'John' });ใช้ alias ได้:
/* [R938.change] {>0} */
UPDATE users SET name = :name WHERE id = :id;คืนค่า true เมื่อ changedRows ผ่านเงื่อนไข ไม่ผ่านจะคืน false
🔹 Check serverStatus / status
/* [R938.serverStatus] {>0} */
UPDATE users SET name = :name WHERE id = :id;ใช้ alias ได้:
/* [R938.status] {>0} */
UPDATE users SET name = :name WHERE id = :id;คืนค่า true เมื่อ serverStatus ผ่านเงื่อนไข ไม่ผ่านจะคืน false
🔹 Return insertId / id
/* [R938.insertId] {} */
INSERT INTO users(name) VALUES(:name);const id = await db.use('createUser', { name: 'John' });ใช้ alias ได้:
/* [R938.id] {} */
INSERT INTO users(name) VALUES(:name);คืนค่า insertId เมื่อ insert สำเร็จ ไม่สำเร็จจะคืน false
🔹 Custom Callback
/* [R938.callback] {
if(data && data.length){
return data.map(d => d.name);
}
return [];
} */
SELECT * FROM users;🔹 Custom Parameter Logic
/* [R938.parameter] {
return data.filter(d => d.active);
} */🔐 Parameter Types
| Syntax | Description |
|-----------|--------------------|
| :id | string / number |
| :[ids] | array |
| $id{key:{value},$:{default}} | เลือก SQL fragment จาก key ที่กำหนดไว้ |
| $(separator)[key:{sql},$:{default}] | รวม SQL fragment ตาม key ที่มีใน data และใช้ $ เป็น default |
⚙️ Debug Mode
const db = new NagaSQL({
mysql,
config,
path: './sql',
debug: true
});Output
[R938.SQL.debug.use] Query(getUser): SELECT ...🧪 Full Example
SQL (sql/getUser.sql)
/* [R938.one] {} */
SELECT * FROM users WHERE id = :id;SQL (sql/listUsers.sql)
SELECT * FROM users
WHERE 1=1
$status{ AND status = :status }{ }JS
(async () => {
const user = await db.use('getUser', { id: 1 });
console.log(user);
const users = await db.use('listUsers', { status: 'active' });
console.log(users);
})();❗ Notes
.sqlfilename = function name- Duplicate filename จะถูก ignore
- Query ถูก compile เป็น function เพื่อเพิ่ม performance
💡 Tips
- แยก SQL ตาม feature → maintain ง่าย
- ใช้ conditional → ลด query ซ้ำ
- ใช้ callback ใน SQL → ลด logic ฝั่ง JS
