## The Challenge with Traditional SOQL in Apex

Verbose SOQL strings, the complexity of relationship queries, and slow, brittle, database-dependent tests... these are challenges every Salesforce developer faces.

While powerful, the standard ways of writing queries in Apex often lead to code that is difficult to read, maintain, and, most importantly, test.
- ❌ Poor Readability: Long, manually concatenated SOQL strings quickly become unmanageable.
- ❌ Complex Dynamic Conditions: Adding conditions within an `if` block requires awkward string manipulation.
- ❌ No Type Safety: Field name typos in a string query are only caught at runtime.
- ❌ Difficult Relationship Queries: Handling parent and child relationships requires knowledge of specific, often non-intuitive relationship names.
- ❌ Difficult to Test: Business logic is tightly coupled to the database, forcing the creation of extensive test data and leading to slow test execution.

`ApexEloquent` was born to solve these challenges.

## The Solution: A Fluent, Testable ORM

`ApexEloquent` is an ORM framework, inspired by Laravel Eloquent, that provides a fluent and intuitive interface for all data operations. It consists of two core components:
- `Scribe`: A powerful, immutable query builder that allows you to construct any SOQL query through a chain of easy-to-understand methods.
- `Eloquent`: The execution engine that runs the queries built by `Scribe` against the database. It also includes `MockEloquent` for testing.

## Basic Usage

Building a query is simple and readable. You "describe" what you want, then "get" it.
```apex
// 1. Arrange: Build the query with Scribe
// Get the Id and Name of all Accounts in the 'Technology' industry
Scribe scribe = Scribe.source(Account.getSObjectType())
    .fields(new List<String>{'Id', 'Name'})
    .whereEqual('Industry', 'Technology')
    .orderBy('Name');

// 2. Act: Execute the query with Eloquent
List<IEntry> accounts = (new Eloquent()).get(scribe);

// 3. Utilize: Access the results
for (IEntry acc : accounts) {
    System.debug(acc.getName());
}
```

This is far more maintainable than the equivalent SOQL string:
```soql
SELECT Id, Name FROM Account WHERE Industry = 'Technology' ORDER BY Name
```

## Key Features in Action

### Building Dynamic Queries

`Scribe`'s immutable design makes it easy to add conditions dynamically without complex string logic.

> The `if` form below also adds SELECT fields. If you are only toggling **WHERE conditions**, `ignoreWhen` expresses it as a single chain with no branching (`whereIn('Id', ids).ignoreWhen(ids.isEmpty())`).
```apex
Scribe scribe = Scribe.source(Opportunity.getSObjectType())
    .fields(new List<String>{'Name', 'Amount'})
    .whereIn('StageName', new List<String>{'Prospecting', 'Qualification'});

// Add another condition only if a certain criteria is met
if (includeHighValueDeals) {
    scribe = scribe.whereGreaterThan('Amount', 100000);
}

List<IEntry> opps = (new Eloquent()).get(scribe);
```

### Handling Relationships with Ease

You no longer need to look up confusing relationship names.
```apex
// Get an Account and all of its related Contacts
Scribe scribe = Scribe.source(Account.getSObjectType())
    .field('Name')
    .withChildren(
        Scribe.asChild(Contact.getSObjectType())
            .fields(new List<String>{'LastName', 'Email'})
    )
    .whereEqual('Id', someAccountId);

IEntry account = (new Eloquent()).first(scribe);
List<IEntry> contacts = account.getChildren('Contact');
```

## Liberation from the Database: True Unit Testing

The true power of `ApexEloquent` lies in its testability.

**Scenario**: Test a service method, `AccountService.updateAccountType`, which updates an Opportunity's parent Account `Type` to 'Customer' if the Opportunity stage is 'Closed Won'.

**Before**: **Traditional Testing**

This requires inserting multiple records, making the test slow and dependent on the database.
```apex
// Test data must be inserted
Account testAcc = new Account(Name='Test', Type='Prospect');
insert testAcc;
Opportunity testOpp = new Opportunity(Name='Test Opp', ...);
insert testOpp;

// Execute and Assert
Account updatedAccount = AccountService.updateAccountType(testOpp.Id);
Assert.areEqual('Customer', updatedAccount.Type);
```

**After**: **ApexEloquent**

With `MockEloquent`, you test your logic in complete isolation, without any DML.
```apex
// Set up the expected query result in memory
IEloquent mockEloquent = new MockEloquent(
    new MockEntry(
        new Opportunity(Id = '...', StageName = 'Closed Won'),
        new Map<String, Object>{
            'AccountId' => new MockEntry(new Account(Id = '...', Type = 'Prospect'))
        }
    )
);

// Test the service class directly, with no database access
AccountService service = new AccountService(mockEloquent);
Account updatedAccount = service.updateAccountType('...');

// Assert the value of the object updated in memory
Assert.areEqual('Customer', updatedAccount.Type);
```

## Summary: Why Choose ApexEloquent?

|Feature|Traditional SOQL|ApexEloquent|
|--------|------------------|----------------|
|Readability|Poor for complex queries|✅ Excellent via fluent API|
|Dynamic WHERE|Manual string building|✅ Safe, chained methods|
|Relationships|Requires relation name lookup|✅ Intuitive .withChildren() etc.|
|Testability|❌ Requires DML & Test Data|✅ Database-free via MockEloquent|
|Safety|Runtime errors for typos|✅ Finds errors during testing|
