canjs / can-query-logic

Perform data queries and compare queries against each other. Provides logic useful for data caching and real-time behavior.

Home Page:https://canjs.com/doc/can-query-logic.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support custom sort functions

m-mujica opened this issue · comments

Sometimes you have to use a custom sort function on Lists, being unable to use this function in can-query-logic means that unexpected insertion/removals will happen when using real-time.

// sorter
function sortByName(item1, item2) {
  var val1 = item1.name.toLowerCase();
  var val2 = item2.name.toLowerCase()
 ...
}

// adding the symbol to the list
...
list.sort(sortByName);
list[canSymbol.for('can.listQuery')] = { sort: 'name' };

When real-time tries to figure where a new (or existing) item should be placed on the lists it calls getIndex which will sometimes not match the position where the instance "should be placed" based on the sortByName comparator logic.

Ideally we should be able to pass sortByName so can-query-logic can determine the position correctly.

A work around would be to add additional properties like nameLowerCase on your data returned by the server and then sort by that property.

@m-mujica when querying, is case also ignored? Should {filter: {name: "manuel"}} match {name: "ManuEL"}? If yes, then something like this should work: https://codepen.io/justinbmeyer/pen/aQReVq?editors=0011 .... but it's not ... I'm fixing this.

This works, does that solve it for you @m-mujica ?

	function StringIgnoreCaseSet(value){
		this.value = value;
	}
	StringIgnoreCaseSet.prototype.valueOf = function(){
		return this.value.toLowerCase();
	};
	canReflect.assignSymbols(StringIgnoreCaseSet.prototype,{
		"can.serialize": function(){
			return this.value;
		}
	});
	var StringIgnoreCase = canReflect.assignSymbols({},{
		"can.SetType": StringIgnoreCaseSet,
		"can.new": function(value){
			return value;
		}
	});

	var queryLogic = new QueryLogic({
		keys: {
			name: StringIgnoreCase
		},
		identity: ["id"]
	});

	var filter = queryLogic.filterMembers(
		{sort: "name"},
		[{id: 1, name: "grab coffee"},
		{id: 2, name: "finish these docs"},
		{id: 3, name: "Learn CanJS"}]
	);
	QUnit.deepEqual([
		{id: 2, name: "finish these docs"},
		{id: 1, name: "grab coffee"},
		{id: 3, name: "Learn CanJS"}
	], filter);

@justinbmeyer I haven't tried this out... About the querying, yes, the casing is totally ignored.

I'lll let you know once I test your workaround. Thanks.