Skip to content

Commit

Permalink
documentation update
Browse files Browse the repository at this point in the history
  • Loading branch information
pgajek2 committed May 17, 2023
1 parent 45585ed commit 68dc052
Showing 1 changed file with 115 additions and 7 deletions.
122 changes: 115 additions & 7 deletions website/docs/key-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ sidebar_position: 2
## Concepts

SOQL Library consist of:

- `SOQL Builder`
- `SOQL Selector`

### SOQL Builder
## SOQL Builder

SOQL Builder allows to build query dynamically and execute it.

Expand All @@ -36,40 +37,49 @@ List<Account> accounts = SOQL.of(Account.SObjectType)
}).toList();
```

### SOQL Selector
## SOQL Selector

> A selector layer contains code responsible for querying records from the database. Although you can place SOQL queries in other layers, a few things can happen as the complexity of your code grows. ~ Salesforce
**SOQL Lib provides the whole new concept for Selectors usage.**

#### Old Approach
### Old Approach

[FFLIB Selector](https://github.com/apex-enterprise-patterns/fflib-apex-common/blob/master/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls) concept assumes that all queries are be stored in Selector class.

- To avoid duplicates.
- One place to manage all queries.

**Selector Issues**:
**Issues**:
- One-time queries (like aggregation, case specific) added to Selector.
- Huge class with a lot of methods.
- Queries are difficult for reuse.
- Similar methods with small differences like limit, offset.
- Problem with naming methods.
- Merge conflicts.

#### New Approach
### New Approach

SOQL Lib has slightly different approach.

**Assumption**:

Most of the SOQLs on the project are one-time queries executed for specific business case.

**Solution**:
1. **Small Selector Classes** - Selector class should be small and contains ONLY query base configuration (fields, sharing settings) and very generic methods (`getById`, `getByRecordType`)
1. **Small Selector Classes** - Selector class should be small and contains ONLY query base configuration (fields, sharing settings) and very generic methods (`byId`, `byRecordType`)
2. **Build SOQL inline in a place of need** - Business specific SOQLs should be build inline via SOQL builder in a place of need.
3. **Do not spend time on selector methods naming** - Queries are created inline, so not need to find a name.
4. **Keep Selector Strengths** - Set default Selector configuration (default fields, sharing settings), keep generic methods.

### Build Your Own Selector

Our Lib does NOT provide one method to build selectors. Select approach that meet you needs. Below you will find a few examples:

#### Interface + static (Recommended)

Use `SOQL.Selector` and create `static` methods.

```apex
public with sharing class AccountSelector implements SOQL.Selector {
public static SOQL query() {
Expand Down Expand Up @@ -103,7 +113,105 @@ public with sharing class ExampleController {
}
public static List<Account> getAccountsByRecordType(String recordType) {
return AccountSelector.getByRecordType(recordType)
return AccountSelector.byRecordType(recordType)
.with(Account.ParentId)
.toList();
}
}
```

#### Interface + non-static

Very useful when you have different teams/streams who need different query configuration.

```apex
public with sharing virtual class BaseAccountSelector implements SOQL.Selector {
public virtual SOQL query() {
return SOQL.of(Account.SObjectType)
.with(new List<SObjectField>{
Account.Id,
Account.Name
});
}
public SOQL byRecordType(String rt) {
return query().with(new List<SObjectField>{
Account.BillingCity,
Account.BillingCountry
}).whereAre(SOQL.Filter.recordType().equal(rt));
}
}
```

```apex
public with sharing class MyTeam_AccountSelector extends BaseAccountSelector implements SOQL.Selector {
public override SOQL query() {
return SOQL.of(Account.SObjectType)
.with(new List<SObjectField>{
Account.Id,
Account.AccountNumber
})
.systemMode()
.withoutSharing();
}
}
```

```apex
public with sharing class ExampleController {
public static List<Account> getAccounts(String accountName) {
return new MyTeam_AccountSelector().query()
.with(Account.BillingCity)
.with(Account.BillingCountry)
.whereAre(SOQL.Filter.with(Account.Name).contains(accountName))
.toList();
}
public static List<Account> getAccountsByRecordType(String recordType) {
return new MyTeam_AccountSelector().byRecordType(recordType)
.with(Account.ParentId)
.toList();
}
}
```

#### Custom

Create Selectors in your own way.

```apex
public with sharing virtual class AccountSelector {
public static SOQL query {
return SOQL.of(Account.SObjectType)
.with(new List<SObjectField>{
Account.Id,
Account.Name
});
}
public static SOQL byRecordType(String rt) {
return query.with(new List<SObjectField>{
Account.BillingCity,
Account.BillingCountry
}).whereAre(SOQL.Filter.recordType().equal(rt));
}
}
```

```apex
public with sharing class ExampleController {
public static List<Account> getAccounts(String accountName) {
return AccountSelector().query
.with(Account.BillingCity)
.with(Account.BillingCountry)
.whereAre(SOQL.Filter.with(Account.Name).contains(accountName))
.toList();
}
public static List<Account> getAccountsByRecordType(String recordType) {
return AccountSelector.byRecordType(recordType)
.with(Account.ParentId)
.toList();
}
Expand Down

1 comment on commit 68dc052

@vercel
Copy link

@vercel vercel bot commented on 68dc052 May 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.