data icon indicating copy to clipboard operation
data copied to clipboard

How to create a `snapshot` instance

Open ppcano opened this issue 10 years ago • 24 comments

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.

ppcano avatar Feb 17 '15 08:02 ppcano

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 avatar Feb 17 '15 09:02 wecc

@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.

ppcano avatar Feb 17 '15 09:02 ppcano

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.

kimroen avatar Feb 17 '15 11:02 kimroen

@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 avatar Feb 19 '15 14:02 bmac

@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?

wecc avatar Feb 19 '15 17:02 wecc

:+1: We too have several customer adapters and that is our primary use case. It would also be helpful in unit testing our serializers.

workmanw avatar Feb 26 '15 13:02 workmanw

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.

pmdarrow avatar Feb 26 '15 18:02 pmdarrow

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 avatar Mar 16 '15 18:03 bmac

@bmac Ok. Might be worth closing this issue then if the decision is final.

pmdarrow avatar Mar 16 '15 19:03 pmdarrow

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?

workmanw avatar Mar 16 '15 20:03 workmanw

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.

bmac avatar Mar 16 '15 21:03 bmac

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 avatar Sep 09 '15 20:09 jcbvm

@jcbvm buildURL already receives a snapshot/array of snapshots. http://emberjs.com/api/data/classes/DS.BuildURLMixin.html#method_buildURL

wecc avatar Sep 10 '15 18:09 wecc

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.

jcbvm avatar Sep 10 '15 19:09 jcbvm

How can I write a unit test for adapter.createRecord without this?

yaymukund avatar Oct 23 '15 22:10 yaymukund

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.

amk221 avatar Jul 22 '16 13:07 amk221

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.

wecc avatar Oct 22 '16 16:10 wecc

Any updates here? a snapshot() test helper would be really helpful.

Syzygy24 avatar Aug 14 '17 20:08 Syzygy24

@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. 😛

tomdale avatar Aug 20 '17 19:08 tomdale

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.

workmanw avatar Aug 20 '17 20:08 workmanw

@tomdale record.serialize() helps with unit testing serializer, but how does it help me unit test my custom adapter methods, which require snapshots?

hvgotcodes avatar Sep 12 '17 17:09 hvgotcodes

@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.

sdhull avatar Jul 19 '18 07:07 sdhull

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

runspired avatar Nov 16 '18 22:11 runspired

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.

runspired avatar May 22 '21 06:05 runspired

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.

runspired avatar Nov 17 '22 02:11 runspired