Masalah dengan Boolean di SQLite
Jika Anda pernah bekerja dengan SQLite, Anda harus mengetahui tipe data yang didukung dan Boolean
bukan salah satunya. Lebih khusus seperti yang dinyatakan di sini:
2.1. Tipe Data Boolean
SQLite tidak memiliki kelas penyimpanan Boolean terpisah. Sebagai gantinya, nilai Boolean disimpan sebagai bilangan bulat 0 (salah) dan 1 (benar).
SQLite mengenali kata kunci "TRUE" dan "FALSE", pada versi 3.23.0 (2018-04-02) tetapi kata kunci tersebut sebenarnya hanyalah ejaan alternatif untuk literal integer 1 dan 0 masing-masing.
Sebagian besar pustaka JavaScript untuk SQLite3 tidak mendukung TRUE
dan FALSE
kata kunci dan mereka mengharuskan Anda untuk menyiapkan pernyataan dalam kode Anda menggunakan bilangan bulat. Misalnya, di better-sqlite3 Anda harus melakukan ini:
const payload = {
isActive: 1, // <======
username: 'Brad',
password: '1234',
email: '[email protected]',
};
const result = database
.prepare(
`INSERT INTO accounts(isActive, username, password, email) VALUES(@isActive, @username, @password, @email) `
)
.run({ bucketID, taskSiteID, name, username, password, email }).changes;
Menggunakan number
bukannya boolean
di seluruh aplikasi Anda akan memberikan pengalaman pengembang yang buruk (ditambah mungkin menggunakan lebih banyak memori).
Anda dapat menggunakan fungsi pembantu untuk mengubah boolean objects objek muatan Anda properti ke angka (Saya sebenarnya pernah melakukan ini sekali, di masa lalu), tetapi kemudian Anda harus menjalankannya secara manual sebelum setiap kueri. Astaga. Bukankah lebih bagus jika logika ini dijalankan di latar belakang, setiap kali kita menyiapkan dan menjalankan sebuah pernyataan?
Selamat datang ES6 Proxy 👋
Salah satu fitur JavaScript yang lebih baru adalah Proxy
obyek. Proxy pada dasarnya adalah "perangkap" yang mencegat operasi objek seperti getter, setter, dan panggilan fungsi. Menggunakan Proxy kita dapat memodifikasi perpustakaan pembungkus SQLite JS untuk mengeksekusi logika kita sendiri, seperti middleware.
Menulis fungsi pembantu
Untuk kemudahan pengembangan, kita akan menggunakan mapValues
&isPlainObject
fungsi utilitas dari lodash , tetapi Anda tentu saja dapat membuat kode sendiri. Fungsi di bawah ini akan memetakan melalui objek (kedalaman satu tingkat) dan mengonversi nilai tipe boolean
untuk mengetik number
.
import { mapValues } from 'lodash';
const booleanEntriesToNumbers = (object) =>
mapValues(object, (value) =>
typeof value === 'boolean' ? Number(value) : value
);
Menggunakan proxy untuk mencegat panggilan kueri
Di bawah ini kami mengimpor better-sqlite3
library dan membuat instance database baru. Setelah itu, kami mengganti default prepare
dengan metode kita sendiri, yang pada gilirannya menimpa metode run
, get
dan all
, dengan membuat proxy baru untuk masing-masing proxy. Anda tentu saja dapat membuat proxy untuk metode lain yang Anda inginkan.
import Database from 'better-sqlite3';
// Create new database instance
const db = new Database(dbFilePath);
// We will use this function to override the default "prepare" method
const proxiedPrepare = new Proxy(db.prepare, {
apply: (prepare, prepareThisArg, [stringStatement]) => {
const statement = prepare.call(prepareThisArg, stringStatement);
// Override the default "run" method
statement.run = new Proxy(statement.run, {
apply: (run, runThisArg, args) => {
const mappedArgs = args.map((arg) =>
isPlainObject(arg) ? booleanEntriesToNumbers(arg) : arg
);
return run.call(runThisArg, ...mappedArgs);
},
});
// Override the default "get" method
statement.get = new Proxy(statement.get, {
apply: (get, getThisArg, args) => {
const mappedArgs = args.map((arg) =>
isPlainObject(arg) ? booleanEntriesToNumbers(arg) : arg
);
return get.call(getThisArg, ...mappedArgs);
},
});
// Override the default "all" method
statement.all = new Proxy(statement.all, {
apply: (all, allThisArg, args) => {
const mappedArgs = args.map((arg) =>
isPlainObject(arg) ? booleanEntriesToNumbers(arg) : arg
);
return all.call(allThisArg, ...mappedArgs);
},
});
return statement;
},
});
// Override the default "prepare" method
db.prepare = proxiedPrepare;
Intinya, sekali panggilan ke prepare
metode dipicu, kami memberi tahu JavaScript:Tunggu! Kami ingin mengubah panggilan fungsi ini. Alih-alih mengeksekusi logika yang dimaksudkan pengembang asli, kami ingin mengeksekusi logika kami sendiri terlebih dahulu (yang merupakan pemetaan muatan objek). Setelah menjalankan logika kita sendiri, kita mengembalikan hasil pemanggilan metode asli dengan menggunakan call
untuk mengikat this
argumen. Jika Anda ingin membaca lebih lanjut tentang cara kerja proxy, baca di sini. Untuk implementasi kami, kami menggunakan apply
metode di sini.
Terima kasih telah membaca posting ini, saya harap ini membantu seseorang yang bekerja dengan SQLite di JavaScript