ต่อฐานข้อมูลและไฟล์ ด้วยชุดเครื่องมือเดียว
CKN Data คือชั้นเข้าถึงข้อมูลของ framework ที่ให้ทีมพัฒนาใช้ฐานข้อมูล 6 ชนิด ไฟล์ Excel, Word, CSV และ pipeline ผ่าน API ชุดเดียวกัน ทีมเรียนรู้ครั้งเดียว ย้ายระบบได้ง่าย และไม่ต้องพึ่งไลบรารีภายนอกหลายตัวที่ต้องคอยตามอัปเดต
สิ่งที่ CKN Data ทำได้
ฐานข้อมูลทุกชนิด ใช้วิธีเดียว
MySQL, PostgreSQL, Oracle, SQL Server, MongoDB และ Firestore ใช้คำสั่งชุดเดียวกัน ระบบเปลี่ยนฐานข้อมูลได้โดยแก้โค้ดน้อยที่สุด และ driver โหลดเมื่อเชื่อมต่อจริงเท่านั้น
- query, insert, update, delete, count, upsert
- ตรวจความสามารถของแต่ละฐานข้อมูลได้ด้วย capabilities
- ตั้งขนาด connection pool ได้ทุก adapter
- ปกป้องจาก SQL injection ด้วย parameterized query
Transaction ที่ปลอดภัยโดยดีฟอลต์
คำสั่งที่อยู่ในบล็อก transaction จะอยู่ใน transaction เดียวกันโดยอัตโนมัติ แม้เรียกผ่านฟังก์ชันอื่น ถ้าเกิดข้อผิดพลาด ทุกอย่างจะย้อนกลับครบ
- transaction ซ้อนกันได้ (savepoint)
- แยก transaction อิสระได้ เช่น บันทึกสาเหตุที่ปฏิเสธรายการ
- ล็อกแถวด้วย SELECT .. FOR UPDATE กันการแย่งกันเขียน
- MongoDB ลองใหม่เองเมื่อเจอ conflict ชั่วคราว
ข้อมูลก้อนใหญ่ โดยไม่กินหน่วยความจำ
อ่านข้อมูลหลายแสนแถวแบบ stream ทีละชุด และเขียนแบบ bulk ที่ปรับขนาดชุดคำสั่งตามฐานข้อมูลแต่ละชนิดแล้ว
- stream() บนทุก adapter ยกเว้น Firestore
- queryColumnFrame() สำหรับสรุปผลข้อมูลก้อนใหญ่
- upsert และ bulkUpdate แบบหลายแถวต่อคำสั่ง
- ตั้ง timeout ของคำสั่งได้
Excel, Word, PowerPoint, CSV และ ZIP
สร้าง อ่าน และแก้ไขเอกสารสำนักงานจากโค้ดโดยตรง ใช้ออกรายงาน ใบเสนอราคา และนำเข้าข้อมูลจากไฟล์ที่ลูกค้าส่งมา
- ExcelFile, WordFile, PowerPointFile และ Excel Online
- สกัดข้อความจากเอกสารเพื่อส่งให้ AI อ่านต่อ
- ไฟล์เขียนแบบ atomic และจำกัดโฟลเดอร์ที่เข้าถึงได้
- เปิด ZIP จากภายนอกแบบจำกัดขนาด ป้องกันไฟล์อันตราย
Pipeline และ connector เชื่อมระบบอื่น
สร้างงาน ETL/ELT ที่ต่อจากฐานข้อมูล ไฟล์ และ message broker ไปยังปลายทางได้ พร้อมจุดกู้คืนเมื่อ run ล้มกลางทาง
- HTTP, S3, SFTP, Kafka, Redis Streams, CDC, DuckDB, SOAP
- checkpoint และ dead-letter เก็บรายการที่ประมวลผลไม่ได้
- ข้อมูลที่มาช้าถูกนับและแยกไว้ ไม่ถูกทิ้งเงียบ ๆ
- กำหนด pipeline ด้วย spec แบบ declarative
งานบำรุงข้อมูลที่ระบบจริงต้องมี
รวมโมดูลที่ระบบธุรกิจต้องใช้ ตั้งแต่การส่งอีเวนต์ให้ครบ ไปจนถึงการอัปเกรดโครงสร้างตารางและค้นหาข้อความภาษาไทย
- Outbox: ส่งอีเวนต์ซ้ำได้ปลอดภัย ไม่ซ้ำซ้อนด้วย idempotency key
- วางแผน migration ของ schema และตรวจชนิดคอลัมน์ก่อนรัน
- Validation, import/export และ sync ข้อมูล
- จัดเก็บ RAG บน PostgreSQL พร้อมค้นหาข้อความภาษาไทย
ตัวเลขที่วัดจริง
ตัวเลขมาจากชุดวัดผลของเราเอง รันบน Apple M1 Pro กับ Docker (ฐานข้อมูล 2 CPU, 2 GB, ข้อมูล 100,000 แถว) ค่าสัมบูรณ์บนเครื่องนี้ต่ำกว่า server จริง ใช้ดูสัดส่วนเทียบกับ driver ตรงและก่อนหลังการปรับปรุงจะเหมาะกว่า
ตัวเลขจากชุดทดสอบและ benchmark ภายในของ CKN ผลจริงขึ้นกับเครื่องและปริมาณข้อมูลของแต่ละระบบ
ธุรกิจของคุณได้อะไร
ต้นทุนการพัฒนาและดูแลต่ำลง
ทีมใช้ API เดียวกับทั้งฐานข้อมูล ไฟล์ และ pipeline จึงฝึกคนใหม่ได้เร็ว และโค้ดที่เขียนครั้งเดียวใช้ซ้ำข้ามระบบได้ งานที่ปกติต้องหาไลบรารีมาเสริม เช่น ออกไฟล์ Excel หรือ Word ก็ทำได้ในชุดเดียวกัน
ความเสี่ยงต่ำลงเมื่อเงินและสต็อกเกี่ยวข้อง
transaction ที่ย้อนกลับครบ การล็อกแถว และ Outbox ที่ส่งอีเวนต์ซ้ำได้โดยไม่ซ้ำซ้อน ช่วยกันปัญหา เช่น สต็อกติดลบหรือคำสั่งซื้อซ้ำ และชุดทดสอบรันกับ server จริงของทั้ง 6 ฐานข้อมูล ไม่ใช่แค่ mock
เป็นเจ้าของ stack เอง ไม่ผูกกับผู้ขายรายเดียว
ส่วนที่เขียนไฟล์ Word, CSV และ XML เป็นโค้ดของเราเอง ลดการพึ่งไลบรารีภายนอกที่ต้องตามแก้ช่องโหว่ ติดตั้งเฉพาะ driver ของฐานข้อมูลที่ใช้จริง และย้ายไปฐานข้อมูลอื่นได้โดยไม่ต้องเขียนชั้นข้อมูลใหม่ทั้งหมด
ตัวอย่าง: นำเข้าราคา แล้วตัดสต็อกแบบไม่มีการแย่งกัน
ใช้งานอยู่ในส่วนต่าง ๆ ของ CKN stack
- บริการธุรกิจทั้ง 14 ตัวของ CKN ใช้เป็นชั้นฐานข้อมูลหลัก (PostgreSQL)
- บริการแพลตฟอร์ม เช่น identity, integration, portal, intelligent และ engine
- แอปภายใน CKN Works (โครงการ ตั๋วงาน ต้นทุน เอกสาร ค่าใช้จ่าย)
- เครื่องมือ ckn CLI ใช้สร้างโค้ดชั้นฐานข้อมูลให้แอปใหม่
import { PostgreSQL } from "@ckn-technology/data/database";
const db = new PostgreSQL({
host: process.env.MAIN_DB_HOST ?? "", port: 5432, user: process.env.MAIN_DB_USER ?? "",
password: process.env.MAIN_DB_PASSWORD ?? "", database: "app", schema: "sales", enableLog: false,
});
await db.upsert("price", [{ sku: "A-100", company_code: "TH01", price: 890, currency: "THB" }], ["sku", "company_code"]);
await db.transaction(async (tx) => {
const [s] = (await tx.query("SELECT qty FROM stock WHERE sku = $1 FOR UPDATE", ["A-100"])).rows;
if (!s || s.qty < 5) throw new Error("not enough A-100"); // rolls everything back
await tx.update("stock", { qty: s.qty - 5 }, "sku = $1", ["A-100"]);
});
await db.close();
