# DataSource Layer

> The `src/<Module>/…` paths used throughout this document are drawn from a
> representative CG Mobile customer workspace. Your workspace may use different
> module names, but the folder structure (`DS/`, `BO/`, `LO/`, `PR/`, `UI/`)
> and naming conventions are identical.

## Overview

DataSources (DS) are the bridge between Salesforce objects and the mobile application's business layer. They define how Salesforce fields map to application attributes and specify the queries used to fetch data.

## DataSource Fundamentals

### Purpose

DataSources (DS) serve as the data access layer that:

-   Map Salesforce object fields to business object attributes
-   Define query conditions and parameters for data retrieval
-   Specify which Salesforce backend system to use
-   Configure read/write permissions and behavior

### Directory Structure

```
src/
├── Visit/
│   └── DS/
│       └── DsBoAccount_sf.datasource.xml       # Simple BO datasource
├── Call/
│   └── DS/
│       └── DsLoAccountReceivables_sf.datasource.xml  # ListObject datasource
└── [module]/
    └── DS/
        └── [datasources]
```

## DataSource XML Structure

### Root Element Attributes

```xml
<DataSource
  name="DsBoAccount"                    <!-- DS identifier -->
  backendSystem="sf"                     <!-- Backend: "sf" = Salesforce -->
  businessObjectClass="BoAccount"        <!-- Associated BO/LO class -->
  external="false"                       <!-- Internal vs external datasource -->
  readOnly="false"                       <!-- Data modification allowed? -->
  distinct="false"                       <!-- Return distinct records? -->
  editableEntity="Account"               <!-- Salesforce object for write operations -->
  schemaVersion="2.0"                    <!-- DS schema version -->
>
```

### Key Elements

| Element            | Description                              | Required |
| ------------------ | ---------------------------------------- | -------- |
| `<Attributes>`     | Maps DS attributes to Salesforce fields  | Yes      |
| `<Entities>`       | Defines Salesforce objects used in query | Yes      |
| `<QueryCondition>` | SOQL WHERE clause with parameters        | No       |
| `<OrderCriteria>`  | Sorting specification                    | No       |
| `<Parameters>`     | Input parameters for queries             | No       |

## Example 1: Simple DataSource - DsBoAccount

**Location:** `src/Visit/DS/DsBoAccount_sf.datasource.xml`
**Purpose:** Loads a single Account record by ID
**Type:** Business Object DataSource (BO)

### Complete XML

```xml
<DataSource name="DsBoAccount" backendSystem="sf" businessObjectClass="BoAccount"
            external="false" editableEntity="Account" schemaVersion="2.0">
  <Attributes>
    <Attribute name="pKey" table="Account" column="Id" />
    <Attribute name="name" table="Account" column="Name" />
  </Attributes>
  <Entities>
    <Entity name="Account" alias="" idAttribute="Id" />
  </Entities>
  <QueryCondition><![CDATA[
        Account.Id = #pKey#
      ]]></QueryCondition>
  <OrderCriteria />
  <Parameters>
    <Parameter name="pKey" type="TEXT" />
  </Parameters>
</DataSource>
```

### Analysis

#### Attributes Mapping

| DS Attribute | Salesforce Object | Salesforce Field | Purpose                |
| ------------ | ----------------- | ---------------- | ---------------------- |
| `pKey`       | Account           | Id               | Primary key identifier |
| `name`       | Account           | Name             | Account name           |

#### Query Behavior

**Generated SOQL (conceptual):**

```sql
SELECT Id, Name
FROM Account
WHERE Account.Id = :pKey
```

**Parameters:**

-   `pKey` (TEXT): The Salesforce Account Id to load

**Key Characteristics:**

-   Simple 1:1 mapping to Account object
-   Minimal attribute set (only ID and Name)
-   Direct primary key lookup
-   Suitable for lightweight Account references

#### Entity Definition

```xml
<Entity name="Account" alias="" idAttribute="Id" />
```

-   **name:** Salesforce object API name
-   **alias:** Optional table alias (empty = use full name)
-   **idAttribute:** Primary key field for the entity

#### Backend System

`backendSystem="sf"` indicates this datasource queries Salesforce.

Other possible values:

-   `sqlite` - Local SQLite database (synced data)
-   `rest` - REST API endpoint
-   Custom backend identifiers

## Example 2: Complex DataSource - DsLoAccountReceivables

**Location:** `src/Call/DS/DsLoAccountReceivables_sf.datasource.xml`
**Purpose:** Loads list of Account Receivable records for a customer
**Type:** List Object DataSource (LO)

### Complete XML

