Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/cron.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
cfengine: ["lucee@5", "lucee@6", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1"]
cfengine: ["lucee@5", "lucee@6", "lucee@6-full-null", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1"]
coldbox: ["coldbox@^7", "coldbox@^8"]
experimental: [ false ]
include:
Expand Down Expand Up @@ -95,4 +95,4 @@ jobs:
DB_NAME: quick
DB_USER: quick
DB_PASSWORD: quick
run: box testbox run
run: box testbox run
4 changes: 2 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
strategy:
fail-fast: false
matrix:
cfengine: ["lucee@5", "lucee@6", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1"]
cfengine: ["lucee@5", "lucee@6", "lucee@6-full-null", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1"]
coldbox: ["coldbox@^7", "coldbox@^8"]
services:
mysql:
Expand Down Expand Up @@ -97,4 +97,4 @@ jobs:
- name: Commit Format Changes
uses: stefanzweifel/git-auto-commit-action@v5.2.0
with:
commit_message: Apply cfformat changes
commit_message: Apply cfformat changes
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
cfengine: ["lucee@5", "lucee@6", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1"]
cfengine: ["lucee@5", "lucee@6", "lucee@6-full-null", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1"]
coldbox: ["coldbox@^7", "coldbox@^8"]
services:
mysql:
Expand Down
21 changes: 21 additions & 0 deletions server-lucee@6-full-null.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name":"quick-lucee@6-full-null",
"app":{
"serverHomeDirectory":".engine/lucee6FullNull",
"cfengine":"lucee@6"
},
"jvm":{
"properties":{
"lucee.full.null.support":"true"
}
},
"web":{
"http":{
"port":"60299"
},
"rewrites":{
"enable":"true"
}
},
"openBrowser":"false"
}
9 changes: 9 additions & 0 deletions tests/resources/ModuleIntegrationSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,13 @@ component extends="coldbox.system.testing.BaseTestCase" appMapping="/app" {
return arraySlice( createObject( "java", "java.util.HashSet" ).init( arguments.items ).toArray(), 1 );
}

/**
* Returns whether the current Lucee server is running with full null support.
*/
public boolean function hasFullNullSupport() {
return server.keyExists( "lucee" ) &&
server.system.properties.keyExists( "lucee.full.null.support" ) &&
server.system.properties[ "lucee.full.null.support" ] == "true";
}

}
36 changes: 30 additions & 6 deletions tests/specs/integration/BaseEntity/AsQuerySpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ component extends="tests.resources.ModuleIntegrationSpec" {
result.createdDate = dateTimeFormat( result.createdDate, "yyyy-mm-dd hh:nn:ss" );
result.modifiedDate = dateTimeFormat( result.modifiedDate, "yyyy-mm-dd hh:nn:ss" );
}

expect( results[ 1 ] ).toBeStruct();
expect( results[ 1 ] ).toBe( {
var expectedFirstResult = {
"city" : "Salt Lake City",
"countryId" : "02B84D66-0AA0-F7FB-1F71AFC954843861",
"createdDate" : "2017-07-28 02:06:36",
Expand All @@ -36,9 +35,9 @@ component extends="tests.resources.ModuleIntegrationSpec" {
"type" : "admin",
"username" : "elpete",
"zip" : "84123"
} );
};
expect( results[ 2 ] ).toBeStruct();
expect( results[ 2 ] ).toBe( {
var expectedSecondResult = {
"city" : "Salt Lake City",
"countryId" : "02B84D66-0AA0-F7FB-1F71AFC954843861",
"createdDate" : "2017-07-28 02:07:16",
Expand All @@ -57,7 +56,28 @@ component extends="tests.resources.ModuleIntegrationSpec" {
"type" : "limited",
"username" : "johndoe",
"zip" : "84123"
} );
};
if ( hasFullNullSupport() ) {
expect( results[ 1 ].email ).toBeNull();
expect( results[ 1 ].streetTwo ).toBeNull();
expect( results[ 2 ].email ).toBeNull();
expect( results[ 2 ].favoritePost_id ).toBeNull();
expect( results[ 2 ].streetTwo ).toBeNull();
results[ 1 ].delete( "email" );
results[ 1 ].delete( "streetTwo" );
results[ 2 ].delete( "email" );
results[ 2 ].delete( "favoritePost_id" );
results[ 2 ].delete( "streetTwo" );
expectedFirstResult.delete( "email" );
expectedFirstResult.delete( "streetTwo" );
expectedSecondResult.delete( "email" );
expectedSecondResult.delete( "favoritePost_id" );
expectedSecondResult.delete( "streetTwo" );
}
expect( results[ 1 ] ).toHaveLength( expectedFirstResult.count() );
expect( results[ 2 ] ).toHaveLength( expectedSecondResult.count() );
expectedFirstResult.each( ( key, value ) => expect( results[ 1 ][ key ] ).toBe( value ) );
expectedSecondResult.each( ( key, value ) => expect( results[ 2 ][ key ] ).toBe( value ) );
} );

it( "can execute with subselects", function() {
Expand All @@ -74,7 +94,11 @@ component extends="tests.resources.ModuleIntegrationSpec" {
expect( results[ 1 ][ "latestPostId" ] ).toBe( 523526 );
expect( results[ 2 ] ).toBeStruct();
expect( results[ 2 ] ).toHaveKey( "latestPostId" );
expect( results[ 2 ][ "latestPostId" ] ).toBe( "" );
if ( hasFullNullSupport() ) {
expect( results[ 2 ][ "latestPostId" ] ).toBeNull();
} else {
expect( results[ 2 ][ "latestPostId" ] ).toBe( "" );
}
} );

it( "can do eager loading", function() {
Expand Down
12 changes: 10 additions & 2 deletions tests/specs/integration/BaseEntity/AttributeCastsSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,20 @@ component extends="tests.resources.ModuleIntegrationSpec" {
it( "preserves null values when using BooleanCast", () => {
var pn = getInstance( "PhoneNumber" ).find( 3 );
expect( pn.isNullAttribute( "confirmed" ) ).toBeTrue( "[confirmed] should be considered null" );
expect( pn.getConfirmed() ).toBe( "" );
if ( hasFullNullSupport() ) {
expect( pn.getConfirmed() ).toBeNull();
} else {
expect( pn.getConfirmed() ).toBe( "" );
}

pn.update( { "active" : false } ).refresh();

expect( pn.isNullAttribute( "confirmed" ) ).toBeTrue( "[confirmed] should remain null after saving" );
expect( pn.getConfirmed() ).toBe( "" );
if ( hasFullNullSupport() ) {
expect( pn.getConfirmed() ).toBeNull();
} else {
expect( pn.getConfirmed() ).toBe( "" );
}
} );

it( "allows custom casts to handle null database values", () => {
Expand Down
12 changes: 9 additions & 3 deletions tests/specs/integration/BaseEntity/AttributeSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ component extends="tests.resources.ModuleIntegrationSpec" {
var memento = getInstance( "User" ).findOrFail( 1 ).getMemento();
memento.createdDate = dateTimeFormat( memento.createdDate, "yyyy-mm-dd hh:nn:ss" );
memento.modifiedDate = dateTimeFormat( memento.modifiedDate, "yyyy-mm-dd hh:nn:ss" );
expect( memento ).toBe( {
var expected = {
"id" : 1,
"username" : "elpete",
"firstName" : "Eric",
Expand All @@ -190,7 +190,7 @@ component extends="tests.resources.ModuleIntegrationSpec" {
"modifiedDate" : "2017-07-28 02:06:36",
"type" : "admin",
"email" : "",
"externalId" : "1234",
"externalID" : "1234",
"address" : {
"streetOne" : "123 Elm Street",
"streetTwo" : "",
Expand All @@ -199,7 +199,13 @@ component extends="tests.resources.ModuleIntegrationSpec" {
"zip" : "84123"
},
"favoritePost_id" : "1245"
} );
};
if ( hasFullNullSupport() ) {
expect( memento.address.streetTwo ).toBeNull();
memento.address.delete( "streetTwo" );
expected.address.delete( "streetTwo" );
}
expect( memento ).toBe( expected );
} );

// https://github.com/coldbox-modules/quick/issues/127
Expand Down
10 changes: 8 additions & 2 deletions tests/specs/integration/BaseEntity/MementoSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ component extends="tests.resources.ModuleIntegrationSpec" {
memento.publishedDate = dateTimeFormat( memento.publishedDate, "yyyy-mm-dd hh:nn:ss" );
memento.author.createdDate = dateTimeFormat( memento.author.createdDate, "yyyy-mm-dd hh:nn:ss" );
memento.author.modifiedDate = dateTimeFormat( memento.author.modifiedDate, "yyyy-mm-dd hh:nn:ss" );
expect( memento ).toBe( {
var expected = {
"post_pk" : "1245",
"body" : "My awesome post body",
"createdDate" : "2017-07-28 02:07:00",
Expand Down Expand Up @@ -77,7 +77,13 @@ component extends="tests.resources.ModuleIntegrationSpec" {
},
"favoritePost_id" : "1245"
}
} );
};
if ( hasFullNullSupport() ) {
expect( memento.author.address.streetTwo ).toBeNull();
memento.author.address.delete( "streetTwo" );
expected.author.address.delete( "streetTwo" );
}
expect( memento ).toBe( expected );
} );

it( "can check if two entities are the same", function() {
Expand Down
15 changes: 12 additions & 3 deletions tests/specs/integration/BaseEntity/NullValuesSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@ component extends="tests.resources.ModuleIntegrationSpec" {

function run() {
describe( "Null Values Spec", function() {
it( "returns null values as a string by default", function() {
it( "returns database nulls according to the engine null-support mode", function() {
var user = getInstance( "User" ).findOrFail( 3 );
expect( user.getCountryId() ).toBe( "" );
expect( user.getMemento().countryId ).toBe( "" );

if ( hasFullNullSupport() ) {
expect( user.getCountryId() ).toBeNull( "The entity getter should preserve the database null." );
expect( user.getMemento().countryId ).toBe(
"",
"Mementifier should apply its configured nullDefaultValue."
);
} else {
expect( user.getCountryId() ).toBe( "" );
expect( user.getMemento().countryId ).toBe( "" );
}
} );

it( "saves a column containing an empty string as null in the database by default", function() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,11 @@ component extends="tests.resources.ModuleIntegrationSpec" {
post.author()
.dissociate()
.save();
expect( post.retrieveAttribute( "user_id" ) ).toBe( "" );
if ( hasFullNullSupport() ) {
expect( post.retrieveAttribute( "user_id" ) ).toBeNull();
} else {
expect( post.retrieveAttribute( "user_id" ) ).toBe( "" );
}
expect(
getInstance( "User" )
.find( userId )
Expand Down
6 changes: 5 additions & 1 deletion tests/specs/integration/BaseEntity/SaveSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ component extends="tests.resources.ModuleIntegrationSpec" {
existingUser.save();
var userRowsPostSave = queryExecute( "SELECT * FROM users" );
expect( userRowsPostSave ).toHaveLength( 5 );
expect( userRowsPostSave.email ).toBe( "" );
if ( hasFullNullSupport() ) {
expect( userRowsPostSave.email ).toBeNull();
} else {
expect( userRowsPostSave.email ).toBe( "" );
}
} );

it( "uses the sqltype attribute if present for each column", function() {
Expand Down
Loading