Skip to content

Commit d9d5222

Browse files
committed
Tighten return formatter propagation
1 parent 87b31a0 commit d9d5222

3 files changed

Lines changed: 56 additions & 5 deletions

File tree

models/Query/QueryBuilder.cfc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4377,7 +4377,7 @@ component displayname="QueryBuilder" accessors="true" {
43774377
*/
43784378
private any function runQuery( required string sql, struct options = {}, string returnObject = "query" ) {
43794379
structAppend( arguments.options, getDefaultOptions(), false );
4380-
normalizeQueryExecuteReturnTypeOptions( arguments.options );
4380+
guardAgainstReturnTypeOption( arguments.options );
43814381
var bindings = getBindings( except = getAggregate().isEmpty() ? [] : [ "select" ] );
43824382

43834383
var result = grammar.runQuery(
@@ -4435,7 +4435,8 @@ component displayname="QueryBuilder" accessors="true" {
44354435
columnFormatter = isNull( getColumnFormatter() ) ? javacast( "null", "" ) : getColumnFormatter(),
44364436
parentQuery = isNull( getParentQuery() ) ? javacast( "null", "" ) : getParentQuery(),
44374437
defaultOptions = getDefaultOptions(),
4438-
validateQueryExecuteReturnType = getValidateQueryExecuteReturnType()
4438+
validateQueryExecuteReturnType = getValidateQueryExecuteReturnType(),
4439+
collectQueryLog = getCollectQueryLog()
44394440
);
44404441
}
44414442

@@ -4560,7 +4561,6 @@ component displayname="QueryBuilder" accessors="true" {
45604561
* @return qb.models.Query.QueryBuilder
45614562
*/
45624563
public QueryBuilder function setReturnFormat( required any format, struct options = {} ) {
4563-
structDelete( variables.defaultOptions, "returntype" );
45644564
if ( isClosure( arguments.format ) || isCustomFunction( arguments.format ) ) {
45654565
variables.returnFormat = format;
45664566
} else {
@@ -4605,7 +4605,7 @@ component displayname="QueryBuilder" accessors="true" {
46054605
return result;
46064606
}
46074607

4608-
private void function normalizeQueryExecuteReturnTypeOptions( required struct options ) {
4608+
private void function guardAgainstReturnTypeOption( required struct options ) {
46094609
if ( !arguments.options.keyExists( "returntype" ) ) {
46104610
return;
46114611
}

models/Query/ReturnFormatterRegistry.cfc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ component accessors="true" singleton {
6464
}
6565

6666
var definition = variables.returnFormatters[ arguments.name ];
67-
var formatterOptions = duplicate( definition.options );
67+
var formatterOptions = {};
68+
structAppend( formatterOptions, definition.options, true );
6869
structAppend( formatterOptions, arguments.options, true );
6970

7071
var factory = resolveFactory( definition.factory, definition.properties );

tests/specs/Query/Abstract/QueryExecutionSpec.cfc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,36 @@ component extends="testbox.system.BaseSpec" {
13931393
expect( results ).toBe( "account-1" );
13941394
} );
13951395

1396+
it( "carries return formatter settings to new queries and clones", function() {
1397+
var registry = new qb.models.Query.ReturnFormatterRegistry();
1398+
registry.registerReturnFormatter( "firstId", function( options ) {
1399+
return function( q ) {
1400+
return q.id[ 1 ];
1401+
};
1402+
} );
1403+
var builder = getMockBox()
1404+
.createMock( "qb.models.Query.QueryBuilder" )
1405+
.init(
1406+
grammar = getMockBox().createMock( "qb.models.Grammars.BaseGrammar" ).init(),
1407+
returnFormatterRegistry = registry,
1408+
validateQueryExecuteReturnType = true,
1409+
collectQueryLog = false
1410+
);
1411+
1412+
var newBuilder = builder.newQuery();
1413+
var clonedBuilder = builder.clone();
1414+
1415+
expect( newBuilder.getReturnFormatterRegistry() ).toBe( registry );
1416+
expect( newBuilder.getValidateQueryExecuteReturnType() ).toBeTrue();
1417+
expect( newBuilder.getCollectQueryLog() ).toBeFalse();
1418+
newBuilder.setReturnFormat( "firstId" );
1419+
1420+
expect( clonedBuilder.getReturnFormatterRegistry() ).toBe( registry );
1421+
expect( clonedBuilder.getValidateQueryExecuteReturnType() ).toBeTrue();
1422+
expect( clonedBuilder.getCollectQueryLog() ).toBeFalse();
1423+
clonedBuilder.setReturnFormat( "firstId" );
1424+
} );
1425+
13961426
it( "creates a default return formatter registry when none is passed", function() {
13971427
var builder = getBuilder();
13981428
builder.setReturnFormat( "none" );
@@ -1460,6 +1490,26 @@ component extends="testbox.system.BaseSpec" {
14601490
expect( builder.getGrammar().$callLog().runQuery[ 1 ].options ).toBe( {} );
14611491
} );
14621492

1493+
it( "can strip native queryExecute returntype options from default options without mutating them", function() {
1494+
var builder = getBuilder();
1495+
builder.mergeDefaultOptions( { "returntype": "array", "columnkey": "id", "columnKey": "id" } );
1496+
builder.setReturnFormat( "query" );
1497+
var expectedQuery = queryNew( "id", "integer", [ { "id": 1 } ] );
1498+
builder
1499+
.getGrammar()
1500+
.$( "runQuery" )
1501+
.$results( expectedQuery );
1502+
1503+
var results = builder
1504+
.select( "id" )
1505+
.from( "users" )
1506+
.get();
1507+
1508+
expect( results ).toBe( expectedQuery );
1509+
expect( builder.getGrammar().$callLog().runQuery[ 1 ].options ).toBe( {} );
1510+
expect( builder.getDefaultOptions() ).toBe( { "returntype": "array", "columnkey": "id", "columnKey": "id" } );
1511+
} );
1512+
14631513
it( "can validate native queryExecute returntype options", function() {
14641514
var builder = getMockBox()
14651515
.createMock( "qb.models.Query.QueryBuilder" )

0 commit comments

Comments
 (0)