diff --git a/README.md b/README.md
index bb70507..dd098fe 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
-
+
diff --git a/force-app/main/default/classes/DML.cls b/force-app/main/default/classes/DML.cls
index 3a5b509..558d7aa 100644
--- a/force-app/main/default/classes/DML.cls
+++ b/force-app/main/default/classes/DML.cls
@@ -126,6 +126,7 @@ public inherited sharing class DML implements Commitable {
// Field Level Security
Commitable userMode();
Commitable systemMode();
+ Commitable accessMode(System.AccessLevel accessMode);
// Sharing Mode
Commitable withSharing();
Commitable withoutSharing();
@@ -669,14 +670,16 @@ public inherited sharing class DML implements Commitable {
// Field Level Security
public Commitable userMode() {
- return this.setAccessMode(System.AccessLevel.USER_MODE);
+ this.configuration.accessMode(System.AccessLevel.USER_MODE);
+ return this;
}
public Commitable systemMode() {
- return this.setAccessMode(System.AccessLevel.SYSTEM_MODE);
+ this.configuration.accessMode(System.AccessLevel.SYSTEM_MODE);
+ return this;
}
- private Commitable setAccessMode(System.AccessLevel accessMode) {
+ public Commitable accessMode(System.AccessLevel accessMode) {
this.configuration.accessMode(accessMode);
return this;
}
diff --git a/force-app/main/default/classes/DML.cls-meta.xml b/force-app/main/default/classes/DML.cls-meta.xml
index 82775b9..cad713d 100644
--- a/force-app/main/default/classes/DML.cls-meta.xml
+++ b/force-app/main/default/classes/DML.cls-meta.xml
@@ -1,5 +1,5 @@
- 65.0
+ 66.0
Active
diff --git a/force-app/main/default/classes/DML_Test.cls b/force-app/main/default/classes/DML_Test.cls
index 52c8e87..15405a1 100644
--- a/force-app/main/default/classes/DML_Test.cls
+++ b/force-app/main/default/classes/DML_Test.cls
@@ -3532,7 +3532,28 @@ private class DML_Test {
Assert.areEqual('Access to entity \'Case\' denied', expectedException.getMessage(), 'Expected exception message should be thrown.');
}
+ @IsTest
+ static void toInsertWithUserModeExplicitlySetAccessMode() {
+ // Setup
+ Case newCase = getCase(1);
+
+ Exception expectedException = null;
+ // Test
+ Test.startTest();
+ System.runAs(minimumAccessUser()) {
+ try {
+ new DML().toInsert(newCase).accessMode(System.AccessLevel.USER_MODE).commitWork();
+ } catch (Exception e) {
+ expectedException = e;
+ }
+ }
+ Test.stopTest();
+
+ // Verify
+ Assert.isNotNull(expectedException, 'Expected exception to be thrown.');
+ Assert.areEqual('Access to entity \'Case\' denied', expectedException.getMessage(), 'Expected exception message should be thrown.');
+ }
@IsTest
static void toInsertWithInvalidRelationshipSingleRecord() {
diff --git a/force-app/main/default/classes/DML_Test.cls-meta.xml b/force-app/main/default/classes/DML_Test.cls-meta.xml
index 82775b9..cad713d 100644
--- a/force-app/main/default/classes/DML_Test.cls-meta.xml
+++ b/force-app/main/default/classes/DML_Test.cls-meta.xml
@@ -1,5 +1,5 @@
- 65.0
+ 66.0
Active
diff --git a/package/main/default/classes/DML.cls b/package/main/default/classes/DML.cls
index 12acc6b..6d9594d 100644
--- a/package/main/default/classes/DML.cls
+++ b/package/main/default/classes/DML.cls
@@ -126,6 +126,7 @@ global inherited sharing class DML implements Commitable {
// Field Level Security
Commitable userMode();
Commitable systemMode();
+ Commitable accessMode(System.AccessLevel accessMode);
// Sharing Mode
Commitable withSharing();
Commitable withoutSharing();
@@ -669,14 +670,16 @@ global inherited sharing class DML implements Commitable {
// Field Level Security
global Commitable userMode() {
- return this.setAccessMode(System.AccessLevel.USER_MODE);
+ this.configuration.accessMode(System.AccessLevel.USER_MODE);
+ return this;
}
global Commitable systemMode() {
- return this.setAccessMode(System.AccessLevel.SYSTEM_MODE);
+ this.configuration.accessMode(System.AccessLevel.SYSTEM_MODE);
+ return this;
}
- private Commitable setAccessMode(System.AccessLevel accessMode) {
+ global Commitable accessMode(System.AccessLevel accessMode) {
this.configuration.accessMode(accessMode);
return this;
}
diff --git a/package/main/default/classes/DML.cls-meta.xml b/package/main/default/classes/DML.cls-meta.xml
index 82775b9..cad713d 100644
--- a/package/main/default/classes/DML.cls-meta.xml
+++ b/package/main/default/classes/DML.cls-meta.xml
@@ -1,5 +1,5 @@
- 65.0
+ 66.0
Active
diff --git a/package/main/default/classes/DML_Full_Test.cls b/package/main/default/classes/DML_Full_Test.cls
index e2836a0..1f09221 100644
--- a/package/main/default/classes/DML_Full_Test.cls
+++ b/package/main/default/classes/DML_Full_Test.cls
@@ -6853,6 +6853,29 @@ private class DML_Full_Test {
Assert.areEqual('Access to entity \'Case\' denied', expectedException.getMessage(), 'Expected exception message should be thrown.');
}
+ @IsTest
+ static void toInsertWithUserModeExplicitlySetAccessMode() {
+ // Setup
+ Case newCase = getCase(1);
+
+ Exception expectedException = null;
+
+ // Test
+ Test.startTest();
+ System.runAs(minimumAccessUser()) {
+ try {
+ new DML().toInsert(newCase).accessMode(System.AccessLevel.USER_MODE).commitWork();
+ } catch (Exception e) {
+ expectedException = e;
+ }
+ }
+ Test.stopTest();
+
+ // Verify
+ Assert.isNotNull(expectedException, 'Expected exception to be thrown.');
+ Assert.areEqual('Access to entity \'Case\' denied', expectedException.getMessage(), 'Expected exception message should be thrown.');
+ }
+
@IsTest
static void toUpdateWithUserMode() {
// Setup
@@ -6903,6 +6926,31 @@ private class DML_Full_Test {
Assert.areEqual('Access to entity \'Case\' denied', expectedException.getMessage(), 'Expected exception message should be thrown.');
}
+ @IsTest
+ static void toUpdateWithUserModeExplicitlySetAccessMode() {
+ // Setup
+ Case newCase = getCase(1);
+ insert newCase;
+
+ Exception expectedException = null;
+
+ // Test
+ Test.startTest();
+ System.runAs(minimumAccessUser()) {
+ try {
+ newCase.Subject = 'Updated Test Case';
+ new DML().toUpdate(newCase).accessMode(System.AccessLevel.USER_MODE).commitWork();
+ } catch (Exception e) {
+ expectedException = e;
+ }
+ }
+ Test.stopTest();
+
+ // Verify
+ Assert.isNotNull(expectedException, 'Expected exception to be thrown.');
+ Assert.areEqual('Access to entity \'Case\' denied', expectedException.getMessage(), 'Expected exception message should be thrown.');
+ }
+
@IsTest
static void toUpsertWithUserMode() {
// Setup
@@ -6965,6 +7013,37 @@ private class DML_Full_Test {
);
}
+ @IsTest
+ static void toUpsertWithUserModeExplicitlySetAccessMode() {
+ // Setup
+ Case newCase1 = getCase(1);
+ Case newCase2 = getCase(2);
+
+ insert newCase1;
+
+ Exception expectedException = null;
+
+ // Test
+ Test.startTest();
+ System.runAs(minimumAccessUser()) {
+ try {
+ newCase1.Subject = 'Updated Test Case';
+
+ new DML().toUpsert(newCase1).toUpsert(newCase2).accessMode(System.AccessLevel.USER_MODE).commitWork();
+ } catch (Exception e) {
+ expectedException = e;
+ }
+ }
+ Test.stopTest();
+
+ // Verify
+ Assert.isNotNull(expectedException, 'Expected exception to be thrown.');
+ Assert.isTrue(
+ expectedException.getMessage().contains('Operation failed due to fields being inaccessible on Sobject Case, check errors on Exception or Result'),
+ 'Expected exception message should be thrown.'
+ );
+ }
+
@IsTest
static void toDeleteWithUserMode() {
// Setup
@@ -7013,6 +7092,30 @@ private class DML_Full_Test {
Assert.areEqual('Access to entity \'Case\' denied', expectedException.getMessage(), 'Expected exception message should be thrown.');
}
+ @IsTest
+ static void toDeleteWithUserModeExplicitlySetAccessMode() {
+ // Setup
+ Case newCase = getCase(1);
+ insert newCase;
+
+ Exception expectedException = null;
+
+ // Test
+ Test.startTest();
+ System.runAs(minimumAccessUser()) {
+ try {
+ new DML().toDelete(newCase).accessMode(System.AccessLevel.USER_MODE).commitWork();
+ } catch (Exception e) {
+ expectedException = e;
+ }
+ }
+ Test.stopTest();
+
+ // Verify
+ Assert.isNotNull(expectedException, 'Expected exception to be thrown.');
+ Assert.areEqual('Access to entity \'Case\' denied', expectedException.getMessage(), 'Expected exception message should be thrown.');
+ }
+
@IsTest
static void toHardDeleteWithUserMode() {
// Setup
@@ -7111,6 +7214,34 @@ private class DML_Full_Test {
Assert.isTrue(expectedException.getMessage().contains('invalid record id'), 'Expected exception message should be thrown.');
}
+ @IsTest
+ static void toUndeleteWithUserModeExplicitlySetAccessMode() {
+ // Setup
+ Case newCase = getCase(1);
+ insert newCase;
+
+ delete newCase;
+
+ Assert.areEqual(0, [SELECT COUNT() FROM Case], 'Cases should be deleted.');
+
+ Exception expectedException = null;
+
+ // Test
+ Test.startTest();
+ System.runAs(minimumAccessUser()) {
+ try {
+ new DML().toUndelete(newCase).accessMode(System.AccessLevel.USER_MODE).commitWork();
+ } catch (Exception e) {
+ expectedException = e;
+ }
+ }
+ Test.stopTest();
+
+ // Verify
+ Assert.isNotNull(expectedException, 'Expected exception to be thrown.');
+ Assert.isTrue(expectedException.getMessage().contains('invalid record id'), 'Expected exception message should be thrown.');
+ }
+
@IsTest
static void toMergeWithUserMode() {
// Setup
diff --git a/package/main/default/classes/DML_Full_Test.cls-meta.xml b/package/main/default/classes/DML_Full_Test.cls-meta.xml
index 82775b9..cad713d 100644
--- a/package/main/default/classes/DML_Full_Test.cls-meta.xml
+++ b/package/main/default/classes/DML_Full_Test.cls-meta.xml
@@ -1,5 +1,5 @@
- 65.0
+ 66.0
Active
diff --git a/sfdx-project.json b/sfdx-project.json
index 8e774b1..81103af 100644
--- a/sfdx-project.json
+++ b/sfdx-project.json
@@ -16,7 +16,7 @@
"name": "dml-lib",
"namespace": "btcdev",
"sfdcLoginUrl": "https://login.salesforce.com",
- "sourceApiVersion": "65.0",
+ "sourceApiVersion": "66.0",
"packageAliases": {
"DML Lib": "0HoP600000001IfKAI",
"DML Lib@0.1.0-1": "04tP6000002A7BxIAK",
diff --git a/website/configuration/field-level-security.md b/website/configuration/field-level-security.md
index 32095c6..92db837 100644
--- a/website/configuration/field-level-security.md
+++ b/website/configuration/field-level-security.md
@@ -17,6 +17,39 @@ System.runAs(minimalAccessUser) {
}
```
+## accessMode
+
+Set access mode explicitly using the Salesforce `System.AccessLevel` enum.
+
+**Signature**
+
+```apex
+Commitable accessMode(System.AccessLevel accessMode);
+```
+
+Use `accessMode(System.AccessLevel.USER_MODE)` as an alternative to `userMode()`, and `accessMode(System.AccessLevel.SYSTEM_MODE)` as an alternative to `systemMode()`.
+
+**Standard DML**
+
+```apex
+insert as user new Account(Name = 'My Account');
+insert as system new Case(Subject = 'System Mode Case');
+```
+
+**DML Lib**
+
+```apex
+new DML()
+ .toInsert(new Account(Name = 'My Account'))
+ .accessMode(System.AccessLevel.USER_MODE)
+ .commitWork();
+
+new DML()
+ .toInsert(new Case(Subject = 'System Mode Case'))
+ .accessMode(System.AccessLevel.SYSTEM_MODE)
+ .commitWork();
+```
+
## userMode
Execute DML operations respecting user permissions. This is the **default behavior**.
@@ -75,13 +108,16 @@ Use `systemMode()` with caution. It bypasses field-level security, which could e
Field-level security and sharing mode are independent settings that work together.
-| Configuration | FLS | Sharing Rules |
-|---------------|-----|---------------|
-| `userMode()` | Enforced | Enforced |
-| `userMode().withSharing()` | Enforced | Enforced |
-| `userMode().withoutSharing()` | Enforced | Enforced |
-| `systemMode().withSharing()` | Bypassed | Enforced |
-| `systemMode().withoutSharing()` | Bypassed | Bypassed |
+| Configuration | FLS | Sharing Rules |
+| ------------------------------------------------------------- | -------- | ------------- |
+| `userMode()` | Enforced | Enforced |
+| `accessMode(System.AccessLevel.USER_MODE)` | Enforced | Enforced |
+| `userMode().withSharing()` | Enforced | Enforced |
+| `userMode().withoutSharing()` | Enforced | Enforced |
+| `systemMode().withSharing()` | Bypassed | Enforced |
+| `accessMode(System.AccessLevel.SYSTEM_MODE).withSharing()` | Bypassed | Enforced |
+| `systemMode().withoutSharing()` | Bypassed | Bypassed |
+| `accessMode(System.AccessLevel.SYSTEM_MODE).withoutSharing()` | Bypassed | Bypassed |
**Example**
diff --git a/website/configuration/sharing-mode.md b/website/configuration/sharing-mode.md
index fa582aa..174f48f 100644
--- a/website/configuration/sharing-mode.md
+++ b/website/configuration/sharing-mode.md
@@ -42,7 +42,7 @@ We suggest using `.systemMode().withoutSharing()` in triggers, as trigger logic
By default, the DML library uses `with sharing`, meaning it respects the sharing context of the calling class.
Sharing mode is enforced by `userMode()`, which is the default mode.
-Only when `.systemMode()` is used, `.withSharing()` can control the sharing mode.
+Only when `.systemMode()` or `.accessMode(System.AccessLevel.SYSTEM_MODE)` is used, `.withSharing()` can control the sharing mode.
Execute DML operations enforcing sharing rules. Records the user doesn't have access to will cause errors.
@@ -76,7 +76,7 @@ new DML()
## withoutSharing
Execute DML operations bypassing sharing rules. All records are accessible regardless of sharing settings.
-To use `.withoutSharing()`, the `.systemMode()` must be enabled.
+To use `.withoutSharing()`, `.systemMode()` or `.accessMode(System.AccessLevel.SYSTEM_MODE)` must be enabled.
**Signature**
diff --git a/website/dml/delete.md b/website/dml/delete.md
index 2e01b8d..123762e 100644
--- a/website/dml/delete.md
+++ b/website/dml/delete.md
@@ -154,7 +154,7 @@ OperationResult deleteImmediately(List records);
```
::: tip
-All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `deleteImmediately`.
+All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `accessMode(System.AccessLevel)`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `deleteImmediately`.
:::
### Single Record
diff --git a/website/dml/insert.md b/website/dml/insert.md
index 6f9a0ea..9f30193 100644
--- a/website/dml/insert.md
+++ b/website/dml/insert.md
@@ -245,7 +245,7 @@ OperationResult insertImmediately(DML.Records records);
```
::: tip
-All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `insertImmediately`.
+All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `accessMode(System.AccessLevel)`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `insertImmediately`.
:::
### Single Record
diff --git a/website/dml/undelete.md b/website/dml/undelete.md
index 9d33bc8..1cc840a 100644
--- a/website/dml/undelete.md
+++ b/website/dml/undelete.md
@@ -154,7 +154,7 @@ OperationResult undeleteImmediately(List records);
```
::: tip
-All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `undeleteImmediately`.
+All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `accessMode(System.AccessLevel)`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `undeleteImmediately`.
:::
### Single Record
diff --git a/website/dml/update.md b/website/dml/update.md
index 93f97d6..15d392d 100644
--- a/website/dml/update.md
+++ b/website/dml/update.md
@@ -232,7 +232,7 @@ OperationResult updateImmediately(DML.Records records);
```
::: tip
-All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `updateImmediately`.
+All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `accessMode(System.AccessLevel)`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `updateImmediately`.
:::
### Single Record
diff --git a/website/dml/upsert.md b/website/dml/upsert.md
index 22e9a94..a1a1ef7 100644
--- a/website/dml/upsert.md
+++ b/website/dml/upsert.md
@@ -316,7 +316,7 @@ OperationResult upsertImmediately(DML.Records records);
```
::: tip
-All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `upsertImmediately`.
+All DML settings configured on the `DML` instance (such as `userMode()`, `systemMode()`, `accessMode(System.AccessLevel)`, `withSharing()`, `withoutSharing()`, `allowPartialSuccess()`) are inherited when executing `upsertImmediately`.
:::
### Single Record