can-query-logic
Version:
96 lines (87 loc) • 3.02 kB
JavaScript
import {canReflect, QueryLogic} from "can";
// Takes the value of `name` (ex: `"chicken"`)
function SearchableStringSet(value) {
this.value = value;
}
canReflect.assignSymbols(SearchableStringSet.prototype,{
// Returns if the name on a todo is actually a member of the set.
"can.isMember": function(value){
return value.includes(this.value);
},
// Converts back to a value that can be in a query.
"can.serialize": function(){
return this.value;
}
});
// Specify how to do the fundamental set comparisons.
QueryLogic.defineComparison(SearchableStringSet,SearchableStringSet,{
// Return a set that would load all records in searchA and searchB.
union(searchA, searchB){
// If searchA's text contains searchB's text, then
// searchB will include searchA's results.
if(searchA.value.includes(searchB.value)) {
// A:`food` ∪ B:`foo` => `foo`
return searchB;
}
if(searchB.value.includes(searchA.value)) {
// A:`foo` ∪ B:`food` => `foo`
return searchA;
}
// A:`ice` ∪ B:`cream` => `ice` || `cream`
return new QueryLogic.ValueOr([searchA, searchB]);
},
// Return a set that would load records shared by searchA and searchB.
intersection(searchA, searchB){
// If searchA's text contains searchB's text, then
// searchA is the shared search results.
if(searchA.value.includes(searchB.value)) {
// A:`food` ∩ B:`foo` => `food`
return searchA;
}
if(searchB.value.includes(searchA.value)) {
// A:`foo` ∩ B:`food` => `food`
return searchB;
}
// A:`ice` ∩ B:`cream` => `ice` && `cream`
// But suppose AND isn't supported,
// So we return `UNDEFINABLE`.
return QueryLogic.UNDEFINABLE;
},
// Return a set that would load records in searchA that are not in
// searchB.
difference(searchA, searchB){
// if searchA's text contains searchB's text, then
// searchA has nothing outside what searchB would return.
if(searchA.value.includes(searchB.value)) {
// A:`food` \ B:`foo` => ∅
return QueryLogic.EMPTY;
}
// If searchA has results outside searchB's results
// then there are records, but we aren't able to
// create a string that represents this.
if(searchB.value.includes(searchA.value)) {
// A:`foo` \ B:`food` => UNDEFINABLE
return QueryLogic.UNDEFINABLE;
}
// A:`ice` \ B:`cream` => `ice` && !`cream`
// If there's another situation, we
// aren't able to express the difference
// so we return UNDEFINABLE.
return QueryLogic.UNDEFINABLE;
}
});
const recipes = [
{id: 1, name: "garlic chicken"},
{id: 2, name: "ice cream"},
{id: 3, name: "chicken kiev"}
];
const queryLogic = new QueryLogic({ keys: {
name : {[Symbol.for("can.SetType")]: SearchableStringSet}
}});
const result = queryLogic.filterMembers({
filter: {name: "chicken"}
}, recipes);
console.log( result ); //-> [
// {id: 1, name: "garlic chicken"},
// {id: 3, name: "chicken kiev"}
// ]