Created
August 1, 2012 07:38
-
-
Save nakamura-to/3224648 to your computer and use it in GitHub Desktop.
Cache-enabled Gateway for Metro Style Applicatoin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
/* */ | |
/* EXAMPLE */ | |
/* */ | |
//var db = new KageDB({ | |
// name: "db", | |
// version: 1, | |
// migration: { | |
// 1: function (ctx, next) { | |
// var db = ctx.db; | |
// db.createObjectStore("__cacheStatus", { keyPath: "id" }); | |
// var person = db.createObjectStore("person", { autoIncrement: true }); | |
// next(); | |
// } | |
// } | |
//}); | |
// | |
//var gateway = new Gateway({ | |
// db: db, | |
// baseUrl: "http://localhost:49637/api" | |
//}); | |
// | |
//gateway.get({ | |
// path: "person/get", | |
// pkey: "name", | |
//}).then(function (data) { | |
// console.log(data); | |
//}); | |
"use strict"; | |
function Gateway(options) { | |
this.options = options || {}; | |
} | |
Gateway.prototype.get = function get(options) { | |
var self = this; | |
options = this._mergeOptions(options); | |
var store = extractObjectStore(); | |
var path = makePath(); | |
return isCached().then(function (cached) { | |
if (cached) { | |
return getFromCache(); | |
} else { | |
return getFromServer(); | |
} | |
}); | |
function extractObjectStore() { | |
var path = options.path; | |
var pos = path.indexOf("/"); | |
if (pos > -1) { | |
return path.substr(0, pos); | |
} | |
return path; | |
} | |
function makePath() { | |
var path = options.path; | |
if (options.data) { | |
Object.keys(options.data).forEach(function (key, i) { | |
if (i === 0) { | |
path += "?"; | |
} else { | |
path += "&"; | |
} | |
var value = options.data[key]; | |
if (value == null) { | |
value = ""; | |
} | |
path = path + key + "=" + value; | |
}); | |
} | |
return path; | |
} | |
function isCached() { | |
return new WinJS.Promise(function (c) { | |
if (options.cache) { | |
options.db.tx(["__cacheStatus"], function (tx, status) { | |
status.get(path, function (result) { c(!!result) }); | |
}); | |
} else { | |
c(false); | |
} | |
}); | |
} | |
function getFromCache() { | |
return new WinJS.Promise(function (c) { | |
options.db.tx([store], function (tx, store) { | |
store.fetch({ filter: filter }, c); | |
function filter(row) { | |
return row.__cacheKeys.indexOf(path) > -1; | |
} | |
}); | |
}); | |
} | |
function getFromServer() { | |
return self._xhr("get", path, null, options).then(function (result) { | |
var data; | |
if (options.responseType === "json") { | |
data = JSON.parse(result.response); | |
} | |
// TODO handle other responseTypes | |
if (options.cache) { | |
return cache(data).then(function () { | |
return data; | |
}); | |
} | |
return data; | |
}); | |
} | |
function cache(data) { | |
return new WinJS.Promise(function (c) { | |
options.db.tx(["__cacheStatus", store], "readwrite", function (tx, status, store) { | |
status.put({ id: path }, function () { | |
var pkey = options.pkey; | |
var array = Array.isArray(data) ? data : [data]; | |
var len = array; | |
store.openCursor(function (cursor) { | |
if (cursor) { | |
var row = cursor.value; | |
for (var i = 0; i < array.length; i++) { | |
var newRow = array[i]; | |
if (row[pkey] == newRow[pkey]) { | |
row.__cacheKeys.push(path); | |
cursor.update(row); | |
break; | |
} | |
} | |
cursor.cont(); | |
} else { | |
array.forEach(function (row) { | |
row.__cacheKeys = [path]; | |
}); | |
store.bulkPut(array, c); | |
} | |
}); | |
}); | |
}); | |
}); | |
} | |
}; | |
Gateway.prototype.post = function post(options) { | |
options = this._mergeOptions(options); | |
// TODO | |
}; | |
Gateway.prototype.put = function put(options) { | |
options = this._mergeOptions(options); | |
// TODO | |
}; | |
Gateway.prototype.del = function del(options) { | |
options = this._mergeOptions(options); | |
// TODO | |
}; | |
Gateway.prototype._mergeOptions = function _mergeOptions(options) { | |
options = options || {}; | |
var result = {}; | |
Object.keys(this.options).forEach(function (key) { | |
result[key] = this.options[key]; | |
}, this); | |
Object.keys(options).forEach(function (key) { | |
result[key] = options[key]; | |
}); | |
// verify | |
if (result.baseUrl == null) throw new Error("`baseUrl` is required."); | |
if (result.db == null) throw new Error("`db` is required."); | |
if (result.path == null) throw new Error("`path` is required."); | |
if (result.pkey == null) throw new Error("`pkey` is required."); | |
// default settings | |
if (result.cache == null) result.cache = true; | |
if (result.responseType == null) result.responseType = "json"; | |
if (result.user == null) user: result.user = ""; | |
if (result.password == null) result.password = ""; | |
if (result.customRequestInitializer == null) result.customRequestInitializer = function () { }; | |
return result; | |
}; | |
Gateway.prototype._xhr = function (type, path, data, options) { | |
var url; | |
if (options.baseUrl.charAt(options.baseUrl.length - 1) === "/") { | |
url = options.baseUrl + path; | |
} else { | |
url = options.baseUrl + "/" + path; | |
} | |
var xhrOptions = { | |
type: type, | |
url: url, | |
data: data, | |
headers: { "Content-type": "application/json; charset=utf-8" }, | |
responseType: options.responseType, | |
user: options.user || "", | |
password: options.password || "", | |
customRequestInitializer: options.customRequestInitializer || function () { } | |
}; | |
return WinJS.xhr(xhrOptions); | |
} | |
// TODO | |
window.Gateway = Gateway; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment