อินเทอร์เฟซ PostgreSQL สำหรับ Node.js
สร้างขึ้นจาก node-postgres ไลบรารีนี้เพิ่มสิ่งต่อไปนี้:
ณ จุดเริ่มต้นในปี 2558 ไลบรารีนี้เพียงเพิ่มสัญญาให้กับไดรเวอร์พื้นฐานเท่านั้น ดังนั้นชื่อ pg-promise
และในขณะที่ชื่อเดิมยังคงอยู่ ฟังก์ชั่นของห้องสมุดก็ขยายออกไปอย่างมากมาย โดยคำสัญญาที่ตอนนี้เป็นเพียงส่วนเล็กๆ เท่านั้น
ฉันให้การสนับสนุนฟรีที่นี่และบน StackOverflow
และถ้าคุณต้องการช่วยโครงการนี้ ฉันรับ Bitcoin ได้: 1yki7MXMkuDw8qqe5icVdh1GJZSQSzKZp
การใช้บทด้านล่างนี้จะอธิบายพื้นฐานที่คุณต้องรู้ ในขณะที่เอกสารอย่างเป็นทางการจะช่วยให้คุณเริ่มต้นได้ และมีลิงก์ไปยังแหล่งข้อมูลอื่นๆ ทั้งหมด
โปรดอ่านบันทึกการมีส่วนร่วมก่อนที่จะเปิดฉบับใหม่หรือการประชาสัมพันธ์
เมื่อคุณสร้างออบเจ็กต์ฐานข้อมูลแล้ว ตามขั้นตอนในเอกสารอย่างเป็นทางการ คุณจะสามารถเข้าถึงวิธีการที่ระบุไว้ด้านล่าง
วิธีการสืบค้นทั้งหมดของไลบรารีจะขึ้นอยู่กับการสืบค้นวิธีทั่วไป
โดยปกติคุณควรใช้เฉพาะวิธีการเฉพาะผลลัพธ์ที่ได้รับมาในการดำเนินการค้นหา ซึ่งทั้งหมดนี้ตั้งชื่อตามจำนวนแถวข้อมูลที่คาดว่าจะส่งคืน ดังนั้นสำหรับการสืบค้นแต่ละครั้ง คุณควรเลือกวิธีที่ถูกต้อง: ไม่มี หนึ่ง oneOrNone, หลาย, manyOrNone = ใดๆ อย่าสับสนชื่อวิธีการสำหรับจำนวนแถวที่จะได้รับผลกระทบจากแบบสอบถาม ซึ่งไม่เกี่ยวข้องเลย
ด้วยการอาศัยวิธีการเฉพาะผลลัพธ์ คุณจะปกป้องโค้ดของคุณจากแถวข้อมูลที่ไม่คาดคิด ซึ่งจะถูกปฏิเสธโดยอัตโนมัติ (ถือเป็นข้อผิดพลาด)
นอกจากนี้ยังมีวิธีการเฉพาะบางประการที่คุณมักจะต้องใช้:
โปรโตคอลสามารถปรับแต่ง / ขยายได้อย่างเต็มที่ผ่านการขยายเหตุการณ์
สำคัญ:
วิธีการที่สำคัญที่สุดที่ต้องทำความเข้าใจตั้งแต่เริ่มต้นคืองานและ tx/txIf (ดูงานและธุรกรรม) ตามที่ระบุไว้สำหรับการสืบค้นเมธอด จะรับและปล่อยการเชื่อมต่อ ซึ่งทำให้เป็นตัวเลือกที่ไม่ดีสำหรับการดำเนินการสืบค้นหลายรายการพร้อมกัน ด้วยเหตุนี้ Chaining Queries จึงเป็นสิ่งที่ต้องอ่าน เพื่อหลีกเลี่ยงการเขียนโค้ดที่ใช้การเชื่อมต่อในทางที่ผิด
เรียนรู้ตามตัวอย่างเป็นบทช่วยสอนสำหรับผู้เริ่มต้นโดยอิงตามตัวอย่าง
ไลบรารีนี้มาพร้อมกับเอ็นจิ้นการจัดรูปแบบคิวรีแบบฝังที่ให้การหลีกเลี่ยงค่าที่มีประสิทธิภาพสูง ความยืดหยุ่น และความสามารถในการขยาย โดยจะใช้เป็นค่าเริ่มต้นกับวิธีการสืบค้นทั้งหมด เว้นแต่คุณจะเลือกไม่ใช้งานทั้งหมดผ่านตัวเลือก pgFormatting
ภายในตัวเลือกการเริ่มต้น
วิธีการจัดรูปแบบทั้งหมดที่ใช้ภายในมีให้ใช้งานจากเนมสเปซการจัดรูปแบบ ดังนั้นจึงสามารถนำมาใช้โดยตรงเมื่อจำเป็นได้ วิธีการหลักคือการจัดรูปแบบ ซึ่งใช้โดยวิธีการสืบค้นทุกวิธีเพื่อจัดรูปแบบแบบสอบถาม
ไวยากรณ์การจัดรูปแบบสำหรับตัวแปรจะตัดสินใจจากประเภทของ values
ที่ส่งผ่าน:
values
เป็นอาร์เรย์หรือประเภทพื้นฐานเดียวvalues
เป็นวัตถุ (นอกเหนือจาก Array
หรือ null
)ข้อควรระวัง: ห้ามใช้สตริงเทมเพลต ES6 หรือการต่อข้อมูลด้วยตนเองเพื่อสร้างการสืบค้น เนื่องจากทั้งสองอย่างอาจส่งผลให้เกิดการสืบค้นที่เสียหายได้ง่าย! มีเพียงกลไกการจัดรูปแบบของไลบรารีนี้เท่านั้นที่รู้วิธีหลีกเลี่ยงค่าตัวแปรสำหรับ PostgreSQL อย่างเหมาะสม
การจัดรูปแบบที่ง่ายที่สุด (คลาสสิก) ใช้ไวยากรณ์ $1, $2, ...
เพื่อแทรกค่าลงในสตริงการสืบค้น โดยอิงตามดัชนี (จาก $1
ถึง $100000
) จากอาร์เรย์ของค่า:
await db . any ( 'SELECT * FROM product WHERE price BETWEEN $1 AND $2' , [ 1 , 10 ] )
กลไกการจัดรูปแบบยังรองรับการกำหนดพารามิเตอร์ค่าเดียวสำหรับการสืบค้นที่ใช้เฉพาะตัวแปร $1
:
await db . any ( 'SELECT * FROM users WHERE name = $1' , 'John' )
อย่างไรก็ตาม สิ่งนี้ใช้ได้กับประเภท number
, bigint
, string
, boolean
, Date
และ null
เท่านั้น เนื่องจากประเภทเช่น Array
และ Object
จะเปลี่ยนวิธีการตีความพารามิเตอร์ นั่นเป็นเหตุผลที่แนะนำให้ส่งตัวแปรดัชนีภายในอาร์เรย์ว่าปลอดภัยกว่า เพื่อหลีกเลี่ยงความคลุมเครือ
เมื่อวิธีการสืบค้นถูกกำหนดพารามิเตอร์ด้วย values
เป็นอ็อบเจ็กต์ กลไกการจัดรูปแบบคาดว่าแบบสอบถามจะใช้ไวยากรณ์ของพารามิเตอร์ที่มีชื่อ $*propName*
โดยที่ *
เป็นคู่เปิด-ปิดใดๆ ต่อไปนี้: {}
, ()
, <>
, []
, //
.
// We can use every supported variable syntax at the same time, if needed:
await db . none ( 'INSERT INTO users(first_name, last_name, age) VALUES(${name.first}, $, $/age/)' , {
name : { first : 'John' , last : 'Dow' } ,
age : 30
} ) ;
สิ่งสำคัญ: ห้ามใช้ไวยากรณ์ ${}
ที่สงวนไว้ภายในสตริงเทมเพลต ES6 เนื่องจากไม่มีความรู้เกี่ยวกับวิธีการจัดรูปแบบค่าสำหรับ PostgreSQL ภายในสตริงเทมเพลต ES6 คุณควรใช้หนึ่งใน 4 ทางเลือก - $()
, $<>
, $[]
หรือ $//
โดยทั่วไป คุณควรใช้สตริงมาตรฐานสำหรับ SQL หรือวาง SQL ลงในไฟล์ภายนอก - โปรดดูไฟล์แบบสอบถาม
ชื่อตัวแปรที่ถูกต้องถูกจำกัดให้ใช้ไวยากรณ์ของตัวแปร JavaScript ชื่อเปิด และชื่อ this
มีความหมายพิเศษ - หมายถึงวัตถุการจัดรูปแบบเอง (ดูด้านล่าง)
โปรดทราบว่าแม้ว่าค่าคุณสมบัติ null
และ undefined
จะถูกจัดรูปแบบเป็น null
ทั้งคู่ แต่ข้อผิดพลาดจะเกิดขึ้นเมื่อไม่มีคุณสมบัติดังกล่าว
การอ้างอิง this
คุณสมบัติ this
อ้างถึงออบเจ็กต์การจัดรูปแบบเอง ที่จะแทรกเป็นสตริงที่จัดรูปแบบ JSON
await db . none ( 'INSERT INTO documents(id, doc) VALUES(${id}, ${this})' , {
id : 123 ,
body : 'some text'
} )
//=> INSERT INTO documents(id, doc) VALUES(123, '{"id":123,"body":"some text"}')
พารามิเตอร์ที่มีชื่อสนับสนุนการซ้อนชื่อคุณสมบัติที่มีความลึกใดๆ
const obj = {
one : {
two : {
three : {
value1 : 123 ,
value2 : a => {
// a = obj.one.two.three
return 'hello' ;
} ,
value3 : function ( a ) {
// a = this = obj.one.two.three
return 'world' ;
} ,
value4 : {
toPostgres : a => {
// Custom Type Formatting
// a = obj.one.two.three.value4
return a . text ;
} ,
text : 'custom'
}
}
}
}
} ;
await db . one ( 'SELECT ${one.two.three.value1}' , obj ) ; //=> SELECT 123
await db . one ( 'SELECT ${one.two.three.value2}' , obj ) ; //=> SELECT 'hello'
await db . one ( 'SELECT ${one.two.three.value3}' , obj ) ; //=> SELECT 'world'
await db . one ( 'SELECT ${one.two.three.value4}' , obj ) ; //=> SELECT 'custom'
นามสกุลในมติจะเป็นอะไรก็ได้ รวมทั้ง:
กล่าวคือห่วงโซ่การแก้ปัญหามีความยืดหยุ่นอย่างไร้ขีดจำกัด และรองรับการเรียกซ้ำโดยไม่มีขีดจำกัด
อย่างไรก็ตาม โปรดทราบว่าพารามิเตอร์ที่ซ้อนกันไม่ได้รับการสนับสนุนภายในเนมสเปซตัวช่วย
ตามค่าเริ่มต้น ค่าทั้งหมดจะถูกจัดรูปแบบตามประเภท JavaScript ตัวกรองการจัดรูปแบบ (หรือตัวแก้ไข) เปลี่ยนสิ่งนั้น เพื่อให้ค่ามีการจัดรูปแบบแตกต่างออกไป
โปรดทราบว่าตัวกรองการจัดรูปแบบใช้งานได้กับการสืบค้นปกติเท่านั้น และไม่มีอยู่ใน PreparedStatement หรือ parameterizedQuery เนื่องจากตัวกรองเหล่านั้นมีการจัดรูปแบบบนฝั่งเซิร์ฟเวอร์ตามคำจำกัดความ
ตัวกรองใช้ไวยากรณ์เดียวกันสำหรับตัวแปรดัชนีและพารามิเตอร์ที่มีชื่อ โดยตามด้วยชื่อตัวแปรทันที:
await db . any ( 'SELECT $1:name FROM $2:name' , [ 'price' , 'products' ] )
//=> SELECT "price" FROM "products"
await db . any ( 'SELECT ${column:name} FROM ${table:name}' , {
column : 'price' ,
table : 'products'
} ) ;
//=> SELECT "price" FROM "products"
รองรับตัวกรองต่อไปนี้:
:name
/ ~
- ชื่อ SQL:alias
- ตัวกรองนามแฝง:raw
/ ^
- ข้อความดิบ:value
/ #
- ค่าเปิด:csv
/ :list
- ตัวกรอง CSV:json
- ตัวกรอง JSON เมื่อชื่อตัวแปรลงท้ายด้วย :name
หรือมีรูปแบบที่สั้นกว่า ~
(tilde) ชื่อตัวแปรนั้นจะแทนชื่อ SQL หรือตัวระบุ ที่จะต้องหลีกตาม:
await db . query ( 'INSERT INTO $1~($2~) VALUES(...)' , [ 'Table Name' , 'Column Name' ] ) ;
//=> INSERT INTO "Table Name"("Column Name") VALUES(...)
await db . query ( 'INSERT INTO $1:name($2:name) VALUES(...)' , [ 'Table Name' , 'Column Name' ] ) ;
//=> INSERT INTO "Table Name"("Column Name") VALUES(...)
โดยทั่วไป ตัวแปรชื่อ SQL จะเป็นสตริงข้อความ ซึ่งต้องมีความยาวอย่างน้อย 1 อักขระ อย่างไรก็ตาม pg-promise
รองรับหลายวิธีในการระบุชื่อ SQL:
*
(เครื่องหมายดอกจัน) จะได้รับการยอมรับโดยอัตโนมัติว่าเป็น คอลัมน์ทั้งหมด : await db . query ( 'SELECT $1:name FROM $2:name' , [ '*' , 'table' ] ) ;
//=> SELECT * FROM "table"
await db . query ( 'SELECT ${columns:name} FROM ${table:name}' , {
columns : [ 'column1' , 'column2' ] ,
table : 'table'
} ) ;
//=> SELECT "column1","column2" FROM "table"
const obj = {
one : 1 ,
two : 2
} ;
await db . query ( 'SELECT $1:name FROM $2:name' , [ obj , 'table' ] ) ;
//=> SELECT "one","two" FROM "table"
นอกจากนี้ ไวยากรณ์ยังสนับสนุน this
เพื่อระบุชื่อคอลัมน์จากออบเจ็กต์การจัดรูปแบบ:
const obj = {
one : 1 ,
two : 2
} ;
await db . query ( 'INSERT INTO table(${this:name}) VALUES(${this:csv})' , obj ) ;
//=> INSERT INTO table("one","two") VALUES(1, 2)
การใช้การจัดรูปแบบประเภทนี้สำหรับชื่อ sql และตัวระบุ ควบคู่ไปกับการจัดรูปแบบตัวแปรปกติจะช่วยปกป้องแอปพลิเคชันของคุณจากการแทรก SQL
วิธีการ as.name ใช้การจัดรูปแบบ
นามแฝงเป็นเวอร์ชันที่ง่ายกว่าและเข้มงวดน้อยกว่าของตัวกรอง :name
ซึ่งสนับสนุนเฉพาะสตริงข้อความ กล่าวคือ ไม่สนับสนุน *
, this
, อาร์เรย์ หรืออ็อบเจ็กต์เป็นอินพุต เช่นเดียวกับ :name
อย่างไรก็ตาม รองรับกรณียอดนิยมอื่นๆ ที่มีความเข้มงวดน้อยกว่า แต่ครอบคลุมอย่างน้อย 99% ของกรณีการใช้งานทั้งหมด ดังที่แสดงด้านล่าง
await db . any ( 'SELECT full_name as $1:alias FROM $2:name' , [ 'name' , 'table' ] ) ;
//=> SELECT full_name as name FROM "table"
.
จากนั้น Escape แต่ละส่วนแยกจากกัน จึงรองรับชื่อ SQL แบบผสมอัตโนมัติ: await db . any ( 'SELECT * FROM $1:alias' , [ 'schemaName.table' ] ) ;
//=> SELECT * FROM "schemaName".table
สำหรับรายละเอียดเพิ่มเติม โปรดดูเมธอด as.alias ที่ใช้การจัดรูปแบบ
เมื่อชื่อตัวแปรลงท้ายด้วย :raw
หรือไวยากรณ์ที่สั้นกว่า ^
ค่านั้นจะถูกแทรกเป็นข้อความดิบโดยไม่ต้อง Escape
ตัวแปรดังกล่าวไม่สามารถเป็น null
หรือ undefined
เนื่องจากความหมายที่คลุมเครือในกรณีนี้ และค่าเหล่านั้นจะทำให้เกิดข้อผิดพลาด Values null/undefined cannot be used as raw text.
const where = pgp . as . format ( 'WHERE price BETWEEN $1 AND $2' , [ 5 , 10 ] ) ; // pre-format WHERE condition
await db . any ( 'SELECT * FROM products $1:raw' , where ) ;
//=> SELECT * FROM products WHERE price BETWEEN 5 AND 10
รองรับไวยากรณ์พิเศษ this:raw
/ this^
เพื่อแทรกออบเจ็กต์การจัดรูปแบบเป็นสตริง JSON แบบดิบ
คำเตือน:
ตัวกรองนี้ไม่ปลอดภัย และไม่ควรใช้กับค่าที่มาจากฝั่งไคลเอ็นต์ เนื่องจากอาจส่งผลให้เกิดการแทรก SQL
เมื่อชื่อตัวแปรลงท้ายด้วย :value
หรือไวยากรณ์ที่สั้นกว่า #
ชื่อตัวแปรนั้นจะถูกหลีกตามปกติ ยกเว้นเมื่อชนิดเป็นสตริง เครื่องหมายอัญประกาศต่อท้ายจะไม่ถูกเพิ่ม
ค่าเปิดส่วนใหญ่จะสามารถเขียนคำสั่งไดนามิก LIKE
/ ILIKE
ที่สมบูรณ์ในไฟล์ SQL ภายนอก โดยไม่ต้องสร้างในโค้ด
คือคุณสามารถสร้างตัวกรองแบบนี้ในโค้ดของคุณ:
const name = 'John' ;
const filter = '%' + name + '%' ;
จากนั้นส่งผ่านเป็นตัวแปรสตริงปกติ หรือคุณสามารถส่งผ่านเฉพาะ name
เท่านั้น และให้แบบสอบถามของคุณใช้ไวยากรณ์ค่าเปิดเพื่อเพิ่มตรรกะการค้นหาเพิ่มเติม:
SELECT * FROM table WHERE name LIKE ' %$1:value% ' )
คำเตือน:
ตัวกรองนี้ไม่ปลอดภัย และไม่ควรใช้กับค่าที่มาจากฝั่งไคลเอ็นต์ เนื่องจากอาจส่งผลให้เกิดการแทรก SQL
วิธีการ as.value ดำเนินการจัดรูปแบบ
เมื่อชื่อตัวแปรลงท้ายด้วย :json
การจัดรูปแบบ JSON ที่ชัดเจนจะถูกนำไปใช้กับค่า
ตามค่าเริ่มต้น ออบเจ็กต์ใดๆ ที่ไม่ใช่ Date
, Array
, Buffer
, null
หรือประเภทแบบกำหนดเอง (ดูการจัดรูปแบบประเภทแบบกำหนดเอง) จะถูกจัดรูปแบบเป็น JSON โดยอัตโนมัติ
วิธีการ as.json ดำเนินการจัดรูปแบบ
เมื่อชื่อตัวแปรลงท้ายด้วย :csv
หรือ :list
ชื่อตัวแปรนั้นจะถูกจัดรูปแบบเป็นรายการค่าที่คั่นด้วยเครื่องหมายจุลภาค โดยแต่ละค่าจะถูกจัดรูปแบบตามประเภท JavaScript
โดยทั่วไป คุณจะใช้สิ่งนี้กับค่าที่เป็นอาร์เรย์ แม้ว่าจะใช้ได้กับค่าเดียวก็ตาม ดูตัวอย่างด้านล่าง
const ids = [ 1 , 2 , 3 ] ;
await db . any ( 'SELECT * FROM table WHERE id IN ($1:csv)' , [ ids ] )
//=> SELECT * FROM table WHERE id IN (1,2,3)
const ids = [ 1 , 2 , 3 ] ;
await db . any ( 'SELECT * FROM table WHERE id IN ($1:list)' , [ ids ] )
//=> SELECT * FROM table WHERE id IN (1,2,3)
การใช้การแจงนับคุณสมบัติอัตโนมัติ:
const obj = { first : 123 , second : 'text' } ;
await db . none ( 'INSERT INTO table($1:name) VALUES($1:csv)' , [ obj ] )
//=> INSERT INTO table("first","second") VALUES(123,'text')
await db . none ( 'INSERT INTO table(${this:name}) VALUES(${this:csv})' , obj )
//=> INSERT INTO table("first","second") VALUES(123,'text')
const obj = { first : 123 , second : 'text' } ;
await db . none ( 'INSERT INTO table($1:name) VALUES($1:list)' , [ obj ] )
//=> INSERT INTO table("first","second") VALUES(123,'text')
await db . none ( 'INSERT INTO table(${this:name}) VALUES(${this:list})' , obj )
//=> INSERT INTO table("first","second") VALUES(123,'text')
วิธีการ as.csv ดำเนินการจัดรูปแบบ
ไลบรารีรองรับไวยากรณ์คู่สำหรับ CTF (การจัดรูปแบบประเภทแบบกำหนดเอง):
ไลบรารีจะตรวจสอบ Symbolic CTF ก่อนเสมอ และหากไม่มีการใช้ไวยากรณ์ดังกล่าว ไลบรารีจะตรวจสอบ Explicit CTF เท่านั้น
ค่า/อ็อบเจ็กต์ใดๆ ที่ใช้ฟังก์ชันกับ toPostgres
จะถือเป็นประเภทการจัดรูปแบบแบบกำหนดเอง จากนั้นฟังก์ชันจะถูกเรียกเพื่อรับค่าจริง โดยส่งผ่านวัตถุผ่านบริบท this
และบวกเป็นพารามิเตอร์เดียว (ในกรณีที่ toPostgres
เป็นฟังก์ชันลูกศร ES6):
const obj = {
toPostgres ( self ) {
// self = this = obj
// return a value that needs proper escaping
}
}
ฟังก์ชัน toPostgres
สามารถส่งคืนอะไรก็ได้ รวมถึงอ็อบเจ็กต์อื่นที่มีฟังก์ชัน toPostgres
ของตัวเอง เช่น รองรับประเภทแบบกำหนดเองที่ซ้อนกัน
ค่าที่ส่งคืนจาก toPostgres
จะถูกหลีกตามประเภท JavaScript เว้นแต่ว่าออบเจ็กต์จะมีคุณสมบัติ rawType
ที่ตั้งค่าเป็นค่าความจริงด้วย ซึ่งในกรณีนี้ค่าที่ส่งคืนจะถือว่ามีการจัดรูปแบบไว้ล่วงหน้า และด้วยเหตุนี้จึงมีการแทรกโดยตรงเป็นข้อความดิบ:
const obj = {
toPostgres ( self ) {
// self = this = obj
// return a pre-formatted value that does not need escaping
} ,
rawType : true // use result from toPostgres directly, as Raw Text
}
ตัวอย่างด้านล่างใช้คลาสที่จัดรูปแบบอัตโนมัติ ST_MakePoint
จากพิกัด:
class STPoint {
constructor ( x , y ) {
this . x = x ;
this . y = y ;
this . rawType = true ; // no escaping, because we return pre-formatted SQL
}
toPostgres ( self ) {
return pgp . as . format ( 'ST_MakePoint($1, $2)' , [ this . x , this . y ] ) ;
}
}
และไวยากรณ์แบบคลาสสิกสำหรับคลาสดังกล่าวนั้นง่ายกว่า:
function STPoint ( x , y ) {
this . rawType = true ; // no escaping, because we return pre-formatted SQL
this . toPostgres = ( ) => pgp . as . format ( 'ST_MakePoint($1, $2)' , [ x , y ] ) ;
}
ด้วยคลาสนี้คุณสามารถใช้ new STPoint(12, 34)
เป็นค่าการจัดรูปแบบที่จะถูกฉีดอย่างถูกต้อง
คุณยังสามารถใช้ CTF เพื่อแทนที่ประเภทมาตรฐานใดก็ได้:
Date . prototype . toPostgres = a => a . getTime ( ) ;
ข้อแตกต่างเพียงอย่างเดียวจาก Explicit CTF คือเราตั้งค่าเป็น toPostgres
และ rawType
เป็นคุณสมบัติ ES6 Symbol ซึ่งกำหนดไว้ในเนมสเปซ ctf:
const { toPostgres , rawType } = pgp . as . ctf ; // Global CTF symbols
const obj = {
[ toPostgres ] ( self ) {
// self = this = obj
// return a pre-formatted value that does not need escaping
} ,
[ rawType ] : true // use result from toPostgres directly, as Raw Text
} ;
เนื่องจากสัญลักษณ์ CTF เป็นแบบสากล คุณจึงสามารถกำหนดค่าออบเจ็กต์ได้อย่างอิสระจากไลบรารีนี้:
const ctf = {
toPostgres : Symbol . for ( 'ctf.toPostgres' ) ,
rawType : Symbol . for ( 'ctf.rawType' )
} ;
นอกจากนั้น มันทำงานเหมือนกับ Explicit CTF ทุกประการ แต่ไม่มีการเปลี่ยนแปลงลายเซ็นของออบเจ็กต์
หากคุณไม่ทราบว่ามันหมายถึงอะไร โปรดอ่าน ES6 Symbol API และการใช้สำหรับชื่อคุณสมบัติเฉพาะ แต่โดยสรุป คุณสมบัติ Symbol จะไม่ถูกแจกแจงผ่าน for(name in obj)
กล่าวคือ โดยทั่วไปจะไม่สามารถมองเห็นได้ใน JavaScript ผ่าน API Object.getOwnPropertySymbols
ที่เฉพาะเจาะจงเท่านั้น
การใช้ไฟล์ SQL ภายนอก (ผ่าน QueryFile) มีข้อดีหลายประการ:
debug
) โดยไม่ต้องรีสตาร์ทแอปparams
ตัวเลือก) การจัดรูปแบบ SQL สองขั้นตอนโดยอัตโนมัติminify
+ compress
) เพื่อการตรวจหาข้อผิดพลาดตั้งแต่เนิ่นๆ และการสืบค้นแบบกะทัดรัด const { join : joinPath } = require ( 'path' ) ;
// Helper for linking to external query files:
function sql ( file ) {
const fullPath = joinPath ( __dirname , file ) ;
return new pgp . QueryFile ( fullPath , { minify : true } ) ;
}
// Create a QueryFile globally, once per file:
const sqlFindUser = sql ( './sql/findUser.sql' ) ;
db . one ( sqlFindUser , { id : 123 } )
. then ( user => {
console . log ( user ) ;
} )
. catch ( error => {
if ( error instanceof pgp . errors . QueryFileError ) {
// => the error is related to our QueryFile
}
} ) ;
ไฟล์ findUser.sql
:
/*
multi-line comments are supported
*/
SELECT name, dob -- single-line comments are supported
FROM Users
WHERE id = ${id}
วิธีการสืบค้นทุกวิธีของไลบรารีสามารถยอมรับประเภท QueryFile เป็นพารามิเตอร์ query
ประเภท QueryFile จะไม่แสดงข้อผิดพลาดใดๆ ทิ้งไว้ให้วิธีการสืบค้นปฏิเสธอย่างสวยงามด้วย QueryFileError
แนะนำให้ใช้พารามิเตอร์ที่มีชื่อภายในไฟล์ SQL ภายนอกเหนือตัวแปรดัชนี เนื่องจากจะทำให้ SQL อ่านและทำความเข้าใจได้ง่ายขึ้นมาก และเนื่องจากยังอนุญาตให้ใช้พารามิเตอร์ที่มีชื่อซ้อนกัน ดังนั้นจึงสามารถจัดกลุ่มตัวแปรในไฟล์ SQL ขนาดใหญ่และซับซ้อนในเนมสเปซได้ เพื่อการแยกการมองเห็นที่ง่ายยิ่งขึ้น
งานแสดงถึงการเชื่อมต่อที่ใช้ร่วมกันสำหรับการดำเนินการหลายแบบสอบถาม:
db . task ( t => {
// execute a chain of queries against the task context, and return the result:
return t . one ( 'SELECT count(*) FROM events WHERE id = $1' , 123 , a => + a . count )
. then ( count => {
if ( count > 0 ) {
return t . any ( 'SELECT * FROM log WHERE event_id = $1' , 123 )
. then ( logs => {
return { count , logs } ;
} )
}
return { count } ;
} ) ;
} )
. then ( data => {
// success, data = either {count} or {count, logs}
} )
. catch ( error => {
// failed
} ) ;
งานจัดเตรียมบริบทการเชื่อมต่อที่ใช้ร่วมกันสำหรับฟังก์ชันการเรียกกลับ ซึ่งจะเผยแพร่เมื่อเสร็จสิ้น และต้องใช้เมื่อใดก็ตามที่ดำเนินการค้นหามากกว่าหนึ่งรายการในแต่ละครั้ง ดูเพิ่มเติม Chaining Queries เพื่อทำความเข้าใจความสำคัญของการใช้งาน
คุณสามารถเลือกแท็กงานได้ (ดูแท็ก) และใช้ไวยากรณ์อะซิงก์ ES7:
db . task ( async t => {
const count = await t . one ( 'SELECT count(*) FROM events WHERE id = $1' , 123 , a => + a . count ) ;
if ( count > 0 ) {
const logs = await t . any ( 'SELECT * FROM log WHERE event_id = $1' , 123 ) ;
return { count