# elastic-mapping
[](https://crates.io/crates/elastic-mapping)
[](https://docs.rs/elastic-mapping)
[](https://opensource.org/licenses/MIT)
Generate Elasticsearch mapping definitions from Rust structs and enums using derive macros.
## Features
- **Derive macro** for automatic mapping generation from Rust types
- **Serde compatibility** - respects `#[serde(rename)]`, `#[serde(rename_all)]`, `#[serde(flatten)]` and enum representations
- **Enum support** - handles externally tagged, internally tagged (`#[serde(tag = "...")]`), and adjacently tagged (`#[serde(tag = "...", content = "...")]`) enums
- **Field annotations** - configure analyzers, keyword fields, and other Elasticsearch-specific settings
- **Optional feature flags** - support for `chrono`, `url`, and `uuid` types
## Available Features
- `chrono` - Adds support for `chrono::DateTime<Utc>` (mapped as `date`)
- `url` - Adds support for `url::Url` (mapped as `text`)
- `uuid` - Adds support for `uuid::Uuid` (mapped as `text`)
- `full` - Enables all optional features
## Usage
### Basic Example
```rust
use elastic_mapping::{Document, MappingObject};
use serde::Serialize;
#[derive(Debug, Serialize, Document)]
struct BlogPost {
title: String,
content: String,
published: bool,
views: i64,
}
fn main() {
let mapping = BlogPost::document_mapping();
println!("{}", serde_json::to_string_pretty(mapping.inner()).unwrap());
}
```
Output:
```json
{
"mappings": {
"properties": {
"content": {
"type": "text"
},
"published": {
"type": "boolean"
},
"title": {
"type": "text"
},
"views": {
"type": "long"
}
}
}
}
```
### Field Annotations
```rust
use elastic_mapping::{Document, MappingObject};
#[derive(Debug, Document)]
struct Article {
#[document(analyzer = "english")]
title: String,
#[document(keyword(index = false))]
internal_id: String,
#[document(keyword(ignore_above = 256))]
category: String,
}
```
### Serde Compatibility
The macro respects serde attributes:
```rust
use elastic_mapping::{Document, MappingObject};
use serde::Serialize;
#[derive(Debug, Serialize, Document)]
#[serde(rename_all = "camelCase")]
struct UserProfile {
first_name: String,
last_name: String,
email_address: String,
}
// Field names will be mapped as: firstName, lastName, emailAddress
```
### Nested Structures
```rust
use elastic_mapping::{Document, MappingObject};
#[derive(Debug, Document)]
struct Address {
street: String,
city: String,
country: String,
}
#[derive(Debug, Document)]
struct User {
name: String,
address: Address,
tags: Vec<String>,
}
```
### Enum Support
#### Externally Tagged Enums
```rust
use elastic_mapping::{Document, MappingObject};
#[derive(Debug, Document)]
enum Event {
Created { id: String, timestamp: i64 },
Updated { id: String, changes: String },
Deleted { id: String },
}
```
#### Internally Tagged Enums
```rust
use elastic_mapping::{Document, MappingObject};
use serde::Serialize;
#[derive(Debug, Serialize, Document)]
#[serde(tag = "type")]
enum Message {
Text { content: String },
Image { url: String, width: u32, height: u32 },
}
```
#### Adjacently Tagged Enums
```rust
use elastic_mapping::{Document, MappingObject};
use serde::Serialize;
#[derive(Debug, Serialize, Document)]
#[serde(tag = "type", content = "data")]
enum Notification {
Email { to: String, subject: String },
SMS { phone: String, message: String },
Push { device_id: String, title: String },
}
```
### Flatten Support
```rust
use elastic_mapping::{Document, MappingObject};
use serde::Serialize;
#[derive(Debug, Serialize, Document)]
struct Metadata {
created_at: i64,
updated_at: i64,
}
#[derive(Debug, Serialize, Document)]
struct Document {
title: String,
content: String,
#[serde(flatten)]
metadata: Metadata,
}
// Fields created_at and updated_at will be flattened into Document
```
### With Optional Features
| `chrono::DateTime<Utc>` | `date` | `chrono` |
| `url::Url` | `text` | `url` |
| `uuid::Uuid` | `text` | `uuid` |
## Available Attributes
### Field-level `#[document(...)]` Attributes
- `analyzer = "analyzer_name"` - Sets the analyzer for a text field
- `keyword(index = bool)` - Adds a keyword subfield with index configuration
- `keyword(ignore_above = u32)` - Adds a keyword subfield with ignore_above setting
### Serde Attributes
The following serde attributes are respected:
- `#[serde(rename = "name")]` - Rename a field or variant
- `#[serde(rename_all = "case")]` - Rename all fields or variants (supports `camelCase`, `kebab-case`, `snake_case`, `SCREAMING_SNAKE_CASE`, etc.)
- `#[serde(flatten)]` - Flatten nested structure fields
- `#[serde(tag = "...")]` - Internally tagged enum representation
- `#[serde(tag = "...", content = "...")]` - Adjacently tagged enum representation
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.