diff --git a/sfdx-project.json b/sfdx-project.json index 47f3e51..fd57b49 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -9,7 +9,7 @@ "default": true }, { - "path": "sfdx-source/apex-domainbuilder-samplecode", + "path": "sfdx-source/apex-domainbuilder-sample", "default": false } ], diff --git a/sfdx-source/apex-domainbuilder-sample/classes/Random.cls b/sfdx-source/apex-domainbuilder-sample/classes/Random.cls index 0ec760c..c141465 100644 --- a/sfdx-source/apex-domainbuilder-sample/classes/Random.cls +++ b/sfdx-source/apex-domainbuilder-sample/classes/Random.cls @@ -1,3 +1,4 @@ +@IsTest public class Random { public String string() { diff --git a/sfdx-source/apex-domainbuilder-sample/classes/domains/Account_t.cls b/sfdx-source/apex-domainbuilder-sample/classes/domains/Account_t.cls index 03a41c1..c58a643 100644 --- a/sfdx-source/apex-domainbuilder-sample/classes/domains/Account_t.cls +++ b/sfdx-source/apex-domainbuilder-sample/classes/domains/Account_t.cls @@ -3,7 +3,7 @@ public class Account_t extends DomainBuilder { public Account_t() { super(Account.SObjectType); - + name('Acme Corp'); } diff --git a/sfdx-source/apex-domainbuilder-sample/classes/test/DomainBuilder_Test.cls b/sfdx-source/apex-domainbuilder-sample/classes/test/DomainBuilder_Test.cls index 0cb8dbb..53cdf31 100644 --- a/sfdx-source/apex-domainbuilder-sample/classes/test/DomainBuilder_Test.cls +++ b/sfdx-source/apex-domainbuilder-sample/classes/test/DomainBuilder_Test.cls @@ -1,10 +1,30 @@ @IsTest public class DomainBuilder_Test { + @IsTest + private static void staticHappyPath() { + + Contact_t joe = new Contact_t().first('Joe').last('Harris'); + + new Account_t() + .name('Acme Corp') + .add( new Contact_t() ) + .add( new Opportunity_t() + .amount(1000) + .closes(2019, 12) + .contact(joe)); + + DomainBuilder.save(); + + System.assertEquals(2, [SELECT Count() FROM Account]); + System.assertEquals(1, [SELECT Count() FROM Opportunity]); + System.assertEquals(2, [SELECT Count() FROM Contact]); + System.assertEquals(1, [SELECT Count() FROM OpportunityContactRole]); + } @IsTest private static void happyPath() { - Contact_t joe = new Contact_t().first('Ron').last('Harris'); + Contact_t joe = new Contact_t().first('Joe').last('Harris'); new Account_t() .name('Acme Corp') @@ -15,7 +35,7 @@ public class DomainBuilder_Test { .contact(joe)) .persist(); - System.assertEquals(2, [SELECT Count() FROM Account]); + System.assertEquals(2, [SELECT Count() FROM Account]); System.assertEquals(1, [SELECT Count() FROM Opportunity]); System.assertEquals(2, [SELECT Count() FROM Contact]); System.assertEquals(1, [SELECT Count() FROM OpportunityContactRole]); @@ -72,7 +92,7 @@ public class DomainBuilder_Test { .persist(); - System.assertEquals(1, [SELECT Count() FROM Account]); + System.assertEquals(2, [SELECT Count() FROM Account]); System.assertEquals(1, [SELECT Count() FROM Opportunity]); System.assertEquals(2, [SELECT Count() FROM Contact]); } @@ -188,18 +208,19 @@ public class DomainBuilder_Test { private static void noUnneededRecords() { // Setup & Exercise - Contact_t con = new Contact_t(); // 1x insert - Opportunity_t opp = new Opportunity_t(); // 1x insert - - new Account_t() // 1x insert - .add(new Contact_t()) // 1x insert - .add(con) // 0x insert - .add(opp // 0x insert - .add(con)) // 1x insert OpportunityContactRole - .persist(); // 1x setSavepoint - - // Verify - System.assertEquals(6, Limits.getDmlRows()); + Contact_t con = new Contact_t(); // 1x insert statement, 1x row + Opportunity_t opp = new Opportunity_t(); // 1x insert statement, 1x row + + new Account_t() // 1x insert statement, 1x row + .add(new Contact_t()) // 0x insert statement (both contacts are inserted together at the same time in the same DML), 1x row + .add(con) // 0x insert statement, 0x row + .add(opp // 0x insert statement, 0x row + .add(con)) // 1x insert OpportunityContactRole, 1x row + .persist(); // 1x setSavepoint statement, 0x row + + // Verify + System.assertEquals(5, Limits.getDmlStatements()); + System.assertEquals(5, Limits.getDmlRows()); System.assertEquals(1, [SELECT Count() FROM Account]); System.assertEquals(2, [SELECT Count() FROM Contact]); System.assertEquals(1, [SELECT Count() FROM Opportunity]); diff --git a/sfdx-source/apex-domainbuilder/main/classes/DomainBuilder.cls b/sfdx-source/apex-domainbuilder/main/classes/DomainBuilder.cls index 929cd8b..12efd73 100644 --- a/sfdx-source/apex-domainbuilder/main/classes/DomainBuilder.cls +++ b/sfdx-source/apex-domainbuilder/main/classes/DomainBuilder.cls @@ -3,10 +3,7 @@ public abstract class DomainBuilder { private static DirectedGraph graph = new DirectedGraph(); private static Set objects = new Set(); - private Boolean isSetupObject; private Map parentByRelationship = new Map(); - private Map>> relationshipsToSync - = new Map>>(); public SObject record; public SObjectType type; public Id id { private set; get {return record.Id;} } @@ -14,25 +11,23 @@ public abstract class DomainBuilder { // CONSTRUCTORS - public DomainBuilder(SObjectType type, Boolean isSetupObject) { + public DomainBuilder(SObjectType type) { this.type = type; this.record = type.newSObject(null, true); - this.isSetupObject = isSetupObject; graph.node(type); objects.add(this); } - public DomainBuilder(SObjectType type) { - this(type, false); - } - - // PUBLIC - public SObject persist() { - fflib_SObjectUnitOfWork uow = unitOfWork(); + public static void save() { + save(new fflib_SObjectUnitOfWork.SimpleDML()); + } + + public static void save(fflib_SObjectUnitOfWork.IDML dml) { + fflib_SObjectUnitOfWork uow = unitOfWork(dml); for(DomainBuilder obj: objects) { if(obj.record.Id == null) { @@ -48,12 +43,20 @@ public abstract class DomainBuilder { uow.commitWork(); objects.clear(); + } - return record; + public SObject persist() { + return persist(new fflib_SObjectUnitOfWork.SimpleDML()); } + public SObject persist(fflib_SObjectUnitOfWork.IDML dml) { + save(dml); - public DomainBuilder recordType(String developerName) { + return record; + } + + // Note: virtual so it can be extended by implementations in order to cast the return type to its specifyc type + public virtual DomainBuilder recordType(String developerName) { Id rtId = type.getDescribe().getRecordTypeInfosByDeveloperName().get(developerName).getRecordTypeId(); return set('RecordTypeId', rtId); } @@ -78,10 +81,6 @@ public abstract class DomainBuilder { parent.registerIncludingParents(); } - if(relationshipsToSync.containsKey(relationship)) { - synchronize(relationship); - } - graph.edge(this.type, parent.type); // Note: Return parent instead of this as we call this always from the parent @@ -89,20 +88,6 @@ public abstract class DomainBuilder { } - protected void syncOnChange(SObjectField sourceField, DomainBuilder targetObject, SObjectField targetField) { - if( !relationshipsToSync.containsKey(sourceField)) { - relationshipsToSync.put(sourceField, new Map>()); - } - if( !relationshipsToSync.get(sourceField).containsKey(targetField)) { - relationshipsToSync.get(sourceField).put(targetField, new List()); - } - - relationshipsToSync.get(sourceField).get(targetField).add(targetObject); - - synchronize(sourceField); - } - - protected DomainBuilder set(String fieldName, Object value) { record.put(fieldName, value); return this; @@ -137,25 +122,14 @@ public abstract class DomainBuilder { } - private void synchronize(SObjectField sourceField) { - for(SObjectField targetField: relationshipsToSync.get(sourceField).keySet()) { - for(DomainBuilder obj : relationshipsToSync.get(sourceField).get(targetField)) { - - DomainBuilder parent = parentByRelationship.get(sourceField); - obj.setParent(targetField, parent); - } - } - } - - - private static fflib_SObjectUnitOfWork unitOfWork() { + private static fflib_SObjectUnitOfWork unitOfWork(fflib_SObjectUnitOfWork.IDML dml) { List insertOrder = new List(); List sorted = graph.sortTopologically(); for(Integer i = sorted.size() - 1; i >= 0; i--){ insertOrder.add(sorted[i]); } - return new fflib_SObjectUnitOfWork(insertOrder); + return new fflib_SObjectUnitOfWork(insertOrder, dml); }