```xml
<DataSource name="DsLoAccountReceivables" backendSystem="sf"
            businessObjectClass="LoAccountReceivables"
            external="false" distinct="false" readOnly="true"
            editableEntity="Account_Receivable__c" schemaVersion="2.0">
  <Attributes>
    <Attribute name="pKey" table="Account_Receivable__c" column="Id" />
    <Attribute name="externalId" table="Account_Receivable__c" column="External_Id__c" />
    <Attribute name="documentType" table="Account_Receivable__c" column="Document_Type__c" />
    <Attribute name="receiptDate" table="Account_Receivable__c" column="Receipt_Date__c" />
    <Attribute name="dueDate" table="Account_Receivable__c" column="Due_Date__c" />
    <Attribute name="amount" table="Account_Receivable__c" column="Amount__c" />
    <Attribute name="amountOpen" table="Account_Receivable__c" column="Amount_Open__c" />
    <Attribute name="invoiceStatus" table="Account_Receivable__c" column="Invoice_Status__c" />
  </Attributes>
  <Entities>
    <Entity name="Account_Receivable__c" alias="" idAttribute="Id" />
  </Entities>
  <QueryCondition><![CDATA[
			Account_Receivable__c.Account__c = #customerPKey#
		]]></QueryCondition>
  <OrderCriteria>
    <OrderCriterion entity="Account_Receivable__c" attribute="Receipt_Date__c" direction="ASC" />
    <OrderCriterion entity="Account_Receivable__c" attribute="External_Id__c" direction="ASC" />
  </OrderCriteria>
  <Parameters>
    <Parameter name="customerPKey" type="TEXT" />
  </Parameters>
</DataSource>
```

### Analysis

#### Attributes Mapping

| DS Attribute    | Salesforce Object       | Salesforce Field    | Data Type | Purpose                    |
| --------------- | ----------------------- | ------------------- | --------- | -------------------------- |
| `pKey`          | Account_Receivable\_\_c | Id                  | ID        | Primary key                |
| `externalId`    | Account_Receivable\_\_c | External_Id\_\_c    | Text      | External system reference  |
| `documentType`  | Account_Receivable\_\_c | Document_Type\_\_c  | Picklist  | Invoice, Credit Note, etc. |
| `receiptDate`   | Account_Receivable\_\_c | Receipt_Date\_\_c   | Date      | When received              |
| `dueDate`       | Account_Receivable\_\_c | Due_Date\_\_c       | Date      | Payment due date           |
| `amount`        | Account_Receivable\_\_c | Amount\_\_c         | Currency  | Original amount            |
| `amountOpen`    | Account_Receivable\_\_c | Amount_Open\_\_c    | Currency  | Outstanding amount         |
| `invoiceStatus` | Account_Receivable\_\_c | Invoice_Status\_\_c | Picklist  | Status (Open, Paid, etc.)  |

#### Query Behavior

**Generated SOQL (conceptual):**

```sql
SELECT Id, External_Id__c, Document_Type__c, Receipt_Date__c,
       Due_Date__c, Amount__c, Amount_Open__c, Invoice_Status__c
FROM Account_Receivable__c
WHERE Account_Receivable__c.Account__c = :customerPKey
ORDER BY Receipt_Date__c ASC, External_Id__c ASC
```

**Parameters:**

-   `customerPKey` (TEXT): The Account Id to filter receivables by

**Key Characteristics:**

-   Custom object datasource (Account_Receivable\_\_c)
-   Read-only (`readOnly="true"`) - no modifications allowed
-   Filtered by relationship (Account\_\_c lookup field)
-   Ordered results (by date, then by external ID)
-   Suitable for list/collection displays

#### Order Criteria

```xml
<OrderCriterion entity="Account_Receivable__c" attribute="Receipt_Date__c" direction="ASC" />
<OrderCriterion entity="Account_Receivable__c" attribute="External_Id__c" direction="ASC" />
```

**Sort Order:**

1. Primary: Receipt Date (oldest first)
2. Secondary: External ID (alphabetical)

#### Read-Only Flag

`readOnly="true"` means:

-   Data cannot be modified through this datasource
-   No `INSERT`, `UPDATE`, or `DELETE` operations
-   Suitable for display-only data or calculated values

## DataSource Patterns

### Naming Conventions

| Pattern    | Description                                | Example                |
| ---------- | ------------------------------------------ | ---------------------- |
| `DsBo*`    | Business Object datasource (single entity) | DsBoAccount            |
| `DsLo*`    | List Object datasource (collection)        | DsLoAccountReceivables |
| `DsLu*`    | Lookup datasource (reference data)         | DsLuCustomer           |
| `*_sf`     | Salesforce backend                         | DsBoAccount_sf         |
| `*_sqlite` | SQLite backend                             | DsBoAccount_sqlite     |

