4 คะแนน โดย GN⁺ 2023-10-16 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เป็นไคลเอนต์ PostgreSQL ที่ใช้กับ Node.js และ Deno โดยใช้ ES6 tagged template strings เป็น API หลัก และติดตั้งผ่านแพ็กเกจ npm postgres
  • พารามิเตอร์ของคิวรีจะถูกประมวลผลก่อนการแทรกค่า และแทนที่ด้วย placeholder ของโปรโตคอล PostgreSQL คือ $1, $2, ... จากนั้นค่าจะถูกส่งไปยังฐานข้อมูลแยกต่างหาก เพื่อให้ฐานข้อมูลจัดการการ escape และ casting
  • การเรียก `sql``...``` รองรับการสร้างคิวรีที่ปลอดภัยและการประกอบคิวรีแบบไดนามิก โดยจัดการได้ทั้ง partial query, ฟิลเตอร์แบบไดนามิก, การจัดเรียงแบบไดนามิก และการประกอบ identifier ของชื่อตารางและชื่อคอลัมน์ โดยไม่มีความเสี่ยงจาก SQL injection ที่มาจากการต่อสตริงแบบทั่วไป
  • สามารถตั้งค่าการเชื่อมต่อได้ผ่าน URL แบบ postgres://, อ็อบเจ็กต์ตัวเลือก หรือ environment variable แบบเดียวกับที่ใช้ใน psql และค่าในอ็อบเจ็กต์ตัวเลือกจะเขียนทับค่าจาก URL
  • คิวรีจะถูกรันเมื่อมีการ await และผลลัพธ์จะถูกส่งกลับเป็นอาร์เรย์ Result ที่แมปชื่อคอลัมน์เข้ากับอ็อบเจ็กต์ของแต่ละแถว และสามารถใช้ .execute() เพื่อรันทันทีได้
  • โฟลว์การใช้งานหลักประกอบด้วย insert/update แบบไดนามิก, การ insert หลายแถว, รายการค่า where in, ทรานแซกชัน sql.begin, savepoint, prepared transaction, คิวรีจากไฟล์, cursor และเมธอดคิวรีขั้นสูงอย่าง .forEach, .describe, .values, .raw
  • รองรับการเชื่อมกับความสามารถของ PostgreSQL เช่น LISTEN/NOTIFY, การสมัครรับข้อมูลแบบเรียลไทม์ บนโปรโตคอล logical replication, การเปิดเผยสตรีม Node.js ของ COPY ... และการยกเลิกคิวรีที่กำลังทำงานอยู่
    • การสมัครรับข้อมูลแบบเรียลไทม์ต้องมีการสร้าง publication ในฐานข้อมูล, ตั้งค่า wal_level = logical ใน postgresql.conf และเชื่อมต่อด้วยผู้ใช้ replication หรือ superuser
    • API สตรีมของ COPY ... ไม่ได้ให้ type safety และต้องจัดให้พารามิเตอร์ของ copy query สอดคล้องกับโค้ดอ่าน/เขียนสตรีมของ Node.js รวมถึงการจัดการ backpressure
  • ตัวเลือกการแปลงข้อมูลรองรับการแปลงระหว่าง camelCase, PascalCase, Kebab-Case และ snake_case, การแปลงค่า undefined และฟังก์ชันแปลง column/value/row แบบกำหนดเอง
  • connection pool จะถูกสร้างแบบหน่วงเวลาเมื่อมีการสร้างคิวรี โดยจำนวนการเชื่อมต่อสูงสุดเริ่มต้นคือ max: 10 และระหว่างทำทรานแซกชันจะมีการจองการเชื่อมต่อไว้จากพูลก่อนส่งคืนหลังเสร็จสิ้น
  • รองรับ TCP socket API ของ Cloudflare Workers และหากต้องการให้ทำงานในสภาพแวดล้อม Workers ต้องตั้งค่า compatibility_flags = ["nodejs_compat"] ใน wrangler.toml
  • การรองรับ TypeScript มีเป้าหมายเพื่อให้ type ของ public API แต่มีข้อจำกัดว่าประเภทข้อมูลอาจไม่ได้อัปเดตพร้อมกันทุกครั้งเมื่อมีการเพิ่มหรือเปลี่ยนฟีเจอร์

