bramski / angular-indexedDB

An angularjs serviceprovider to utilize indexedDB with angular
165 stars 49 forks source link

Feature: Create stores dynamically #29

Open prabhuish opened 9 years ago

prabhuish commented 9 years ago

In my case, I have to add stores when needed. But looks like this implementation offers to create stores during config phase. Can you please guide me to create multiple stores dynamically.

bramski commented 9 years ago

You want it, write a PR. I have no need for this functionality and it does not exist. I personally think that an implementation that dynamically makes object stores is broken design.

theBull commented 9 years ago

Hey guys,

First off, you don't need to create/connect to your DB solely in your config phase, you can do it in any service (might take a couple tweaks in the library to do so, I can't remember).

I've done some work around this. I've extended the library to support managing multiple indexedDB databases at once rather than having only one at a time. I modified the connection mechanism to allow you to switch between any N number of DBs you create within a single session on your browser. I haven't gotten around to doing the PR for that (plus some other optimizations) yet, but I'll try to do it soon. That should give you the functionality you're looking for @prabhuish

@bramski I can see what you mean by "broken design", but there are instances where you'll need to establish more than 1 indexedDB. In my scenario. I can explain mine if you'd like :]

theBull commented 9 years ago

Here's an example of how I am connecting to this local DB from within a service called localDatabaseService. I am doing this dynamically; my app allows users to connect to any N number of SharePoint storage endpoints; each of which have a corresponding client-side indexedDB implementation for offline storage and other things. So when the user connects to a different SharePoint URL, I switch my connection to the appropriate indexedDB locally.

Anyway, notice that I am referencing the $indexedDB service directly (rather than the provider). Also note that I had to extend the service with an explicit open(databaseName) method. The reason for this is that the $indexedDBProvider and the $indexedDB service expose a slightly different set of methods (which I'm not too fond of, TBH).

$indexedDB.connection(databaseName)
    .upgradeDatabase(1, function (event, db, tx) {
        console.log('connecting to database: ', databaseName);

        // Clauses store
        var clausesStore = db.createObjectStore('clauses', { keyPath: 'Id' });
        clausesStore.createIndex('search_index', 'SearchIndices', { multiEntry: true });
        clausesStore.createIndex('groupId_index', 'GroupId', { unique: false });

        // Groups store
        var groupsStore = db.createObjectStore('groups', { keyPath: 'Id' });
        groupsStore.createIndex('parentId_index', 'ParentId', { unique: false });

        // Tags store
        var tagsStore = db.createObjectStore('tags', { keyPath: 'Id' });
        tagsStore.createIndex('title_index', 'Title', { unique: false });

        // External links store
        var externalLinksStore = db.createObjectStore('externalLinks', { keyPath: 'Id' });
    });

    return $indexedDB.open(databaseName);

To get this to work, I had to extend the actual service with a couple of methods in the return object at the very bottom of the angular-indexed-db.js file:

return {
    // ... other methods ...

    // this is needed to directly invoke the openDatabase() method in the provider's $get definition. 
    // ignore the databases[databaseName] for now; that's part of the multiple database support 
    // I was talking about...more on that later.
    open: function (databaseName, version) {
        var db = this.exists(databaseName) ?
        databases[databaseName] :
        (databases[databaseName] = new DB(databaseName));

        currentDatabase = db.name;

        return openDatabase();
     },

     // this just allows access to the same connection method you call when you do
     // $indexedDBProvider.connection in the config function.
     connection: function (databaseName) {
         return self.connection(databaseName);
     },
     // ...
}
bramski commented 9 years ago

I don't really want this kind of complexity. In my 16 years developing Web applications, the only time I have an application that talks to multiple databases is for database administration or some kind of sharding (which is purely for scalability).

What is the useage case for this? You haven't actually given me a solid reason for multiple DBs on one app. I understand upgrading a running DB without code changes for more esoteric database useages but multiple DBs is highly complex.

Right now my answer is that you should roll your own solution to this problem because as the maintainer of this project I don't agree with this use case. But please do attempt to convince me otherwise, I am listening. On Jun 26, 2015 4:11 PM, "Danny Bullis" notifications@github.com wrote:

Here's an example of how I am connecting to this local DB from within a service called localDatabaseService. Notice that I am referencing the $indexedDB service directly (rather than the provider). Also note that I had to extend the service with an explicit open(databaseName) method. The reason for this is that the $indexedDBProvider and the $indexedDB service expose a slightly different set of methods (which I'm not too fond of, TBH).

