immutable chrome sqlite return objects - javascript

I am using a sqlite DB as a storage system for a webapp. I been using the objects that are returned from queries directly in application. For example:
function get_book_by_id(id,successCallback,errorCallback)
{
function _successCallback(transaction, results)
{
if(results.rows.length==0) {successCallback(null);}
else
{
book=results.rows.item(0);
successCallback(book);
}
}
db.transaction(
function (transaction) {
transaction.executeSql("SELECT id,title,content,last_read from books where id=?;",[id], _successCallback, errorCallback);
});
}
This returns me an object with the given id, all columns are provided as properties. Nice. The problem I just figured out is that all the properties of the result set object are immutable. So for example if I want to change the property 'title' it takes no effect, which in my opinion makes no sense. Example:
get_book_by_id(1,handle,error);
function handle(book)
{
//THIS DOESN'T WORK, book.title is still what it was.
book.title=book.title+"more text";
}
I of course can convert all my DB objects into mutable objects, but I rather would not do that.
Is that an expected behavior? Can I request mutable objects?
I am using google chrome 9.0 on Mac OS X.

The WebSQL spec doesn't require for the returned item to be sealed, but it's up to the implementation (the spec does require for the item to be an ordered dictionary with the properties in the same order as the columns in your query).
And no, there is no way to explicitly request a mutable object, so you'll want to do something like the convert_to_mutable() approach suggested by Stan.
BTW, assuming you're using a 3rd party library, it probably has a function for this, for example jQuery.extend() or _.extend().

Building on Stepan's answer, but for people like me that want a quick fix from SO.
You can create another basic object and copy the sqlite row properties onto it.
Something like this:
var immutable_book = results.rows.item(0);
var book = {};
for (var prop in immutable_book) {
if (immutable_book.hasOwnProperty(prop)) {
book[prop] = immutable_book[prop];
}
}
That goes in the _successCallback, and then later you can do this:
book.title=book.title+"more text"; // works now !
I came across this issue in iOS Safari, but in Chrome and Android web-kit browsers I was able to update properties of the returned row object directly.

Related

How can I apply Storage methods to a JS object?

I would like to be able to call the same methods of Storage { } to JS Objects { }.
These are particulary : element.key(index) and element.length.
I first though maybe we could do something as simple as var NoBrowserBasedStorage = localStorage; but it seems that it won't work, and localStorage will be used in parallel. The idea is to have a custom Object that is not at all based on the Browser, but still work as fast, as well and as if it was a localStorage.
Additional sub question, which is faster? Object {} or Storage {}?

Unresolved property variable when returned from method

