# Examples

## Context for the following example

To demonstrate how the computed field works, consider this use case:

> **Goal**: Calculate the sales **over 12 months** for items in the **IT category** per user.

For simplicity, this example focuses on the **IT category**. However, the computed field can be scaled to compute the amount for all categories, not just IT.

In this scenario, the computed field will:

1. Aggregate the order amounts over the last 12 months.
2. Filter the data based on the **IT category** (or any other category, depending on the use case).

By scaling this approach, you can calculate the sales amount for multiple categories, ensuring flexibility and extensibility in your calculations.

## **Step 1: Define your context for the Datamart Function**

In this use case, we need to declare the **State**, **Result**, and **UserActivity** for computing the sales amount over the last 12 months for items in the **IT category**.

### **State Declaration**

The **State** stores the order amounts for each day, categorized by **IT** items, for the last 12 months. Here's how the state structure looks :

```typescript
export interface State {
  activities_for_the_last_12 _months: { 
    [date: number] : [{
      amount: number;
    }]
  }
}
```

The `activities_for_the_last_12_months` keeps the amount data for each day, where the `date` is represented by a numeric value (e.g., timestamp), and the `amount` is the total order value for that day.

### **Result Declaration**

The **Result** represents the total sales amount over the last 12 months for the **IT category**.

```typescript
export interface Result {
  IT_amount_for_the_last_12_months: number;
}
```

The result will return the computed `IT_amount_for_the_last_12_months` after summing up the values stored in the state.

### **UserActivity Declaration**

The **UserActivity** defines the structure of the activity that triggers the update. In this example, we focus on the items bought, particularly in the IT category.&#x20;

```typescript
interface Items {
    category: string;
    price: number;
}

interface UserActivity {
  items_bought: Items[];
}
```

The `items_bought` array contains details about each item, such as `category` (IT, for example) and `price`.

{% hint style="info" %}
To get some examples of your activity structure, you can look at the activity returned in the User lookup page in Navigator.&#x20;
{% endhint %}

## **Step 2: Declare your Computed Field class**

With the context declared, you can implement your computed field logic. Here's how the **MyComputedField** class looks:

```typescript
export class MyComputedField extends core.ComputedFieldPlugin<State, Result, UserActivity, UserProfile, ComputedField> { 
    constructor() { 
        super(); 
    }
 
    // Function to Update the state
    onUpdateActivity(state: State, userActivity: UserActivity): State { ... }
    
    // Won't be used but need to be declared;
    onUpdateUserProfile(state: State, userProfile: UserProfile, operation: core.Operation): State {
       return state;
    }

    // Won't be used but need to be declared;
    onUpdateComputedField(state: State, computedField: ComputedField): State {
        return state;
    }
  
    // Function to compute the Result
    buildResult(state: State | null): Result { ... }
}
```

### **onUpdateActivity**

* **Goal**: Update the state with new IT category purchases and remove activities older than 12 months.
  * It filters the UserActivity to ensure only IT items are included.
  * Removes old activities beyond the 12-month period.

{% hint style="info" %}
**Best practice:** Use the `Events filter` to exclude activities or profiles that are not relevant to your computed field, rather than adding a filter within your function.
{% endhint %}

### **buildResult**

* **Goal**: Sum all the basket amounts stored in the state and return the total.
  * It checks each stored activity date to ensure it is within the last 12 months and sums the `amount` for each IT purchase.

{% hint style="warning" %}
The `onUpdateActivity` function is triggered only when a new activity occurs. Therefore, you need to handle outdated activities within your function if the UserPoint does not receive a new event to update the State.
{% endhint %}

## **Step 3: Test your plugin**

Before deploying the plugin, create tests to ensure the function behaves as expected. Test cases might include:

* Adding new activities and verifying the state is updated correctly.
* Checking that old activities are purged.
* Validating that the correct basket amounts are returned in the result.

## **Step 4: Declare your Computed Field in the schema**

Once the computed field is implemented, you need to declare it in your schema as follows:

```graphql
type UserPoint {
  id: ID!
  accounts: [UserAccount]
  …
  IT_amount_for_the_last_12_months: Int! @ComputedField(technical_name = “IT_Amount”) @TreeIndex(index:"USER_INDEX")
}
```

This will link the computed field (`IT_amount_for_the_last_12_months`) to your schema, making it available for querying.

***

## **Handling Profile and Activity Information**

When working with **profile** and **activity** information:

Be mindful that the **computed field** needs to be **commutative** during the initial loading. For cases where UserProfile and UserActivity need to be aggregated, it might be necessary to store more information in the **State** to ensure consistency and accuracy during this phase.

**Example use-case: Basket amount by fidelity card**

During initial loading, if you need to track the basket amount for **current fidelity cards**, you may need to store all activities grouped by fidelity card in the state. This is because, until the initial loading completes, you may not know which fidelity cards are currently active for the user.
