Problém s Booleany v SQLite
Pokud jste někdy pracovali s SQLite, měli byste si být vědomi podporovaných datových typů a Boolean
není jedním z nich. Přesněji, jak je uvedeno zde:
2.1. Booleovský datový typ
SQLite nemá samostatnou booleovskou třídu úložiště. Místo toho jsou booleovské hodnoty uloženy jako celá čísla 0 (nepravda) a 1 (pravda).
SQLite rozpoznává klíčová slova „TRUE“ a „FALSE“ od verze 3.23.0 (2018-04-02), ale tato klíčová slova jsou ve skutečnosti pouze alternativní hláskování pro celočíselné literály 1 a 0.
Většina knihoven JavaScriptu pro SQLite3 nepodporuje TRUE
a FALSE
klíčová slova a vyžadují, abyste připravili příkazy v kódu pomocí celých čísel. Například v better-sqlite3 byste museli udělat toto:
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;
Pomocí number
místo boolean
napříč celou vaší aplikací by to znamenalo pro vývojáře hrozný zážitek (a navíc pravděpodobně spotřeboval více paměti).
K transformaci booleovských hodnot objektů můžete použít pomocnou funkci vlastnosti na čísla (Ve skutečnosti jsem to udělal jednou, v minulosti), ale pak byste to museli ručně spustit před každým dotazem. Fuj. Nebylo by skvělé, kdyby tato logika byla provedena na pozadí pokaždé, když jsme připravili a spustili prohlášení?
Vítejte ES6 proxy 👋
Jednou z novějších funkcí JavaScriptu je Proxy
objekt. Proxy jsou v podstatě "pasti", které zachycují operace s objekty, jako jsou getry, nastavovače a volání funkcí. Pomocí Proxy můžeme upravit knihovnu obalu SQLite JS tak, aby spouštěla naši vlastní logiku, něco jako middleware.
Zápis pomocné funkce
Pro usnadnění vývoje budeme používat mapValues
&isPlainObject
obslužné funkce z lodash , ale můžete samozřejmě kódovat své vlastní. Funkce níže bude mapovat objekt (hloubka jedné úrovně) a převádět hodnoty typu boolean
zadejte number
.
import { mapValues } from 'lodash';
const booleanEntriesToNumbers = (object) =>
mapValues(object, (value) =>
typeof value === 'boolean' ? Number(value) : value
);
Použití proxy k zachycení dotazů
Níže importujeme better-sqlite3
knihovnu a vytvořte novou instanci databáze. Poté přepíšeme výchozí prepare
metoda s naší vlastní, která zase přepíše metody run
, get
a all
vytvořením nového proxy pro každého. Můžete samozřejmě vytvořit proxy pro jakoukoli jinou metodu, kterou chcete.
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;
V podstatě jednou zavoláte prepare
je spuštěna metoda, řekneme JavaScriptu:Počkejte! Chceme upravit toto volání funkce. Namísto provádění logiky, kterou zamýšlel původní vývojář, místo toho chceme nejprve provést naši vlastní logiku (což je mapování užitečného zatížení objektu). Po provedení naší vlastní logiky vrátíme výsledek volání původní metody pomocí call
svázat this
argument. Pokud si chcete přečíst více o tom, jak fungují proxy, čtěte zde. Pro naši implementaci jsme použili apply
metoda zde.
Děkuji za přečtení tohoto příspěvku, doufám, že to pomohlo někomu, kdo pracuje s SQLite v JavaScriptu 👊