Am I over complicating things by using Storage instead of Sqlite or NoSQL?


#22

Yes in the sense that I would not bother with providers for individual Files or Grades, as (as I understand your explanation to be) those concepts don’t have independent meaning outside of the context of their enclosing Session, so all edit activity should take place on a Session object. No in the sense that I would not use Ionic’s NavParams to sling these Session objects around, both because of my earlier comment about having the same thing in different places and because you again are going to be taking needless serialization/deserialization hits doing that.

So I would have a provider that exposes a Session somehow, and all other objects in your app needing to futz with it would inject that provider. You can also look into the Ionic-Native network connectivity plugin if you want to consider automating the uploading process. Instructors without data plans can put their devices in airplane mode, and then when they take it off airplane mode, the app can automatically sense this and start uploading.

Absent other concerns, I would tend to prefer this option of having all modifications be made to a session object, which will keep the data in one authoritative place always. When you start to get cute with hacking off bits of it and folding modifications back in, you will create significant additional complexity. Unless there’s some other worthwhile benefit, I would try to stay away from that.


#23

So I would have a provider that exposes a Session somehow, and all other objects in your app needing to futz with it would inject that provider.

Lets say I have a page that has a list with every single session in storage. On this page I call a getAll() method in my service provider that returns all the sessions in storage. All the information for every session is already available on this page, even though I am only displaying a few things from each (i.e. name, date, session length, etc).

Now when the user clicks on a particular session (lets say with id: 3), it takes them to another component. In the 2nd component how would I get info for that particular session? Do I pass the id to the 2nd component and in ionViewDidLoad or ...WillLoad() call my service provider to return that particular session object by using the id?

and just so i’m understanding correctly, when i want to update grades I should be calling something like serviceProvider.saveGrades(session, new grades) and in that function use session.sessionInfo.grades = updatedGrades?

Also what do you use to generate your V4 UUIDs?


#24

You can either pass the id along to each page, or a pattern I like as long as you are careful about it is to have your service have a currentSession property. Then have a setCurrentSession method that takes in either a session ID or session object, and don’t let anything else set that session. Then just create a getter for that session object, and in all your pages you can just do like sessionService.currentSession.student = myStudent, or whatever.

There are a number of npm modules that generate uuids, or check out the second solution here if you just want to add your own function: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript


#25

Thank you for the get and set for the currentSession idea. That will be useful because on the home page they want a button to take them to the last session they were working on.


#26

Since you (presumably) want to keep the current session up to date in storage, I’d probably add helper functions to my service like:

myservice {
  private sessions: SessionInterface[];
  private currentSessionId: string;

  async constructor() {
    this.sessions = await this.storage.get('sessions');
  }

  get currentSession() {
    return this.currentSessionId ? this.sessions[this.currentSessionId] : null;
  }

  setCurrentSessionFromStorage(id) {
    this.currentSessionId = id;
  }

  addStudentInfoToCurrentSession(studentInfo: StudentInfo) {
    this.currentSession.studentInfo = studentInfo;
    this.saveCurrentSession();
  }

  addSessionInfoToSession(sessionInfo: SessionInfo) {
    this.currentSession.sessionInfo.push(sessionInfo);
    this.saveCurrentSession();
  }

  saveCurrentSession() {
    this.storage.save('sessions', this.sessions);
  }
}

So, the idea being that it would grab the full array on app startup and keep it there. When someone set an id you’d store that as well. Then you’d have helper methods for all modifications you’d make that would not only set the new data for you, but also store everything back to storage. This is quick pseudo code and doesn’t include error handling etc, just an idea. Of course you could also call save at various points, depends how you want the caching to work.


#27

For generating UUIDs I use the node-uuid package (now just called “uuid”).

An addition to the “currentSession” concept that may or may not be useful to your situation is to expose it as a BehaviorSubject. That way anybody (pages, custom components, other providers, whatever) who cares what the current session is can simply subscribe to that and be notified whenever a different session becomes current.

Incidentally, in mobile apps I also prefer that currentSession approach over providing arbitrary sessions from an ID within the app. I find it fits better in the mobile usage paradigm, where you virtually always have only a single active whatever at any given time.

Also, FWIW, I’m philosophically opposed to magical getter/setter functions unless absolutely necessitated by outside forces. When I first started working in C++, I became enamored with operator overloading, but after a while decided that it tends to violate the principle of least surprise. a = b should not generate a function call IMHO.


#28

I don’t like having all the sessions as part of a single object, because it makes partial access harder, more fragile, and heavier. Instead I would use storage.keys() here (with one key per session) and only grab that at startup, leaving loading of each actual session contents as an on-demand situation.


#29

ah, i see so not an array of sessions where each has an id property, but rather individual session objects stored with a key that is the uuid. That’s getting deep into actual implementation details but ya, makes sense to me. Until he has to list all sessions or something and then it’s kind of a pain, but, ya, still might be the best way.


#30

If your data is not relational, don’t use SQL. I use IndexedDB on mobile to maintain a database of thousands of records for a very high performance app. No problems. Don’t use Storage either. It’s too simple. IndexedDB is awesome and fast on iOS and Android. I’ve got a lot of experience with this.


#31

Given the design that OP has described so far, can you elaborate on what you think raw IndexedDB access would be needed for that could not be achieved using Storage (keeping in mind that Storage can be configured to use IndexedDB as a backend)?


#32

I implemented my own Storage before Storage was added to Ionic. IndexDB has some specialized high performance methods, can do transactions, etc. Take a look at the spec. And it also does indices.


#33

I’m not asking you how IndexedDB works. I’m asking what you think Storage would be incapable of doing that OP needs, given what we’ve heard so far about the app.


#34

I looked at Storage. It’s provides fewer APIs that I need and with simple assumptions. Also, I don’t see anything there for schema upgrading. It seems like it a facade for a key/value store, which then can provide a simple interface. That’s what I’m need. My use cases required taking benefit of IndexDB capabilities and performance optimizations - getAll, cursors, transactions, etc. Local storage has a pretty low size limit too. I’m dealing with a very large mobile database - many thousands of records spread across lots of tables - still barely relational. I can see the connection between local storage and IndexedDB storage because both work as document-oriented storage. But SQL is quite different as it is schema based. I suspect Storage is using SQL in a simple way and not making use of SQL based features. I think the right choice for you depends on your use cases and performance requirements. Generally speaking, if you could have a lot of data (exceeding 5MB) then local storage should not be used (even by Storage facade). IndexedDB is great if your data is not relational or could you could provide some relational optimizations through ad-hoc approach. And of course debugging is a breaks – no cordova plug. I’d use SQL only if the data is relational. I realize that I don’t know the specifics of your use case. I’ve been down this road. At times it was rough going.

I hope that helps.

:slight_smile: