> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# What is a Model?

> Understanding the role and structure of Sonamu Model

Model is a core layer of Sonamu that handles business logic and data access. Based on Entity definitions, it provides database queries, API endpoints, and type-safe data processing.

## Role of Model

<CardGroup cols={2}>
  <Card title="Data Access" icon="database">
    Database CRUD operations Type-safe queries through Puri query builder
  </Card>

  <Card title="Business Logic" icon="code">
    Implementing domain rules Data validation, transformation, calculation
  </Card>

  <Card title="API Endpoints" icon="globe">
    Automatic HTTP API generation REST API provided via @api decorator
  </Card>

  <Card title="Type Safety" icon="shield-check">
    Compile-time type checking Auto-generated types based on Entity
  </Card>
</CardGroup>

## Position in Sonamu Architecture

```mermaid theme={null}
flowchart TD
    Client[Client/Frontend]
    API[API Layer]
    Model[Model Layer]
    DB[(Database)]

    Client -->|HTTP Request| API
    API -->|@api decorator| Model
    Model -->|Puri Query| DB
    DB -->|Data| Model
    Model -->|Type-safe Response| API
    API -->|JSON| Client

    style Model fill:#4f46e5,color:#fff
```

**Layer Structure**:

1. **Client** - Frontend (React, Vue, etc.)
2. **API Layer** - HTTP endpoints (@api decorator)
3. **Model Layer** - Business logic ⭐
4. **Database** - PostgreSQL

<Info>
  Model is the **business logic layer** between API Layer and Database. All data access and business
  rules are handled in Model.
</Info>

## Model Class Structure

### Basic Structure

```typescript title="user.model.ts" theme={null}
import { BaseModelClass, api } from "sonamu";
import type { UserSubsetKey, UserSubsetMapping } from "../sonamu.generated";
import { userLoaderQueries, userSubsetQueries } from "../sonamu.generated.sso";

class UserModelClass extends BaseModelClass<
  UserSubsetKey, // "A" | "P" | "SS"
  UserSubsetMapping, // Type for each subset
  typeof userSubsetQueries, // Subset query functions
  typeof userLoaderQueries // Loader query functions
> {
  constructor() {
    super("User", userSubsetQueries, userLoaderQueries);
  }

  @api({ httpMethod: "GET" })
  async findById(id: number): Promise<UserSubsetMapping["A"]> {
    // Business logic implementation
  }
}

export const UserModel = new UserModelClass();
```

### Generic Type Parameters

| Parameter        | Description                    | Example                  |
| ---------------- | ------------------------------ | ------------------------ |
| `TSubsetKey`     | Union type of Subset keys      | `"A" \| "P" \| "SS"`     |
| `TSubsetMapping` | Result type mapping per Subset | `{ A: UserA, P: UserP }` |
| `TSubsetQueries` | Subset query function type     | Auto-generated           |
| `TLoaderQueries` | Loader query type              | Auto-generated           |

<Tip>
  These generic types are automatically generated in `sonamu.generated.ts` and
  `sonamu.generated.sso.ts`, so you don't need to write them manually.
</Tip>

## Model vs Entity vs Types

Let's clarify commonly confused concepts in Sonamu:

| Category             | Entity                     | Types                 | Model                 |
| -------------------- | -------------------------- | --------------------- | --------------------- |
| **File**             | `{entity}.entity.json`     | `{entity}.types.ts`   | `{entity}.model.ts`   |
| **Role**             | Data structure definition  | Type definition       | Business logic        |
| **Creation**         | Manual (Sonamu UI)         | Auto-generated        | Manual (Scaffold)     |
| **Content**          | Tables, columns, relations | TypeScript types, Zod | Methods, API, queries |
| **Change frequency** | Low                        | Auto-regenerated      | High                  |

**Examples**:

<CodeGroup>
  ```json title="user.entity.json (Entity)" theme={null}
  {
    "id": "User",
    "table": "users",
    "props": [
      { "name": "id", "type": "integer" },
      { "name": "email", "type": "string" }
    ]
  }
  ```

  ```typescript title="user.types.ts (Types - auto-generated)" theme={null}
  export type User = {
    id: number;
    email: string;
  };

  export type UserSubsetA = User;
  ```

  ```typescript title="user.model.ts (Model)" theme={null}
  class UserModelClass extends BaseModelClass {
    async findById(id: number): Promise<User> {
      // Business logic
      const user = await this.getPuri("r").from("users").where("id", id).first();
      return user;
    }
  }
  ```
</CodeGroup>

## Features Provided by Model

### 1. Type-Safe Data Access

```typescript theme={null}
// ✅ Type safe: type inference based on subset
const user = await UserModel.findById("A", 1);
// user type: UserSubsetMapping["A"]

// ✅ Compile error: invalid subset
const user = await UserModel.findById("INVALID", 1);
//                                      ^^^^^^^^^
// Error: Argument of type '"INVALID"' is not assignable
```

### 2. Subset-Based Queries

```typescript theme={null}
async findMany<T extends UserSubsetKey>(
  subset: T,
  params: UserListParams
): Promise<ListResult<UserSubsetMapping[T]>> {
  const { qb } = this.getSubsetQueries(subset);

  // Automatically SELECT only fields matching the subset
  qb.where("id", params.id);

  return this.executeSubsetQuery({ subset, qb, params });
}
```

<Info>
  Subsets reduce network traffic and improve performance by selecting only the fields needed for API
  responses.
</Info>

### 3. Automatic API Generation

