State Persistence
Common state persistence pattern with gstate.
- Call async functions to persist data into database.
- If the persist action successful, use state.set to update internal state.
- Call async function to read data from database.
- When the read action completed, use state.set to update internal state.
// persist user object
function insert_new_user(state, user_data){
return db.collection("users").insert(user_data).then(user_id => {
state.set(["users", user_id], user_data);
});
}
// reload user object
function read_user(state, user_id){
return db.collection("users").find({_id: user_id}).then(user_data => {
state.set(["users", user_id], user_data);
});
}
Besides the pattern, gstate provides a high optional persistence interface.
Persistence interface
const persist = require("gstate/persist");
const db = persist(adapter, options);
//Rebuild persistent state.
await db.find(state);
//Insert new object at path and update state
await db.insert(state, path, value);
//Update object at path and update state
await db.update(state, path, value);
//Delete object at path and update state
await db.remove(state, path);
Adapter is implementation for actual data storage.
function adapter(options){
return {
_find(query){},
_insert(path, value){},
_update(path, value){},
_remove(path, value){},
_sync(callback){} // callback = (op, path, value) => ();
}
}
The sample Nedb adapter:
const Datastore = require("nedb");
function path_to_id(path) {
return path.join(".");
}
class NedbAdapter {
constructor(options = {}) {
this._db = new Datastore(options);
}
_find(query) {
return new Promise((ok, fail) => {
this._db.find({}, (err, docs) => {
if (err) return fail(err);
const values = Array(docs.length);
for (let i = 0; i < docs.length; i++) {
const path = docs[i]._id;
const v = docs[i].v;
values[i] = [path, v];
}
ok(values);
});
});
}
_insert(path, value) {
path = path_to_id(path);
return new Promise((ok, fail) => {
this._db.insert(
{ _id: path, v: value },
err => (err ? fail(err) : ok())
);
});
}
_update(path, value) {
path = path_to_id(path);
return new Promise((ok, fail) => {
this._db.update(
{ _id: path },
{ $set: flatten("v", value) },
(err, numAffected) =>
err || numAffected == 0 ? fail(err) : ok()
);
});
}
_remove(path) {
path = path_to_id(path);
return new Promise((ok, fail) => {
this._db.remove(
{ _id: path },
(err, numRemoved) => (err || numRemoved == 0 ? fail(err) : ok())
);
});
}
}
module.exports = function(options) {
return new NedbAdapter(options);
};