can-query-logic
Version:
100 lines (89 loc) • 3.19 kB
JavaScript
import {canReflect, DefineMap, 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 SearchableString = {
[Symbol.for("can.SetType")]: SearchableStringSet
};
const Todo = DefineMap.extend({
id: {type: "number", identity: true},
name: SearchableString,
});
const todos = [
{id: 1, name: "important meeting"},
{id: 2, name: "fall asleep during meeting"},
{id: 3, name: "find out what important means"}
];
const queryLogic = new QueryLogic(Todo);
const result = queryLogic.filterMembers({
filter: {name: "important"}
}, todos);
console.log( result ); //->[{id: 1, name: "important meeting"},{id: 3, name: "find out what important means"}]