코딩/React

ElectronJS 일렉트론 강좌 4편 SQLite3 sql.js

드리프트 2022. 1. 15. 22:24
728x170

 

안녕하세요?

 

ElectronJS 일렉트론 강좌를 3편에서 끝냈었는데요.

 

댓글로 어떤 분께서 SQLite3 CRUD(Create, Read, Update, Delete) 예제를 보고 싶다고 해서 4편을 작성해 봤습니다.

 

먼저, 기존 강좌 3편 링크입니다.

 

https://cpro95.tistory.com/500

 

ElectronJS 일렉트론 강좌 1편 SQLite3 sql.js

안녕하세요? 오늘은 Electron 강좌를 시작해 볼까 합니다. ElectronJS는 웹상의 기술인 HTML, CSS, Javascript로 데스크톱 애플리케이션을 만들 수 있는 NodeJS 패키지인데요. HTML, CSS, Javascript로 작동되다..

cpro95.tistory.com

https://cpro95.tistory.com/501

 

ElectronJS 일렉트론 강좌 2편 SQLite3 sql.js

안녕하세요? 지난 시간에 이어 2편 진행토록 하겠습니다. 1편: https://cpro95.tistory.com/500 ElectronJS 일렉트론 강좌 1편 SQLite3 sql.js 안녕하세요? 오늘은 Electron 강좌를 시작해 볼까 합니다. ElectronJ..

cpro95.tistory.com

https://cpro95.tistory.com/502

 

ElectronJS 일렉트론 강좌 3편 SQLite3 sql.js

안녕하세요? 지난 시간에 이어 3편 진행토록 하겠습니다. 1편: https://cpro95.tistory.com/500 ElectronJS 일렉트론 강좌 1편 SQLite3 sql.js 안녕하세요? 오늘은 Electron 강좌를 시작해 볼까 합니다. ElectronJ..

cpro95.tistory.com

 

일렉트론에 CRUD를 적용하기 전에 CRUD 용 NodeJS 로직(함수)을 만들어서 테스트해보겠습니다.

 

일렉트론에 UI와 함께 적용하는 거는 다음 편에 작성토록 하고, 먼저 로직 구현에 집중해 보겠습니다.

 

전에도 말씀드렸지만 SQLite3 라이브러리는 C 언어 패키지입니다.

 

C 언어로 만든 패키지를 javascript로 웹 어셈블리어로 옮긴 게 바로 sql.js인데요.

 

https://github.com/sql-js/sql.js

 

GitHub - sql-js/sql.js: A javascript library to run SQLite on the web.

A javascript library to run SQLite on the web. . Contribute to sql-js/sql.js development by creating an account on GitHub.

github.com

 

기존 NodeJS 패키지인 sqlite3 앱과는 사용방법이 조금 다릅니다.

 

sql.js 사용법이니까 참고 바랍니다.

 

먼저 Helper 함수 및 기초 세팅입니다.

 

const fs = require("fs");
const initSqlJs = require("sql.js");

const dbFileName = "./test.db";

let _rowsFromSqlDataArray = function (object) {
  let data = [];
  let i = 0;
  let j = 0;
  for (let valueArray of object.values) {
    data[i] = {};
    j = 0;
    for (let column of object.columns) {
      Object.assign(data[i], { [column]: valueArray[j] });
      j++;
    }
    i++;
  }
  return data;
};

 

참고로 _rowsFromSqlDataArray 함수는 sql 데이터를 자바스크립트 Array로 변환시켜주는 함수입니다.
 

1. Create Table

function createAndReadTest() {
  initSqlJs().then((SQL) => {
    const db = new SQL.Database();
    let sqlstr =
      "CREATE TABLE Users (id integer primary key, name text not null, email text unique, password text)";
    db.exec(sqlstr);

    let sqlstr2 = `
    INSERT INTO Users(name, email, password) VALUES ("ki-hun", "ki-hun@squid.game", "password456"); \
    INSERT INTO Users(name, email, password) VALUES ("san-gwoo", "sang-woo@squid.game", "password218"); \
  `;

    db.exec(sqlstr2);

    let res = db.exec("SELECT * FROM Users;");
    if (res.length === 0) console.log("No Data found!");
    else {
      res = _rowsFromSqlDataArray(res[0]);
      console.log(res);
    }

    const data = db.export();
    const buffer = new Buffer.from(data);
    fs.writeFileSync(dbFileName, buffer);
  });
}

createAndReadTest();

 

먼저, Create 테스트입니다.

 

sql.js 패키지는 initSqlJs() 리턴된 Promise내에서 이루어져야 합니다.

 

그래서 위에서 보면은 initSqlJS(). then((SQL) => ) 형식으로 콜백 함수 내에서 Table을 만들고 자료를 Insert 했습니다.

 

그리고 sql.js는 기본적으로 메모리에 모든 자료를 관리하기 때문에 파일로 저장하려면 위와 같이 Buffer.from NodeJS 함수를 이용해서 파일에 저장해야 합니다.

 

한번 테스트해볼까요?

 

 

Table 생성 및 자료 Insert 작업이 완벽히 작동하고 있네요.

 

 

2. Read Test

 

두 번째는 Read Test입니다.

 

function readTest() {
  initSqlJs().then((SQL) => {
    SQL.dbOpen = function (databaseFileName) {
      try {
        return new SQL.Database(fs.readFileSync(databaseFileName));
      } catch (error) {
        console.log("Can't open database file.", error.message);
        return null;
      }
    };

    let db = SQL.dbOpen(dbFileName);

    let res = db.exec("SELECT * FROM Users;");
    // console.log(res.legth);
    if (res.length === 0) console.log("No Data found!");
    else {
      res = _rowsFromSqlDataArray(res[0]);
      console.log(res);
    }
  });
}

