From 28d140543dddedb611c40d1d4b593e99b323dac3 Mon Sep 17 00:00:00 2001 From: "Karlin [bot]" Date: Tue, 26 May 2026 06:58:23 -0700 Subject: [PATCH] feat(moduleconfig): add shouldWrapValues module setting, applied to grammar at module load --- CHANGELOG.md | 6 +++ ModuleConfig.cfc | 8 +++ tests/specs/Query/ShouldWrapValuesSpec.cfc | 61 ++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 tests/specs/Query/ShouldWrapValuesSpec.cfc diff --git a/CHANGELOG.md b/CHANGELOG.md index 981849c..1601e04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,12 @@ + __postgres:__ normalize cast shorthand in default expressions ([0d60086](https://github.com/coldbox-modules/qb/commit/0d600861475e80c769ddcfc9fb649ea8453a169a)) +# v13.0.20 + +### feat + ++ __moduleconfig:__ Add shouldWrapValues module setting, applied to configured grammar at module load + ([0000000](https://github.com/coldbox-modules/qb/commit/0000000)) # v13.0.19 ## 19 Feb 2026 — 19:37:21 UTC diff --git a/ModuleConfig.cfc b/ModuleConfig.cfc index 47148a8..706a79f 100644 --- a/ModuleConfig.cfc +++ b/ModuleConfig.cfc @@ -14,6 +14,7 @@ component { "validateOperatorsAndCombinators": true, "collectQueryLog": true, "convertEmptyStringsToNull": true, + "shouldWrapValues": true, "validateQueryParamStructKeys": true, "numericSQLType": "NUMERIC", "integerSQLType": "INTEGER", @@ -72,6 +73,13 @@ component { .map( alias = "SchemaBuilder@qb", force = true ) .to( "qb.models.Schema.SchemaBuilder" ) .initArg( name = "grammar", ref = settings.defaultGrammar ); + + // Apply shouldWrapValues setting to the configured grammar singleton. + // When defaultGrammar is AutoDiscover@qb, the setting is forwarded via + // onMissingMethod to whatever concrete grammar AutoDiscover resolves at runtime. + if ( structKeyExists( settings, "shouldWrapValues" ) ) { + wirebox.getInstance( settings.defaultGrammar ).setShouldWrapValues( settings.shouldWrapValues ); + } } } diff --git a/tests/specs/Query/ShouldWrapValuesSpec.cfc b/tests/specs/Query/ShouldWrapValuesSpec.cfc new file mode 100644 index 0000000..dfb50cd --- /dev/null +++ b/tests/specs/Query/ShouldWrapValuesSpec.cfc @@ -0,0 +1,61 @@ +component extends="testbox.system.BaseSpec" { + + function run() { + describe( "shouldWrapValues setting", function() { + + it( "defaults to true in BaseGrammar", function() { + var utils = getMockBox().createMock( "qb.models.Query.QueryUtils" ).init(); + var grammar = getMockBox().createMock( "qb.models.Grammars.PostgresGrammar" ).init( utils ); + + expect( grammar.getShouldWrapValues() ).toBeTrue( "shouldWrapValues should default to true" ); + } ); + + it( "wraps identifiers in double quotes when shouldWrapValues is true", function() { + var utils = getMockBox().createMock( "qb.models.Query.QueryUtils" ).init(); + var grammar = getMockBox().createMock( "qb.models.Grammars.PostgresGrammar" ).init( utils ); + grammar.setShouldWrapValues( true ); + + var builder = getMockBox().createMock( "qb.models.Query.QueryBuilder" ).init( grammar ); + + var sql = builder.from( "users" ).select( "name" ).toSQL(); + + expect( sql ).toBe( 'SELECT "name" FROM "users"' ); + + sql = builder.from( "users" ).select( "id" ).where( "email", "test@test.com" ).toSQL( withBindings = true ); + + expect( sql ).toBe( 'SELECT "id" FROM "users" WHERE "email" = ?' ); + } ); + + it( "does not wrap identifiers when shouldWrapValues is false", function() { + var utils = getMockBox().createMock( "qb.models.Query.QueryUtils" ).init(); + var grammar = getMockBox().createMock( "qb.models.Grammars.PostgresGrammar" ).init( utils ); + grammar.setShouldWrapValues( false ); + + var builder = getMockBox().createMock( "qb.models.Query.QueryBuilder" ).init( grammar ); + + var sql = builder.from( "users" ).select( "name" ).toSQL(); + + expect( sql ).toBe( "SELECT name FROM users" ); + + sql = builder.from( "users" ).select( "id" ).where( "email", "test@test.com" ).toSQL(); + + expect( sql ).toBe( "SELECT id FROM users WHERE email = ?" ); + } ); + + it( "per-query withoutWrappingValues overrides grammar default", function() { + var utils = getMockBox().createMock( "qb.models.Query.QueryUtils" ).init(); + var grammar = getMockBox().createMock( "qb.models.Grammars.PostgresGrammar" ).init( utils ); + grammar.setShouldWrapValues( true ); + + var builder = getMockBox().createMock( "qb.models.Query.QueryBuilder" ).init( grammar ); + + // Grammar default is true, but per-query override to false + var sql = builder.withoutWrappingValues().from( "users" ).select( "name" ).toSQL(); + + expect( sql ).toBe( "SELECT name FROM users" ); + } ); + + } ); + } + +}