SQLite
 sql >> Baza danych >  >> RDS >> SQLite

Jak obsługiwać wartości logiczne w SQLite za pomocą proxy JavaScript?

Problem z wartościami boolowskimi w SQLite

Jeśli kiedykolwiek pracowałeś z SQLite, powinieneś wiedzieć o obsługiwanych typach danych i Boolean nie jest jednym z nich. Dokładniej, jak podano tutaj:

2.1. Typ danych logicznych

SQLite nie ma oddzielnej klasy pamięci Boolean. Zamiast tego wartości logiczne są przechowywane jako liczby całkowite 0 (fałsz) i 1 (prawda).

SQLite rozpoznaje słowa kluczowe „TRUE” i „FALSE” od wersji 3.23.0 (2018-04-02), ale te słowa kluczowe są tak naprawdę tylko alternatywną pisownią odpowiednio dla literałów całkowitych 1 i 0.

Większość bibliotek JavaScript dla SQLite3 nie obsługuje TRUE i FALSE słowa kluczowe i wymagają przygotowania instrukcji w kodzie przy użyciu liczb całkowitych. Na przykład w better-sqlite3 musiałbyś to zrobić:

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;

Korzystanie z number zamiast boolean w całej aplikacji spowodowałoby to okropne wrażenia dla programistów (i prawdopodobnie zużyłoby więcej pamięci).

Możesz użyć funkcji pomocniczej, aby przekształcić wartość logiczną swoich obiektów ładunku właściwości do liczb (Właściwie zrobiłem to raz, w przeszłości), ale wtedy musiałbyś uruchamiać go ręcznie przed każdym zapytaniem. Ojej. Czy nie byłoby wspaniale, gdyby ta logika była wykonywana w tle, za każdym razem, gdy przygotowywaliśmy i uruchamialiśmy oświadczenie?

Witamy na serwerach proxy ES6 👋 

Jedną z nowszych funkcji JavaScript jest Proxy obiekt. Proxy są zasadniczo „pułapkami”, które przechwytują operacje na obiektach, takie jak pobierające, ustawiające i wywołania funkcji. Korzystanie z proxy możemy zmodyfikować bibliotekę opakowującą SQLite JS, aby wykonywała własną logikę, coś w rodzaju oprogramowania pośredniczącego.

Pisanie funkcji pomocniczej

Dla ułatwienia programowania użyjemy mapValues &isPlainObject funkcje użytkowe z lodash , ale możesz oczywiście zakodować własne. Poniższa funkcja mapuje przez obiekt (jednopoziomowa głębokość) i konwertuje wartości typu boolean aby wpisać number .

import { mapValues } from 'lodash';

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

Używanie serwerów proxy do przechwytywania wywołań zapytań

Poniżej importujemy better-sqlite3 bibliotekę i utworzyć nową instancję bazy danych. Następnie nadpisujemy domyślne prepare z naszą własną, która z kolei nadpisuje metody run , get i all , tworząc dla każdego nowego proxy. Możesz oczywiście utworzyć proxy dla dowolnej innej metody.

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;

Zasadniczo po wywołaniu prepare metoda zostanie wyzwolona, ​​mówimy JavaScript:Czekaj! Chcemy zmodyfikować to wywołanie funkcji. Zamiast wykonywać logikę zamierzoną przez pierwotnego programistę, zamiast tego chcemy najpierw wykonać własną logikę (która jest mapowaniem ładunku obiektu). Po wykonaniu własnej logiki zwracamy wynik wywołania oryginalnej metody za pomocą call aby powiązać this argument. Jeśli chcesz dowiedzieć się więcej o działaniu serwerów proxy, przeczytaj tutaj. Do naszej implementacji użyliśmy apply metoda tutaj.

Dziękuję za przeczytanie tego posta, mam nadzieję, że pomogło to komuś pracującemu z SQLite w JavaScript 👊


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wstaw wiele wierszy w błędzie SQLite (kod błędu =1)

  2. Sqlite3 nie wstawia wielu wierszy w kolejności

  3. Eksportuj całą bazę danych SQLite do pliku SQL

  4. jak pobrać pierwszy lub (dowolny) element z listy LiveData w architekturze Android MVVM?

  5. Pokoj najlepsze sposoby tworzenia kopii zapasowych dla aplikacji offline?