You are best off storing your fixtures in a separate isomorphic repo, and then essentially creating a fixture generator within that repo as a bin that overrides to JSON files, which are what’s actually passed around to your fontend & backend.
Create your set algebra in model, and then require it into your fixtures to keep things DRY.
// #assets/models/fixtures/todo
var todos = require('@acme/fixtures').todos,
algebra = require('../todo').algebra,
fixture = require('can-fixture');
var store = fixture.store(todos, algebra);
fixture({
'GET /todos': store.findAll,
'GET /todos/{_id}': store.findOne,
'POST /todos': store.create,
'PUT /todos/{_id}': store.update,
'DELETE /todos/{_id}': store.destroy
});
module.exports = store;
Switch over to using can-connect/can/super-map/
from can.Model
. It’s a lot more feature rich, and doing so will let you take advantage of the newer fixture functionality. Otherwise, it reverts to legacy mode.
// #assets/models/todo
var superMap = require('can-connect/can/super-map/'),
tag = require('can-connect/can/tag/'),
config = require('config'),
set = require('can-set'),
can = require('can');
var algebra = new set.Algebra(
set.comparators.id('_id')
);
require('can/map/define/');
var Todo = can.Map.extend({}, {
define: {
__v: {
value: 0,
type: 'number',
serialize: false
}
}
});
Todo.List = can.List.extend({
Map: Todo
}, {});
var connection = superMap({
url: {
resource: config.hosts.api + '/todos'
},
idProp: '_id',
Map: Todo,
algebra: algebra,
List: Todo.List,
name: 'todo'
});
tag('todo-model', connection);
exports.Todo = Todo;
exports.algebra = algebra;
exports.connection = connection;
exports.store = connection.instanceStore;
Pro tip #1: Make a “config” module that maps to JSON files for the respect environment. This should be essentially identical to the config
module conventions. This one doesn’t really make sense as an isomorphic config just because the server side config will almost assurdely have sensitive information.
"system": {
"directories": {
"lib": "assets"
},
"envs": {
"development": {
"map": {
"config": "./assets/config/development.json"
}
},
"production": {
"map": {
"config": "./assets/config/production.json"
}
},
"staging": {
"map": {
"config": "./assets/config/staging.json"
}
}
},
"npmAlgorithm": "flat",
"map": {
"config": "./assets/config/development.json"
}
},
Pro tip #2: lists can be replaces from promises or constructed from promises.
These all work:
var todos = new Todo.List({}); // implicit findAll
var todos = new Todo.List([]);
todos.replace(Todo.findAll({}));
var todos = new Todo.List(Todo.findAll({}));
This is really helpful because you’ll find it’s easier & more performant to split up behavior accross multiple props.
Pro tip #3: Split up your behavior
todos: {
value: Array,
Type: Todo.List,
get: function( list ) {
var promise = this.attr('promise');
if (promise) {
list.replace(promise);
}
return list
}
},
params: {
// I like using this.serialize within a getter. This approach requires debouncing / batching usually
// You can also inline replace properties on a map to make your resultant value idempotent.
value: Object,
get: function( map ) {
map.attr(this.serialize(), true);
return map;
}
},
promise: {
// Convert params into AJAX request
}
Good luck!