### Parameter Usage

Parameters allow dynamic queries based on runtime context:

```xml
<Parameters>
  <Parameter name="pKey" type="TEXT" />
  <Parameter name="customerPKey" type="TEXT" />
  <Parameter name="fromDate" type="DATE" />
</Parameters>
```

Parameter types:

-   `TEXT` - String values
-   `DATE` - Date values
-   `DATETIME` - DateTime values
-   `INTEGER` - Numeric values
-   `BOOLEAN` - True/false values

### Query Conditions

Query conditions use parameter placeholders with `#paramName#` syntax:

```xml
<QueryCondition><![CDATA[
  Account_Receivable__c.Account__c = #customerPKey#
  AND Account_Receivable__c.Due_Date__c >= #fromDate#
]]></QueryCondition>
```

**SOQL Translation:**

```sql
WHERE Account__c = :customerPKey
  AND Due_Date__c >= :fromDate
```

### Entity Aliases

Aliases simplify complex queries with multiple tables:

```xml
<Entity name="Account_Receivable__c" alias="AR" idAttribute="Id" />
<Entity name="Account" alias="A" idAttribute="Id" />
```

Usage in query:

```xml
<QueryCondition><![CDATA[
  AR.Account__c = A.Id
  AND A.Type = 'Customer'
]]></QueryCondition>
```

## Salesforce Object Mapping

### Standard Objects

Common Salesforce standard objects used in datasources:

-   `Account` - Accounts (customers, partners)
-   `Contact` - Individual contacts
-   `Opportunity` - Sales opportunities
-   `Product2` - Products
-   `Pricebook2` - Price books
-   `User` - Salesforce users

### Custom Objects

Custom objects follow `*__c` naming convention:

-   `Account_Receivable__c`
-   `Visit__c`
-   `Promotion__c`
-   `Order_Item__c`

### Field Naming

Standard fields: `Name`, `Id`, `CreatedDate`, `LastModifiedDate`
Custom fields: `External_Id__c`, `Amount__c`, `Due_Date__c`

## DataSource to Salesforce Field Mapping

### DsBoAccount Field Mapping

| DS Attribute | SF Object | SF Field API Name | SF Field Type | Notes                |
| ------------ | --------- | ----------------- | ------------- | -------------------- |
| pKey         | Account   | Id                | ID(18)        | Salesforce record ID |
| name         | Account   | Name              | Text(255)     | Account name         |

**Missing Common Fields** (could be added):

-   AccountNumber
-   Type
-   Industry
-   Phone
-   BillingAddress
-   ShippingAddress
-   OwnerId
-   ParentId

### DsLoAccountReceivables Field Mapping

| DS Attribute  | SF Object               | SF Field API Name   | SF Field Type | Notes          |
| ------------- | ----------------------- | ------------------- | ------------- | -------------- |
| pKey          | Account_Receivable\_\_c | Id                  | ID(18)        | Record ID      |
| externalId    | Account_Receivable\_\_c | External_Id\_\_c    | Text          | ERP system ID  |
| documentType  | Account_Receivable\_\_c | Document_Type\_\_c  | Picklist      | Invoice type   |
| receiptDate   | Account_Receivable\_\_c | Receipt_Date\_\_c   | Date          | Creation date  |
| dueDate       | Account_Receivable\_\_c | Due_Date\_\_c       | Date          | Payment due    |
| amount        | Account_Receivable\_\_c | Amount\_\_c         | Currency      | Total amount   |
| amountOpen    | Account_Receivable\_\_c | Amount_Open\_\_c    | Currency      | Outstanding    |
| invoiceStatus | Account_Receivable\_\_c | Invoice_Status\_\_c | Picklist      | Payment status |

**Relationship Fields:**

-   Account_Receivable**c.Account**c -> Account.Id (Master-Detail or Lookup)

## DataSource Lifecycle

### 1. Datasource Definition (Design Time)

Developer creates XML datasource file:

```
src/Visit/DS/DsBoAccount_sf.datasource.xml
```

### 2. Build Process (Compile Time)

Modeler plugin compiles datasource:

```bash
sf mdl build
```

Output: `appl/build/app/clockwork/dataSource/DsBoAccount.js`

### 3. Runtime Execution (Mobile App)

When a Business Object loads:

1. BO references datasource: `<DataSource name="DsBoAccount" />`
2. DS generates SOQL query with parameters
3. Query executes against local SQLite (synced from Salesforce)
4. Results map to BO attributes via DS attribute definitions
5. BO populates with data

