Reputation: 13
This is Worklight 6.1 code with dojo, testing with Chrome and the std dev server Liberty. What I want this code to do is to query a collection, which should have 0 or 1 entries, and either retrieve the one entry if it exists or create an entry with a supplied set of values. What I'm trying to do is store a url, id, and password for a service. If this is the first time the app has run after installation I want to prompt the user for this info and store it. The code to prompt the user will be added later. If it is not the first run of the app then the values should be stored in the collection and be retrieved. I'll add code later to allow the user to change and update the values.
What is happening now is that the .add never seems to be executed, and also the execution sequence I'm seeing thru the breakpoints I've set seems weird.
Here is the setup code
// set up the jsonStore
var collectionName = 'servers';
var collections = {};
collections[collectionName] = {};
// initialize the default jsonStore Monitor credentials
var jsonURL = 'http://myserver.com:9082';
var jsonUser = 'keyser';
var jsonPassword = 'soze';
And here is the problem code
// Initialize the JSONStore
WL.JSONStore.init(collections)
.then(function() {
console.log("store initialized");
// query the store
var query = {_id: 0};
WL.JSONStore.get(collectionName)
.find(query)
.then(function(arrayResults) {
console.log("credentials retrieved " + arrayResults.length);
if (arrayResults.length > 0) {
// retrieve the credentials from the json object
console.log("password retrieved " + arrayResults[0].json.password);
jsonURL = arrayResults[0].json.url;
jsonUser = arrayResults[0].json.user;
jsonPassword = arrayResults[0].json.password;
} else {
// load the default credentials into jsonStore
var credentials = {url: jsonURL, user: jsonUser, password: jsonPassword};
WL.JSONStore.get(collectionName)
.add(credentials)
.then(function() {
console.log("credentials loaded " + credentials.url);
})
.fail(function(errorObject) {
console.log("credential load failed");
});
} // end of else
// Query the model list
queryModels();
}) // end of get(collectionName) then
.fail(function(errorObject) {
console.log("credentials not retrived");
}); // end of get(collectionName) fail
}) // end of init(collections) then
.fail(function(errorObject) {
console.log("store init failed" + errorObject);
}); // end of init(collections) fail
}); // end of ready
When I step thru it flows in this sequence.
init(collections)
Then it jumps immediately to the "end of ready". Seems weird but I'm a rookie so maybe it's OK?
Back to the get(collectionName)
to the .then and logs "credentials retrieved" with and array length of 0
To the else clause of the statement
And it breaks on the get(collectionName) in the else clause. So far so good
From here it jumps to queryModels(), skipping over the .add (far as I can tell)
Then it returns to the .then under the 2nd get and logs "credentials loaded"
At this point execution ends "normally" except, The item never gets added to the collection, and The queryModels runs before I expect it to, I want it to run after the item is added.
By now it's probably obvious that I'm a rookie, so I'm probably making the rookie mistake. I know I'm dealing with deferreds here with the .then and .fails, and I'm nesting them, which seems to be an accepted technique, but I'm not getting the execution sequence I want.
I've tried this code commenting out the 2nd get(collections) in a couple of formats and it barfs both ways.
// WL.JSONStore.get(collectionName)
.add(credentials)
and
// WL.JSONStore.get(collectionName)
servers.add(credentials)
Any help greatly appreciated. Thanks!
Here's my "answer" below based on what I learned from the other answers below.
Bluewing and cnandrue's answers were both very helpful, and I got it working. The main issues I had turned out to be.
I had failed to grasp that slot 0 in a collection equates to a document _id key of 1. I was trying to query _id = 0, and never getting a hit. The add to the collection was working all along, I was just not reading it correctly.
Moving the queryModels into the if/else clauses (bluewing's suggestion) worked, and reading the material cnandreu referenced (very worthwhile to read) explained why it worked. Thanks!
The tip about the "weird" execution sequence being an artifact of the breakpoints was also very useful, I quit chasing that red herring.
Here is a working draft of the code after fixing these issues. I did not implement all of the suggestions yet, but probably will as I polish this up. Thanks again.
// Initialize the JSONStore - you have to .init to start the collection before you can read it.
WL.JSONStore.init(collections)
.then(function() {
console.log("store initialized");
// query the store
var query = {_id: 1};
WL.JSONStore.get(collectionName) // get 1
.find(query)
.then(function(arrayResults) {
console.log("credentials retrieved " + arrayResults.length);
if (arrayResults.length > 0) {
// retrieve the credentials from the json object
console.log("password retrieved " + arrayResults[0].json.password);
jsonURL = arrayResults[0].json.url;
jsonUser = arrayResults[0].json.user;
jsonPassword = arrayResults[0].json.password;
queryModels();
} else {
// load the default credentials into jsonStore
var credentials = {url: jsonURL, user: jsonUser, password: jsonPassword};
WL.JSONStore.get(collectionName) // get 2
.add(credentials)
.then(function(numberOfDocumentsAdded) {
console.log("Number of Docs Added" + numberOfDocumentsAdded);
queryModels();
}); // end of .add then
} // end of else
}); // end of get(collectionName) 1 then
}) // end of init(collections) then
.fail(function(errorObject) {
console.log("something failed" + errorObject);
}); // end of init(collections) fail
Upvotes: 1
Views: 173
Reputation: 5111
My suggestion is the same as Bluewings', but I wanted to share some pseudocode:
function handleCredentials (arrayResults, callback) {
if (arrayResults.length > 0) {
//.... synchronous code here.
setTimeout(function () {
callback();
}, 0);
} else {
WL.JSONStore.get(collectionName)
.add({url: jsonURL, user: jsonUser, password: jsonPassword})
.then(function() {
callback();
});
}
}
WL.JSONStore.init(collections)
.then(function() {
WL.JSONStore.get(collectionName)
.find({_id: 1})
.then(function (arrayResults) {
handleCredentials(arrayResults, function () {
queryModels();
});
});
});
Notice I created a function for handleCredentials
, that function will either do a synchronous operation (setting some variables with the result from the find
call) or an asynchronous operation (calling add
to add credentials). A setTimeout with 0 is called to preserve async behavior, this is explained in detail here. After the handleCredentials
function has finished, you call the queryModels
function via the callback pattern.
As an aside, I recommended reading this blog post: What’s so great about JavaScript Promises?. Especially the "Error Handling" section. You don't need to add a .fail
to every promise, you can get away with less failure functions and the error object should provide enough details into what went wrong. JSONStore error objects are documented here, notice they contain the source of the failure (e.g. src: 'find'
).
Upvotes: 0
Reputation: 3488
All the JSON store calls ( like add , init etc) are asynchronous. So only you are getting that weird flows when you are checking with Breakpoints.
To get you execution sequence try to move the queryModels();
once the credentials are loaded.
WL.JSONStore.get(collectionName)
.add(credentials)
.then(function() {
console.log("credentials loaded " + credentials.url);
queryModels();
})
Upvotes: 1