Skip to content

Commit

Permalink
Merge branch 'main' into feature/sobject-cache
Browse files Browse the repository at this point in the history
  • Loading branch information
rob-baillie-ortoo committed Apr 1, 2022
2 parents 2ccc43a + 68b8323 commit de09d1a
Show file tree
Hide file tree
Showing 23 changed files with 599 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@
* Copyright (c), FinancialForce.com, inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the FinancialForce.com, inc nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* - Neither the name of the FinancialForce.com, inc nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Expand Down Expand Up @@ -367,19 +367,26 @@ public virtual class fflib_SObjectUnitOfWork
{
if (record.Id == null)
throw new UnitOfWorkException('New records cannot be registered as dirty');
String sObjectType = record.getSObjectType().getDescribe().getName();

SobjectType oSobjectType = record.getSObjectType();
String sObjectType = oSobjectType.getDescribe().getName();

assertForNonEventSObjectType(sObjectType);
assertForSupportedSObjectType(m_dirtyMapByType, sObjectType);

// If record isn't registered as dirty, or no dirty fields to drive a merge
if (!m_dirtyMapByType.get(sObjectType).containsKey(record.Id) || dirtyFields.isEmpty())
{
// Register the record as dirty
m_dirtyMapByType.get(sObjectType).put(record.Id, record);
}
else
{
if ( dirtyFields.isEmpty() )
{
m_dirtyMapByType.get(sObjectType).put(record.Id, record);
}
else
{
if ( !m_dirtyMapByType.get(sObjectType).containsKey(record.Id) )
{
// If the record isn't already there, put a new skeleton one in there
m_dirtyMapByType.get(sObjectType).put(record.Id, oSobjectType.newSObject( record.id ) );
}

// Update the registered record's fields
SObject registeredRecord = m_dirtyMapByType.get(sObjectType).get(record.Id);

Expand Down Expand Up @@ -426,7 +433,7 @@ public virtual class fflib_SObjectUnitOfWork
**/
public void registerUpsert(SObject record)
{
if (record.Id == null)
if (record.Id == null)
{
registerNew(record, null, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,35 @@ private with sharing class fflib_SObjectUnitOfWorkTest
System.assertEquals('Expected', mockDML.recordsForUpdate.get(0).get(Schema.Opportunity.Name));
}

/**
* Try registering a single field as dirty on first call
*
* Testing:
*
* - only that field is updated
*/
@IsTest
private static void testRegisterDirtyOnce_field() {
Opportunity opp = new Opportunity(
Id = fflib_IDGenerator.generate(Schema.Opportunity.SObjectType),
Name = 'test name',
StageName = 'Open',
CloseDate = System.today());

Opportunity amountUpdate = new Opportunity(Id = opp.Id, Name = 'ShouldNotAppear', Amount = 250);
MockDML mockDML = new MockDML();
fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(MY_SOBJECTS, mockDML);
uow.registerDirty(amountUpdate, new List<SObjectField> { Opportunity.Amount } );
uow.commitWork();

System.assertEquals(1, mockDML.recordsForUpdate.size());

System.assertEquals(true, mockDML.recordsForUpdate.get(0).getPopulatedFieldsAsMap().containsKey( 'Amount' ));
System.assertEquals(false, mockDML.recordsForUpdate.get(0).getPopulatedFieldsAsMap().containsKey( 'Name' ));

System.assertEquals(amountUpdate.Amount, mockDML.recordsForUpdate.get(0).get(Schema.Opportunity.Amount));

}
/**
* Try registering a single field as dirty.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ public inherited sharing class ApplicationMockRegistrar
* @param Type The type (interface) for which the mock app logic class should be registered
* @return Amoss_Instance The controller for the mock Service
*/
// TODO: test
public static Amoss_Instance registerMockAppLogic( Type appLogicType )
{
Amoss_Instance mockAppLogicController = new Amoss_Instance( appLogicType );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -617,8 +617,9 @@ public inherited sharing virtual class SecureDml extends fflib_SobjectUnitOfWork
String label = Label.ortoo_core_fls_violation;
String modeDescription = descriptionByMode.get( mode );
String sobjectTypeName = SobjectUtils.getSobjectName( sobjectType );
String fieldsInViolationString = String.join( ListUtils.convertToListOfStrings( fieldsInViolation ), ', ' );

throw new SecureDmlException( StringUtils.formatLabel( label, new List<String>{ modeDescription, sobjectTypeName, fieldsInViolation.toString() } ) )
throw new SecureDmlException( StringUtils.formatLabel( label, new List<String>{ modeDescription, sobjectTypeName, fieldsInViolationString } ) )
.setErrorCode( FrameworkErrorCodes.DML_ON_INACCESSIBLE_FIELDS )
.addContext( 'sobjectTypeName', sobjectTypeName )
.addContext( 'fieldsInViolation', fieldsInViolation )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ private without sharing class NullDomainTest
private static void constructorClass_buildsANullDomain() // NOPMD: Test method name format
{
NullDomain nullDomain = (NullDomain)new NullDomain.Constructor().construct( LIST_OF_SOBJECTS );
System.assertNotEquals( null, nullDomain, 'constructor, when called, does not throw an exception' );
System.assertNotEquals( null, nullDomain, 'constructor method, when called, will not throw an exception and returns a non null NullDomain' );
}

@isTest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ public virtual inherited sharing class DmlRecord
return this.recordToDml;
}

/**
* Returns the Id that is on the SObject this will perform the DML against.
* Is populated after an insert has been performed
*
* @return Id The Id on the SObject
*/
public Id getSobjectId()
{
return this.recordToDml.Id;
}

/**
* Defines the context of a 'type' of child, thus allowing children of that type to be added
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ private without sharing class DmlRecordTest
ortoo_Asserts.assertContains( 'DmlRecord constructor called with a null recordToDml', exceptionMessage, 'constructor, when given null, will throw an exception' );
}

@isTest
private static void getSobjectId_willReturnTheIdOfTheSobject() // NOPMD: Test method name format
{
Id accountId = TestIdUtils.generateId( Account.sobjectType );

DmlRecord dmlRecord = new DmlRecord( new Account( Id = accountId ) );

Test.startTest();
Id got = dmlRecord.getSobjectId();
Test.stopTest();

System.assertEquals( accountId, got, 'getSobjectId, will return the Id of the SObject' );
}

@isTest
private static void addChildContect_whenCalled_willInitialiseADefinerForThatType() // NOPMD: Test method name format
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @group Utils
*/
@isTest
public with sharing class TestIdUtils
public inherited sharing class TestIdUtils
{
private static Integer highestGeneratedId = 0;
private static Map<SobjectType,String> objectPrefixesBySobjectType = new Map<SobjectType,String>();
Expand Down
15 changes: 15 additions & 0 deletions framework/default/ortoo-core/default/classes/utils/ListUtils.cls
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,19 @@ public inherited sharing class ListUtils
}
return returnList;
}

/**
* Given a Set of any Strings, will return a List of those Strings
*
* @param Set<String> The set of strings to convert
* @return List<String> The converted list
*/
public static List<String> convertToListOfStrings( Set<String> setOfStrings )
{
if ( setOfStrings == null )
{
return new List<String>();
}
return new List<String>( setOfStrings );
}
}
Loading

0 comments on commit de09d1a

Please sign in to comment.