## DataSource Best Practices

### 1. Attribute Naming

-   Use camelCase for DS attributes: `externalId`, `receiptDate`
-   Match naming to BO properties for clarity
-   Prefix with context if ambiguous: `accountName`, `contactName`

### 2. Query Performance

-   Include only needed fields in Attributes
-   Use indexes in QueryCondition (Id, lookup fields)
-   Limit result sets with appropriate conditions
-   Use OrderCriteria only when needed

### 3. Parameter Design

-   Use strongly typed parameters (TEXT, DATE, etc.)
-   Validate parameters in BO business logic before DS call
-   Provide meaningful parameter names

### 4. Read-Only vs Editable

-   Set `readOnly="true"` for calculated/aggregated data
-   Use `editableEntity` to specify write target
-   Consider data ownership for custom objects

### 5. Backend Selection

-   Use `sf` for Salesforce native queries
-   Use `sqlite` for local-only queries (synced data)
-   Leverage SQLite for complex joins and filtering

## Common DataSource Patterns

### Pattern 1: Single Entity Lookup

```xml
<!-- Load one record by primary key -->
<QueryCondition><![CDATA[
  Account.Id = #pKey#
]]></QueryCondition>
<Parameters>
  <Parameter name="pKey" type="TEXT" />
</Parameters>
```

### Pattern 2: Parent-Child Relationship

```xml
<!-- Load child records for a parent -->
<QueryCondition><![CDATA[
  Order_Item__c.Order__c = #orderPKey#
]]></QueryCondition>
<Parameters>
  <Parameter name="orderPKey" type="TEXT" />
</Parameters>
```

### Pattern 3: Date Range Filter

```xml
<!-- Load records within date range -->
<QueryCondition><![CDATA[
  Visit__c.Visit_Date__c >= #fromDate#
  AND Visit__c.Visit_Date__c <= #toDate#
]]></QueryCondition>
<Parameters>
  <Parameter name="fromDate" type="DATE" />
  <Parameter name="toDate" type="DATE" />
</Parameters>
```

### Pattern 4: Multi-Criteria Filter

```xml
<!-- Complex filtering -->
<QueryCondition><![CDATA[
  Account_Receivable__c.Account__c = #accountId#
  AND Account_Receivable__c.Invoice_Status__c = 'Open'
  AND Account_Receivable__c.Amount_Open__c > 0
]]></QueryCondition>
```

## Integration Points

### DataSource to Business Object

Business Objects reference datasources:

```xml
<BusinessObject name="BoAccount" schemaVersion="1.1">
  <DataSource name="DsBoAccount" />
  <SimpleProperties>
    <SimpleProperty name="pKey" type="DomPKey" dataSourceProperty="pKey" />
    <SimpleProperty name="name" type="DomText" dataSourceProperty="name" />
  </SimpleProperties>
</BusinessObject>
```

**Mapping:**

-   BO property `dataSourceProperty` attribute -> DS `Attribute name`
-   DS attribute `column` -> Salesforce field API name

### DataSource to ListObject

List Objects reference datasources for collections:

```xml
<ListObject name="LoAccountReceivables" schemaVersion="1.1">
  <DataSource name="DsLoAccountReceivables" />
  <ItemProperties>
    <ItemProperty name="pKey" type="DomPKey" dataSourceProperty="pKey" />
    <ItemProperty name="amount" type="DomCurrency" dataSourceProperty="amount" />
  </ItemProperties>
</ListObject>
```

## Key Takeaways

1. **DataSources are declarative mappings** from Salesforce objects to application attributes
2. **Naming convention** indicates usage: DsBo* (single), DsLo* (list), DsLu\* (lookup)
3. **Parameters enable dynamic queries** based on runtime context
4. **Backend system** specifies data source: `sf` (Salesforce), `sqlite` (local)
5. **Query conditions** use `#paramName#` placeholders for safe parameterization
6. **Order criteria** controls result sorting for lists
7. **Read-only flag** prevents modifications for display-only data
8. **Attribute mappings** are 1:1 between DS attributes and Salesforce fields

## Files Referenced

| File Path                                            | Purpose                                 |
| ---------------------------------------------------- | --------------------------------------- |
| src/Visit/DS/DsBoAccount_sf.datasource.xml           | Simple Account datasource               |
| src/Call/DS/DsLoAccountReceivables_sf.datasource.xml | Account Receivables list datasource     |
| src/Visit/BO/BoAccount/BoAccount.businessobject.xml  | Business Object referencing DsBoAccount |

---

_This documentation is maintained by the Modeler CLI plugin and refreshed on workspace upgrade._
