Het probleem met Booleans in SQLite
Als je ooit met SQLite hebt gewerkt, moet je op de hoogte zijn van de ondersteunde gegevenstypen en Boolean
is niet een van hen. Meer specifiek zoals hier vermeld:
2.1. Booleaans gegevenstype
SQLite heeft geen aparte Booleaanse opslagklasse. In plaats daarvan worden Booleaanse waarden opgeslagen als gehele getallen 0 (false) en 1 (true).
SQLite herkent de trefwoorden "TRUE" en "FALSE", vanaf versie 3.23.0 (2018-04-02), maar die trefwoorden zijn eigenlijk slechts alternatieve spellingen voor respectievelijk de integer-letterwoorden 1 en 0.
De meeste JavaScript-bibliotheken voor SQLite3 bieden geen ondersteuning voor TRUE
en FALSE
trefwoorden en ze vereisen dat u de instructies in uw code voorbereidt met behulp van gehele getallen. In better-sqlite3 zou je bijvoorbeeld dit moeten doen:
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;
Gebruik number
in plaats van boolean
in je hele app zou zorgen voor een vreselijke ontwikkelaarservaring (plus waarschijnlijk meer geheugen gebruiken).
Je zou een hulpfunctie kunnen gebruiken om de boolean . van je payload-objecten te transformeren eigenschappen naar nummers (Ik had dit in het verleden een keer gedaan), maar dan zou je het voor elke query handmatig moeten uitvoeren. Jakkes. Zou het niet geweldig zijn als deze logica op de achtergrond werd uitgevoerd, elke keer dat we een verklaring voorbereidden en uitvoerden?
Welkom ES6-proxy's 👋
Een van de nieuwere JavaScript-functies is de Proxy
voorwerp. Volmachten zijn in wezen "vallen" die objectbewerkingen zoals getters, setters en functieaanroepen onderscheppen. Proxies gebruiken we kunnen de SQLite JS-wrapperbibliotheek aanpassen om onze eigen logica uit te voeren, een soort middleware.
De helperfunctie schrijven
Voor het gemak van ontwikkeling gaan we mapValues
. gebruiken &isPlainObject
hulpprogramma functies van lodash , maar u kunt natuurlijk uw eigen coderen. De onderstaande functie zal door een object (één niveau diep) in kaart brengen en waarden van het type boolean
converteren om number
te typen .
import { mapValues } from 'lodash';
const booleanEntriesToNumbers = (object) =>
mapValues(object, (value) =>
typeof value === 'boolean' ? Number(value) : value
);
Proxies gebruiken om query-oproepen te onderscheppen
Hieronder importeren we better-sqlite3
bibliotheek en maak een nieuwe database-instance. Daarna overschrijven we de standaard prepare
methode met de onze, die op zijn beurt de methoden run
. overschrijft , get
en all
, door voor elke een nieuwe proxy te maken. U kunt natuurlijk een proxy maken voor elke andere methode die u wilt.
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;
In wezen, een keer een oproep aan de prepare
methode wordt geactiveerd, vertellen we JavaScript:Wacht! We willen deze functieaanroep wijzigen. In plaats van de logica uit te voeren die de oorspronkelijke ontwikkelaar bedoelde, willen we in plaats daarvan eerst onze eigen logica uitvoeren (dit is het in kaart brengen van de objectlading). Na het uitvoeren van onze eigen logica, retourneren we het resultaat van het aanroepen van de originele methode met behulp van call
om de this
. te binden argument. Als je meer wilt lezen over hoe proxy's werken, lees dan hier. Voor onze implementatie gebruikten we de apply
methode hier.
Bedankt voor het lezen van dit bericht, ik hoop dat het iemand heeft geholpen die met SQLite in JavaScript werkt 👊