# Models

> Learn how to define data structures using models in Taxi, and understand the distinction between models and types

Source: https://taxilang.org/docs/language/models

## Overview

Models in Taxi describe the data structures that your systems actually work with - the JSON (or other format) returned 
from API calls, database records, event payloads, and so on.

```taxi
// This might be the JSON response from GET /api/customers/123
model Customer {
    id: CustomerId
    firstName: FirstName  
    lastName: LastName
    email: EmailAddress
    createdAt: Timestamp
}
```
What makes Taxi models special is that they're built from semantic types, 
which gives meaning to each field. This allows consumers to query for exactly the data they need,
regardless of how the original structure is organized.

> **Note: Consumer Data Contracts**
>
> Producers publish models composed of semantic types, but consumers can query for just the data they need using projections. This decouples consumers from the producer's specific model structure.

## Basic syntax

```taxi
// Producer publishes a model
model CustomerRecord {
    id: CustomerId
    profile: UserProfile
    accountStatus: AccountStatus
    createdAt: Timestamp
}

// Consumer queries with their own data contract
find { CustomerRecord } as {
    customerId: CustomerId
    status: AccountStatus
    // Only the fields the consumer needs
}
```

**Things to note**
 * Model fields are composed of semantic types that convey meaning
 * The `?` operator marks fields as optional (nullable)
 * Arrays are declared using `[]` syntax after the type
 * Comments use `//` for single lines or `/* */` for blocks

## Parameter and closed models

By default, when you run a TaxiQL query, the query engine will try to construct any model it needs by combining available data and calling services to populate missing fields. This automatic construction happens at query time.

Often this isn't what you want. The `parameter` and `closed` modifiers control when and how the TaxiQL engine can construct models.

### Default behavior (consumer models)

Without any modifiers, models are "consumer models" - the TaxiQL engine will actively try to construct them:

```taxi
model CustomerSummary {
    id: CustomerId
    name: CustomerName
    email: EmailAddress
    orderCount: OrderCount
}

// During query execution, TaxiQL might:
find { Customer } as CustomerSummary
// 1. Get CustomerId, CustomerName, EmailAddress from Customer
// 2. Call a service to get OrderCount using the CustomerId
// 3. Construct the CustomerSummary with all fields populated
```

This automatic construction is powerful for data integration, but sometimes inappropriate.

### Parameter models

Use `parameter` for models that represent input to operations. The TaxiQL engine can only construct these when preparing to call a service:

```taxi
parameter model CreateCustomerRequest {
    firstName: FirstName
    lastName: LastName
    email: EmailAddress
}

service CustomerService {
    operation createCustomer(CreateCustomerRequest): Customer
}

// TaxiQL can construct CreateCustomerRequest, but only to call createCustomer
// It won't try to construct this model for general querying
```

**Parameter models are constructed:**
- When TaxiQL needs to call an operation that requires them as input
- From available data that matches the required fields

**Parameter models are NOT constructed:**
- For general query results or projections

### Closed models

Use `closed` for models that can only be returned from services, never constructed by combining data:

```taxi
closed model CustomerRecord {
    id: CustomerId               // System-generated
    name: CustomerName
    internalScore: InternalScore // Calculated by the system
    lastModified: Timestamp      // System-managed
}

service CustomerService {
    operation getCustomer(CustomerId): CustomerRecord
}

// TaxiQL will NEVER try to construct CustomerRecord
// It can only get instances by calling getCustomer()
```

**Closed models:**
- Can only be obtained by calling services that return them
- Are never constructed by combining fields from other sources
- Prevent unwanted automatic construction of system-managed data

### Parameter closed models

Some models serve as both input and output, needing both modifiers:

```taxi
parameter closed model Customer {
    id: CustomerId?          // Optional for creates, required for updates
    name: CustomerName
    email: EmailAddress
}

service CustomerDatabase {
    operation insertCustomer(Customer): CustomerId    // Customer as parameter
    operation updateCustomer(Customer): Customer      // Customer as parameter  
    operation findCustomer(CustomerId): Customer      // Customer as closed result
}

// TaxiQL can construct Customer, but only:
// - As input when calling insertCustomer or updateCustomer
// - Never for general querying (closed prevents this)
```

### Model types summary

