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

Storage-first/storage-only option for [store.connect] #210

Closed
cyruseuros opened this issue Jul 15, 2023 · 10 comments
Closed

Storage-first/storage-only option for [store.connect] #210

cyruseuros opened this issue Jul 15, 2023 · 10 comments
Labels
store Applies to the store feature

Comments

@cyruseuros
Copy link

The offline: key basically implements a network-first strategy. Looking at the code though, it feels like a substantial chunk can be re-used to implement a more generic/robust version of this suggestion.

Worth exploring or out of scope for the library?

@smalluban
Copy link
Contributor

smalluban commented Jul 16, 2023

The offline feature of the store allows to keep data in local storage for outage access. However, it does not force you to set your data source as an external API endpoint. You can combine whatever you want defining get and set methods, even another local storage key (in this case it is pointless).

By the idea, it is not there to give you another source, but this is only another cache layer, which holds data automatically. As a bonus, it can help even when a user is online, as the data is returned immediately (and it's fetched in the same time).

@smalluban smalluban added the store Applies to the store feature label Jul 16, 2023
@cyruseuros
Copy link
Author

No doubt that offline: is useful - it basically gives you stale-while-revalidate without a service worker (if you don't really need one) which is awesome.

I just feel like there is a lot of nice logic that can be re-used for another localStorage-only source which I think would be exceptionally frequently used. It would have unique challenges (i.e. how to store nested models - likely by id-based refs) that probably shouldn't be implemented by every application.

I guess my question is does this belong in hybrids core or should someone (probably me) write it as a plugin?

@smalluban
Copy link
Contributor

smalluban commented Jul 17, 2023

Ok, I get it. The offline is indeed a localStorage implementation, but the main reason why I put it inside the library, is that it needs internal APIs to work best. It is connected with functions that are not meant to be public.

I think it should be straightforward to make a simplified example of LC source API "plugin" (I assume that It would be in the wild if hybrids had a bigger community):

function localStorage(key) {
  const models = JSON.parse(localStorage.getItem(key) || "{}");

  return {
    get: (id) => models[id],
    set(id, values) {
      models[id] = values;
      localStorage.setItem(key, JSON.strinfigy(models));
      return values;
    },
  };
}

const Model = {
   ...,
   [store.connect]: localStorage("models"),
};

@cyruseuros
Copy link
Author

I see - thanks for the help! Will probably hack something like this together with a bit of indexedDB flair once i'm done building my first app in hybrids to figure it out a bit more.

Out of curiosity, how would this example handle an instance when the id is an object identifier like e.g. {foo: "bar"}?

@smalluban
Copy link
Contributor

smalluban commented Jul 20, 2023

Here you have what the docs say:

The value for the identifier can be a string, or an object record (a map of primitive values, which is normalized and serialized to string representation). The object record allows identifying models by multiple parameters rather than on string id.

More info here https://hybrids.js.org/#/store/model?id=singleton-amp-enumerables

@cyruseuros
Copy link
Author

Understood - but what i meant to clarify is that the implementation above would break if you actually tried to pass in an object right? I.e. there is no magic the framework does to translate said object to an id it might be in localStorage under?

@smalluban
Copy link
Contributor

Yes, it only supports flat records. If you pass a "real" object, which does not meet the requirements, it should throw an error.

@cyruseuros
Copy link
Author

Amazing, thanks for the clarification! Closing the issue but just to check my understanding: to make store.set(instanceObj, values) work, one needs to implement a custom set function under [store.connect] that maps object instances to IDs (at the very least by getting the instanceObj.id property). I.e. inside the set function, you need to check whether you got an object or string ID at runtime?

@smalluban
Copy link
Contributor

The store.set serialize id (to a flat record) before calling [store.connect].set. If you pass object record, you don't have to worry, the set method will take a record, but the memory cache will use strigified version.

@cyruseuros
Copy link
Author

got it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
store Applies to the store feature
Development

No branches or pull requests

2 participants