I used sqlite to populate a DB with some Tables in it.
I made a function at another javascript page that executes the database & selects some values from the table. The function is called at $(document).ready().
Javascript:
//DB Population
function onDeviceReady() {
var db = window.openDatabase("Database", "1.0", "SqliteTrial", 20000);
db.transaction(populateDB, errorCB, successCB);
}
function populateDB(tx) {
tx.executeSql('DROP TABLE IF EXISTS Subjects');
tx.executeSql('CREATE TABLE IF NOT EXISTS Subjects (id unique, subjectname)');
tx.executeSql('INSERT INTO Subjects (id, subjectname) VALUES (1, "Math")');
tx.executeSql('INSERT INTO Subjects (id, subjectname) VALUES (2, "Science")');
}
function GetSubjectsFromDB()
{
console.log("");
tx.executeSql('SELECT * FROM Subjects', [], queryNSuccess, errorCB);
}
function queryNSuccess(tx, results) {
alert("Query Success");
console.log("Returned rows = " + results.rows.length);
if (!results.rowsAffected) {
console.log('No rows affected!');
return false;
}
console.log("Last inserted row ID = " + results.insertId);
}
function errorCB(err) {
alert("Error processing SQL: "+err.code);
}
Is there some problem with this line?
tx.executeSql('SELECT * FROM Subjects', [], queryNSuccess, errorCB);
The queryNSuccess isn't called, neither is the errorCB so I don't know what's wrong.
This is how I call it at another page:
Javascript:
$(document).ready(function () {
DisplayData();
GetSubjectsFromDB(tx);
});
No, it doesn't work like that. tx variable is actually a parameter that will be sent into the specified callback function by db.transaction method. So you're probably want to do this instead:
$(document).ready(function () {
...
db.transaction(GetSubjectsFromDB);
});
... and rewrite this function definition as...
function GetSubjectsFromDB(tx) { ... something to do with tx ... }
But there's another problem actually, as I see it. Your db variable, which stores the connection handle (created by window.openDatabase call) is local to onDeviceReady function - in other words, it's not visible outside of this function.
The easiest way to solve this is to define this variable at the Global context:
var dbh; // the SQLite connection handle
function onDeviceReady() { ... dbh = window.openDatabase ... }
function GetSubjects() { ... dbh.transaction(getSubjectsFromDb) ... }
function getSubjectsFromDb(tx) { ... tx.executeSql(...) ... }
Here's a great presentation describing general usage of WebSQL DB. But I'd also like to add that WebSQL DB API is considered deprecated; it's recommended to use IndexedDB instead. Here's something to read about it.
Related
I am using Sails v0.11 and am developing an standalone importer script in order to import data to mongoDB and - that is now the not-working part - build the associations between the models.
For this process I introduced temporary helper properties in the models in order to find the associated records and replace them by in real MongoDB _ids.
The script starts Sails in order to be able use its features (waterline, etc.):
var app = Sails();
app.load({
hooks: { grunt: false },
log: { level: 'warn' }
}, function sailsReady(err){
processUsers() finds all users and their _ids and iterates over them to invoke a second function addOrgsToOneUser()
var processUsers = function() {
// Iterate through all users in order to retrieve their _ids and
app.models['user'].native(function(err, collection) {
collection.find({}, projectionOrgInUser).toArray(function (err, users) {
Async.eachSeries(users, function (user, next){
// prepare userInOrgs
whereUserInOrg = { orgId: { $in: userInOrgs } };
//This is invoking
addOrgsToOneUser(user, whereUserInOrg);
next();
}, function afterwards (err) {
if (err) {
console.error('Import failed, error details:\n',err);
return process.exit(1);
}
console.log("done");
return process.exit(0); // This returns too early, not executing the addOrgsToOneUser
});
});
});
};
addOrgsToOneUser() finds all orgs belonging to THIS user and updates then the orgs array property of THIS user
var addOrgsToOneUser = function(user, whereUserInOrg) {
var projectionUserInOrg = "...";
// Find all orgs that this user is associated to and store it in inOrgs
app.models['org'].native(function(err, collection) {
collection.find(whereUserInOrg, projectionUserInOrg).toArray(function (err, orgs) {
// prepare inOrgs which is needed for updating
//update user to have an updated orgs array based on inOrgs.
app.models['user'].update({'id' : user._id.toString()}, {'orgs': inOrgs}).exec(function afterwards(err, updated){
console.log('Updated user ' + user._id.toString() + ' to be in their orgs');
});
});
});
}
Problem:
Process.exit(0) is called before the query/update of saddOrgsToOneUser() has completed. It behaves as expected if saddOrgsToOneUser() contains just a console.log for instance, but queries are triggered ansynchronously of course.
In case I comment out Process.exit(0), the script never stops, but the queries are executed as intented.
As the script will have further nested queries, I need a better approach to this as manually kill this script ...
How is nesting queries and iterating over their results done properly?
Thank you very much,
Manuel
addOrgsToOneUser is asynchronous. next() needs to be called after everything is done inside addOrgsToOneUser. The way I would do it is to pass in a callback (next) and call it when everything is done. So the call is
addOrgsToOneUser(user, whereUserInOrg, next);
and the addOrgsToOneUser will have an extra argument:
var addOrgsToOneUser = function(user, whereUserInOrg, callback) {
var projectionUserInOrg = "...";
// Find all orgs that this user is associated to and store it in inOrgs
app.models['org'].native(function(err, collection) {
collection.find(whereUserInOrg, projectionUserInOrg).toArray(function (err, orgs) {
// prepare inOrgs which is needed for updating
//update user to have an updated orgs array based on inOrgs.
app.models['user'].update({'id' : user._id.toString()}, {'orgs': inOrgs}).exec(function afterwards(err, updated){
console.log('Updated user ' + user._id.toString() + ' to be in their orgs');
callback(); // your original next() is called here
});
});
});
}
I am developing a mobile application using phonegap that store some data into the local database (sqlite DB).
I need to know if the database exist or not, and that to determine which process need to execute.
var database = window.openDatabase("my_db", "1.0", "sample DB", 30000);
if (check_db_exist()) {
process_1();
}
else
{
process_2();
}
I needed to do something similar, I needed to check if the application had a db already created (legacy DB) and if so export all the data to the new db (new and improved DB) and then delete this DB.
Background Info: I was moving from simple keyvalue tables to complex relational DB with cascades etc.
function onDeviceReady() {
// CHECK IF LEGACY DATABASE EXISTS. IF DOES EXPORT EXISTING DATA TO NEW DB THEN DELETE LEGACY
window.resolveLocalFileSystemURL(cordova.file.applicationStorageDirectory + "/databases/<DatabaseName>.db", exportToNewDB, setupDB);
}
Note: If file exists (success), then we need to do our export code in here, then delete file so this method will always fail. If file doesn't exist - user has already exported to new DB or they our new user and never had legacy DB.
// Fail Method
function setupDB() {
newDB = window.sqlitePlugin.openDatabase({ name: "<NewImprovedDBName>.db" });
newDB.transaction(sql.initDB, sql.errorCallback, sql.successCallBack);
}
// Success Method
function exportToNewDB() {
db = window.sqlitePlugin.openDatabase({ name: "<LegacyDBName>.db" });
db.transaction(function (tx) {
setupDB();
// Insert Export code Here
// Delete DB
window.sqlitePlugin.deleteDatabase("<LegacyDBName>.db", sqlSuccess, sqlFail);
}, sqlFail);
}
Answer to your Question:
window.resolveLocalFileSystemURL(cordova.file.applicationStorageDirectory + "/databases/my_db.db", process_1, process_2);
The best way for determining if the DB exists or not is to check if the file that represents it exists. This is a simple IO operation, like the following example:
string path = Path.Combine(ApplicationData.Current.LocalFolder.Path, databaseName);
if (File.Exists(path))
{
//your code here
}
I don't think that you can check for the existence of the DB directly. I've researched and haven't found a way to do it using a simple function call. However, this seems to be a popular request, and here's a workaround:
var db = window.openDatabase("my.db", "1", "Demo", -1);
db.transaction(function (tx) {
/*I don't think that there is a way to check if a database exists.
As I think that the openDatabase call above will just create
a missing DB. Here is a second-best way to do it - there
is a way to check to see if a table exists. Just pick a table that
your DB should have and query it. If you get an ERROR, then you
can assume your DB is missing and you will need to create it. */
console.log("Trying to get the test data");
tx.executeSql("select * from test_table", [], function (tx, res) {
var len = res.rows.length, i;
for (i = 0; i < len; i++) {
console.log(res.rows.item(i).data);
}
}, function (err) {
console.log("Error selecting: " + err);
//NOW we need to create the DB and populate it
tx.executeSql('CREATE TABLE IF NOT EXISTS test_table (id integer primary key, data text)');
tx.executeSql('INSERT INTO test_table (data) VALUES("test data one")');
tx.executeSql('INSERT INTO test_table (data) VALUES("test data two")');
//now test select
tx.executeSql("select * from test_table", [], function (tx, res) {
var len = res.rows.length, i;
for (i = 0; i < len; i++) {
console.log(res.rows.item(i).data);
}
});
//now clean up so we can test this again
tx.executeSql('DROP TABLE IF EXISTS test_table', [], function (tx, res) {
console.log("dropped table");
}, function (err) {
console.log("Error dropping table: " + err);
});
});
});
As you can see, the error function during the first query will create and populate the DB. It's using exception handling for program logic flow, but it works!
My question is based on W3C Web SQL Database. I am trying to populate SQL with the data I am getting from API. Here is my code
var db = window.openDatabase("Database", "1.0", "Cordova Demo", 200000);
for(i=0;i<data.responseMsg.length;i++){
var assignid_check = data.responseMsg[i].assignId;//------->3
db.transaction(queryDB, errorCB);//------->4
function errorCB(tx, err)
{
alert("Error processing SQL: "+err);
}
function queryDB(tx)
{
tx.executeSql('SELECT * FROM table_assign WHERE assign_id='+assignid_check, [], querySuccess, errorCB);
}
function querySuccess(tx, results) {
var len = results.rows.length;
if(len>0) //if exist jump to next array
{
alert("exist");
}
else //if not exist insert
{
tx.executeSql('INSERT INTO table_assign (audit_id,assign_id) VALUES (1,'+assignid_check+')');
alert("not exist");
}
}
}
Here problem is in line number 3 after getting "assignid_check" value I am calling transaction method. After transaction method I just want to call callback function i.e queryDB(tx) and if there is any error I want errorCB(tx,results) to get called. But soon after line 3 gets executed line 4 will execute and then again in for loop I value will get incremented and then it will execute line 3 and then 4. Only for the last value i.e only for last I value transaction will call queryDB(tx) callback function.
I am doing this for a phonegap application. Can someone help me on this?
I'm new to PhoneGap I'm using database and its working fine with below code
db = window.openDatabase("Sample", "1.0", "PhoneGap Demo", 200000);
db.transaction(getDetails, transaction_error);
function transaction_error(tx, error) {
$('#busy').hide();
alert("Database Error: " + error);
}
function getUserDetails(tx) {
var sql = "select id, Name, DisplayName from details where Name=Name";
try {
tx.executeSql(sql, [],getList_success);
}
catch(err)
{
alert(err);
}
}
function getList_success(tx, results)
{
var len = results.rows.length;
for(var i=0; i <len; i++)
{
//Some code goes here
}
db = null;
}
Now i want to use the functions getUserDetails and getList_success by passing paramenters, i tried the below code its giving error
db = window.openDatabase("Sample", "1.0", "PhoneGap Demo", 200000);
getUserDetails(db);
function getUserDetails(tx) {
var sql = "select id, Name, DisplayName from details where Name=Name";
try {
tx.executeSql(sql, [],getList_success);
}
catch(err)
{
alert(err);
}
}
the error is TypeError:'undefined' is not a function in the catch block, can any one help me to get through this?.
Thanks in advance
The executeSql function need 4 parameters, try this:
function errorCallback(err){
//show error
}
...
tx.executeSql(sql, [],getList_success,errorCallback);
The problem is that you are handing over a callback function to db.transaction. If you want to provide some data to the callee you have to provide this in the context of the caller by using a closure.
var db = window.openDatabase("Sample", "1.0", "PhoneGap Demo", 200000);
var context = {val1: 'x', val2: 'y'};
db.transaction(function(tx){
myfunction(tx,context);
},
tx_error,
tx_success);
function myfunction(ty,context){
tx.executeSql(query,[context.val1,context.val2],myf_success,myf_error);
}
Keep in mind that this happens in a new thread! So if you call db.transaction be aware that this happens concurrently to the caller. If e.g. you are calling db.transaction() from inside the success callback of a jQuery.ajax() call the ajax thread will run on and the complete callback may be executed while the transaction is still in progress.
Look at your code:
db.transaction(getDetails, transaction_error);
getDetails!
Look at the functions you declared:
function getUserDetails(tx) {...}
function getList_success(tx, results) {....}
getDetails is not getUserDetails....
That's why you are getting the error.
I am trying to store some data in a database which i create using phonegap like
document.addEventListener("deviceready", onDeviceReady, false);
function populateDB(tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS DEMO (id unique, data)');
tx.executeSql('INSERT INTO DEMO (id, data) VALUES (1, "First row")');
tx.executeSql('INSERT INTO DEMO (id, data) VALUES (2, "Second row")');
}
// Query the database
//
function queryDB(tx) {
tx.executeSql('SELECT * FROM DEMO', [], querySuccess, errorCB);
}
// Query the success callback
//
function querySuccess(tx, results) {
var len = results.rows.length;
console.log("DEMO table: " + len + " rows found.");
for (var i=0; i<len; i++){
console.log("Row = " + i + " ID = " + results.rows.item(i).id + " Data = " + results.rows.item(i).data);
}
}
// Transaction error callback
//
function errorCB(err) {
console.log("Error processing SQL: "+err.code);
}
// Transaction success callback
//
function successCB() {
var db = window.openDatabase("Database", "1.0", "PhoneGap Demo", 200000);
db.transaction(queryDB, errorCB);
}
// PhoneGap is ready
//
function onDeviceReady() {
var db = window.openDatabase("Database", "1.0", "PhoneGap Demo", 200000);
db.transaction(populateDB, errorCB, successCB);
}
But the database is not getting created..Instead it is saving it in /data/data/package-name/app_database/file__0/00000000000000001.db
I want to save the data in /data/data/package-name/database/Database.db
How to do it?
You can't change the directory in which the database is created unless you modify the PhoneGap source code. I guess a better question is why do you want to save the data in /data/data/package-name/database/Database.db instead of /data/data/package-name/app_database/file__0/00000000000000001.db?
Update: Now that I understand the requirement better the only way you are going to be able to do this is to write a plugin for Android that interfaces the JavaScript side to the native Java side. Then you can open and read the DB in Java that your Service has created and populated.
Marc Murphy (CommonsWare) goes over the why in this thread.
See: http://developer.android.com/guide/topics/data/data-storage.html#db and http://developer.android.com/guide/developing/tools/adb.html#sqlite. When creating the database, you can specify the database name and a file name with .db will be created in /data/data/package name/databases/.
Sorry, but the code you have provided doesn't show how the database has been created.
I would suggest that you use LocalStorage instread of sqlite for this purpose.
You can refer to Local storage at : http://docs.phonegap.com/en/1.0.0/phonegap_storage_storage.md.html
Example :
localStorage.setItem("ItemName",yourItem);
localStorage.getItem("ItemName");
It provides a better way to store and retrieve your data easily and effectively
As the documentation states, Phonegap doesn't really use a SQLite database, but a WebSQL implementation or localStorage.
If you want to use native SQLite, have a look at this plugin, the syntax for database operations are nearly the same as for the Storage API of Phonegap.