sql >> Database teknologi >  >> RDS >> SQLite

Sådan håndteres booleske værdier i SQLite ved hjælp af JavaScript-proxies

Problemet med Booleans i SQLite

Hvis du nogensinde har arbejdet med SQLite, bør du være opmærksom på de understøttede datatyper og Boolean er ikke en af ​​dem. Mere specifikt som angivet her:

2.1. boolesk datatype

SQLite har ikke en separat boolesk lagerklasse. I stedet gemmes booleske værdier som heltal 0 (falsk) og 1 (sand).

SQLite genkender nøgleordene "TRUE" og "FALSE", fra og med version 3.23.0 (2018-04-02), men disse nøgleord er egentlig bare alternative stavemåder for de heltallige bogstaver henholdsvis 1 og 0.

De fleste JavaScript-biblioteker til SQLite3 understøtter ikke TRUE og FALSE nøgleord, og de kræver, at du forbereder udsagn i din kode ved hjælp af heltal. For eksempel, i better-sqlite3 skulle du gøre dette:

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;

Brug af number i stedet for boolean på tværs af hele din app ville give en forfærdelig udvikleroplevelse (plus sandsynligvis bruge mere hukommelse).

Du kan bruge en hjælpefunktion til at transformere dine nyttelastobjekters boolean egenskaber til numre (Jeg havde faktisk gjort dette en gang tidligere), men så skulle du køre det manuelt før hver forespørgsel. Yikes. Ville det ikke være fantastisk, hvis denne logik blev udført i baggrunden, hver gang vi forberedte og kørte en erklæring?

Velkommen til ES6 Proxies 👋 

En af de nyere JavaScript-funktioner er Proxy objekt. Fuldmagter er i det væsentlige "fælder", der opsnapper objektoperationer som gettere, sættere og funktionskald. Brug af Proxyer vi kan ændre SQLite JS wrapper-biblioteket til at udføre vores egen logik, lidt som en middleware.

Skrivning af hjælpefunktionen

For at lette udviklingen vil vi bruge mapValues &isPlainObject hjælpefunktioner fra lodash , men du kan selvfølgelig kode din egen. Funktionen nedenfor vil kortlægge et objekt (et niveau dybt) og konvertere værdier af typen boolean for at indtaste number .

import { mapValues } from 'lodash';

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

Brug af proxyer til at opsnappe forespørgselsopkald

Nedenfor importerer vi better-sqlite3 bibliotek og opret en ny databaseinstans. Bagefter tilsidesætter vi standard prepare metode med vores egen, som igen tilsidesætter metoderne run , get og all , ved at oprette en ny proxy for hver enkelt. Du kan selvfølgelig oprette en proxy for enhver anden metode, du ønsker.

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 det væsentlige, når et opkald til prepare metode udløses, fortæller vi JavaScript:Vent! Vi ønsker at ændre dette funktionskald. I stedet for at udføre den logik, som den oprindelige udvikler havde til hensigt, ønsker vi i stedet at udføre vores egen logik først (som er kortlægningen af ​​objektets nyttelast). Efter at have udført vores egen logik, returnerer vi resultatet af at kalde den oprindelige metode ved at bruge call for at binde this argument. Hvis du vil læse mere om, hvordan fuldmagter fungerer, så læs med her. Til vores implementering brugte vi apply metode her.

Tak fordi du læste dette indlæg, jeg håber det hjalp nogen, der arbejder med SQLite i JavaScript 👊


  1. Ét sikkerhedssystem til applikation, forbindelsespooling og PostgreSQL - sagen til LDAP

  2. Bedste måde at vælge tilfældige rækker PostgreSQL

  3. Find partitioneringskolonnen for en opdelt tabel i SQL Server (T-SQL)

  4. Hvad er mere effektivt:Flere MySQL-tabeller eller et stort bord?