Skip to content

Commit

Permalink
Merge pull request #20 from e-line-websolutions/null-save
Browse files Browse the repository at this point in the history
Null save
  • Loading branch information
mjhagen authored May 19, 2021
2 parents 745a188 + 0fcf3cc commit bb3e66d
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 104 deletions.
113 changes: 70 additions & 43 deletions base.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder" hide=true {
property name="id" type="string" fieldType="id" generator="uuid";

this.version = "4.3.0";
this.version = "4.4.1";
this.sanitizeDataTypes = listToArray( "date,datetime,double,float,int,integer,numeric,percentage,timestamp" );
this.logLevels = listToArray( "debug,information,warning,error,fatal" );
this.logFields = listToArray( "createcontact,createdate,createip,updatecontact,updatedate,updateip" );
Expand Down Expand Up @@ -168,6 +168,7 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
var skipMatrix = getSkipMatrix( property, formData, depth );

if ( skipProperty( skipMatrix ) ) {
if ( request.context.debug ) writeOutput( '<br>skipping #key# (#serializeJson( skipMatrix )#)' );
continue;
}

Expand Down Expand Up @@ -223,7 +224,7 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"

// Process queued instructions
if ( depth == 0 ) {
processQueue( );
processQueue();
logChanges( savedState );
}

