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

Type coercion in set algebra - dev mode warnings ~13

justinbmeyer opened this issue · comments

@DesignByOnyx commented on Mon Aug 08 2016

The problem lies in the fact that set algebra is type-specific. In a situation where a request uses an integer (Model.findAll({ taskId: 1234 })) and a later response sends a string ({ id: 1, taskId: "1234"}), the set algebra sees this as two different objects and does not reconcile the two. This behavior is academically correct, but in practice causes some headaches. For example, getting a value from the URL or a form field always needs to be converted to a proper type before invoking set logic. This is not always clear to users because because the string "false" or string "1234" will result in successful http requests and db queries and successful math (15/"5" === 3), but will cause set logic to fail.

So, should a library should coerce certain values to their primitive counterparts:

  • "false" -> false
  • "null" -> null
  • "undefined" -> undefined
  • "1234" -> 1234

The short answer is "no" - implementers should do this, not the library. I can't find the discussion that express bodyParser had on this, but after a long debate they decided not to coerce, and neither should we. However, we lost lots of time trying to track down two different issues where numbers were transmitted as strings, so I have two proposals:

  1. Allow optional coercion of values behind a flag. Implementers will then need to know that the string values mentioned above will be converted to primitives, and will need to sanitize their data manually and account for this throughout their code (not ideal).
  2. dev-mode only warnings. In dev mode, we might consider evaluating data used in set logic and if we detect two objects such as { id: 1, taskId: 1234 } and { id: 1, taskId: "1234" } - we warn the user that we found data which looks similar but isn't.

@justinbmeyer commented on Thu Sep 01 2016

I think can-util should provide a "fuzzy" converter (which would be useful several places). This would be able to do those fuzzy string conversions like "false" -> false.

Then, people can set that on their algebra.

I think can be done with a type like:

import stringToAny from "can-string-to-any"

FuzzyType = canReflect.assignSymbols(toBoolean,{
	"can.new": function(value){
		 return typeof value === "string" ? stringToAny(value) : value;
	},
        "can.getName": function(){
           return "FuzzyType";
        },
	"can.isMember": function(value) {
		return true;
	}
});

And then in your schema:

{
  keys: {foo: FuzzyType}
}

Though I don't I don't think this is necessary as you should be saying taskId: MaybeString now.