1 ความคิดเห็น

 
GN⁺ 2023-10-16
ความคิดเห็นจาก Hacker News
  • ถ้าอยากใช้ SQL โดยตรง เพื่อดึงจุดเด่นของ Postgres ออกมา ไลบรารีนี้ทำงานด้วยแล้วสนุกมาก
    ไม่มี abstraction ที่ดูหรูและทำเป็นทันสมัยแบบ Prisma ไม่มี type annotation ซับซ้อนเหมือนไลบรารี TypeScript อื่น ๆ แค่เขียนคำสั่ง SQL ธรรมดา ๆ ตามสไตล์ JavaScript ก็พอ
    หลายปีก่อนผมเบื่อกับการฝืนปรับตัวให้เข้ากับ Prisma เลยเริ่มเรียน Postgres อย่างจริงจังและลองทางเลือกหลายตัว แต่พอได้ใช้ตัวนี้ไม่กี่นาทีก็รู้สึกว่าจะไม่กลับไปอีกแล้ว

    • อยากให้ JavaScript มีไลบรารีแบบ Ecto ของ Elixir บ้าง เป็นเครื่องมือจัดการ SQL ที่ดีที่สุดเท่าที่เคยเห็นมา เรียบง่ายแต่ทรงพลังและเข้าใจง่าย
    • วิธีซ้อนเลเยอร์ทับ SQL นี่ไม่เคยชอบมาตั้งแต่แรกแล้ว SQL เป็นสิ่งที่ต่อให้ตายก็ไม่อยากให้ใครพรากไปจากมือ
    • คงสนุกมากถ้าต้องมารับโค้ดแบบนี้ต่อหลังจากนักพัฒนาที่รับผิดชอบลาออกจากบริษัทไป ไม่มี type ไม่มีคอมเมนต์ ไม่มี abstraction ไม่มี migration เหลือแค่ SQL ล้วน
    • อยากรู้ว่าฟีเจอร์ raw query ของ Prisma มีจุดไหนที่ไม่ถูกใจ
  • ไลบรารีนี้เร็วจริง ๆ อย่ามัวเทียบกับไลบรารีอื่นเพราะเห็นแค่ไวยากรณ์ string template คล้ายกันแล้วพลาดสาระสำคัญไป
    มันไม่ได้พึ่ง pg แต่ implement low-level client เอง
    ผมสร้างระบบที่โหลดเรคคอร์ดทีละ 10,000 รายการหลายครั้งด้วยตัวนี้ แล้วประสิทธิภาพเหนือชั้นมาก

    • ถ้าอธิบายเพิ่มอีกหน่อย คือโหลดเรคคอร์ดราว 10,000~20,000 รายการได้ในไม่เกิน 20ms ทั้งที่งานแบบนี้เดิมน่าจะใช้ประมาณ 150ms
      ขึ้นกับ use case แค่นี้ก็อาจเปลี่ยนเกมได้แล้ว และถ้าคุ้นกับมาตรฐานที่คิดว่าเป็นไปได้ในสภาพแวดล้อมอย่าง Ruby ก็จะยิ่งน่าประทับใจ
      นอกจากนี้ยังรองรับ logical decoding ด้วย จึงเปิดความเป็นไปได้หลายอย่างสำหรับการประมวลผลอีเวนต์การเปลี่ยนผ่าน เป็นโปรเจกต์ที่น่าประทับใจจริง ๆ และน่าเสียดายถ้ามองข้าม
  • บทความที่เกี่ยวข้อง:
    Show HN: Postgres.js – Fastest Full-Featured PostgreSQL Client for Node and Deno - https://news.ycombinator.com/item?id=30794332 - มีนาคม 2022, 83 ความคิดเห็น
    Show HN: Postgres.js – Fast PostgreSQL Client for Node.js - https://news.ycombinator.com/item?id=21864245 - ธันวาคม 2019, 12 ความคิดเห็น

  • อาจไม่ได้มีฟีเจอร์มากเท่าไลบรารีในโพสต์ต้นฉบับ แต่ https://pgtyped.dev/ ก็มีประโยชน์เหมือนกัน
    ถ้าเขียน query เป็น ไฟล์ SQL pgtyped จะสร้างฟังก์ชันที่มี type กำกับให้เรียกด้วยพารามิเตอร์ของ query ได้

  • ผมเป็นผู้เขียนเอง อยากเสริมว่าตอนนี้รองรับ Cloudflare แล้วด้วย

  • ชอบตรงที่มี dependency 0 รายการ

    • ทุกวันนี้ถือว่าหายากพอสมควร จึงควรเน้นแยกออกมาเลย
  • สงสัยว่าประโยค “prepared statement จะถูกสร้างโดยอัตโนมัติสำหรับทุก query ที่สามารถอนุมานได้ว่าเป็น static query” หมายความว่าอย่างไรกันแน่
    หมายถึงจะสร้าง prepared statement จริง ๆ ใน DB session แม้ไม่มี binding variable และ query นั้นถูกเรียกแค่ครั้งเดียวหรือเปล่า?
    ถ้าใช่ก็น่าสนใจ แต่ดูเป็นแนวทางที่มีจุดยืนค่อนข้างชัดเจนทีเดียว

    • ถ้าใช้ query แบบ parameterized ก็จำเป็นต้องใช้ extended query flow ของ PostgreSQL และหลายคนน่าจะถือว่านั่นคือ prepared statement อยู่แล้ว ตัวมันเองไม่ได้เป็นตัวเลือกที่มีความเห็นแรงอะไรนัก
      แต่โดยทั่วไปจะใช้ prepared statement หรือ portal แบบไม่มีชื่อ และ PostgreSQL จะจัดการเก็บกวาดให้ จึงเท่ากับคงไว้จริง ๆ แค่หนึ่งรายการต่อ session หรือก็คือต่อ connection
      ผมไม่เข้าใจประโยคนั้นเลยไปดูโค้ด พบว่าที่พูดถึงคือการใช้ prepared statement แบบมีชื่อโดยอัตโนมัติ เพื่อ cache prepared statement ทั้งใน PostgreSQL และภายใน driver เอง มีการสร้าง signature ของ statement อยู่ ดังนั้นนี่เป็นการออกแบบที่มีจุดยืนชัดเจนจริง ๆ
      ส่วนตัวคิดว่าโค้ดบริเวณที่สร้างข้อมูล parse/describe/bind/execute/sync เป็นหลักนั้นค่อนข้างไม่ค่อยดี: https://github.com/porsager/postgres/blob/bf082a5c0ffe214924...
    • Postgres รองรับ prepared statement สองชนิด คือ generic prepared statement ที่รับพารามิเตอร์ได้ และ custom prepared statement ที่เตรียมไว้สำหรับการรันเฉพาะครั้ง โดยนำพารามิเตอร์เข้าไปมีผลต่อแผนด้วย
      มีอธิบายไว้ที่ https://www.postgresql.org/docs/current/sql-prepare.html และดูประเภทของแผนได้ในส่วน “Notes”
  • คิดว่าควรพูดถึง Zapatos ด้วย เป็น Postgres JavaScript client อีกตัวที่มีการออกแบบคล้ายกันมาก คือเขียน SQL ใน template string แต่ให้ type safety เต็มรูปแบบ
    ถ้าชอบ TypeScript น่าจะถูกใจ: https://jawj.github.io/zapatos/
    ส่วนตัวรู้สึกว่าเป็นหนึ่งในไลบรารี TypeScript ที่ออกแบบและทำเอกสารได้ดีที่สุดตัวหนึ่ง และเสียดายที่ไม่ค่อยเป็นที่รู้จัก

    • สุดท้ายต้องเลิกใช้ Zapatos เพราะไม่รองรับ schema หลายชุด และ type ก็ไม่ได้อ่านง่ายเสมอไป
      ผมเลือก PgTyped เป็นทางเลือกแทน และผ่านไป 2 ปีตอนนี้คิดว่าตัดสินใจย้ายถูกมาก
    • เห็นด้วย ฟีเจอร์ lateral join กับการผสมฟังก์ชันลัดทำให้สร้าง backend ได้ง่ายมาก โดยยังเขียน SQL จริงและไม่ต้องเสีย usability ไป
    • มองผ่าน ๆ ดูเหมือน Zapatos จะไม่เข้ากันกับ Cloudflare Workers ถ้าไม่ใช่ก็ยินดีให้แก้ไข
    • อยากรู้ว่ามีใครรู้ไหมว่าทำไม zapatos ถึงพึ่ง pg ไม่ใช่ PostgresJs
  • ผมไปดูมาเพราะสงสัยว่าโปรเจกต์นี้เก่าแค่ไหน:
    v1.0.1 - มกราคม 2020
    v2.0.0 - มิถุนายน 2020 แต่เหมือนจะไม่เคยพ้น beta
    v3.0.0 - มีนาคม 2022 ตั้งแต่นั้นดูเหมือนโปรเจกต์จะเริ่มจริงจัง
    ดูน่าสนใจทีเดียว เลยสงสัยด้วยว่าแข็งแกร่งแค่ไหน

    • ใช้ใน สภาพแวดล้อม production บน Deno มาพักหนึ่งแล้ว ค่อนข้างแข็งแกร่ง แต่เอกสารยังขาดไปมาก เวลาทำงานซับซ้อนจึงมักต้องคลำหาวิธีเอง
  • Postgres.js เป็นหนึ่งในไลบรารีระดับดีที่สุดเท่าที่เคยใช้มา
    วิธีใช้ template ของ JavaScript นั้น intuitive มากจริง ๆ