DEV Community

รู้จักกับ plv8: เมื่อ Postres ต้องมาเชื่อมจิตกับ JavaScript

บทนำ

วันก่อนไปส่อง facebook fanpage ขาเดฟ ซึ่งเป็นแหล่งร่วมตัวเทพ ในวงการ developer ได้โพสเกี่ยวกับส่วนขยาย(extension) ของ postgres ที่ชื่อว่า plv8 ที่ช่วยให้คุณสามารถเขียนฟังก์ชันและทริกเกอร์ด้วยภาษา JavaScript ได้ โดยใช้ V8 JavaScript engine ที่พัฒนาโดย Google

แล้วมันดียังไง

  • ใช้ JavaScript ในฐานข้อมูล: เขียนโค้ด JavaScript ที่ทำงานโดยตรงใน PostgreSQL
  • ประสิทธิภาพสูง: V8 engine มีประสิทธิภาพสูง ทำให้การประมวลผลเร็วกว่าภาษาอื่นๆ เช่น PL/pgSQL
  • ความยืดหยุ่น: สามารถใช้คุณสมบัติของ JavaScript เช่น closures, high-order functions ได้
  • JSON processing: เหมาะสำหรับการทำงานกับข้อมูล JSON ใน PostgreSQL
  • NPM packages: สามารถใช้ JavaScript libraries จาก NPM ได้

การใช้งาน

-ติดตั้ง plv8 extension:

CREATE EXTENSION plv8
Enter fullscreen mode Exit fullscreen mode
  • การสรา้งและเรียกใช้ฟังก์ชั่น:
--สรา้งฟังก์ชั่น hellow_world ในการคืนข้อความ "Hello, World!"
CREATE FUNCTION hello_world() RETURNS text AS $$
    return "Hello, World!";
$$ LANGUAGE plv8;

--การเรียกใช้ function hello_world--
SELECT hello_world();
Enter fullscreen mode Exit fullscreen mode
  • ฟังก์ชันที่ทำงานกับ JSON และใช้ JavaScript Array methods:
CREATE OR REPLACE FUNCTION filter_and_transform_users(users json) RETURNS json AS $$
    const userArray = JSON.parse(users);
    const result = userArray
        .filter(user => user.age > 18)
        .map(user => ({
            fullName: `${user.firstName} ${user.lastName}`,
            isAdult: user.age >= 21,
            emailDomain: user.email.split('@')[1]
        }));
    return JSON.stringify(result);
$$ LANGUAGE plv8;

-- ตัวอย่างการใช้งาน
SELECT filter_and_transform_users('[
    {"firstName": "John", "lastName": "Doe", "age": 25, "email": "john@example.com"},
    {"firstName": "Jane", "lastName": "Smith", "age": 17, "email": "jane@test.com"},
    {"firstName": "Bob", "lastName": "Johnson", "age": 30, "email": "bob@example.com"}
]');
Enter fullscreen mode Exit fullscreen mode
  • ฟังก์ชันที่ใช้ closure และ state ระหว่าง invocations:
CREATE OR REPLACE FUNCTION create_counter() RETURNS json AS $$
    const state = plv8.initialize_state();
    if (!state.counter) state.counter = 0;

    function increment() {
        state.counter++;
        return state.counter;
    }

    function decrement() {
        state.counter--;
        return state.counter;
    }

    function reset() {
        state.counter = 0;
        return state.counter;
    }

    return JSON.stringify({increment, decrement, reset});
$$ LANGUAGE plv8;

-- ตัวอย่างการใช้งาน
DO $$
    const counter = JSON.parse(plv8.execute('SELECT create_counter()')[0].create_counter);
    plv8.elog(NOTICE, counter.increment()); // 1
    plv8.elog(NOTICE, counter.increment()); // 2
    plv8.elog(NOTICE, counter.decrement()); // 1
    plv8.elog(NOTICE, counter.reset()); // 0
$$ LANGUAGE plv8;
Enter fullscreen mode Exit fullscreen mode
  • ฟังก์ชันที่ใช้ external library (ต้องติดตั้ง library ก่อน):
CREATE OR REPLACE FUNCTION validate_email(email text) RETURNS boolean AS $$
    const validator = require('email-validator');
    return validator.validate(email);
$$ LANGUAGE plv8;

-- ตัวอย่างการใช้งาน
SELECT validate_email('user@example.com');
SELECT validate_email('invalid-email');
Enter fullscreen mode Exit fullscreen mode
  • ทริกเกอร์ที่ใช้ PL/V8:
-- สรา้งตารางเก็บชื่อผู้ใช้งาน 
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username TEXT,
    email TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

--สร้างฟังก์ชั่น validate_user() ในการตรวจสอบชื่อผู้ใช้งาน และ email
CREATE OR REPLACE FUNCTION validate_user() RETURNS trigger AS $$
    if (!NEW.username || NEW.username.length < 3) {
        plv8.elog(ERROR, 'Username must be at least 3 characters long');
    }
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(NEW.email)) {
        plv8.elog(ERROR, 'Invalid email format');
    }
    return NEW;
$$ LANGUAGE plv8;

--สร้าง trigger ในการเรียกใช้ฟังก์ชั่น validate_user() ในการตรวจสอบชื่อผู้ใช้งาน และ email
CREATE TRIGGER user_validation_trigger
BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION validate_user();

-- ตัวอย่างการใช้งาน
INSERT INTO users (username, email) VALUES ('jo', 'john@example.com'); -- จะ error
INSERT INTO users (username, email) VALUES ('john', 'invalid-email'); -- จะ error
INSERT INTO users (username, email) VALUES ('john', 'john@example.com'); -- จะสำเร็จ
Enter fullscreen mode Exit fullscreen mode

มีอะไรต้องระวังไหม

  • ต้องติดตั้ง PL/V8 extension เพิ่มเติม
  • การใช้ JavaScript อาจทำให้การ debug ยากขึ้น
  • ต้องระวังเรื่องความปลอดภัย เพราะ JavaScript สามารถเข้าถึงระบบไฟล์ได้

ส่งท้าย

ส่วนขยาย plv8 ช่วยให้ทาง developer สามารถสร้างฟังก์ชั่นที่ทำงานเฉพาะ ซึ่งฝั่ง developer มีความชำนาญ JavaScript อยู่แล้วโดยไม่ต้องพึ่ง Database Admin (ซึ่งส่วนใหญ่จะไม่ค่อยชำนาญภาษา pl/pgsql) อีกทั้งยังสามารถเรียก npm เพื่อเพิ่มความสามารถผ่าน javscript อย่างที่ผมเคยบอกว่า postgres เป็นทุกอย่างให้เธอแล้ว

Top comments (0)