SQLite
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> SQLite

Cách xử lý các giá trị boolean trong SQLite bằng JavaScript Proxy

Sự cố với Booleans trong SQLite

Nếu bạn đã từng làm việc với SQLite, bạn nên biết các kiểu dữ liệu được hỗ trợ và Boolean không phải là một trong số họ. Cụ thể hơn như đã nêu ở đây:

2.1. Boolean Datatype

SQLite không có lớp lưu trữ Boolean riêng biệt. Thay vào đó, các giá trị Boolean được lưu trữ dưới dạng số nguyên 0 (false) và 1 (true).

SQLite nhận ra các từ khóa "TRUE" và "FALSE", kể từ phiên bản 3.23.0 (2018-04-02) nhưng những từ khóa đó thực sự chỉ là cách viết thay thế cho các chữ số nguyên 1 và 0 tương ứng.

Hầu hết các thư viện JavaScript cho SQLite3 không hỗ trợ TRUEFALSE từ khóa và chúng yêu cầu bạn chuẩn bị các câu lệnh trong mã của bạn bằng cách sử dụng số nguyên. Ví dụ:trong better-sqlite3, bạn sẽ phải làm điều này:

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;

Sử dụng number thay vì boolean trên toàn bộ ứng dụng của bạn sẽ tạo ra trải nghiệm khủng khiếp dành cho nhà phát triển (ngoài ra có thể sử dụng nhiều bộ nhớ hơn).

Bạn có thể sử dụng một hàm trợ giúp để chuyển đổi đối tượng tải trọng của mình boolean thuộc tính cho số (Tôi đã thực sự làm điều này một lần trước đây), nhưng sau đó bạn phải chạy nó theo cách thủ công trước mỗi truy vấn. Rất tiếc. Sẽ thật tuyệt nếu logic này được thực thi ở chế độ nền mỗi khi chúng ta chuẩn bị và chạy một câu lệnh phải không?

Chào mừng Proxy ES6 👋

Một trong những tính năng JavaScript mới hơn là Proxy vật. Proxy về cơ bản là các "bẫy" chặn các hoạt động của đối tượng như getters, setters và các lệnh gọi hàm. Sử dụng Proxy chúng ta có thể sửa đổi thư viện trình bao bọc JS của SQLite để thực thi logic của riêng chúng ta, giống như một phần mềm trung gian.

Viết hàm trợ giúp

Để dễ phát triển, chúng tôi sẽ sử dụng mapValues &isPlainObject các chức năng tiện ích từ lodash, nhưng tất nhiên bạn có thể viết mã của riêng mình. Hàm bên dưới sẽ ánh xạ qua một đối tượng (sâu một cấp) và chuyển đổi các giá trị của loại boolean để nhập number .

import { mapValues } from 'lodash';

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

Sử dụng proxy để chặn các cuộc gọi truy vấn

Dưới đây chúng tôi nhập better-sqlite3 thư viện và tạo một phiên bản cơ sở dữ liệu mới. Sau đó, chúng tôi ghi đè prepare mặc định với phương thức riêng của chúng tôi, lần lượt ghi đè các phương thức run , getall , bằng cách tạo một proxy mới cho từng proxy. Tất nhiên, bạn có thể tạo proxy cho bất kỳ phương pháp nào khác mà bạn muốn.

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;

Về cơ bản, một lần gọi đến prepare phương thức được kích hoạt, chúng tôi nói với JavaScript: Chờ đã! Chúng tôi muốn sửa đổi lời gọi hàm này. Thay vì thực thi logic mà nhà phát triển ban đầu dự định, thay vào đó, chúng tôi muốn thực thi logic của riêng mình trước (là ánh xạ của trọng tải đối tượng). Sau khi thực thi logic của riêng mình, chúng tôi trả về kết quả của việc gọi phương thức gốc bằng cách sử dụng call để ràng buộc this lý lẽ. Nếu bạn muốn đọc thêm về cách hoạt động của proxy, hãy đọc tại đây. Để triển khai, chúng tôi đã sử dụng apply phương pháp tại đây.

Cảm ơn bạn đã đọc bài đăng này, tôi hy vọng nó sẽ giúp ai đó làm việc với SQLite trong 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. SQLite JSON_TREE ()

  2. Tự động tăng giá trị 'id' khi chèn vào sqlite

  3. Đã tìm thấy rò rỉ cơ sở dữ liệu SQLite

  4. SQLite Chọn riêng biệt

  5. sqlite get trường với hơn 2 MB