| Model Type         | TaxiQL Construction Behavior                                         |
|--------------------|----------------------------------------------------------------------|
| Default (consumer) | Constructs freely for queries by combining data and calling services |
| `parameter`        | Only constructs when needed as input to operations                   |
| `closed`           | Never constructs - only obtains from service calls                   |
| `parameter closed` | Only constructs as operation input, never for general queries        |

> **Note: Query-Time Construction**
>
> Model construction happens during query execution, not at compile time. The TaxiQL engine decides whether and how to construct models based on these modifiers and the available data sources.

## Partial Models

A partial model creates a new type where all fields from an existing model become optional. This is particularly useful for PATCH operations in REST APIs, where you want to update only specific fields of a resource.

### Basic Usage

```taxi
model Person {
   name: Name inherits String
   age: Age inherits Int
}

partial model PartialPerson from Person
```

The generated `PartialPerson` will have all fields made optional (nullable):
```taxi
model PartialPerson {
   name: Name?
   age: Age?
}
```

### Nested types in partials

When a model contains references to other models or arrays, the compiler automatically creates partial versions of those types too:

```taxi
model Pet {
   name: PetName inherits String
   age: Age inherits Int
   parent: Pet            // Self-referential field
}

model Person {
   name: Name inherits String
   pet: Pet              // Reference to another model
   deadPets: Pet[]       // Array of models
}

partial model PartialPerson from Person
```

This expands to:
```taxi
model PartialPerson { 
   name: Name?           // Primitive types become nullable
   pet: PartialPet?     // Model references become partial and nullable
   deadPets: PartialPet[]?  // Arrays become nullable arrays of partial types
}

model PartialPet {
   name: PetName?
   age: Age?
   parent: PartialPet?   // Self-references become partial too
}
```

### Inheritance and Modifiers

Partial models:
- Do not inherit from their reference type
- Inherit all annotations and modifiers from the reference type
- Can add new annotations and modifiers
- Cannot modify the structure beyond making fields optional
- Cannot be declared as `closed` (the compiler will remove any `closed` modifiers on the created Partial model)

Example with additional modifiers:
```taxi
model Person {
   name: Name inherits String
}

@OmitNulls
partial parameter model PartialPerson from Person
```

## Field types

### Basic fields

```taxi
model Customer {
    // Required fields
    id: CustomerId
    name: CustomerName
    
    // Optional field
    nickname: Nickname?
    
    // Array field
    orders: Order[]
    
    // Map field
    preferences: Map<PreferenceKey, PreferenceValue>
}
```

### Nested objects

```taxi
model Order {
    orderId: OrderId
    
    // Inline object definition
    address: {
        street: StreetAddress
        city: City
        country: CountryCode
    }
    
    // Alternative: reference a defined model
    shippingAddress: Address
}
```

### Inheritance

While possible, model inheritance should be used sparingly:

```taxi
model PersonBase {
    id: PersonId
    firstName: FirstName
    lastName: LastName
}

model Employee inherits PersonBase {
    employeeId: EmployeeId
    department: DepartmentName
}
```

> **Warning: Model Inheritance**
>
> Prefer composition over inheritance for models. Inheritance can create tight coupling between models, which goes against Taxi's principle of loose coupling.

## Best practices
Models are typically defined by producing systems - such as REST APIs, databases, 
or message queues.

The best practices here focus on describing those models using Taxi, rather than
the practices of designing good APIs or event payloads.

### Use semantic types

```taxi
// Good - uses semantic types
model Customer {
    id: CustomerId
    email: EmailAddress
}

// Bad - uses primitive types
model Customer {
    id: String      // What kind of ID?
    email: String   // Is this really an email?
}
```

### Document nullability

```taxi
model User {
    // Required fields - core identity
    id: UserId
    email: EmailAddress
    
    // Optional fields - additional information
    middleName: MiddleName?
    phoneNumber: PhoneNumber?
}
```

### Organization

```taxi
// Service-specific models together
model CreateOrderRequest {
    customerId: CustomerId
    items: OrderItem[]
}

model CreateOrderResponse {
    orderId: OrderId
    status: OrderStatus
}

// Service definition with its models
service OrderService {
    operation createOrder(CreateOrderRequest): CreateOrderResponse
}
```
