@@ -23,6 +23,11 @@ component displayname="QueryBuilder" accessors="true" {
2323 */
2424 property name = " returnFormat" ;
2525
26+ /**
27+ * Registry used to resolve named return formats.
28+ */
29+ property name = " returnFormatterRegistry" ;
30+
2631 /**
2732 * preventDuplicateJoins
2833 * If true, QB will introspect all existing JoinClauses for a match before creating a new join clause.
@@ -38,6 +43,13 @@ component displayname="QueryBuilder" accessors="true" {
3843 */
3944 property name = " validateOperatorsAndCombinators" ;
4045
46+ /**
47+ * If true, QB throws when queryExecute returntype options are passed.
48+ * If false, QB strips those options so return formatters always receive a query.
49+ * @default false
50+ */
51+ property name = " validateQueryExecuteReturnType" ;
52+
4153 /**
4254 * paginationCollector
4355 * A component or struct with a `generateWithResults` method.
@@ -289,11 +301,17 @@ component displayname="QueryBuilder" accessors="true" {
289301 * Default: qb.models.Query.QueryUtils
290302 * @return Format The closure (or string format shortcut) that modifies the query
291303 * and is eventually returned to the caller. Default: 'array'
304+ * @defaultReturnFormatOptions Options passed to the default return formatter.
305+ * Default: {}
306+ * @return FormatterRegistry Registry used to resolve named return formatters.
292307 * @preventDuplicateJoins Whether QB should ignore a .join() statement that matches an existing join
293308 * Default: false
294309 * @validateOperatorsAndCombinators
295310 * Whether QB validates operators/combinators before storing clauses.
296311 * Default: true
312+ * @validateQueryExecuteReturnType
313+ * Whether QB throws when queryExecute returntype options are passed.
314+ * Default: false
297315 * @paginationCollector The closure that processes the pagination result.
298316 * Default: cbpaginator.models.Pagination
299317 * @columnFormatter The closure that modifies each column before being
@@ -315,8 +333,11 @@ component displayname="QueryBuilder" accessors="true" {
315333 grammar = new qb .models .Grammars .BaseGrammar (),
316334 utils = new qb .models .Query .QueryUtils (),
317335 returnFormat = " array" ,
336+ struct defaultReturnFormatOptions = {},
337+ returnFormatterRegistry ,
318338 preventDuplicateJoins = false ,
319339 validateOperatorsAndCombinators = true ,
340+ validateQueryExecuteReturnType = false ,
320341 paginationCollector = new cbpaginator .models .Pagination (),
321342 columnFormatter ,
322343 parentQuery ,
@@ -330,6 +351,11 @@ component displayname="QueryBuilder" accessors="true" {
330351
331352 setPreventDuplicateJoins ( arguments .preventDuplicateJoins );
332353 setValidateOperatorsAndCombinators ( arguments .validateOperatorsAndCombinators );
354+ setValidateQueryExecuteReturnType ( arguments .validateQueryExecuteReturnType );
355+ if ( isNull ( arguments .returnFormatterRegistry ) ) {
356+ arguments .returnFormatterRegistry = new qb .models .Query .ReturnFormatterRegistry ( arguments .utils );
357+ }
358+ setReturnFormatterRegistry ( arguments .returnFormatterRegistry );
333359 if ( isNull ( arguments .columnFormatter ) ) {
334360 arguments .columnFormatter = function ( column ) {
335361 return column ;
@@ -341,7 +367,7 @@ component displayname="QueryBuilder" accessors="true" {
341367 setParentQuery ( arguments .parentQuery );
342368 }
343369 param variables .defaultOptions = {};
344- setReturnFormat ( arguments .returnFormat );
370+ setReturnFormat ( arguments .returnFormat , arguments . defaultReturnFormatOptions );
345371 mergeDefaultOptions ( arguments .defaultOptions );
346372 setSqlCommenter ( arguments .sqlCommenter );
347373 setCollectQueryLog ( arguments .collectQueryLog );
@@ -4310,10 +4336,6 @@ component displayname="QueryBuilder" accessors="true" {
43104336 return ;
43114337 }
43124338
4313- if ( hasExplicitReturnType ( arguments .options ) ) {
4314- return q ;
4315- }
4316-
43174339 if ( isQuery ( q ) ) {
43184340 return returnFormat ( q );
43194341 }
@@ -4329,10 +4351,6 @@ component displayname="QueryBuilder" accessors="true" {
43294351 return { result : q .result , query : returnFormat ( q .query ) };
43304352 }
43314353
4332- private boolean function hasExplicitReturnType ( required struct options ) {
4333- return arguments .options .keyExists ( " returntype" ) && ! isNull ( arguments .options .returntype );
4334- }
4335-
43364354 /**
43374355 * Run a query through the specified grammar then clear all bindings.
43384356 *
@@ -4345,6 +4363,7 @@ component displayname="QueryBuilder" accessors="true" {
43454363 */
43464364 private any function runQuery ( required string sql , struct options = {}, string retur nO bject = " query" ) {
43474365 structAppend ( arguments .options , getDefaultOptions (), false );
4366+ normalizeQueryExecuteReturnTypeOptions ( arguments .options );
43484367 var bindings = getBindings ( except = getAggregate ().isEmpty () ? [] : [ " select" ] );
43494368
43504369 var result = grammar .runQuery (
@@ -4397,10 +4416,12 @@ component displayname="QueryBuilder" accessors="true" {
43974416 grammar = getGrammar (),
43984417 utils = getUtils (),
43994418 returnFormat = getReturnFormat (),
4419+ returnFormatterRegistry = getReturnFormatterRegistry (),
44004420 paginationCollector = isNull ( variables .paginationCollector ) ? javacast ( " null" , " " ) : variables .paginationCollector ,
44014421 columnFormatter = isNull ( getColumnFormatter () ) ? javacast ( " null" , " " ) : getColumnFormatter (),
44024422 parentQuery = isNull ( getParentQuery () ) ? javacast ( " null" , " " ) : getParentQuery (),
4403- defaultOptions = getDefaultOptions ()
4423+ defaultOptions = getDefaultOptions (),
4424+ validateQueryExecuteReturnType = getValidateQueryExecuteReturnType ()
44044425 );
44054426 }
44064427
@@ -4520,27 +4541,19 @@ component displayname="QueryBuilder" accessors="true" {
45204541 * Alternative, the return format can be a closure. The closure is passed the query as the only argument. The result of the closure is returned as the result of the query.
45214542 *
45224543 * @format "query", "array", or a closure.
4544+ * @options Options passed to named return formatter factories.
45234545 *
45244546 * @return qb.models.Query.QueryBuilder
45254547 */
4526- public QueryBuilder function setReturnFormat ( required any format ) {
4548+ public QueryBuilder function setReturnFormat ( required any format , struct options = {} ) {
45274549 structDelete ( variables .defaultOptions , " returntype" );
45284550 if ( isClosure ( arguments .format ) || isCustomFunction ( arguments .format ) ) {
45294551 variables .returnFormat = format ;
4530- } else if ( arguments .format == " array" ) {
4531- variables .returnFormat = function ( q ) {
4532- return getUtils ().queryToArrayOfStructs ( q );
4533- };
4534- } else if ( arguments .format == " query" ) {
4535- variables .returnFormat = function ( q ) {
4536- return q ;
4537- };
4538- } else if ( arguments .format == " none" ) {
4539- variables .returnFormat = function ( q ) {
4540- return q ;
4541- };
45424552 } else {
4543- throw ( type = " InvalidFormat" , message = " The format passed to Builder is invalid." );
4553+ variables .returnFormat = getReturnFormatterRegistry ().getReturnFormatter (
4554+ arguments .format ,
4555+ arguments .options
4556+ );
45444557 }
45454558
45464559 return this ;
@@ -4566,17 +4579,35 @@ component displayname="QueryBuilder" accessors="true" {
45664579 *
45674580 * @return Format "query", "array", or a closure.
45684581 * @callback The code to execute with the given return format.
4582+ * @options Options passed to named return formatter factories.
45694583 *
45704584 * @return any
45714585 */
4572- public any function withReturnFormat ( required any returnFormat , required any callback ) {
4586+ public any function withReturnFormat ( required any returnFormat , required any callback , struct options = {} ) {
45734587 var originalReturnFormat = getReturnFormat ();
4574- setReturnFormat ( arguments .returnFormat );
4588+ setReturnFormat ( arguments .returnFormat , arguments . options );
45754589 var result = callback ();
45764590 setReturnFormat ( originalReturnFormat );
45774591 return result ;
45784592 }
45794593
4594+ private void function normalizeQueryExecuteReturnTypeOptions ( required struct options ) {
4595+ if ( ! arguments .options .keyExists ( " returntype" ) ) {
4596+ return ;
4597+ }
4598+
4599+ if ( getValidateQueryExecuteReturnType () ) {
4600+ throw (
4601+ type = " InvalidQueryExecuteOption" ,
4602+ message = " The queryExecute returntype option cannot be used with qb return formatters."
4603+ );
4604+ }
4605+
4606+ structDelete ( arguments .options , " returntype" );
4607+ structDelete ( arguments .options , " columnkey" );
4608+ structDelete ( arguments .options , " columnKey" );
4609+ }
4610+
45804611 /**
45814612 * Runs the code inside the callback with the given columns selected and then sets the columns back to its original value.
45824613 *
0 commit comments