can-set
can-set is a utility for comparing sets that are represented by the parameters commonly passed to service requests.
Object
Once you've imported the can-set
module into your project, use it to create a set.Algebra
and then use that to compare and perform operations on sets.
var set = require('can-set');
// create an algebra
var algebra = new set.Algebra(
// specify the unique identifier on data
set.props.id("_id"),
// specify that completed can be true, false or undefined
set.props.boolean("completed"),
// specify properties that define pagination
set.props.rangeInclusive("start","end"),
// specify the property that controls sorting
set.props.sort("orderBy"),
)
// compare two sets
algebra.subset({start: 2, end: 3}, {start: 1, end: 4}) //-> true
algebra.difference({} , {completed: true}) //-> {completed: false}
// perform operations on sets
algebra.getSubset({start: 2,end: 3},{start: 1,end: 4},
[{id: 1},{id: 2},{id: 3},{id: 4}])
//-> [{id: 2},{id: 3}]
Use
A Set is a plain JavaScript object used to represent a set of data usually sent to the server to fetch a list of records. For example, a list of all completed todos might be represented by:
{complete: true}
This set might be passed to getList like:
Todo.getList({complete: true})
An Algebra is used to detail the behavior of these sets, often using already provided props comparators:
var todoAlgebra = new set.Algebra(
set.props.boolean("complete"),
set.props.id("_id")
);
Using an algebra, all sorts of special behaviors can be performed. For
example, if we already loaded the incomplete todos ({complete: false}
) and
wanted to load all todos ({}
), we could use a set difference to figure out how to load
only the data that hasn't been loaded.
todoAlgebra.difference({}, {complete: false}) //-> {complete: true}
These algebra's are typically used internally by either can-connect or can-fixture to provide these special behaviors:
var cacheConnection = connect([
require("can-connect/data/memory-cache/memory-cache")
],{
algebra: todoAlgebra
});
var todoConnection = connect([
require("can-connect/data/url/url"),
require("can-connect/cache-requests/cache-requests")
],{
cacheConnection: cacheConnection,
url: "/todos",
algebra: todoAlgebra
});
var todoStore = fixture.store([
{ _id : 1, name : 'Do the dishes', complete: true },
{ _id : 2, name : 'Walk the dog', complete: false }
],
todoAlgebra );
fixture("/todos/{_id}", todoStore);
The best way to think about can-set
is that its a way to detail
the behavior of your service layer so other utilities can benefit.
Solving Common Issues
Configuring the proper set.Algebra
can be tricky. The best way to make sure you
have things working is to create an algebra and make sure some of the basics
work.
The most common problem is that your algebra
isn't configured to know what
instance data belongs in which set.
For example, {id: 1, name: "do dishes"}
should belong to the
set {sort: "name asc"}
, but it doesn't:
var algebra = new set.Algebra();
algebra.has({sort: "name asc"}, {id: 1, name: "do dishes"}) //-> false
The fix is to either ignore sort
like:
var algebra = new set.Algebra({
sort: function() { return true; }
});
algebra.has({sort: "name asc"}, {id: 1, name: "do dishes"}) //-> false
Or even better, make sort
actually able to understand sorting:
var algebra = new set.Algebra(
set.props.sort("sort")
);
algebra.has({sort: "name asc"}, {id: 1, name: "do dishes"}) //-> true
Similarly, you can verify that getSubset works. The following, with a default algebra gives the wrong results:
var algebra = new set.Algebra();
algebra.getSubset(
{offset: 1, limit: 2},
{},
[
{id: 1, name: "do dishes"}
{id: 2, name: "mow lawn"},
{id: 3, name: "trash"}]) //-> []
This is because it's looking for instance data where offset===1
and limit===2
.
Again, you can teach your algebra what to do with these properties like:
var algebra = new set.Algebra(
set.props.offsetLimit("offset","limit")
);
algebra.getSubset(
{offset: 1, limit: 2},
{},
[
{id: 1, name: "do dishes"}
{id: 2, name: "mow lawn"},
{id: 3, name: "trash"}]) //-> [
// {id: 2, name: "mow lawn"},
// {id: 3, name: "trash"}
// ]