LoginSignup
7
4

More than 5 years have passed since last update.

nodejsのsqlite3モジュールをPromiseの非同期処理で使う

Last updated at Posted at 2017-09-10

nodejsのsqliteモジュールで一番DL数が多いsqlite3。
https://www.npmjs.com/package/sqlite3
https://github.com/mapbox/node-sqlite3

コールバックはもう使いたくないのでPromise対応にした。コールバックにPromise.resolve()を付けてるだけだけど。

npmにある他のsqliteモジュールはDL数が桁違いで少なくて使うのが怖いので自作。

メモ

  • 既存のsqlite3モジュールはコールバックの他に、runで独自のthisをbindしているのでアロー関数が使えない。
  • foreachは途中でキャンセルが出来なくて無意味との事なのでスルー。allでやる。
  • その結果、run、get、all、prepareで十分 のはず。serializeやparallelizeは正直良くわからん
sqlite3.js
const sqlite = require('sqlite3').verbose();
class sqlite3{
  constructor(dbFileName){
    // https://github.com/mapbox/node-sqlite3/wiki/API
    this.db = new sqlite.Database(dbFileName);
  }
  /// 戻り値は数字。updateとかdelete分に使う
  run(query,param){
    const p = new Promise((ok,ng)=>{
      this.db.run(query,param,function(err,res){
        // bindしてthisを書き換えてるのでアロー関数は出来ない
        let lastId  = this.lastID  || -1;
        let changes = this.changes || -1;
        if(err){
          ng(new Error(err));
        }else{
          ok({lastId:lastId,changes:changes});
        };
      });
    });
    return p;
  }
  /// 1アイテムだけselectする。結果が0件の時はundefinedになる
  get(query,param){
    const p = new Promise((ok,ng)=>{
      this.db.get(query,param,(err,res)=>{
        if(err){
          ng(new Error(err));
        }else{
          ok(res);
        };
      })
    });
    return p;
  }
  /// 全てselectする
  all(query,param){
    const p = new Promise((ok,ng)=>{
      this.db.all(query,param,(err,res)=>{
        if(err){
          ng(new Error(err));
        }else{
          ok(res);
        };
      })
    });
    return p;
  }
  prepare(query){
    // ここのパラメーターが有効になる条件がわからなかったので、prepareの引数はクエリ文字だけで
    let r = this.db.prepare(query,{});
    return new sqlite3_prepare(r);
  }
}
// finalizeやresetの使い方がわからなかったのでrunだけ
class sqlite3_prepare{
  constructor(statement){
    this.statement = statement;
  }
  run(query){
    const p = new Promise((ok,ng)=>{
      this.statement.run(query,()=>{ok()});
    });
    return p;
  }
}
module.exports = sqlite3;

使い方はこんな感じ

index.js
const sqlite3    = require('./sqlite3');
async function main(){
  const db = new sqlite3("./database.db");
  let yyyList = await transactionText(db);
}
main();
function transactionText(db){
  return Promise.resolve()
    .then(()=>{
      return db.run("BEGIN");
    }).then(()=>db.run(`insert into xxx (v)values(?)`,["test"]))
      .then((item)=>{
        let insertId = item.lastId;
        let statement = db.prepare("INSERT INTO yyy (sub_id,val) VALUES (?,?)");
        return Promise.all(["a","b","c"].map((id)=>{
          return statement.run([insertId,id]);
        }));
    }).then(()=>db.run("COMMIT"))
    }).then(()=>db.get(`select * from yyy`));
}
7
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4