Multiple commits to merge
@taras, the other PR that you saw was a lot older than what you see now in my dev branch. This PR should sync up everything.
Also, I haven't tested anything with IndexedDBShim. Right now, the best native support for IndexedDB is through Chrome. (For testing, I test against Chrome, Chrome Canary and Firefox.) I will probably spend some time next week seeing how things work with IndexedDBShim.
Lastly, feel free to email me any questions as you write up your article. There are some things about IndexedDB that can be confusing and may not be completely abstracted away in EIDB.
@monocle I'm already using your dev branch.
Also, I haven't tested anything with IndexedDBShim. Right now, the best native support for IndexedDB is through > Chrome. (For testing, I test against Chrome, Chrome Canary and Firefox.) I will probably spend some time next week seeing how things work with IndexedDBShim.
It would be good for us to clear this up because I'm getting very conflicted messages about compatibility from what I'm reading. For Embe Sherpa readers, its not going to make much difference because 99% of them use Chrome, Safari or Firefox. The article is designed to show how Ember architecture works and how to structure code, but its inevitable that someone will try to use it in production.
Lastly, feel free to email me any questions as you write up your article.
I will, thank you!
There are some things about IndexedDB that can be confusing and may not be completely abstracted away in EIDB.
I already found a few places where the API is a bit inconsistent and required me to dig into IndexedDB API to figure what's going on.
Would you like me to keep track of those and later we could improve the documentation for this project?
@monocle Would you mind rebasing off my master? I can't cleanly merge this PR.
@taras I would love it if you would keep track of any inconsistencies or whatever. I am interested in hearing them.
@ebryn I will, but with a bit more experience, I'm realizing that what seemed like inconsistencies is actually using the library differently than it was designed.
I started off working directly with db & objectStore instances but I realized that most interactions need to be wrapped in a function that prepares the database before the action can be taken. This fact makes working directly with these objects impractical.
For the article, I created a Storage class that wraps IEDB to offer some abstractions. Mostly, it allows to pass model classes as parameter without manually extracting store names.
I'm really curious about how you think this library fits into the Ember ecosystem. With Ember Data making good progress, its foreseeable that it will become a good defacto standard persistence layer. Do you think this library might be used as IndexedDB adapter for Ember Data?
Sorry I didn't catch that earlier.
I just did the rebase, so it should be good to go.
On Oct 6, 2013, at 8:04 PM, Erik Bryn [email protected] wrote:
@monocle Would you mind rebasing off my master? I can't cleanly merge this PR.
— Reply to this email directly or view it on GitHub.
@taras, you could have worked with the Database and ObjectStore objects directly, but you start to get into the nuances of the IndexedDB API, which in my opinion, is a bit difficult to work with.
One of the reasons I ended up pulling methods up to the EIDB level (EIDB.createObjectStore, EIDB.addRecord, etc), was to remove some of the ceremony involved in the IndexedDB AP. For instance you don't have to open a database and then get the object store just to add a record. Another example is that I set the default behavior to automatically close a database during the next event loop cycle. That way it avoids the database from hanging if the user forgets to close it.
re: Ember Data, here's an example adapter that I created: https://github.com/monocle/eidb-app/blob/master/app/adapters/eidb_record_adapter.js. (It relies on the EIDB database and object store names to be specified in the model https://github.com/monocle/eidb-app/blob/master/app/models/kid.js)
@monocle your summary is what I discovered after working with EIDB for about 1 day.
IMHO, the ceremony that you abstracted in the EIDB interface should be implemented on instance level. IOW, when I started, I was expecting to see your level of abstraction on instance objects.
Instead of EIDB.createObjectStore('my-db', 'photos');, I would prefer to db.createObjectStore('photos'). Calling that should automatically increment DB version and create an object store.
Its possible to have both APIs depending on what the person is more comfortable with.
It is possible to do db.createObjectStore('photos'). However, because of the way IndexedDB does database versioning, it requires more work. For example, if at the start of a script you open the database and just kept a reference to it
var db;
EIDB.open('foo').then(function(_db) { db = _db; });
If at some point later in the script, you check to see whether an object store is needed, you won't be able to use the reference to the db that you created earlier:
db.createObjectStore('photos'); // this won't work
Instead, you would have to manually open the database again with a new version number. This would then put you in an onupgradeneeded callback which is needed to create an object store:
EIDB.open('foo', 2, function(db2) {
db2.createObjectStore('photos');
});
In this case, having the reference to the db at the top of the script doesn't help. The other thing is that it would be easy to mistakenly try to create the object store in the then part of the Promise instead of a callback to #open:
EIDB.open('foo', 2).then(function(db2) {
db2.createObjectStore('photos'); // this won't work
});
I think having EIDB do all of this with EIDB.createObjectStore('foo', 'photos') will save people from missteps and debugging.
Keeping a reference to a previously opened database is problematic in general, especially since the default behavior right now for EIDB.open is to close the database on the next event loop cycle. If we made the default behavior to allow the database to stay open until the user manually closed it, it would require more understanding of the IndexedDB API.
Could we open the database every time, here is some pseudo code...
Database.prototype = {
dbName: null,
...
createObjectStore: function(storeName, options) {
var createObjectStore = function(db) {
// ideally, this would resolve to an instance of ObjectStore
// that could be used to make queries against it
return db.createObjectStore(storeName);
}
return this.open()
.then(bumpVersion)
.then(createObjectStore)
.then(null, handleErrors);
},
...
};
We would automatically close the db after API calls via EIDB object, but require for them to be closed manually when using instance API. This way, people who use instances only need to know that they need to close the connection after they're finished. People who don't want to go that deep can use EIDB interface.
For people who are using instances, they could use onbeforeunload event to close the database after they're finished.
There's some recursion going on that I don't think we could get around.
The #open method isn't a Database method. #open gets called on the browser's indexedDB object and would give a new Database object in the callback.
There's some recursion going on that I don't think we could get around.
You're probably right, if I can get testing figured out, then maybe I can experiment with this abit. Getting cross browser stuff working is pretty critical though... because without that, all of this effort is only half usable.