$indexedDB.connection(databaseName) .upgradeDatabase(1, function (event, db, tx) { console.log('connecting to database: ', databaseName);

    // Clauses store
    var clausesStore = db.createObjectStore('clauses', { keyPath: 'Id' });
    clausesStore.createIndex('search_index', 'SearchIndices', { multiEntry: true });
    clausesStore.createIndex('groupId_index', 'GroupId', { unique: false });

    // Groups store
    var groupsStore = db.createObjectStore('groups', { keyPath: 'Id' });
    groupsStore.createIndex('parentId_index', 'ParentId', { unique: false });

    // Tags store
    var tagsStore = db.createObjectStore('tags', { keyPath: 'Id' });
    tagsStore.createIndex('title_index', 'Title', { unique: false });

    // External links store
    var externalLinksStore = db.createObjectStore('externalLinks', { keyPath: 'Id' });
});

return $indexedDB.open(databaseName);

To get this to work, I had to extend the actual service with a couple of methods in the return object at the very bottom of the angular-indexed-db.js file:

return { // ... other methods ...

// this is needed to directly invoke the openDatabase() method in the provider's $get definition.
// ignore the databases[databaseName] for now; that's part of the multiple database support
// I was talking about...more on that later.
open: function (databaseName, version) {
    var db = this.exists(databaseName) ?
    databases[databaseName] :
    (databases[databaseName] = new DB(databaseName));

    currentDatabase = db.name;

    return openDatabase();
 },

 // this just allows access to the same connection method you call when you do
 // $indexedDBProvider.connection in the config function.
 connection: function (databaseName) {
     return self.connection(databaseName);
 },
 // ...

}

— Reply to this email directly or view it on GitHub https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-115913805 .

theBull commented 9 years ago

@bramski I know what you mean. It's not too highly complex though. Think of a scenario where you can have a user simultaneously access two separate accounts in your app within the same session. Twitter is an example of this; you can switch between connected accounts. Rather than blasting the entire indexedDB when you switch the account, you can simply tell your library to point to the DB for account A, or to account B.

