Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Create stores dynamically #29

Open
prabhuish opened this issue May 4, 2015 · 14 comments
Open

Feature: Create stores dynamically #29

prabhuish opened this issue May 4, 2015 · 14 comments

Comments

@prabhuish
Copy link

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
Copy link
Owner

bramski commented Jun 7, 2015

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.

@bramski bramski changed the title Create multiple store dynamically (Not during config) Feature: Create stores dynamically Jun 7, 2015
@theBull
Copy link

theBull commented Jun 26, 2015

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
Copy link

theBull commented Jun 26, 2015

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
Copy link
Owner

bramski commented Jun 28, 2015

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" [email protected] 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
#29 (comment)
.

@theBull
Copy link

theBull commented Jun 29, 2015

@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
Copy link
Owner

bramski commented Jun 29, 2015

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
Copy link

theBull commented Jun 29, 2015

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
Copy link

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
Copy link
Owner

bramski commented Aug 9, 2015

Talk is cheap. Write a pull request!
On Aug 8, 2015 2:19 PM, "CraigWarford" [email protected] 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
#29 (comment)
.

@CraigWarford
Copy link

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" [email protected] wrote:

Talk is cheap. Write a pull request!
On Aug 8, 2015 2:19 PM, "CraigWarford" [email protected] 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
<
#29 (comment)

.


Reply to this email directly or view it on GitHub
#29 (comment)
.

@bramski
Copy link
Owner

bramski commented Aug 9, 2015

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" [email protected] 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" [email protected] wrote:

Talk is cheap. Write a pull request!
On Aug 8, 2015 2:19 PM, "CraigWarford" [email protected] 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
<

#29 (comment)

.


Reply to this email directly or view it on GitHub
<
#29 (comment)

.


Reply to this email directly or view it on GitHub
#29 (comment)
.

@CraigWarford
Copy link

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" [email protected] 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" [email protected] 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" [email protected]
wrote:

Talk is cheap. Write a pull request!
On Aug 8, 2015 2:19 PM, "CraigWarford" [email protected]
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
<

#29 (comment)

.


Reply to this email directly or view it on GitHub
<

#29 (comment)

.


Reply to this email directly or view it on GitHub
<
#29 (comment)

.


Reply to this email directly or view it on GitHub
#29 (comment)
.

@prabhuish
Copy link
Author

@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
Copy link
Owner

bramski commented Aug 12, 2015

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants