data
data copied to clipboard
How to create a `snapshot` instance
When using serializers with 1.0.0.beta.15, they expect to receive a snapshot
instead of the record
.
I have missed any doc that states which is the default way to create a snapshot
.
new Snapshot(record)
// or
record._createSnapshot()
Some documentation shows the _createSnapshot
method but it's marked as private, so I think, the default way is the first option.
Currently both new Snapshot(record)
and record._createSnapshot()
are marked as private since you're not really supposed to use snapshots outside of serializers yet.
What's your use case for having to create a snapshot manually?
@wecc, our use case is a little tricky.
A model property config
is defined by a json raw as:
load_schedule: [{duration: 5, users: 20}]
network_emulation: {client: "li", network: "unlimited"}
server_metric_agents: []
source_ips: 1
tracks: [{clips: [{user_scenario_id: 16, percent: 100}], loadzone: "amazon:us:ashburn"}]
user_type: "sbu"
Then, a custom transform serialises this config
data transforming it to a custom Em.Object
which is represented by the UI making use of CP/.... in order to facility user interaction with this data.
Then, whenever any change is done, we need to deserialised only this config
model property to use it on some specific api
calls.
We would like to use Snapshots as well. Our cases are things like this:
We have Users - they can "like" Things. The Things they like is a hasMany
relationship between the User and the Thing. We tell if someone has liked anything by the number of items in this relationship.
If we do it the normal way, we'll suddenly load hundreds of these Things that the User has potentially liked, so we use the private _relationships.<nameOfAttr>.members.list.length
to check. We would rather like to make a Snapshot and check the length of hasMany()
on it.
This is also useful for checking if the current User likes the Thing they are currently viewing, as we only need the ids to do that.
@wecc Seems people need a public way to create snapsnots for custom adapters (example). I'd be in favor of making the constructor public but I know there were some reservations about that in the original snapshots pr. Thoughts?
@bmac Yeah, initially there was record.snapshot()
as a public API in the PR but this got removed before merge. I'm not too sure on why though.
I think it makes sense to provide a public API to create snapshots but I would prefer record.snapshot()
over new Snapshot(record)
to encapsulate the creating of the snapshot as this might change in the future.
@igorT @wycats @tomdale thoughts?
:+1: We too have several customer adapters and that is our primary use case. It would also be helpful in unit testing our serializers.
Similar to @workmanw we need to create snapshots in order to unit test our custom serializers. It would be nice to have a public API for this.
This issue was discussed in the last Ember Data meeting and it was decided that adapters will get passed an instance of a snapshot instead of a record. For unit testing custom serializers it is suggested that you use a model's serialize
function.
@bmac Ok. Might be worth closing this issue then if the decision is final.
I can live with that. It's not as nice as I'd like, but not a huge deal. Just curious, is there any particular concern that caused this to sway to staying a private api vs becoming public?
I believe the main concern was attempting to reduce the surface area of the public api. The hope is that https://github.com/emberjs/data/pull/2883 will fix most of the reasons why a public api is currently needed. If that does not then the decision may be revisited in the future.
What about buildURL which is a public method on an adapter. I need to build an URL from an existing model but can't find a way at the moment to pass a snapshot to the buildURL because there seems no public way to retrieve the snapshot from the model.
@jcbvm buildURL
already receives a snapshot/array of snapshots. http://emberjs.com/api/data/classes/DS.BuildURLMixin.html#method_buildURL
Let me explain my use case a little more. I have a service which performs ajax requests the same way as saving or creating a model, but more like performing an action. To do this, the service uses the adapter to build the URL from a model (so the URL will look the same as saving a model, but with an extra path at the end for a specific action).
So the code looks something like this:
let adapter = this.store.adapterFor('someModel');
let url = adapter.buildURL('someModelName', id, snapshot);
Here I want to pass the snapshot to the buildURL (because adapter might alter the URL by using snapshot data).
I know that maybe it's a bad idea to do it this way, but I didn't find a more proper way of doing this.
How can I write a unit test for adapter.createRecord
without this?
My use-case for wanting a public way to create snapshots is purely for unit testing purposes. Some Serializer methods accept a snapshot as a parameter. I could send in a fake snapshot-like object, but that is a bit of a pain to do each time. example.
The long-term solution here is to create better tools for unit testing adapters and serializers but in the meantime I think a snapshot()
test helper could work.
Any updates here? a snapshot() test helper would be really helpful.
@Syzygy24 Does record.serialize()
not solve your use case?
I'm :-1: on providing functionality for creating snapshots just for unit testing adapters or serializers. The public interface for snapshots is pretty simple but the point of them is to encapsulate internal state at a moment in time.
If you want to "unit test" a serializer, creating an actual snapshot instance means you're no longer unit testing. If you truly want to unit test, creating a mock/stub snapshot should be straightforward in whatever test library you're using. If you want Ember Data to create a snapshot for you, you should just write an integration test. 😛
It seems like a reasonable compromise could be to add a public record.snapshot()
function to create a snapshot of the record, while still keeping the details encapsulated. This compromise wouldn't really expand the surface of the API given that both record
and snapshot
are public entities.
I also have wanted this several times. Not just for testing, but also to be able to manually call adapter functions on rare occasions.
@tomdale record.serialize()
helps with unit testing serializer, but how does it help me unit test my custom adapter methods, which require snapshots?
@tomdale we're using a technique outlined on EmberIgniter to save only dirty attributes, however in some scenarios we want to serialize everything.
We thought we might be able to do let vanillaSerializer = DS.JSONAPISerializer.create()
and then vanillaSerializer.serialize(...)
but obviously we'd need a snapshot
in order to do that.
We've worked around it by overridding serialize()
so that it passes options
into serializeAttribute
but it's not ideal.
Another option for our specific use-case would be if model.serialize()
took a {serializer}
option. Wouldn't help people with testing adapters & serializers of course.
If anyone has a moment to take on an easy RFC, we'd love to add the ability for folks to create snapshots for unit and integration tests: https://github.com/emberjs/rfcs/issues/396
Revisiting this: While we'd probably still be open to an rfc for a public API, a better way to do this is to test adapters and serializers via interacting with the store in the manner that you'd expect to trigger those methods. This ensures that everything (not just the snapshot) is in a realistic state did the test.
I paired with @jherdman today for his work updating the active-model-serializer to show him how this is done, and perhaps adding this to the testing guide / testing blueprints would be enough to help folks off on the right foot.
Additional note: the RequestManager RFC removes the concept of Snapshots entirely when no longer using the legacy adapters and serializers: https://github.com/emberjs/rfcs/pull/860
Instead, users will use public store apis to speak directly with the cache.
Given this and my comment immediately above, I'm closing this issue.