| ... | @@ -64,7 +64,7 @@ _Neglecting to include the secured attribute in an API function definition will | 
... | @@ -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:
 | 
 | 
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( {  
 | 
 | 
   .withAction( {  
 | 
| 
 | 
      GET = "list"  
 | 
 | 
      GET = "list"  
 | 
| 
 | 
   } )  
 | 
 | 
   } )  
 | 
| ... | @@ -240,5 +240,62 @@ The Report Builder is the library service for all reportable entities within inL | 
... | @@ -240,5 +240,62 @@ The Report Builder is the library service for all reportable entities within inL | 
| 
 | 
 | 
 | 
 | 
| 
 | 
* **Common Entities** that form the basis of each report: Players, Registered Players, Volunteers, Teams, Games, Volunteer Points, Score Transactions (e.g. yellow cards), and financial transactions. Some entities share data (e.g. **PlayerCommon** contains filters and output columns common to both Players and Registered Players).
 | 
 | 
* **Common Entities** that form the basis of each report: Players, Registered Players, Volunteers, Teams, Games, Volunteer Points, Score Transactions (e.g. yellow cards), and financial transactions. Some entities share data (e.g. **PlayerCommon** contains filters and output columns common to both Players and Registered Players).
 | 
| 
 | 
  * Entities map to a Quick 'root entity' (e.g. `/reportBuilder/CommonEntities/Player.cfc:getFreshEntity()` upon which all operations are performed, before dropping to `.asQuery()` and returning an array of structs
 | 
 | 
  * Entities map to a Quick 'root entity' (e.g. `/reportBuilder/CommonEntities/Player.cfc:getFreshEntity()` upon which all operations are performed, before dropping to `.asQuery()` and returning an array of structs
 | 
| 
 | 
* **Resolvers** on each entity that map to data fields containing one or both of a **where resolver** (aka 'filter') that governs the criteria of the report (e.g. 'all (entities) where (field) is (value) and a **select resolver** that governs the display.
 | 
 | 
* **Resolvers** on each entity that map to data fields containing one or both of a **where resolver** (aka 'filter') that governs the criteria of the report (e.g. 'all (entities) where (field) is (value) and a **select resolver** that governs the display. Each resolver is a private attribute on the entity's report builder component (e.g. `this.birthCert` in the first example below) which is appended to a function that returns all resolvers (e.g. `playerAndRegisteredPlayerCommonResolvers()` on `PlayerCommon.cfc`.
 | 
| 
 | 
* **Utilities** for generating and evaluating resolvers and populating select lists
 | 
 | 
* **Utilities** for generating and evaluating resolvers and populating select lists
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
## Example "Query Targets" (Resolvers)
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
Resolvers conform to the following schema:
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
```
 | 
 | 
 | 
 | 
{
 | 
 | 
 | 
 | 
    "v": 4 // imported / interpreted results from the previous gen v3 report builder use 3; 4 is any resolver we've written expressly for this (v4) report builder
 | 
 | 
 | 
 | 
    "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",
 | 
 | 
 | 
 | 
         "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
 | 
 | 
 | 
 | 
              entity.where( "someField", "=", args.value )
 | 
 | 
 | 
 | 
         }
 | 
 | 
 | 
 | 
    },
 | 
 | 
 | 
 | 
    "resolveSelect" : ( entity, args, $args ) => {
 | 
 | 
 | 
 | 
           // lambda function adding output columns to the entity and (optionally) registering a callback on the results to modify that output
 | 
 | 
 | 
 | 
           entity.addSelect( "someField" )
 | 
 | 
 | 
 | 
    }
 | 
 | 
 | 
 | 
}
 | 
 | 
 | 
 | 
```
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
### 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)
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
### Nullable Boolean Where Resolver
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
```
 | 
 | 
 | 
 | 
	this.birthCert = {
 | 
 | 
 | 
 | 
		"v" : 4,
 | 
 | 
 | 
 | 
		"name" : "birthCert",
 | 
 | 
 | 
 | 
		"filterable" : {
 | 
 | 
 | 
 | 
			"label" : "Birth Certificate",
 | 
 | 
 | 
 | 
			"type" : "nullableBoolean",
 | 
 | 
 | 
 | 
			"tooltip" : "Returns players that have (or don't have) a birth certificate.",
 | 
 | 
 | 
 | 
			"resolveWhere" : ( entity, args ) => {
 | 
 | 
 | 
 | 
				reportBuilderUtils.v4_nullableBooleanResolver(
 | 
 | 
 | 
 | 
					entity = entity,
 | 
 | 
 | 
 | 
					unsafeRaw_columnNameOrExpr = "birthCertificate",
 | 
 | 
 | 
 | 
					value = args.value
 | 
 | 
 | 
 | 
				)
 | 
 | 
 | 
 | 
			}
 | 
 | 
 | 
 | 
		},
 | 
 | 
 | 
 | 
                "resolveSelect" : ( entity, args, $args ) => {
 | 
 | 
 | 
 | 
			entity.addSelect( "birthCertificate" );
 | 
 | 
 | 
 | 
			$args.ctx.registerOnLoadCallback( ( array results ) => {
 | 
 | 
 | 
 | 
				for ( var row in results ) {
 | 
 | 
 | 
 | 
					row.birthCertificate = yesNoFormat( row.birthCertificate );
 | 
 | 
 | 
 | 
				}
 | 
 | 
 | 
 | 
			})
 | 
 | 
 | 
 | 
		}
 | 
 | 
 | 
 | 
	}
 | 
 | 
 | 
 | 
``` | 
 | 
 | 
 | 
\ No newline at end of file |