Skip to content

Commit 1517bfa

Browse files
committed
documentation
1 parent c8ec064 commit 1517bfa

File tree

3 files changed

+105
-50
lines changed

3 files changed

+105
-50
lines changed

website/docs/docs/getting-started.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Profile systemAdminProfile = (Profile) SOQLCache.of(Profile.SObjectType)
5252

5353
## Selector
5454

55-
```apex
55+
```apex title="SOQL_Contact.cls"
5656
public inherited sharing class SOQL_Contact extends SOQL implements SOQL.Selector {
5757
public static SOQL_Contact query() {
5858
return new SOQL_Contact();
@@ -80,7 +80,7 @@ public inherited sharing class SOQL_Contact extends SOQL implements SOQL.Selecto
8080

8181
**Usage**
8282

83-
```apex
83+
```apex title="ExampleController.cls"
8484
public with sharing class ExampleController {
8585
@AuraEnabled
8686
public static List<Contact> getAccountContacts(Id accountId) {
@@ -95,7 +95,7 @@ public with sharing class ExampleController {
9595

9696
## Cached Selector
9797

98-
```apex
98+
```apex title="SOQL_ProfileCache.cls"
9999
public with sharing class SOQL_ProfileCache extends SOQLCache implements SOQLCache.Selector {
100100
public static SOQL_ProfileCache query() {
101101
return new SOQL_ProfileCache();
@@ -120,7 +120,7 @@ public with sharing class SOQL_ProfileCache extends SOQLCache implements SOQLCac
120120

121121
**Usage**
122122

123-
```apex
123+
```apex title="ExampleController.cls"
124124
public with sharing class ExampleController {
125125
@AuraEnabled
126126
public static void createNewAdministrator(User newUser) {

website/docs/docs/overview.md

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,69 +4,95 @@ sidebar_position: 15
44

55
# Overview
66

7-
## Assumptions
7+
## Concept
88

9-
1. **Small Selector Classes** - The selector class should be small and contain ONLY query base configuration (fields, sharing settings) and very generic methods (`byId`, `byRecordType`). Why?
10-
- Huge classes are hard to manage.
11-
- A lot of merge conflicts.
12-
- Problems with method naming.
13-
2. **Build SOQL inline in a place of need** - Business-specific SOQLs should be built inline via `SOQL` builder in a place of need.
14-
- Most of the queries on the project are case-specific and are not generic. There is no need to keep them in the Selector class.
15-
3. **Build SOQL dynamically via builder** - Developers should be able to adjust queries with specific fields, conditions, and other SOQL clauses.
16-
4. **Do not spend time on selector method naming** - It can be difficult to find a proper name for a method that builds a query. The selector class contains methods like `selectByFieldAAndFieldBWithDescOrder`. It can be avoided by building SOQL inline in a place of need.
17-
5. **Control FLS and sharing settings** - Selector should allow to control Field Level Security and sharing settings by simple methods like `.systemMode()`, `.withSharing()`, `.withoutSharing()`.
18-
6. **Auto binding** - The selector should be able to bind variables dynamically without additional effort from the developer side.
19-
7. **Mock results in Unit Tests** - The selector should allow mocking data in unit tests.
9+
SOQL Lib is a modern Apex library designed as an intuitive alternative to the popular [FFLib Selectors](https://github.com/apex-enterprise-patterns/fflib-apex-common) framework. While FFLib was created over 10 years ago, we believe it hasn't kept up with modern Apex development practices, becoming a complex and cumbersome solution that often makes code more complicated than necessary.
2010

21-
## Concepts
11+
Drawing from the best aspects of FFLib and other selector patterns, we've built SOQL Lib to be intuitive, performant, and reliable. This library is part of the Beyond The Cloud ecosystem, designed specifically for modern Salesforce development.
2212

23-
SOQL Library consists of:
13+
## Design Principles
2414

25-
- `SOQL Builder`
26-
- `SOQL Selector`
15+
We built SOQL Lib based on several key design principles that address common pain points in Salesforce development:
2716

28-
## SOQL Builder
17+
1. **Lightweight Selector Classes** - Selector classes should remain focused and contain only essential query configurations (default fields, sharing settings) and generic, chainable methods like `byId()`, `byRecordType()`, and `byParentId()`. We avoid storing all queries in selector classes because:
18+
- Large selector classes become difficult to maintain and navigate
19+
- They create frequent merge conflicts in team environments
20+
- Complex query methods lead to unwieldy naming conventions
2921

30-
SOQL Builder allows you to build queries dynamically and execute them.
22+
2. **Inline Query Construction** - Business-specific queries should be built inline using the `SOQL` builder exactly where they're needed:
23+
- Most queries in a project are context-specific rather than reusable
24+
- Developers can construct queries dynamically using our fluent API
25+
- This approach eliminates the need for countless specialized selector methods
26+
27+
3. **Dynamic Query Building** - The library provides full flexibility to adjust queries with specific fields, conditions, and SOQL clauses at runtime, enabling responsive and adaptable code.
28+
29+
4. **Simplified Method Naming** - By building queries inline, developers avoid the complexity of naming methods like `selectByFieldAAndFieldBWithDescOrder()`. The fluent API speaks for itself.
30+
31+
5. **Granular Security Controls** - Built-in support for Field-Level Security and sharing settings through intuitive methods like `.systemMode()`, `.withSharing()`, and `.withoutSharing()`.
32+
33+
6. **Automatic Variable Binding** - Dynamic variable binding eliminates boilerplate code and reduces the potential for binding errors.
34+
35+
7. **Comprehensive Testing Support** - Native mocking capabilities make unit testing SOQL queries straightforward and reliable.
36+
37+
8. **Performance Optimization** - Query results can be cached at multiple levels (Org Cache, Session Cache, Apex Transaction Cache) to improve application performance.
38+
39+
9. **Developer Experience** - The API is designed to be intuitive and self-documenting, minimizing the learning curve while maximizing productivity.
40+
41+
## Architecture
42+
43+
SOQL Lib consists of three distinct modules, each designed to address different use cases and development preferences:
44+
45+
### [`SOQL`](../soql/getting-started.md) - Core Module
46+
47+
The foundation of SOQL Lib, providing a comprehensive fluent API for constructing and executing SOQL queries. This module includes both SOQL Builder for direct query construction and SOQL Selectors for reusable query patterns. The architecture is flexible—developers can build queries directly without selectors or leverage selectors for commonly used query configurations.
48+
49+
**Key Features:**
50+
- Fluent API for intuitive query construction
51+
- Field-Level Security enforcement with `withUserMode()` and `systemMode()`
52+
- Granular sharing control (`withSharing()` and `withoutSharing()`)
53+
- Automatic variable binding and SOQL injection prevention
54+
- Comprehensive result transformation methods
55+
- Built-in mocking support for unit tests
3156

3257
```apex
33-
// SELECT Id, Name, Industry FROM Account
58+
// SELECT Id, Name, Industry FROM Account WITH USER_MODE
3459
List<Account> accounts = SOQL.of(Account.SObjectType)
3560
.with(Account.Id, Account.Name, Account.Industry)
3661
.toList();
3762
```
3863

39-
## SOQL Selector
40-
41-
> 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
42-
43-
**SOQL Lib provides the whole new concept for Selectors usage.**
44-
45-
### Old Approach
64+
### [`Cache`](../cache/getting-started.md) - Performance Module _(Optional)_
4665

47-
[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 should be stored in the Selector class.
66+
An optional but highly recommended module that dramatically improves application performance by caching query results across different storage levels. Ideal for frequently accessed, slowly-changing data such as configuration records, metadata, and reference data.
4867

49-
- To avoid duplicates.
50-
- One place to manage all queries.
68+
**Key Features:**
69+
- Multi-level caching: Org Cache, Session Cache, and Apex Transaction Cache
70+
- Automatic cache expiration with `maxHoursWithoutRefresh()`
71+
- Built-in cache management and removal capabilities
5172

52-
**Issues**:
53-
- One-time queries (like aggregation, case specific) added to Selector.
54-
- Huge class with a lot of methods.
55-
- Queries are difficult to reuse.
56-
- Similar methods with small differences like limit, offset.
57-
- Problem with naming methods.
58-
- Merge conflicts.
59-
60-
### New Approach
73+
```apex
74+
// Cached query with 24-hour refresh policy
75+
Profile profile = (Profile) SOQLCache.of(Profile.SObjectType)
76+
.with(Profile.Id, Profile.Name)
77+
.whereEqual(Profile.Name, 'System Administrator')
78+
.cacheInOrgCache()
79+
.maxHoursWithoutRefresh(24)
80+
.toObject();
81+
```
6182

62-
The SOQL Lib has a slightly different approach.
83+
### [`Evaluator`](../evaluator/getting-started.md) - Legacy Bridge Module _(Optional)_
6384

64-
**Assumption**:
85+
Designed for developers who prefer traditional SOQL syntax but want to leverage SOQL Lib's enhanced capabilities. This module processes static query result, providing advanced result transformation methods and mocking capabilities without requiring adoption of the full SOQL Builder syntax.
6586

66-
Most of the SOQLs on the project are **one-time** queries executed for specific business cases.
87+
**Key Features:**
88+
- Process results from standard SOQL queries
89+
- Enhanced result transformation methods (`toIds()`, `toValueOf()`, `toMap()`, etc.)
90+
- Simplified mocking for unit tests
91+
- Field-Level Security processing with `stripInaccessible()`
92+
- Zero learning curve for traditional SOQL developers
6793

68-
**Solution**:
69-
1. **Small Selector Classes** - Selector class should be small and contain ONLY query base configuration (fields, sharing settings) and very generic methods (`byId`, `byRecordType`)
70-
2. **Build SOQL inline in a place of need** - Business-specific SOQLs should be built inline via the SOQL builder in the place of need.
71-
3. **Do not spend time on selector method naming** - Queries are created inline, so there's no need to find a name.
72-
4. **Keep Selector Strengths** - Set default Selector configuration (default fields, sharing settings), keep generic methods.
94+
```apex
95+
// Enhanced processing of standard SOQL results
96+
Set<Id> accountIds = SOQLEvaluator.of([SELECT Id FROM Account]).toIds();
97+
Boolean hasAccounts = SOQLEvaluator.of([SELECT Id FROM Account]).doExist();
98+
```

website/docs/soql/build-selector.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,35 @@ SOQL Lib is agile, so you can adjust the solution according to your needs.
1919

2020
**We don't force one approach over another; you can choose your own**.
2121

22+
## Old Approach
23+
24+
[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 should be stored in the Selector class.
25+
26+
- To avoid duplicates.
27+
- One place to manage all queries.
28+
29+
**Issues**:
30+
- One-time queries (like aggregation, case specific) added to Selector.
31+
- Huge class with a lot of methods.
32+
- Queries are difficult to reuse.
33+
- Similar methods with small differences like limit, offset.
34+
- Problem with naming methods.
35+
- Merge conflicts.
36+
37+
## New Approach
38+
39+
The SOQL Lib has a slightly different approach.
40+
41+
**Assumption**:
42+
43+
Most of the SOQLs on the project are **one-time** queries executed for specific business cases.
44+
45+
**Solution**:
46+
1. **Small Selector Classes** - Selector class should be small and contain ONLY query base configuration (fields, sharing settings) and very generic methods (`byId`, `byRecordType`)
47+
2. **Build SOQL inline in a place of need** - Business-specific SOQLs should be built inline via the SOQL builder in the place of need.
48+
3. **Do not spend time on selector method naming** - Queries are created inline, so there's no need to find a name.
49+
4. **Keep Selector Strengths** - Set default Selector configuration (default fields, sharing settings), keep generic methods.
50+
2251
## A - Inheritance - extends SOQL, implements Interface + static _(Recommended)_
2352

2453
Most Flexible Approach:

0 commit comments

Comments
 (0)