-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to get a selector without sharing #62
Comments
When might a Selector be the top-level Apex code that would thus define the sharing model? Would the calling code -- having "with" or "without sharing" or implied in some way -- define the sharing model, which an "inherited sharing" Selector would implicitly enforce? |
Typically, selectors should default to I don't think If you are set on using different instances of the selector for each variant, I suggest extending public class with sharing ContactSelector
extends ApplicationSObjectSelector
implements IContactSelector
{
public Contact[] selectById(Set<Id> ids) {
return (Contact[])selectSObjectById(ids);
}
public Contact[] selectByIdWithoutSharing(Set<Id> ids) {
return new WithoutSharing().selectById(this, ids);
}
public class without sharing WithoutSharing {
private WithoutSharing() {}
public Contact[] selectById(IContactSelector selector, Set<Id> ids) {
return selector.selectById(ids);
}
}
} |
Hi @chazwatkins Thank you for clarifying. This code has been thoroughly vetted with my favorite text editor, so take it for what it's worth. 😇 However I think, based on my understanding, this is the first step that I'd take down the path that's been charted. Keeping Application and the core ContactSelector pure for the most part, I've kept the two selector separated -- S in SOLID -- but one could put a static factory method in ContactSelector if they felt strongly about it. With this, the consuming business logic would be free of extraneous code, as typical, and the unit test classes would still simply provide a mock selector to the Application, as typical when needed. Please give this a whirl in a project, where you probably have some robust testing setup. I'm genuinely interested if this is going in the right direction and not broken in some way. Regards! public interface IContactSelector {
Contact[] selectById(Set<Id> ids);
}
public virtual with sharing ContactSelector
extends ApplicationSObjectSelector
implements IContactSelector
{
public static IContactSelector newInstance() {
return (IContactSelector) Application.Selector.newInstance(Contact.SObjectType);
}
public virtual Contact[] selectById(Set<Id> ids) {
return (Contact[]) Database.query(...);
}
}
public without sharing ContactSelectorWithoutSharing
extends ContactSelector
{
public static IContactSelector newInstance() {
return new ContactSelectorWithoutSharing();
}
private IContactSelector baseSelector = Application.Selector.newInstance(Contact.SObjectType);
public override Contact[] selectById(Set<Id> ids) {
return baseSelector.selectById(ids);
}
} |
Hi @stohn777 , Thanks for the response. I agree that the inner-class approach is not the cleanest solution. I believe most folks, including myself, discover this approach in the blog post Apex Sharing and applying to Apex Enterprise Patterns. The only problem with the approach you outlined is that you're forced to call I believe this is why @wimvelzeboer went the way of extending the selector factory to include sharing variants. Another approach could be to allow the caller to specify the sharing rule within which the query would be executed. IContactSelector selector = (IContactSelector)Application.Selector.newInstance(Contact.SObjectType);
// default sharing rule is inherited sharing
selector.getSharingRule();
// INHERITED
// Executed inherited sharing
selector.selectInjection(...);
selector.selectById(...);
selector.withSharing(); // Sets the sharing rule to with sharing
selector.getSharingRule();
// WITH
// Executed with sharing
selector.selectInjection(...);
selector.selectById(...);
selector.withoutSharing(); // Sets the sharing rule to without sharing
selector.getSharingRule();
// WITHOUT
// Executed without sharing
selector.selectInjection(...);
selector.selectById(...); The selector query methods would no longer directly call
These methods would look at the current sharing rule and call the queries within the corresponding class:
Doing so will allow the same query method to be reused for all the sharing rules, so duplication of method definitions is no longer necessary. With the upcoming changes in I'm happy to implement setting the sharing rule on the selector if the team is interested in adding this. What do you think? BTW - You left me in suspense. What is your favorite text editor?
|
What is the best way to have one selector implementation and be able to choose to have a with sharing and a without sharing selector, with the minimal amount of code duplication.
I currently have something like this, but how do I implement this in AT4DX:
The text was updated successfully, but these errors were encountered: