Skip to content

Commit

Permalink
feat(SqlCommenter): Pass bindings to commenters.
Browse files Browse the repository at this point in the history
Also includes a sample `BindingsCommenter`.
  • Loading branch information
elpete committed Apr 19, 2024
1 parent babb17e commit 753b30b
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 12 deletions.
10 changes: 6 additions & 4 deletions models/Query/QueryBuilder.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -3966,15 +3966,17 @@ component displayname="QueryBuilder" accessors="true" {
*/
private any function runQuery( required string sql, struct options = {}, string returnObject = "query" ) {
structAppend( arguments.options, getDefaultOptions(), false );
var bindings = getBindings( except = getAggregate().isEmpty() ? [] : [ "select" ] );
var result = grammar.runQuery(
sql = variables.sqlCommenter.appendSqlComments(
sql,
arguments.options.keyExists( "datasource" ) && !isNull( arguments.options.datasource ) ? arguments.options.datasource : javacast(
sql = sql,
datasource = arguments.options.keyExists( "datasource" ) && !isNull( arguments.options.datasource ) ? arguments.options.datasource : javacast(
"null",
""
)
),
bindings = bindings
),
bindings = getBindings( except = getAggregate().isEmpty() ? [] : [ "select" ] ),
bindings = bindings,
options = arguments.options,
returnObject = returnObject,
pretend = variables.pretending,
Expand Down
12 changes: 10 additions & 2 deletions models/SQLCommenter/ColdBoxSQLCommenter.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,24 @@ component extends="SQLCommenter" singleton {
* @sql The SQL string to add the comment to.
* @datasource The datasource that will execute the query.
* If null, the default datasource is going to be used.
* @bindings An array of bindings for the query.
*
* @return Commented SQL string
*/
public string function appendSqlComments( required string sql, string datasource ) {
public string function appendSqlComments( required string sql, string datasource, array bindings = [] ) {
if ( !settings.sqlCommenter.enabled ) {
return arguments.sql;
}

var comments = variables.commenters.reduce( ( acc, commenter ) => {
acc.append( commenter.getComments( sql, isNull( datasource ) ? javacast( "null", "" ) : datasource ), true );
acc.append(
commenter.getComments(
sql = sql,
datasource = isNull( datasource ) ? javacast( "null", "" ) : datasource,
bindings = bindings
),
true
);
}, {} );

return appendCommentsToSQL( arguments.sql, comments );
Expand Down
39 changes: 39 additions & 0 deletions models/SQLCommenter/Commenters/BindingsCommenter.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
component singleton accessors="true" {

property name="properties";

/**
* Returns a struct of key/value comment pairs to append to the SQL.
*
* @sql The SQL to append the comments to. This is provided if you need to
* inspect the SQL to make any decisions about what comments to return.
* @datasource The datasource that will execute the query. If null, the default datasource will be used.
* This can be used to make decisions about what comments to return.
*/
public struct function getComments( required string sql, string datasource, array bindings = [] ) {
return { "bindings": serializeBindings( bindings = bindings, delimiter = ";" ) };
}

private string function serializeBindings( required array bindings, string delimiter = ";" ) {
return bindings
.map( function( binding ) {
return limitString(
str = castAsSqlType(
value = binding.null ? javacast( "null", "" ) : binding.value,
sqltype = binding.cfsqltype
),
limit = 100
);
} )
.toList( delimiter );
}

private string function limitString( required string str, required numeric limit, string end = "..." ) {
if ( len( arguments.str ) <= arguments.limit ) {
return arguments.str;
}

return left( arguments.str, arguments.limit ) & arguments.end;
}

}
2 changes: 1 addition & 1 deletion models/SQLCommenter/Commenters/DBInfoCommenter.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ component singleton accessors="true" {
* @datasource The datasource that will execute the query. If null, the default datasource will be used.
* This can be used to make decisions about what comments to return.
*/
public struct function getComments( required string sql, string datasource ) {
public struct function getComments( required string sql, string datasource, array bindings = [] ) {
if ( isNull( arguments.datasource ) ) {
cfdbinfo( type = "version", name = "local.dbInfo" );
} else {
Expand Down
2 changes: 1 addition & 1 deletion models/SQLCommenter/Commenters/FrameworkCommenter.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ component singleton accessors="true" {
* @datasource The datasource that will execute the query. If null, the default datasource will be used.
* This can be used to make decisions about what comments to return.
*/
public struct function getComments( required string sql, string datasource ) {
public struct function getComments( required string sql, string datasource, array bindings = [] ) {
param variables.coldboxVersion = variables.wirebox.getInstance( "coldbox:coldboxSetting:version" );
return { "version": "coldbox-#variables.coldboxVersion#" };
}
Expand Down
3 changes: 2 additions & 1 deletion models/SQLCommenter/Commenters/ICommenter.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ interface displayName="ICommenter" {
* inspect the SQL to make any decisions about what comments to return.
* @datasource The datasource that will execute the query. If null, the default datasource will be used.
* This can be used to make decisions about what comments to return.
* @bindings An array of bindings for the query
*/
public struct function getComments( required string sql, string datasource );
public struct function getComments( required string sql, string datasource, array bindings );

// You can use `accessors="true"` with a `property name="properties";` to implement these methods.
public ICommenter function setProperties( required struct properties );
Expand Down
2 changes: 1 addition & 1 deletion models/SQLCommenter/Commenters/RouteInfoCommenter.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ component singleton accessors="true" {
* @datasource The datasource that will execute the query. If null, the default datasource will be used.
* This can be used to make decisions about what comments to return.
*/
public struct function getComments( required string sql, string datasource ) {
public struct function getComments( required string sql, string datasource, array bindings = [] ) {
var event = wirebox.getInstance( "coldbox:requestContext" );
return {
"event": event.getCurrentEvent(),
Expand Down
2 changes: 1 addition & 1 deletion models/SQLCommenter/NullSQLCommenter.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ component extends="SQLCommenter" singleton {
*
* @return Commented SQL string
*/
public string function appendSqlComments( required string sql, string datasource ) {
public string function appendSqlComments( required string sql, string datasource, array bindings = [] ) {
return arguments.sql;
}

Expand Down
2 changes: 1 addition & 1 deletion models/SQLCommenter/SQLCommenter.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ component singleton {
*
* @return Commented SQL string
*/
public string function appendSqlComments( required string sql, string datasource ) {
public string function appendSqlComments( required string sql, string datasource, array bindings = [] ) {
throw( "appendSqlComments is an abstract method and must be implemented in a subclass." );
}

Expand Down

0 comments on commit 753b30b

Please sign in to comment.