```typescript theme={null}
@api({ httpMethod: "GET", clients: ["axios", "tanstack-query"] })
async findById(id: number): Promise<User> {
  // Method implementation
}
```

**What gets auto-generated**:

* HTTP endpoint: `GET /user/findById?id=1`
* TypeScript client code
* TanStack Query hooks
* API documentation

### 4. Transaction Management

```typescript theme={null}
@transactional()
async updateUserAndProfile(
  userId: number,
  userData: UserData,
  profileData: ProfileData
): Promise<void> {
  // All operations execute in a single transaction
  await this.save([userData]);
  await ProfileModel.save([profileData]);
  // Auto commit or rollback
}
```

### 5. Data Validation and Transformation

```typescript theme={null}
async save(params: UserSaveParams[]): Promise<number[]> {
  // Business rule validation
  for (const param of params) {
    if (param.age && param.age < 18) {
      throw new BadRequestException("Users under 18 cannot register");
    }
  }

  // Data transformation
  const hashedParams = params.map(p => ({
    ...p,
    password: bcrypt.hashSync(p.password, 10)
  }));

  // Save
  return this.getPuri("w").ubUpsert("users", hashedParams);
}
```

## Model Writing Patterns

### CRUD Methods

A typical Model provides the following CRUD methods:

```typescript theme={null}
class UserModelClass extends BaseModelClass {
  // Create
  @api({ httpMethod: "POST" })
  async save(params: UserSaveParams[]): Promise<number[]> {
    // ...
  }

  // Read
  @api({ httpMethod: "GET" })
  async findById(id: number): Promise<User> {
    // ...
  }

  @api({ httpMethod: "GET" })
  async findMany(params: UserListParams): Promise<ListResult<User>> {
    // ...
  }

  // Update
  @api({ httpMethod: "PUT" })
  async update(id: number, params: UserUpdateParams): Promise<User> {
    // ...
  }

  // Delete
  @api({ httpMethod: "DELETE" })
  async del(ids: number[]): Promise<number> {
    // ...
  }
}
```

### Domain-Specific Methods

You can add methods specialized for business domains:

```typescript theme={null}
class UserModelClass extends BaseModelClass {
  @api({ httpMethod: "POST" })
  async login(params: LoginParams): Promise<{ user: User }> {
    // Login logic
  }

  @api({ httpMethod: "POST" })
  async logout(): Promise<{ message: string }> {
    // Logout logic
  }

  @api({ httpMethod: "GET" })
  async me(): Promise<User | null> {
    // Current user info
  }

  @api({ httpMethod: "POST" })
  async changePassword(params: ChangePasswordParams): Promise<void> {
    // Password change
  }
}
```

## BaseModel Methods

`BaseModelClass` provides the following utility methods:

| Method                       | Description              | Return Type        |
| ---------------------------- | ------------------------ | ------------------ |
| `getDB(preset)`              | Get database connection  | `Knex`             |
| `getPuri(preset)`            | Get Puri query builder   | `PuriWrapper`      |
| `getSubsetQueries(subset)`   | Get Subset query builder | `{ qb, onSubset }` |
| `executeSubsetQuery(params)` | Execute Subset query     | `ListResult`       |
| `createEnhancers(enhancers)` | Enhancer creation helper | `EnhancerMap`      |

<Info>
  **Learn More** - [BaseModel Methods](/en/core-concepts/model/basemodel-methods) - Detailed method
  guide
</Info>

## Advantages of Model

<AccordionGroup>
  <Accordion title="Type Safety">
    TypeScript types are auto-generated based on Entity definitions, allowing errors to be caught at compile time.

    ```typescript theme={null}
    // ✅ Type check
    const user: UserSubsetMapping["A"] = await UserModel.findById("A", 1);

    // ❌ Compile error
    user.nonExistentField;
    ```
  </Accordion>

  <Accordion title="Code Reuse">
    Write common logic as Model methods and reuse across multiple APIs.

    ```typescript theme={null}
    // Model method
    async findActiveUsers(): Promise<User[]> {
      return this.getPuri("r").from("users").where("is_active", true);
    }

    // Reuse in multiple APIs
    @api()
    async api1() {
      return this.findActiveUsers();
    }

    @api()
    async api2() {
      const users = await this.findActiveUsers();
      // Additional logic...
    }
    ```
  </Accordion>

  <Accordion title="Testability">
    Models can be tested independently.

    ```typescript theme={null}
    describe("UserModel", () => {
      it("should find user by id", async () => {
        const user = await UserModel.findById("A", 1);
        expect(user.id).toBe(1);
      });
    });
    ```
  </Accordion>

  <Accordion title="Separation of Concerns">
    Clearly separates business logic (Model) from HTTP handling (Controller/API).

    * Model: Data processing, business rules
    * API: HTTP request/response, authentication, authorization
  </Accordion>
</AccordionGroup>

## Next Steps

After understanding the basic concepts of Model, learn the following topics:

<CardGroup cols={2}>
  <Card title="Creating Models" icon="plus" href="/en/core-concepts/model/creating-models">
    Creating Models and using Scaffold
  </Card>

  <Card title="API Decorator" icon="at" href="/en/core-concepts/model/api-decorator">
    Creating API endpoints with @api decorator
  </Card>

  <Card title="Business Logic" icon="lightbulb" href="/en/core-concepts/model/business-logic">
    Business logic writing patterns and examples
  </Card>

  <Card title="BaseModel Methods" icon="book" href="/en/core-concepts/model/basemodel-methods">
    Learn all methods provided by BaseModel
  </Card>
</CardGroup>