In my scenario, my user can choose between any number of SharePoint sites that they have access to. Each SharePoint site contains a series of lists which stores all of the data used by the app (don't ask...). Point is, they can switch between 5 different sites within the same session if they wanted to, use the data, and then connect to a different site. All of that data needs to be stored locally in my situation, so rather than blasting all of the data away in 1 database whenever they switch connections, I maintain all 5 local databases and just update the current database name in the library to keep track of the db they are connected to.

For argument's sake, there isn't really a limit to how many indexedDBs you can create with JavaScript - you could create 2, 3, 4, 5, 10 DBs locally if you wanted (for whatever reason). This angular library shouldn't prevent that by restricting you to only 1 library. Besides, the upgrade is actually very simple, it only took me about 15 minutes to enable the capability of closing the connection to one DB and opening a connection to another DB. Works like a charm.

bramski commented 9 years ago

Are you going to write a PR for this or add an additional service that allows you to manage multiple DBs? I had thought you'd opened a PR to add the functionality you wanted, but I don't see one in the repo.

theBull commented 9 years ago

Yeah, I've been slammed at work so I haven't had a chance to open a PR. Sorry about that. I made the modification directly to the javascript, not the coffeescript, so there's obstacle #2 for me to hurdle :].

I'll try to get something out this week so you can take a look.

CraigWarford commented 9 years ago

Simple example for dynamic creation: I have a logging component that I want to persist data between browser sessions. I'm building it as a reusable component, to be added to multiple applications via bower install. Those applications will call the logging component, but be unaware of the database requirements underneath. They may even have their own IndexedDB, or share a DB, but the structures are abstracted from the main app. So, there are many cases for creating object stores at a component level, not simply at an application level.

bramski commented 9 years ago

Talk is cheap. Write a pull request! On Aug 8, 2015 2:19 PM, "CraigWarford" notifications@github.com wrote:

Simple example for dynamic creation: I have a logging component that I want to persist data between browser sessions. I'm building it as a reusable component, to be added to multiple applications via bower install. Those applications will call the logging component, but be unaware of the database requirements underneath. They may even have their own IndexedDB, or share a DB, but the structures are abstracted from the main app. So, there are many cases for creating object stores at a component level, not simply at an application level.

— Reply to this email directly or view it on GitHub https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129045626 .

CraigWarford commented 9 years ago

Very true, talk is cheap, but it's also true that work is expensive. Put this one at about #50 on my to-do list. I ended up pulling this plugin from my code and wiring it manually, since the time to do it was far less. On Aug 8, 2015 11:24 PM, "Bram Whillock" notifications@github.com wrote:

Talk is cheap. Write a pull request! On Aug 8, 2015 2:19 PM, "CraigWarford" notifications@github.com wrote:

Simple example for dynamic creation: I have a logging component that I want to persist data between browser sessions. I'm building it as a reusable component, to be added to multiple applications via bower install. Those applications will call the logging component, but be unaware of the database requirements underneath. They may even have their own IndexedDB, or share a DB, but the structures are abstracted from the main app. So, there are many cases for creating object stores at a component level, not simply at an application level.

— Reply to this email directly or view it on GitHub < https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129045626

.

— Reply to this email directly or view it on GitHub https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129104683 .

bramski commented 9 years ago

I was not paid to make this plug in better nor open source it. Don't ask for features unless you're willing to put the legwork in to do it. Otherwise this just looks like you complaining to me about the free work I have provided you with. On Aug 9, 2015 6:41 AM, "CraigWarford" notifications@github.com wrote:

Very true, talk is cheap, but it's also true that work is expensive. Put this one at about #50 on my to-do list. I ended up pulling this plugin from my code and wiring it manually, since the time to do it was far less. On Aug 8, 2015 11:24 PM, "Bram Whillock" notifications@github.com wrote:

Talk is cheap. Write a pull request! On Aug 8, 2015 2:19 PM, "CraigWarford" notifications@github.com wrote:

Simple example for dynamic creation: I have a logging component that I want to persist data between browser sessions. I'm building it as a reusable component, to be added to multiple applications via bower install. Those applications will call the logging component, but be unaware of the database requirements underneath. They may even have their own IndexedDB, or share a DB, but the structures are abstracted from the main app. So, there are many cases for creating object stores at a component level, not simply at an application level.

— Reply to this email directly or view it on GitHub <

https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129045626

.

— Reply to this email directly or view it on GitHub < https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129104683

.

— Reply to this email directly or view it on GitHub https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129188736 .

CraigWarford commented 9 years ago

Whoa, chill with the hostilities, man! It was stated that there was no value, and that was flat false. I gave a simple example of where it was useful, and I didn't ask anyone for any changes. Your implications and hostility are unwarranted and not useful for any purpose whatsoever. Go drink a beer or something. Take a vacation. On Aug 9, 2015 9:58 AM, "Bram Whillock" notifications@github.com wrote:

I was not paid to make this plug in better nor open source it. Don't ask for features unless you're willing to put the legwork in to do it. Otherwise this just looks like you complaining to me about the free work I have provided you with. On Aug 9, 2015 6:41 AM, "CraigWarford" notifications@github.com wrote:

Very true, talk is cheap, but it's also true that work is expensive. Put this one at about #50 on my to-do list. I ended up pulling this plugin from my code and wiring it manually, since the time to do it was far less. On Aug 8, 2015 11:24 PM, "Bram Whillock" notifications@github.com wrote:

Talk is cheap. Write a pull request! On Aug 8, 2015 2:19 PM, "CraigWarford" notifications@github.com wrote:

Simple example for dynamic creation: I have a logging component that I want to persist data between browser sessions. I'm building it as a reusable component, to be added to multiple applications via bower install. Those applications will call the logging component, but be unaware of the database requirements underneath. They may even have their own IndexedDB, or share a DB, but the structures are abstracted from the main app. So, there are many cases for creating object stores at a component level, not simply at an application level.

— Reply to this email directly or view it on GitHub <

https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129045626

.

— Reply to this email directly or view it on GitHub <

https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129104683

.

— Reply to this email directly or view it on GitHub < https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129188736

.

— Reply to this email directly or view it on GitHub https://github.com/bramski/angular-indexedDB/issues/29#issuecomment-129194881 .

prabhuish commented 9 years ago

@CraigWarford, please be kind and appreciate what @bramski have done so for the group. You can not generalize it is not useful for any purpose because I am using it for my project which is working fine. I have modified the code slightly to support for my need and it is working fine as expected. I logged this as a needful enhancement because I thought it would be a good feature to have. In many libraries that I have seen so for is working with single store, however it still should be possible to enhance to work with multiple.. @bramski, Appreciate all your work dude..Please consider the nice to have feature and it is upto you to consider it or not.

bramski commented 9 years ago

Ahh yes. Sunday @8am. Probably hungover pre coffee. Sorry for the antagonism!