...
doChunk().then(function (results) {
angular.forEach(results, function (info) {
if (info.data.fields.worklog) {
configProcess.results.push(info.data);
...
The above is just a sample from my AngularJS application, but it's the same issue for all data (and vanilla JS) that's returned from somewhere else - like an HTTP request in this case.
results - is the result of an HTTP request and contains an array of objects.
So when I loop over this array I access different properties of these objects.
All is fine and it works, but how can I declare what the different properties of these methods are?
Basically what I want is to get rid of code inspection errors from WebStorm like these: Unresolved variable fields at line 106.
It makes perfect sense to me why it's reported, but how do I address it?
I can suggest using JSDoc to document such objects received by ajax calls. See How to fight tons of unresolved variables warning in Webstorm?, for example

Extjs - Best way to iterate through displayed records in a buffered store

So, I'm upgrading from EXT 4.1.1a to 4.2.2 and have come across a problem with buffered stores. In 4.1.1a I could use store.each to iterate through the currently displayed store records, but in 4.2.2 I simply get the error:
TypeError: Cannot read property 'length' of undefined
Basically inside the store object the data property does not have an items property anymore, and the each method uses the length property of the items, hence the error. Instead the items in the store seem to reside in data.map. I could loop through data.map but it seems there should be a better way. The docs only mention store.each as the way to do this even though this seems to fail for buffered stores.
I'm iterating through the store on the refresh listener attached to the grids view.
Any help with this would be much appreciated
Apparently they think you can't iterate over the store because it has "sparse" data, but that is not true. Currently, what you could do is the following.
if(store.buffered) {
// forEach is private and part of the private PageMap
store.data.forEach(function(record, recordIdx) {
/* Do stuff with the record here */
}, this);
} else {
store.each(function(record) {
/* Do the same stuff I guess */
}, this);
}
IMPORTANT
Take care that can change the structure of the store in the future which will surely brake your code.
Additionally, I strongly believe that if proper design patterns were used, each had to take care of the looping without caring about the structure.
OPTIMIZATION
What I usually do, when I initialize the store is the following:
if(store.buffered) {
store.iterate = store.data.forEach;
} else {
store.iterate = store.each;
}
Then you could just use it like this:
store.iterate(fn, scope);
This is not the best decision but simplifies writing a lot of if-statements

IndexedDB object.put throwing ConstraintError

I have some javascript which returns an object from IndexedDB, then update some properties, and then tries to 'update' (well, add really) using put, however this throws a Constraint Error and I can't figure out why. The chunk of javascript looks like this:
indexedDbReturnRecord(AddressID, 'AddressID', 'AddressStore', function(retObject) {
retObject.DateMovedIn = getDate();
var dataToUpdate = new Array();
dataToUpdate.push(retObject);
indexedDbAddObject(dataToUpdate, 'AddressStore', function () {
noCss();
$('#CompleteBTN .ui-btn-text').text("Complete").button('refresh');
});
});
You will have to provide some more information...
What is the definition of your objectstore?
The issue will probably be something with the configuration of the key on the object store and not providing it. Is see you are trying to save an array, and in this case I think you will have to use an external key.
Another possibility is issues with indexes on the store.

How to integrate backbone.sync with jstorage?

I'm a newbie javascript developer (first post here!) and been recently trying to play with backbone.sync. I've been reading through the todo example and notice that it uses backbone-localstorage. My feeling is that backbone-localstorage was just a quick implementation that the author used for demo purposes. I also noticed that the keys are randomly generated, whereas I would like something that would allow me to name my own key values.
I've been looking at jstorage (www.jstorage.info), and would really appreciate some pointers (preferably with code samples) on how to integrate it with backbone.js. I imagine backbone.sync would need to be overriden somehow as is done in backbone-localstorage.
Alternatively, what localStorage plugin/wrapper would you recommend, and how would it integrate with backbone?
Thanks for help in advance.
My feeling is that backbone-localstorage was just a quick implementation that the author used for demo purposes.
Exactly right. I'd say that the implementation is fine for most things, but what support you can get for it is probably minimal.
I also noticed that the keys are randomly generated, whereas I would like something that would allow me to name my own key values.
This isn't really correct. I assume you are referring to this:
// Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
// have an id of it's own.
create: function(model) {
if (!model.id) model.id = model.attributes.id = guid();
this.data[model.id] = model;
this.save();
return model;
}
Here, what's happening is that when a create is called on a model, it tries to determine if an id has been set on the model, and if no such id is provided, then the guid function is used to build one. This isn't setting a key randomly, it's fulfilling the requirement that every saved model should have an id (by assigining a random one).
Modifying the backbone-localstorage.js code should be fairly trivial. Let's look at the store constructor as an example
Before:
var Store = function(name) {
this.name = name;
var store = localStorage.getItem(this.name);
this.data = (store && JSON.parse(store)) || {};
};
The only thing we need to update here is the call to localStorage:
After:
var Store = function(name) {
this.name = name;
//Notice here, that jStorage gives us the option to define a default.
var store = $.jStorage.get(this.name, {});
this.data = store;
};
Similarly simple is the save function:
Before:
save: function() {
localStorage.setItem(this.name, JSON.stringify(this.data));
}
again, simply update the call to localStorage:
After:
save: function() {
$.jStorage.set(this.name, this.data);
}
Update: jStorage handles all the JSON.stringify, and JSON.parse for you, so I've updated the above code to reflect that.
Easy peasy, right!
Anyways, this is a great exercise, and I wish you the best of luck. I hope that I've been able to help you out.
P.s. One thing that bothers me about the localStorage plugin is that it uses model.attributes.xxx, where it's better to use model.get("xxx"). This way, if they ever change the internals of model change, your code won't break.
P.p.s. as far as how to generate guids, and weather a random guid is appropriate for you, depends upon your domain. With the TODO example, there is no backing database to sync with, so any old guid would do the trick, but in many other cases, you may be using html5 storage to create an offline version of your app, so id's need to be compatable with the db. In these cases, using a random guid is probably not that great an idea, but the one provided by the backbone-localstorage plugin is designed so that it isn't likely to collide with your db's actual id's, so it's not _that bad. There isn't really a right answer here, so do what makes sense for your domain.
You should probably look first at the local storage plugin that backbone.js provides. There are plenty of code samples that should give you an idea of how you would swap in jstorage as the underlying storage mechanism. See it here:
backbone-localstorage.js

Categories

Resources