Problem z wartościami boolowskimi w SQLite
Jeśli kiedykolwiek pracowałeś z SQLite, powinieneś wiedzieć o obsługiwanych typach danych i Boolean
nie jest jednym z nich. Dokładniej, jak podano tutaj:
2.1. Typ danych logicznych
SQLite nie ma oddzielnej klasy pamięci Boolean. Zamiast tego wartości logiczne są przechowywane jako liczby całkowite 0 (fałsz) i 1 (prawda).
SQLite rozpoznaje słowa kluczowe „TRUE” i „FALSE” od wersji 3.23.0 (2018-04-02), ale te słowa kluczowe są tak naprawdę tylko alternatywną pisownią odpowiednio dla literałów całkowitych 1 i 0.
Większość bibliotek JavaScript dla SQLite3 nie obsługuje TRUE
i FALSE
słowa kluczowe i wymagają przygotowania instrukcji w kodzie przy użyciu liczb całkowitych. Na przykład w better-sqlite3 musiałbyś to zrobić:
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;
Korzystanie z number
zamiast boolean
w całej aplikacji spowodowałoby to okropne wrażenia dla programistów (i prawdopodobnie zużyłoby więcej pamięci).
Możesz użyć funkcji pomocniczej, aby przekształcić wartość logiczną swoich obiektów ładunku właściwości do liczb (Właściwie zrobiłem to raz, w przeszłości), ale wtedy musiałbyś uruchamiać go ręcznie przed każdym zapytaniem. Ojej. Czy nie byłoby wspaniale, gdyby ta logika była wykonywana w tle, za każdym razem, gdy przygotowywaliśmy i uruchamialiśmy oświadczenie?
Witamy na serwerach proxy ES6 👋
Jedną z nowszych funkcji JavaScript jest Proxy
obiekt. Proxy są zasadniczo „pułapkami”, które przechwytują operacje na obiektach, takie jak pobierające, ustawiające i wywołania funkcji. Korzystanie z proxy możemy zmodyfikować bibliotekę opakowującą SQLite JS, aby wykonywała własną logikę, coś w rodzaju oprogramowania pośredniczącego.
Pisanie funkcji pomocniczej
Dla ułatwienia programowania użyjemy mapValues
&isPlainObject
funkcje użytkowe z lodash , ale możesz oczywiście zakodować własne. Poniższa funkcja mapuje przez obiekt (jednopoziomowa głębokość) i konwertuje wartości typu boolean
aby wpisać number
.
import { mapValues } from 'lodash';
const booleanEntriesToNumbers = (object) =>
mapValues(object, (value) =>
typeof value === 'boolean' ? Number(value) : value
);
Używanie serwerów proxy do przechwytywania wywołań zapytań
Poniżej importujemy better-sqlite3
bibliotekę i utworzyć nową instancję bazy danych. Następnie nadpisujemy domyślne prepare
z naszą własną, która z kolei nadpisuje metody run
, get
i all
, tworząc dla każdego nowego proxy. Możesz oczywiście utworzyć proxy dla dowolnej innej metody.
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;
Zasadniczo po wywołaniu prepare
metoda zostanie wyzwolona, mówimy JavaScript:Czekaj! Chcemy zmodyfikować to wywołanie funkcji. Zamiast wykonywać logikę zamierzoną przez pierwotnego programistę, zamiast tego chcemy najpierw wykonać własną logikę (która jest mapowaniem ładunku obiektu). Po wykonaniu własnej logiki zwracamy wynik wywołania oryginalnej metody za pomocą call
aby powiązać this
argument. Jeśli chcesz dowiedzieć się więcej o działaniu serwerów proxy, przeczytaj tutaj. Do naszej implementacji użyliśmy apply
metoda tutaj.
Dziękuję za przeczytanie tego posta, mam nadzieję, że pomogło to komuś pracującemu z SQLite w JavaScript 👊