model-views 0.1.1

Type-safe view types for different access modes (Get, Create, Patch) on data models
Documentation
# model-views

[![Crates.io](https://img.shields.io/crates/v/model-views.svg)](https://crates.io/crates/model-views)
[![Documentation](https://docs.rs/model-views/badge.svg)](https://docs.rs/model-views)
[![License: EUPL-1.2](https://img.shields.io/badge/License-EUPL--1.2-blue.svg)](https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12)
[![Rust Version](https://img.shields.io/badge/rust-1.90%2B-orange.svg)](https://www.rust-lang.org)

Type-safe view types for different access modes on data models.

This library automatically generates specialized view types for Get, Create, and Patch operations from your model structs. Each view type only includes the fields relevant to that operation, enforcing API contracts at compile time and reducing boilerplate.

## Key Features

- **Type Safety**: Different operations use different types, catching errors at compile time
- **Reduced Boilerplate**: Automatically generates DTOs from model definitions
- **Explicit Updates**: `Patch<T>` type makes update intent clear
- **Serde Integration**: Optional serialization/deserialization support
- **Nested Models**: Works seamlessly with nested structures
- **Generic Support**: Handles generic types and where clauses

## Usage

Add this to your `Cargo.toml`:

```toml
[dependencies]
model-views = "0.1"
```

### Basic Example

```rust
use model_views::{Views, Patch};

#[derive(Views)]
#[views(serde)]
struct User {
    // ID is read-only, generated by the system
    #[views(get = "required", create = "forbidden", patch = "forbidden")]
    id: u64,
    
    // Name is required for all operations
    #[views(get = "required", create = "required", patch = "required")]
    name: String,
    
    // Email is optional
    #[views(get = "optional", create = "optional", patch = "optional")]
    email: Option<String>,
}

// Reading a user
let user = UserGet {
    id: 1,
    name: "Alice".to_string(),
    email: Some("alice@example.com".to_string()),
};

// Creating a new user (no ID field)
let create = UserCreate {
    name: "Bob".to_string(),
    email: None,
};

// Updating a user (only specify changed fields)
let patch = UserPatch {
    name: Patch::Update("Charlie".to_string()),
    email: Patch::Ignore, // Don't change email
};
```

### Field Policies

Control field visibility in each view mode:

#### Get Mode

- `get = "required"` - Field is always present (default)
- `get = "optional"` - Field is wrapped in `Option<T>`
- `get = "forbidden"` - Field is excluded

#### Create Mode

- `create = "required"` - Field must be provided (default)
- `create = "optional"` - Field is wrapped in `Option<T>`
- `create = "forbidden"` - Field is excluded

#### Patch Mode

- `patch = "required"` - Field is wrapped in `Patch<T>` (default)
- `patch = "optional"` - Field is wrapped in `Patch<Option<T>>`
- `patch = "forbidden"` - Field is excluded

### Nested Models

```rust
#[derive(Views)]
struct Article {
    #[views(get = "required", create = "forbidden", patch = "forbidden")]
    id: u64,
    
    #[views(get = "required", create = "required", patch = "required")]
    title: String,
    
    // Nested view types are automatically handled
    #[views(get = "required", create = "forbidden", patch = "optional")]
    author: User,
}
```

### The Patch Type

The `Patch<T>` enum makes update intent explicit:

```rust
use model_views::Patch;

// Explicitly ignore a field
let no_change = Patch::Ignore;

// Update a field to a new value
let update = Patch::Update("new value".to_string());

// Convert to/from Option
let opt: Option<String> = update.into();
let patch: Patch<String> = Some("value".to_string()).into();
```

## Cargo Features

The following cargo features are available:

- `derive` (default) - Enables the `#[derive(Views)]` macro
- `serde` - Adds `Serialize`/`Deserialize` support for `Patch<T>`
- `uuid` - Implements `View` for `uuid::Uuid`
- `chrono` - Implements `View` for `chrono::DateTime<Utc>`

## Use Cases

This library is particularly useful for:

- REST API request/response types
- GraphQL input/output types
- Database model transformations
- Form validation and submission
- Any scenario where different operations require different field sets

## License

Licensed under the European Union Public Licence (EUPL), Version 1.2.