Expand Down Expand Up @@ -286,7 +287,9 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
/**
* the entity name (as per CFML ORM standard)
*/
public string function getEntityName( string className = variables.instance.className ) {
public string function getEntityName( string className ) {
param className = variables.instance.className;

var basicEntityName = className.listLast( '.' );
if ( request.allOrmEntities.keyExists( basicEntityName ) ) {
return request.allOrmEntities[ basicEntityName ].name;
Expand All @@ -297,7 +300,9 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
/**
* the database table name (as per CFML ORM standard)
*/
public string function getTableName( string className = variables.instance.className ) {
public string function getTableName( string className ) {
param className = variables.instance.className;

var basicEntityName = className.listLast( '.' );
if ( request.allOrmEntities.keyExists( basicEntityName ) ) {
return request.allOrmEntities[ basicEntityName ].table;
Expand Down Expand Up @@ -531,40 +536,52 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
* @data One or more entities to be converted to a less complex representation
*/
public any function deORM( any data = this ) {
var deWormed = { };

if ( isSimpleValue( data ) ) {
deWormed = data;
return data;

} else if ( isObject( data ) ) {
var properties = data.getInheritedProperties( );
for ( var key in properties ) {
var prop = properties[ key ];
if ( !structKeyExists( data, 'get' & prop.name ) || ( structKeyExists( prop, 'fieldtype' ) && findNoCase(
"-to-",
prop.fieldtype
) ) ) {
continue;
}
deWormed[ prop.name ] = invoke( data, 'get#prop.name#' );
if ( prop.name contains '`' ) {
writeDump(deWormed[ prop.name ]);abort;
}
}
return deWormObject( data );

} else if ( isStruct( data ) ) {
for ( var key in data ) {
if ( structKeyExists( data, key ) ) {
deWormed[ key ] = deORM( data[ key ] );
}
}
return deWormStruct( data );

} else if ( isArray( data ) ) {
var deWormed = [ ];
return deWormArray( data );

for ( var el in data ) {
arrayAppend( deWormed, deORM( el ) );
}
}
}

private struct function deWormObject( data ) {
return data.getInheritedProperties()
.filter( function( key, prop ) { return !isNull( prop ); } )
.filter( function( key, prop ) {
var propertyHasGetter = structkeyExists( this, 'get#prop.name#' );
var isSimpleProperty = !( prop.keyExists( 'fieldtype' ) && prop.fieldtype.findNoCase( '-to-' ) );
return ( propertyHasGetter && isSimpleProperty );
} )
.map( function( key, prop ) {
return invoke( this, 'get#prop.name#' );
} );
}

private struct function deWormStruct( data ) {
if ( isNull( data ) ) return {};

return data
.filter(function(key, value){ return !isNull( value ) })
.map( function(key, value) {
return deORM( value );
} );
}

private array function deWormArray( data ) {
var result = [];

data.each(function(key, value){
result.append( deORM( value ) );
});

return deWormed;
return result;
}

/**
Expand Down Expand Up @@ -746,12 +763,14 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
var dataType = getDatatype( property );

// check inside json obj to see if an ID was passed in
try {
var testForJSON = deserializeJSON( nestedData );
if ( isStruct( testForJSON ) && testForJSON.keyExists( "id" ) ) {
nestedData = testForJSON.id;
if ( property.name != 'savedstate' ) {
try {
var testForJSON = deserializeJSON( nestedData );
if ( isStruct( testForJSON ) && testForJSON.keyExists( "id" ) ) {
nestedData = testForJSON.id;
}
} catch ( any e ) {
}
} catch ( any e ) {
}

if ( request.basecfc.keyExists( "sanitationService" ) && this.sanitizeDataTypes.findNoCase( dataType ) ) {
Expand Down Expand Up @@ -809,7 +828,7 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"

if ( !skipToNextPropery ) {
// remove data if nestedData is empty
if ( isNull( nestedData ) ) {
if ( isNull( nestedData ) || isDeletedEntity( nestedData ) ) {
queueInstruction( this, fn, "null" );

if ( request.context.debug ) {
Expand Down Expand Up @@ -1022,6 +1041,10 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
}

structDelete( formData, "set_#property.name#" );

if ( workData.isEmpty() ) {
formData[ 'set_#property.name#' ] = javaCast( 'null', 0 );
}
}

if ( request.context.debug ) writeOutput( '<br>toMany_convertSetToAdd() #getTickCount()-t#ms.' );
Expand Down Expand Up @@ -1361,6 +1384,8 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
var t = getTickCount();
var parsedVar = variable;

if ( isNull( parsedVar ) || isDeletedEntity( parsedVar ) ) return;

try {
if ( isObject( parsedVar ) && isInstanceOf( parsedVar, cfc ) ) {
if ( request.context.debug ) writeOutput( '<br>toComponent() #getTickCount()-t#ms. (early exit)' );
Expand Down Expand Up @@ -1572,7 +1597,6 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
, notInFormdata( property, formData ) ? 1 : 0
// , (depth>2&&property.keyExists( 'inverse' )) ? 1 : 0
];

return skipMatrix;
}

Expand Down Expand Up @@ -1772,7 +1796,7 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
* - sortorder basecfc-entities always have a sortkey, if you don't use it, set it to 0.
*/
private void function validateBaseProperties() {
if ( variables.instance.className == 'basecfc.base' || variables.instance.className == '' ) {
if ( !variables.keyExists( 'instance' ) || variables.instance.className == 'basecfc.base' || variables.instance.className == '' ) {
return;
}

Expand Down Expand Up @@ -1844,10 +1868,7 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
}

private void function setup() {
if ( !request.keyExists( 'allOrmEntities' ) ) {
return;
}

if ( !request.keyExists( 'allOrmEntities' ) ) return; // Application not set up for ORM
if ( variables.keyExists( 'instance' ) ) return; // entity already set up

param variables.name="";
Expand Down Expand Up @@ -1919,4 +1940,10 @@ component mappedSuperClass=true cacheuse="transactional" defaultSort="sortorder"
throw( logMessage, 'basecfc.global' );
}
}

private boolean function isDeletedEntity( value ) {
if ( isSimpleValue( value ) && value == 'null' ) return true;
if ( isSimpleValue( value ) && value == '' ) return true;
return false;
}
}
42 changes: 18 additions & 24 deletions tests/Application.cfc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
component {
this.name = 'basecfc_test_1001';
this.name = 'basecfc_tests';
this.root = getDirectoryFromPath( getCurrentTemplatePath() ).replace( '\', '/', 'all' );
this.basecfcRoot = this.root.listDeleteAt( this.root.listLen( '/' ), '/' );

Expand All @@ -16,25 +16,17 @@ component {

this.ormEnabled = true;

this.datasource = 'basecfc';
this.datasource = 'basecfc'; // need global ds, not just in orm

this.ormSettings.dbCreate = 'dropcreate';
this.ormSettings.cfcLocation = this.mappings[ '/root' ] & 'orm';
this.ormSettings.sqlScript = 'nuke.sql';

// this.ormSettings.secondaryCacheEnabled = false;
// this.ormSettings.useDBForMapping = false;
// this.ormSettings.autoManageSession = false;
// this.ormSettings.flushAtRequestEnd = false;
// this.ormSettings.cacheConfig = 'ehcache-config_ORM__basecfc.xml';

function onRequest() {
request.appName = 'basecfc';
request.appName = this.name;
request.context.config.root = 'basecfc.tests';

ormReload();

request.allOrmEntities = listAllOrmEntities( this.ormSettings.cfcLocation );
setupORM();

param url.reporter = "simple";
param url.directory = "root.specs";
Expand All @@ -43,19 +35,21 @@ component {
include '/testbox/system/runners/HTMLRunner.cfm';
}

private struct function listAllOrmEntities( cfcLocation ) {
var cacheKey = 'orm-entities';
private void function setupORM() {
ormReload();

var allOrmEntities = {};
var storedEntityNames = createObject( 'java', 'java.util.Arrays' ).asList( ormGetSessionFactory().getStatistics().getEntityNames() );
request.allOrmEntities = {};

storedEntityNames.each((entityName)=>{
var entity = getMetadata( entityNew( entityName ) );
allOrmEntities[ entityName ] = { 'name' = entityName, 'table' = isNull( entity.table ) ? entityName : entity.table };
});
var cacheKey = 'orm-entities';

return allOrmEntities;
createObject( 'java', 'java.util.Arrays' ).asList( ormGetSessionFactory().getStatistics().getEntityNames() ).each( ( entityName )=>{
try {
var entity = getMetadata( entityNew( entityName ) );
request.allOrmEntities[ entityName ] = { 'name' = entityName, 'table' = isNull( entity.table ) ? entityName : entity.table };
} catch ( basecfc.init.invalidPropertiesError e ) {
// allow this error on entity with name "invalid", because that's used for testing
if ( entityName != 'invalid' ) rethrow;
}
} );
}


}
}
4 changes: 1 addition & 3 deletions tests/orm/logging/logentry.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ component extends=basecfc.base persistent=true {

formdata[ 'savedstate' ] = serializeJSON( newstate );

transaction {
var result = save( formdata );
}
var result = save( formdata );

return result;
}
Expand Down
Loading

0 comments on commit bb3e66d

Please sign in to comment.