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

can.connect for advanced persistent data behavior #1213

Closed
justinbmeyer opened this issue Aug 25, 2014 · 11 comments
Closed

can.connect for advanced persistent data behavior #1213

justinbmeyer opened this issue Aug 25, 2014 · 11 comments

Comments

@justinbmeyer
Copy link
Contributor

VOTE HERE

Goal

Create a plugin that allows mixin behavior for CRUD lifecycle events. For example, creating a Person can.Map and adding RESTful behavior might look like:

Person = can.Map.extend({ ... });

can.connect.resource("/people", Person) 

Person.findAll({}) //-> deferred
  • Creating and using the mixins should be easy.
  • can.Model should use this and be backwards compatible.

Proposed mixins

Model instance store

Provides the same behavior as the current model-store

Use

can.connect.store(Person,{id: "personId"})

Implementation

Hooks into:

  • findOne / findAll lifecycle
  • bind / unbind

Realtime connection

Use

can.connect.live(Person,{
  // how to connect to event stream
  // called when items have been requested
  // able to tell system when an item is created / updated
  // destroyed
  connect: function(){},
  // called to disconnect
  disconnect: function(){}
})

Use localStorage as a fall-through cache

Use

can.connect.localCache("people", Person)

Live lists

Live lists would automatically put created items in the list when the realtime connection pushed a new item.

Use

can.connect.live(Person,{});
can.connect.liveLists(Person, {
  // compares the params a list was retrieved with 
  // and an instance and indicates if the instance
  // belongs in the list
  compare: function(){}
})

Queue Plugin

Allows immediate saving and queuing of requests.

Use

can.connect.queue(Person)

Implementation

Hooks into:

  • create / update / destroy lifecycle
  • backup / restore?
@justinbmeyer justinbmeyer added this to the 2.2.0 milestone Aug 25, 2014
@justinbmeyer
Copy link
Contributor Author

Related: #1126

@daffl
Copy link
Contributor

daffl commented Aug 25, 2014

Maybe separate services might provide a better decoupling than mixins. It can potentially be hard to figure out what has been mixed in and effectively the Person model is still coupled to how it connects. I don't think it would make too much of a difference except for that you have a separate service object:

var Person = can.Map.extend({ ... });

// Hook up custom connector
var userService = can.connect({
  findAll: function(params) {
    return new Promise(); // ...
  },

  findOne: function(id) {
    return new Promise(); // ...
  }
}, Person);

// Hook up via REST API
var userService = can.connect(can.connect.rest('/users'), Person);

// Hook up via Feathers
var userService = can.connect(can.connect.feathers('/users'), Person);

userService.findOne(10).then(function(person) {
  console.log(person instanceof Person);
});

userService.findAll().then(function(people) {
  console.log('Found ' + people.length + ' users');
});

userService.on('created', function(person) {
  console.log('Someone created a new user', person);
});

@justinbmeyer
Copy link
Contributor Author

The goal of this is to maintain can.Model's API.

@daffl I'm not sure what you are showing or what you mean by "services". There's unlikely anything better than a "mixin" for decoupling the mixin's themselves.

In your example, userService would still be coupled to "Person".

@matthewp
Copy link
Contributor

What is the API that a connector is implementing here? I want to write a custom connector that connects to indexeddb or some other storage backend that probably won't be in core. How would I do that here?

Also, you can connect multiple backends it seems, so how does it determine which gets called?

@justinbmeyer
Copy link
Contributor Author

I've not started showing how these would be implemented. The first step is to identify common use cases and then see what implementing them might be like.

Sent from my iPhone

On Aug 25, 2014, at 8:45 PM, Matthew Phillips [email protected] wrote:

What is the API that a connector is implementing here? I want to write a custom connector that connects to indexeddb or some other storage backend that probably won't be in core. How would I do that here?

Also, you can connect multiple backends it seems, so how does it determine which gets called?


Reply to this email directly or view it on GitHub.

@Tarabyte
Copy link

@daffl The idea with "services" is really cool. Actually it can be an implementation of Repository Pattern. Which allows to hide storage and transport level details from the model itself.

Quite usefull for advanced scenarios like unit-testing or switching between online and offline application mode.

@daffl
Copy link
Contributor

daffl commented Aug 26, 2014

The service would be coupled to Person but it would separate data accessing logic from the Person map (plus you can create a service without a Map to mix it into). With a mixin everything would still be smushed together in the end (as @matthewp pointed out this can make it hard to know what is actually happening). Also, as @Tarabyte mentioned this also makes things easier to mock and test.

Even with services introduced as a new concept this can still be API backwards compatible because the service basically is the same thing as the mixin object. Simplified something like:

can.extend(Person, userService);

Person.findAll();

Would then provide the same API as can.Model.

@daffl daffl modified the milestones: 2.3.0, 2.2.0 Jan 10, 2015
@wclr
Copy link
Contributor

wclr commented Jan 16, 2015

Is there any progress for this issue? BTW wy can.Model doesn't have default method like sync that would request server new data for partucular instance and merge it with existing data on the client?

@justinbmeyer
Copy link
Contributor Author

findOne can do this

Sent from my iPhone

On Jan 15, 2015, at 6:01 PM, Alex [email protected] wrote:

Is there any progress for this issue? BTW wy can.Model doesn't have default method like sync that would request server new data for partucular instance and merge it with existing data on the client?


Reply to this email directly or view it on GitHub.

@wclr
Copy link
Contributor

wclr commented Jan 16, 2015

I use this method, but I'm not sure that it will work correctly if model instance is not in store.

findOne only will merge incomming data with model with the same id that is in store.

@daffl
Copy link
Contributor

daffl commented Oct 22, 2015

@daffl daffl closed this as completed Oct 22, 2015
@daffl daffl removed this from the 2.3.0 milestone Oct 22, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants