Merge pull request #46 from humphd/websql
WebSQL Storage Provider with tests (4 tests failing still)
This commit is contained in:
commit
1a3a9e62c0
|
@ -23,8 +23,7 @@ module.exports = function(grunt) {
|
||||||
'src/error.js',
|
'src/error.js',
|
||||||
'src/fs.js',
|
'src/fs.js',
|
||||||
'src/shared.js',
|
'src/shared.js',
|
||||||
'src/providers/**/*.js',
|
'src/providers/**/*.js'
|
||||||
'src/filesystems-manager.js'
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,10 @@ define(function(require) {
|
||||||
IDB_RO: 'readonly',
|
IDB_RO: 'readonly',
|
||||||
IDB_RW: 'readwrite',
|
IDB_RW: 'readwrite',
|
||||||
|
|
||||||
|
WSQL_VERSION: "1",
|
||||||
|
WSQL_SIZE: 5 * 1024 * 1024,
|
||||||
|
WSQL_DESC: "FileSystem Storage",
|
||||||
|
|
||||||
MODE_FILE: 'FILE',
|
MODE_FILE: 'FILE',
|
||||||
MODE_DIRECTORY: 'DIRECTORY',
|
MODE_DIRECTORY: 'DIRECTORY',
|
||||||
MODE_SYMBOLIC_LINK: 'SYMLINK',
|
MODE_SYMBOLIC_LINK: 'SYMLINK',
|
||||||
|
|
|
@ -7,7 +7,6 @@ define(function(require) {
|
||||||
window.webkitIndexedDB ||
|
window.webkitIndexedDB ||
|
||||||
window.msIndexedDB;
|
window.msIndexedDB;
|
||||||
|
|
||||||
|
|
||||||
var IDB_RW = require('src/constants').IDB_RW;
|
var IDB_RW = require('src/constants').IDB_RW;
|
||||||
var IDB_RO = require('src/constants').IDB_RO;
|
var IDB_RO = require('src/constants').IDB_RO;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,31 @@
|
||||||
define(function(require) {
|
define(function(require) {
|
||||||
|
|
||||||
|
var IndexedDB = require('src/providers/indexeddb');
|
||||||
|
var WebSQL = require('src/providers/websql');
|
||||||
|
var Memory = require('src/providers/memory');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
IndexedDB: require('src/providers/indexeddb'),
|
IndexedDB: IndexedDB,
|
||||||
Memory: require('src/providers/memory'),
|
WebSQL: WebSQL,
|
||||||
Default: require('src/providers/indexeddb')
|
Memory: Memory,
|
||||||
|
Default: IndexedDB,
|
||||||
|
// The Fallback provider does automatic fallback checks
|
||||||
|
Fallback: (function() {
|
||||||
|
if(IndexedDB.isSupported()) {
|
||||||
|
return IndexedDB;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(WebSQL.isSupported()) {
|
||||||
|
return WebSQL;
|
||||||
|
}
|
||||||
|
|
||||||
|
function NotSupported() {
|
||||||
|
throw "[IDBFS Error] Your browser doesn't support IndexedDB or WebSQL.";
|
||||||
|
}
|
||||||
|
NotSupported.isSupported = function() {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
return NotSupported;
|
||||||
|
}())
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
define(function(require) {
|
||||||
|
var FILE_SYSTEM_NAME = require('src/constants').FILE_SYSTEM_NAME;
|
||||||
|
var FILE_STORE_NAME = require('src/constants').FILE_STORE_NAME;
|
||||||
|
var WSQL_VERSION = require('src/constants').WSQL_VERSION;
|
||||||
|
var WSQL_SIZE = require('src/constants').WSQL_SIZE;
|
||||||
|
var WSQL_DESC = require('src/constants').WSQL_DESC;
|
||||||
|
|
||||||
|
function WebSQLContext(db, isReadOnly) {
|
||||||
|
var that = this;
|
||||||
|
this.getTransaction = function(callback) {
|
||||||
|
if(that.transaction) {
|
||||||
|
callback(that.transaction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Either do readTransaction() (read-only) or transaction() (read/write)
|
||||||
|
db[isReadOnly ? 'readTransaction' : 'transaction'](function(transaction) {
|
||||||
|
that.transaction = transaction;
|
||||||
|
callback(transaction);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
WebSQLContext.prototype.clear = function(callback) {
|
||||||
|
function onError(transaction, error) {
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
|
function onSuccess(transaction, result) {
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
this.getTransaction(function(transaction) {
|
||||||
|
transaction.executeSql("DELETE FROM " + FILE_STORE_NAME,
|
||||||
|
[], onSuccess, onError);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
WebSQLContext.prototype.get = function(key, callback) {
|
||||||
|
function onSuccess(transaction, result) {
|
||||||
|
// If the key isn't found, return null
|
||||||
|
var value = result.rows.length === 0 ? null : result.rows.item(0).data;
|
||||||
|
callback(null, value);
|
||||||
|
}
|
||||||
|
function onError(transaction, error) {
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
|
this.getTransaction(function(transaction) {
|
||||||
|
transaction.executeSql("SELECT data FROM " + FILE_STORE_NAME + " WHERE id = ?",
|
||||||
|
[key], onSuccess, onError);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
WebSQLContext.prototype.put = function(key, value, callback) {
|
||||||
|
function onSuccess(transaction, result) {
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
function onError(transaction, error) {
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
|
this.getTransaction(function(transaction) {
|
||||||
|
transaction.executeSql("INSERT OR REPLACE INTO " + FILE_STORE_NAME + " (id, data) VALUES (?, ?)",
|
||||||
|
[key, value], onSuccess, onError);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
WebSQLContext.prototype.delete = function(key, callback) {
|
||||||
|
function onSuccess(transaction, result) {
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
function onError(transaction, error) {
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
|
this.getTransaction(function(transaction) {
|
||||||
|
transaction.executeSql("DELETE FROM " + FILE_STORE_NAME + " WHERE id = ?",
|
||||||
|
[key], onSuccess, onError);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function WebSQL(name) {
|
||||||
|
this.name = name || FILE_SYSTEM_NAME;
|
||||||
|
this.db = null;
|
||||||
|
}
|
||||||
|
WebSQL.isSupported = function() {
|
||||||
|
return !!window.openDatabase;
|
||||||
|
};
|
||||||
|
|
||||||
|
WebSQL.prototype.open = function(callback) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
// Bail if we already have a db open
|
||||||
|
if(that.db) {
|
||||||
|
callback(null, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var db = window.openDatabase(that.name, WSQL_VERSION, WSQL_DESC, WSQL_SIZE);
|
||||||
|
if(!db) {
|
||||||
|
callback("[WebSQL] Unable to open database.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onError(transaction, error) {
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
|
function onSuccess(transaction, result) {
|
||||||
|
that.db = db;
|
||||||
|
|
||||||
|
function gotCount(transaction, result) {
|
||||||
|
var firstAccess = result.rows.item(0).count === 0;
|
||||||
|
callback(null, firstAccess);
|
||||||
|
}
|
||||||
|
function onError(transaction, error) {
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
|
// Keep track of whether we're accessing this db for the first time
|
||||||
|
// and therefore needs to get formatted.
|
||||||
|
transaction.executeSql("SELECT COUNT(id) AS count FROM " + FILE_STORE_NAME + ";",
|
||||||
|
[], gotCount, onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.transaction(function(transaction) {
|
||||||
|
transaction.executeSql("CREATE TABLE IF NOT EXISTS " + FILE_STORE_NAME + " (id unique, data)",
|
||||||
|
[], onSuccess, onError);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
WebSQL.prototype.getReadOnlyContext = function() {
|
||||||
|
return new WebSQLContext(this.db, true);
|
||||||
|
};
|
||||||
|
WebSQL.prototype.getReadWriteContext = function() {
|
||||||
|
return new WebSQLContext(this.db, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return WebSQL;
|
||||||
|
});
|
|
@ -8,6 +8,10 @@ define(["IDBFS"], function(IDBFS) {
|
||||||
expect(typeof IDBFS.FileSystem.providers.IndexedDB).toEqual('function');
|
expect(typeof IDBFS.FileSystem.providers.IndexedDB).toEqual('function');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("has WebSQL constructor", function() {
|
||||||
|
expect(typeof IDBFS.FileSystem.providers.WebSQL).toEqual('function');
|
||||||
|
});
|
||||||
|
|
||||||
it("has Memory constructor", function() {
|
it("has Memory constructor", function() {
|
||||||
expect(typeof IDBFS.FileSystem.providers.Memory).toEqual('function');
|
expect(typeof IDBFS.FileSystem.providers.Memory).toEqual('function');
|
||||||
});
|
});
|
||||||
|
@ -15,5 +19,9 @@ define(["IDBFS"], function(IDBFS) {
|
||||||
it("has a Default constructor", function() {
|
it("has a Default constructor", function() {
|
||||||
expect(typeof IDBFS.FileSystem.providers.Default).toEqual('function');
|
expect(typeof IDBFS.FileSystem.providers.Default).toEqual('function');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("has Fallback constructor", function() {
|
||||||
|
expect(typeof IDBFS.FileSystem.providers.Fallback).toEqual('function');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
define(["IDBFS"], function(IDBFS) {
|
||||||
|
|
||||||
|
var WEBSQL_NAME = "websql-test-db";
|
||||||
|
|
||||||
|
function wipeDB(provider) {
|
||||||
|
var context = provider.getReadWriteContext();
|
||||||
|
context.clear(function(err) {
|
||||||
|
if(err) {
|
||||||
|
console.error("Problem clearing WebSQL db: [" + err.code + "] - " + err.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!IDBFS.FileSystem.providers.WebSQL.isSupported()) {
|
||||||
|
console.log("Skipping IDBFS.FileSystem.providers.WebSQL tests, since WebSQL isn't supported.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("IDBFS.FileSystem.providers.WebSQL", function() {
|
||||||
|
it("is supported -- if it isn't, none of these tests can run.", function() {
|
||||||
|
expect(IDBFS.FileSystem.providers.WebSQL.isSupported()).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has open, getReadOnlyContext, and getReadWriteContext instance methods", function() {
|
||||||
|
var webSQLProvider = new IDBFS.FileSystem.providers.WebSQL();
|
||||||
|
expect(typeof webSQLProvider.open).toEqual('function');
|
||||||
|
expect(typeof webSQLProvider.getReadOnlyContext).toEqual('function');
|
||||||
|
expect(typeof webSQLProvider.getReadWriteContext).toEqual('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("open an WebSQL provider", function() {
|
||||||
|
afterEach(function() {
|
||||||
|
wipeDB(this.provider);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should open a new WebSQL database", function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
|
||||||
|
var provider = this.provider = new IDBFS.FileSystem.providers.WebSQL(WEBSQL_NAME);
|
||||||
|
provider.open(function(err, firstAccess) {
|
||||||
|
_error = err;
|
||||||
|
_result = firstAccess;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toEqual(null);
|
||||||
|
expect(_result).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Read/Write operations on an WebSQL provider", function() {
|
||||||
|
afterEach(function() {
|
||||||
|
wipeDB(this.provider);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow put() and get()", function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
|
||||||
|
var provider = this.provider = new IDBFS.FileSystem.providers.WebSQL(WEBSQL_NAME);
|
||||||
|
provider.open(function(err, firstAccess) {
|
||||||
|
_error = err;
|
||||||
|
|
||||||
|
var context = provider.getReadWriteContext();
|
||||||
|
context.put("key", "value", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
context.get("key", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
_result = result;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toEqual(null);
|
||||||
|
expect(_result).toEqual("value");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow delete()", function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
|
||||||
|
var provider = this.provider = new IDBFS.FileSystem.providers.WebSQL(WEBSQL_NAME);
|
||||||
|
provider.open(function(err, firstAccess) {
|
||||||
|
_error = err;
|
||||||
|
|
||||||
|
var context = provider.getReadWriteContext();
|
||||||
|
context.put("key", "value", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
context.delete("key", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
context.get("key", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
_result = result;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toEqual(null);
|
||||||
|
expect(_result).toEqual(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow clear()", function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result1, _result2;
|
||||||
|
|
||||||
|
var provider = this.provider = new IDBFS.FileSystem.providers.WebSQL(WEBSQL_NAME);
|
||||||
|
provider.open(function(err, firstAccess) {
|
||||||
|
_error = err;
|
||||||
|
|
||||||
|
var context = provider.getReadWriteContext();
|
||||||
|
context.put("key1", "value1", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
context.put("key2", "value2", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
|
||||||
|
context.clear(function(err) {
|
||||||
|
_error = _error || err;
|
||||||
|
|
||||||
|
context.get("key1", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
_result1 = result;
|
||||||
|
|
||||||
|
context.get("key2", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
_result2 = result;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toEqual(null);
|
||||||
|
expect(_result1).toEqual(null);
|
||||||
|
expect(_result2).toEqual(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fail when trying to write on ReadOnlyContext", function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
|
||||||
|
var provider = this.provider = new IDBFS.FileSystem.providers.WebSQL(WEBSQL_NAME);
|
||||||
|
provider.open(function(err, firstAccess) {
|
||||||
|
_error = err;
|
||||||
|
|
||||||
|
var context = provider.getReadOnlyContext();
|
||||||
|
context.put("key1", "value1", function(err, result) {
|
||||||
|
_error = _error || err;
|
||||||
|
_result = result;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
expect(_result).toEqual(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -32,6 +32,7 @@ define([
|
||||||
"spec/providers/providers.spec",
|
"spec/providers/providers.spec",
|
||||||
"spec/providers/providers.memory.spec",
|
"spec/providers/providers.memory.spec",
|
||||||
"spec/providers/providers.indexeddb.spec",
|
"spec/providers/providers.indexeddb.spec",
|
||||||
|
"spec/providers/providers.websql.spec",
|
||||||
|
|
||||||
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
|
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
|
||||||
"spec/node-js/simple/test-fs-mkdir",
|
"spec/node-js/simple/test-fs-mkdir",
|
||||||
|
|
Loading…
Reference in New Issue