sql >> Database >  >> RDS >> SQLite

Hoe om te gaan met booleaanse waarden in SQLite met JavaScript-proxy's

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 👊


  1. Een experthandleiding voor Slony-replicatie voor PostgreSQL

  2. Maanden toevoegen aan een datum in PostgreSQL

  3. Gemeenschappelijke tabeluitdrukking, waarom puntkomma?

  4. JSON_ARRAYAGG() Functie in Oracle