読者です 読者をやめる 読者になる 読者になる

Momic.DB :: Mongoシェル風のAPIでブラウザのストレージを扱う

前々から欲しかったブラウザの永続ストレージのラッパーを作りました。

mizchi/momic https://github.com/mizchi/momic

momicは"mongo mimic"の略で、mongo風にしたかったけどJavaScriptやストレージの制約を考えると完全な互換にする必要ないんだけど、やっぱそれっぽくしたいが… 作った結果やっぱ擬態でしかない(ミミック)という感じのニュアンスです。

動機

仕事と趣味両方でmongodbをバックエンドにしたシングルページアプリケーション作ってることが多いんですが、クライアントサイドでサーバーサイドのmongo shellと似たようなAPI欲しいなーと前々から思ってました。

パフォーマンスはあんまり気にしていません。ストレスなくそれっぽいAPIを作ることを志しました。気になる人は、詳細は後述しますが、autoSave: false で save()を自前で呼ぶことで最低限の処理だけ走るようになります。

meteorのminimongoをmeteorなしで使いたくて、ydn-db試してみて使い物にならなかったのが作り始めた直接の動機です。

インストール

bowerでインストールできます

bower install momic --save-dev

依存

  • localforage
  • es6-promises

今のchrome34ならPromiseが入ってるのでes6-promisesは不要ですが、残念ながら世の中そんなに便利ではない。

localforageはmozilla製で localStorage, WebSQ, indexedDb を抽象化してくれます。

使い方

Collection#count(), Collection#saved() 以外のすべての関数はpromsiseオブジェクトを返します

new Momic.DB

db = new Momic.DB
  name: 'app' # name is used for namespace prefix
  collections:
    foo:
      hasInstance: true # 実体のインスタンスを抱える。あると速いがメモリを使う
      hasPersistence: true # ストレージに保存する
      autoSave: true # insert, update時に自動保存
      plugins: [] # プラグインあとで解説

DB#init()

collectionを初期化する

db.init().done => db.foo.find().then => # 準備ok

Collection#insert(obj_or_array)

コレクションに挿入します

db.foo.insert({foo: 1})

insetしたときにidプロパティが存在しない場合、自動でidプロパティを生やします。

Collection#update(obj_or_array)

obj.id と同一のidを持つコレクションを更新します。

col.insert(id:1, text: 'a', foo: 3).then =>
  col.update(id:1, text: 'foo') #=> update to {id: 1, text: 'foo', foo: 3}

Collection#find(null_or_func_or_obj)

条件に見合ったものを探す。

col.find()               # fetch all items
col.find((i)->i.num > 5) # fetch items that num > 5 items
col.find({text: 'aaa'})  # fetch items that text is 'aaa'
col.find({text: {content: 'aaa'}})  # nested object is ok!

$gteとかのクエリ式は実装しておりません。残念だったな。ここらへんのやる気がある人はPull Requestください。

Collection#remove(func_or_obj)

findと同じ条件でヒットしたものを削除します。

Collection#save()

現在の状態を保存。autoSave: true のときは呼ぶ必要はありません。

プラグイン機構

各所にフック処理をつけられます。バリデーション書きたい人はここで頑張ってください。

MyPlugin = {
  initialize: (collection) -> # called with collection instance
  preInsertHook: (item) -> # called by each items to modify
  preUpdateHook: (item) -> # called by each items to modify
  preSaveHook: (items) ->  # called once before save
  postSaveHook: (items) -> # called once after save
    console.log 'collection saved!'
}

window.db = new Momic.DB
  name: 'app'
  collections:
    items:
      plugins: [MyPlugin]

注意

今現在chrome34とlocalforageのIndexedDb両方に問題があり、バックエンドとして使うと異常な挙動になります。 ワークアラウンドとして localforage.setDriver('localStorageWrapper') して使ってください。(おそらくIndexedDbの方が速くはなります)

僕が快適に使えるように作っただけなので、安全弁がついてない感じですが、要望がある方は https://github.com/mizchi/momic/issues までどうぞ。