| ... | ... | @@ -64,7 +64,7 @@ _Neglecting to include the secured attribute in an API function definition will | 
| 
 | 
 | 
 | 
| 
 | 
 | 
Prior to April 2020, the current API routing scheme was simple but disorganized due to all API routes living in the `ModuleConfig` for the `v1` module. For instance, the API endpoint to list all available seasons using the `seasons` handler with the `list` function is:
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```.route(:"/seasons/list" )
 | 
| 
 | 
 | 
```.route(:) "/seasons/list"
 | 
| 
 | 
 | 
   .withAction( {  
 | 
| 
 | 
 | 
      GET = "list"  
 | 
| 
 | 
 | 
   } )  
 | 
| ... | ... | @@ -253,7 +253,7 @@ Resolvers conform to the following schema: | 
| 
 | 
 | 
    "name" : "someReolsverName" // a shorthand name for this resolver unique to this entity. The resolver can be invoked via this name from a canned report.
 | 
| 
 | 
 | 
    "filterable" : { // if the resolver is a filter target (e.g. we can query entities WHERE something is the case according to this resolver, this attribute will be present
 | 
| 
 | 
 | 
         "label" : "Human Readable Label", 
 | 
| 
 | 
 | 
         "type" : "oneOfTheFilterableTypesEnum",
 | 
| 
 | 
 | 
         "type" : "oneOfTheFilterableTypesEnum", // see below type list
 | 
| 
 | 
 | 
         "tooltip" : "Text describing what this filter does",
 | 
| 
 | 
 | 
         "resolveWhere" : ( entity, args, $args ) => {
 | 
| 
 | 
 | 
              // lambda function modifying the entity based on the report builder parameters for this function; this can refer to a resolver on reportBuilderUtils or just be a simple entity.where statement
 | 
| ... | ... | @@ -269,12 +269,54 @@ Resolvers conform to the following schema: | 
| 
 | 
 | 
}
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
### Field Types
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
The different value types are statically defined in `model/reportBuilder/Utils.cfc` :  
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
* text
 | 
| 
 | 
 | 
* numeric
 | 
| 
 | 
 | 
* boolean
 | 
| 
 | 
 | 
* nullableBoolean
 | 
| 
 | 
 | 
* functionLike
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
	static {
 | 
| 
 | 
 | 
		//
 | 
| 
 | 
 | 
		// All v4 filterables eventually become "functionlike"s - either they are declared up front as such,
 | 
| 
 | 
 | 
		// or are translated into functionlikes during schema definition expansion.
 | 
| 
 | 
 | 
		// A "functionlike" filterable declares its arguments and their types.
 | 
| 
 | 
 | 
		// Other shorthand values defined here that are not "functionlike" are translated during
 | 
| 
 | 
 | 
		// schema expansion into "functionlike"s having arguments appropriate for their name
 | 
| 
 | 
 | 
		// (e.g. 'boolean' expands into a "functionlike" of 1 argument of type select with 2 options "0" and "1").
 | 
| 
 | 
 | 
		// Schema definitions may declare their filterable to be one of any of these types, but if the schema def needs to manually
 | 
| 
 | 
 | 
		// define an adhoc one-off set of filterable arguments, then it needs to be of type `functionlike` and include
 | 
| 
 | 
 | 
		// the its argument types into the schema def.
 | 
| 
 | 
 | 
		//
 | 
| 
 | 
 | 
		v4_filterableType = {
 | 
| 
 | 
 | 
			functionlike : "functionlike",
 | 
| 
 | 
 | 
			// shorthand for common types
 | 
| 
 | 
 | 
			text : "text",
 | 
| 
 | 
 | 
			numeric : "numeric",
 | 
| 
 | 
 | 
			boolean : "boolean",
 | 
| 
 | 
 | 
			nullableBoolean : "nullableBoolean",
 | 
| 
 | 
 | 
			// deprecated - to be removed, do not use
 | 
| 
 | 
 | 
			binopImplicitLHS : "binop-implicit-lhs"
 | 
| 
 | 
 | 
		}
 | 
| 
 | 
 | 
		v4_op = { "isNull" : "isNull" }
 | 
| 
 | 
 | 
	}
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
### Conventions
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
`$args` in the `resolveWhere` and `resolveSelect` is an internal processing store (not unlike `prc` vs. `rc` in Coldbox) that is consistent across resolvers. It handles pre- and post-processing (e.g. modifying the output of a resolveSelect that has fetched a database column where the value to display is some mutated value based on that column)
 | 
| 
 | 
 | 
`$args` in the `resolveWhere` and `resolveSelect` is an internal processing store (not unlike `prc` vs. `rc` in Coldbox) that is consistent across resolvers. It handles pre- and post-processing (e.g. modifying the output of a resolveSelect that has fetched a database column where the value to display is some mutated value based on that column) and is defined by the result of `model/reportBuilder/Utils.cfc:freshQueryCtx()`
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
### Nullable Boolean Where Resolver
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
Takeaways:
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
* The selected column name must match the struct key (e.g. `this.birthCert` so the column name is aliased as `birthCert` instead of the actual DB column name of `birthCertificate`
 | 
| 
 | 
 | 
* Although this is a nullable boolean type for illustration purposes, the actual DB column here is not nullable
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
	this.birthCert = {
 | 
| 
 | 
 | 
		"v" : 4,
 | 
| ... | ... | @@ -294,7 +336,7 @@ Resolvers conform to the following schema: | 
| 
 | 
 | 
                "selectable" : {
 | 
| 
 | 
 | 
			"label" : "Birth Certificate",
 | 
| 
 | 
 | 
			"resolveSelect" : ( entity, args, $args ) => {
 | 
| 
 | 
 | 
				entity.addSelect( "birthCertificate" );
 | 
| 
 | 
 | 
				entity.addSelect( "birthCertificate birthCert" );
 | 
| 
 | 
 | 
				$args.ctx.registerOnLoadCallback( ( array results ) => {
 | 
| 
 | 
 | 
					for ( var row in results ) {
 | 
| 
 | 
 | 
						row.birthCertificate = yesNoFormat( row.birthCertificate );
 | 
| ... | ... |  | 
| ... | ... |  |