readTest();

sql.js는 initSqlJS()의 리턴된 Promise의 콜백 함수로 이루어져야 합니다.

 

그래서 위에서도 아까와 같이 initSqlJS로 먼저 sql.js를 초기화했고,

 

그리고 이번에는 아까 createAndReadTest() 함수에서 저 정했던 DB를 읽어 들이는 로직이 추가됐습니다.

 

그리고 "SELECT" 쿼리를 이용해서 전체 데이터를 불러오고 있습니다.

 

테스트 결과를 한번 볼까요?

 

역시나 잘 작동되고 있네요.

 

 

3. Update Test

 

업데이트 테스트입니다.

 

SQL에서는 Update는 다음과 같이 사용합니다.

 

"UPDATE Users SET name = 'kihun', email = 'kihun@squid.game' WHERE id = 1"
 
UPDATE Users 라고 테이블을 지정하고
 
그 다음으로 SET을 이용해 테이블의 컬럼 이름과 업데이트할 데이터를 지정합니다.
 
그리고 WHERE 구문을 이용해서 특정 행(Row)를 지정하게 되죠.
 
function updateTest() {
  initSqlJs().then((SQL) => {
    SQL.dbOpen = function (databaseFileName) {
      try {
        return new SQL.Database(fs.readFileSync(databaseFileName));
      } catch (error) {
        console.log("Can't open database file.", error.message);
        return null;
      }
    };

    let db = SQL.dbOpen(dbFileName);
    db.exec(
      "UPDATE Users SET name = 'kihun', email = 'kihun@squid.game' WHERE id = 1"
    );
    const data = db.export();
    const buffer = new Buffer.from(data);
    fs.writeFileSync("test.db", buffer);
  });
}

readTest();
updateTest();
readTest();
 
업데이트를 했으니까 꼭 다시 Buffer.from으로 파일로 저장해야 합니다.
 
이제 테스트해볼까요?
 
 
 

 

ki-hun 이름과 이메일이 kihun으로 바뀐 게 보이시죠.

 

업데이트도 잘 작동되고 있습니다.

 

 

4. Insert Data

 

아까 CreateAndReadTest에서 테이블을 create 하고 insert 데이터로 자료를 추가했는데요.

 

이걸 함수로 만들어 보았습니다.

 

function insertTest(name, email, password) {
  initSqlJs().then((SQL) => {
    SQL.dbOpen = function (databaseFileName) {
      try {
        return new SQL.Database(fs.readFileSync(databaseFileName));
      } catch (error) {
        console.log("Can't open database file.", error.message);
        return null;
      }
    };

    let db = SQL.dbOpen(dbFileName);

    db.exec(
      `INSERT INTO Users(name, email, password) VALUES("${name}","${email}","${password}");`
    );
    const data = db.export();
    const buffer = new Buffer.from(data);
    fs.writeFileSync(dbFileName, buffer);
  });
}

readTest();
insertTest("ali", "ali@squid.game", "password199");
readTest();

ali를 추가했는데요.

 

insertTest함수는 name, email, password를 인자로 받아서 그 인자를 INSERT SQL 쿼리에 배당합니다.

 

근데 여기서 중요한 게 있는데요.

 

`INSERT INTO Users(name, email, password) VALUES("${name}","${email}","${password}");`

 

위와 같이 ${name} 바깥쪽에 ""를 넣었습니다.

 

만약에 바깥쪽에 ""를 넣지 않으면 어떻게 SQL 쿼리가 되는지 볼까요?

 

`INSERT INTO Users(name, email, password) VALUES(ali, ali@squid.game, password199);`

위와 같이 자바스크립트 변수가 변환됩니다.

 

그런데 SQL 쿼리에서는 위와 같이 문자열이 그냥 있으면 에러가 납니다.

 

그래서 ${name} 바깥쪽에 ""를 꼭 넣어줘야 합니다.

 

""를 넣으면 다음과 같이 해석되게 되는 거죠.

 

`INSERT INTO Users(name, email, password) VALUES("ali","ali@squid.game","password199");`

 

그리고 Users뒤에 Users(name, email, password)를 넣었는데요.

 

넣고 싶은 칼럼을 지정할 수 있습니다.

 

만약 컬럼을 지정하지 않으면 Table에 규정된 모든 칼럼의 값을 넣어야 합니다.

 

`INSERT INTO Users VALUES(4, "test", "test@test.com", "passwordtest");`

위와 같이 말입니다.

 

그럼 테스트해볼까요?

 

 

ali가 추가되었네요.

 

 

5. Delete Test

 

마지막으로 Delete 테스트입니다.

 

function deleteTest(email) {
  initSqlJs().then((SQL) => {
    SQL.dbOpen = function (databaseFileName) {
      try {
        return new SQL.Database(fs.readFileSync(databaseFileName));
      } catch (error) {
        console.log("Can't open database file.", error.message);
        return null;
      }
    };

    let db = SQL.dbOpen(dbFileName);

    db.exec(`DELETE FROM Users WHERE email = "${email}";`);
    const data = db.export();
    const buffer = new Buffer.from(data);
    fs.writeFileSync(dbFileName, buffer);
  });
}

readTest();
deleteTest("ali@squid.game");
readTest();

 

DELETE도 UPDATE와 비슷합니다.

 

단지 SET 부분만 없고 WHERE 부분만 잘 넣으시면 됩니다.

 

ali를 지워보도록 하겠습니다.

 

ali가 지워졌습니다.

 

이상으로 Sql.js를 이용해서 CRUD 테스트를 해봤는데요.

 

다음 시간에는 일렉트론 앱에 적용하는 코드를 작성해 볼까 합니다.

 

 

그리드형