Closed Jopie01 closed 1 year ago
There are a few approaches here
1) if name
is a unique
key for the icon, then this is essentially the same as "the username problem", which is how we describe the common issue where folks use a username for the route's url, mapping it to id
in the request to get data, but get back a record that has the actual id. In effect username is a secondary unique-key.
The username problem is solved by configuring the identifiers cache. (Lots of things are solved by configuring this cache, it's why we coordinate identity of opaque objects in this way). You'll want to review these tests for an example implementation and setup that addresses the username problem https://github.com/emberjs/data/blob/a7f521572f55e1845f694d07c6db8d9287b479b3/tests/main/tests/integration/identifiers/scenarios-test.ts#L39
2) if name
is not unique but you want to be able to query local data in the cache, there are 4 approaches
a. use `peekAll` and filter. Ultimately if EmberData ever builds in any sort of sync-client-side-query capability it'll probably be built over `peekAll` and use filter itself too. We've spent a lot of time optimizing live-arrays that would be hard to beat for building up query indeces and whatnot.
b. build secondary request caches in your Cache implementation that populate additional queries, or do so dynamically. E.g. `Cache.peekRequest` could dynamically create a fake request based on data it already has.
c. RFC something akin to `Cache.query` to be a sync method that caches may implement to respond to client-side queries. We're intending to experiment on something like this at some point, but even with it would encourage only using this via (d)
d. create a request handler that uses a combo of [(a) and (b)] or (c) to generate a response. This has the benefit of working with any async storage, so could even work with an indexdb or worker approach.
Thanks for the thorough answer! I'm first going to look into 2a which should be sufficient at first. Then see if I can use handlers and secondary request caches.
BTW, I only have a few @ember-data
packages installed, not the whole thing.
"dependencies": {
"@babel/core": "^7.21.4",
"@ember-data/debug": "4.12.0-alpha.19",
"@ember-data/graph": "4.12.0-alpha.19",
"@ember-data/json-api": "4.12.0-alpha.19",
"@ember-data/request": "4.12.0-alpha.19",
"@ember-data/store": "4.12.0-alpha.19",
"@ember-data/tracking": "4.12.0-alpha.19",
"crypto-js": "^4.1.1",
"ember-simple-auth": "^5.0.0",
"pnpm": "8.1.0"
}
Closing as nothing more to do here (quest linked will be responsible for ensuring the answer here is eventually codified into guides and docs)
To make this complete, I ended up using this.peekAll
and find
to get the record. If there is no result I hand the request over to the query
method which then fetches the data from the backend.
queryRecord(modelName, query, options) {
const data = this.peekAll(modelName).find(d => {
query.domain.forEach(part => {
const [key, operator, value] = part;
if (d[key] === value) {
return d;
}
});
});
if (data !== undefined) {
return Promise.resolve(data);
}
const promise = this.query(modelName, query, options);
return promise.then(document => document[0]);
}
Maybe this can be moved into a request handler at some point, but that is going to be more advanced. I'm now returning one record, but it should be possible then to return multiple records. Also the question then pops up if the cache has all the records or not?. So I'm keeping it this way for the moment.
This is more of a question / thought experiment then an issue. Since PR #8539 everything is working, data is fetched and put into cache. The next time data is taken from cache instead from the backend. I had to make a small adjustment because the data is nested a level deeper (see my repo for what changed).
Imagine the following: I store icon data in my backend and fetch that on application start so I can use those icons throughout my application. I do a call to the backend and get a list of icons back with
id
,name
, andicon_data
. This data is thenput
into the cache where the unique identifier is the hash of the query and thedata
is the list of icons.This works pretty well, the next the query is called and the hash is the same, data is taken from the cache instead of the backend.
Now I want to use an icon and I only know the name, so I do a
this.store.query('icon', [['name', '=', 'my_icon_name']]);
because I already have thequery
working and in the end I only take the first record. Because I already fetched the icons, I would expect that this request doesn't reach to the backend to get the icon. But the hash of this query is different and therefore it reaches out to the backend to fetch the data for that icon (which already exists in cache). Also to note, there is no relationship.So I basically want one record out of the list of
data
but thatdocument
has the wrong key, so thefetch
doesn't find anything and asks the backend for the data. Instead of thethis.store.query
I can create athis.store.queryRecord
which then first tries to find something from the cache and then reaches out to the backend.Is the above possible? Are there some functions / hooks I can call?