SQlite と Sequelize

  • 案件のモック環境の一部で使った
  • 静的サイトジェネレータのデータ管理に使ってみてる

SQlite

  • https://www.sqlite.org/
  • 読み方:エスキューライトとかスクライトとか
  • サーバでなくアプリケーションに組み込んで利用されることが多い軽量のRDB
  • v3.3.8から全文検索をサポート
  • PHP 5から標準で組み込まれてる
  • macにははじめからsqlite3がインストールされてる

インタプリタモードで使う

  • sqlite3 と入力するとインタプリタモードになり対話的に実行できる
$ sqlite3
SQLite version 3.8.10.2 2015-05-20 18:17:19
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> create table foo(
   ...>   id integer primary key,
   ...>   foo_text text
   ...> );
sqlite> .tables
foo
sqlite> insert into foo values(1,'FOO');
sqlite> 
sqlite> select * from foo;
1|FOO

node で使う

npm install --save sqlite3
cd db
touch demo.db
var sqlite3 = require('sqlite3');
module.exports.init = function (file) {
  return new sqlite3.Database(file);
};
var sqlite = require('./module/db.js');
var db = sqlite.init('./db/demo.db');
db.serialize(() => {
  // 処理
});

非同期に処理される

  • callback形式な記述
  • select句の記述がそのままプロパティ名になるw( res['count(*)'] )
db.serialize(() => {

  // ディクショナリをみて指定テーブルが未定義なら create table する
  db.get(
    'select count(*) from sqlite_master where type="table" and name=$name',
    { $name: 'foo_table' },
    function (err, res) {
      console.log(res); // { 'count(*)': 0 } 、「count(*) as cnt」てすれば { cnt: 0 } になる
      if(res['count(*)'] === 0){
        db.run('create table foo_table (id integer primary key, name text)');
      }
    }
  );
});

Promise を使う

  • Promise を使って処理を汎用化するとよさそう
db.serialize(() => {
  // テーブルの有無を調べる関数
  const existsTable = (tableName) => new Promise((resolve, reject) => {
    db.get('select count(*) from sqlite_master where type="table" and name=$name',{ $name: tableName }, (err, res) => {
      resolve(res['count(*)'] > 0);
    });
  });

  // 指定テーブルがなかったら、create table する
  existsTable('foo_table').then(exists => {
    if(!exists){
      db.run('create table foo_table (id integer primary key, name text)');
    }
  });
});

プレースホルダ

db.run(
  'insert into foo_table (id, name) values ($id, $name)', {
    $id: 123,
    $name: 'FOO'
  }
);
db.run('insert into foo_table (id, name) values (?, ?)',
  [ param.id,
    param.name
  ]
);

Sequelize

  • 読み方:シィークゥアラァィズ
  • PromiseベースのNode.js向けのORM
  • PostgreSQL, MySQL, MariaDB, SQLite, MSSQLに対応

インストール

npm install --save sequelize

sqliteを使用する

var Sequelize = require('sequelize');
var sequelize = new Sequelize(
  'database_name',
  '', // user
  '', // password
  {
    dialect:'sqlite',
    storage:'./db/demo.sqlite'
  }
);

モデルの定義

var User = sequelize.define('user', {
  username: Sequelize.STRING,
  birthday: Sequelize.DATE,
  desc: Sequelize.JSON
});

レコードの作成

sequelize.sync(
  force: true // DBを再構築する場合に指定
).then(function() {
  return User.create({
    username: 'janedoe',
    birthday: new Date(1980, 6, 20),
    desc: {
      hobby: 'programming'
    }
  }
  });
}).then(function(jane) {
  console.log(jane.get({
    plain: true
  }));
});
  { id: 1,
     username: 'janedoe',
     birthday: Sun Jul 20 1980 00:00:00 GMT+0900 (JST),
     desc: { hobby: 'programming' },
     updatedAt: Fri Mar 03 2017 10:52:34 GMT+0900 (JST),
     createdAt: Fri Mar 03 2017 10:52:34 GMT+0900 (JST) }

検索

// 1件のみ
User.findOne({
  where: {firstName: 'John'}
}).then(user => {
  console.log('firstName is ' + user.get('firstName')); // or user.firstName
});

// 複数件
User.findAll({
  where: {firstName: 'John'}
}).then(user => {
  // 配列で返される
  console.log(user[0].get('lastName'))
});

// ID指定
User.findById(123).then(user => {
  console.log('birthday is ' + user.get('birthday'));
});

// 検索してなければ作る
User
  .findOrCreate({
    where: {username: 'sdepold'},
    defaults: {job: 'Technical Lead JavaScript'}
  })
  .spread(f(user, created) => {
    console.log(user.get({
      plain: true
    }))
  });

// 件数
User.count({
  where: {firstName: 'John'}
}).then(function(count) {
  console.log(count);
});

削除

User.findOne({
  where: {firstName: 'John'}
}).then(user => {
  user.destroy();
});

更新

User.findOne({
  where: {firstName: 'John'}
}).then(user => {
  user.set('lastName','Lennon').save().then(user => {
    console.log(user.lastName); // Lennon
  });
});

感想

  • SQLぽくかけて便利
  • JSON形式で保存してたデータをSequelizeに変えたらスッキリした
  • 取得→更新→取得みたないなAPIモックに適用すると便利