sql >> Databasteknik >  >> RDS >> SQLite

Hur man hanterar booleska värden i SQLite med JavaScript-proxies

Problemet med Booleans i SQLite

Om du någonsin har arbetat med SQLite bör du vara medveten om vilka datatyper som stöds och Boolean är inte en av dem. Mer specifikt som det står här:

2.1. boolesk datatyp

SQLite har inte en separat boolesk lagringsklass. Istället lagras booleska värden som heltal 0 (falskt) och 1 (sant).

SQLite känner igen nyckelorden "TRUE" och "FALSE", från och med version 3.23.0 (2018-04-02), men dessa nyckelord är egentligen bara alternativa stavningar för heltalsliteralerna 1 respektive 0.

De flesta JavaScript-bibliotek för SQLite3 stöder inte TRUE och FALSE nyckelord och de kräver att du förbereder påståendena i din kod med hjälp av heltal. Till exempel, i better-sqlite3 skulle du behöva göra detta:

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;

Använder number istället för boolean över hela din app skulle ge en fruktansvärd utvecklarupplevelse (plus förmodligen använda mer minne).

Du kan använda en hjälpfunktion för att transformera dina nyttolastobjekts boolean egenskaper till nummer (Jag hade faktiskt gjort det här en gång tidigare), men då måste du köra det manuellt innan varje fråga. Usch. Skulle det inte vara bra om denna logik kördes i bakgrunden, varje gång vi förberedde och körde ett uttalande?

Välkommen ES6 Proxies 👋 

En av de nyare JavaScript-funktionerna är Proxy objekt. Proxies är i huvudsak "fällor" som fångar upp objektoperationer som getters, seters och funktionsanrop. Använda Proxies vi kan modifiera SQLite JS wrapper-biblioteket för att exekvera vår egen logik, ungefär som en mellanprogramvara.

Skriva hjälpfunktionen

För att underlätta utvecklingen kommer vi att använda mapValues &isPlainObject verktygsfunktioner från lodash , men du kan givetvis koda din egen. Funktionen nedan kommer att mappa genom ett objekt (en nivå djupt) och konvertera värden av typen boolean för att skriva number .

import { mapValues } from 'lodash';

const booleanEntriesToNumbers = (object) =>
  mapValues(object, (value) =>
    typeof value === 'boolean' ? Number(value) : value
  );

Använda proxyservrar för att avlyssna frågeanrop

Nedan importerar vi better-sqlite3 biblioteket och skapa en ny databasinstans. Efteråt åsidosätter vi standard prepare metod med vår egen, som i sin tur åsidosätter metoderna run , get och all genom att skapa en ny proxy för var och en. Du kan naturligtvis skapa en proxy för vilken annan metod du vill.

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;

I huvudsak, en gång ett samtal till prepare metoden utlöses säger vi till JavaScript:Vänta! Vi vill modifiera detta funktionsanrop. Istället för att köra den logik som den ursprungliga utvecklaren avsåg, vill vi istället köra vår egen logik först (som är kartläggningen av objektets nyttolast). Efter att ha kört vår egen logik returnerar vi resultatet av att anropa den ursprungliga metoden genom att använda call för att binda this argument. Vill du läsa mer om hur proxy fungerar, läs här. För vår implementering använde vi apply metod här.

Tack för att du läste det här inlägget, jag hoppas att det hjälpte någon som arbetar med SQLite i JavaScript 👊


  1. Vilket är snabbast COALESCE ELLER ISNULL?

  2. CASE kontra DECODE

  3. Hur man ställer in ett standardvärde för en befintlig kolumn

  4. Välj datatyp för fältet i postgres