/*!
Base requirements for indexable document mappings.

Structures that can be indexed in Elasticsearch should implement `DocumentType`.
The `DocumentType` is composed of typical mapping metadata, as well as the mapping
for each of its properties.

Documents can be mapped as indexable types, or as an object field on another type.

# Examples

Define your Elasticsearch types using _Plain Old Rust Structures_.

## Derive Mapping

Mapping can be generated by deriving `ElasticType` on a struct:

```
# #[macro_use]
# extern crate json_str;
# #[macro_use]
# extern crate serde_derive;
# #[macro_use]
# extern crate elastic_types_derive;
# #[macro_use]
# extern crate elastic_types;
# extern crate serde;
# use elastic_types::prelude::*;
#[derive(Serialize, ElasticType)]
pub struct MyType {
    pub my_date: Date<DefaultDateMapping>,
    pub my_string: String,
    pub my_num: i32
}
# fn main() {
# }
```

This will produce the following field mapping:

```
# #[macro_use]
# extern crate json_str;
# #[macro_use]
# extern crate serde_derive;
# #[macro_use]
# extern crate elastic_types_derive;
# #[macro_use]
# extern crate elastic_types;
# extern crate serde;
# extern crate serde_json;
# use elastic_types::prelude::*;
# #[derive(Serialize, ElasticType)]
# pub struct MyType {
#   pub my_date: Date<DefaultDateMapping>,
#   pub my_string: String,
#   pub my_num: i32
# }
# fn main() {
# let mapping = elastic_types::derive::standalone_field_ser(MyTypeMapping).unwrap();
# let json = json_str!(
{
    "type": "nested",
    "properties": {
        "my_date": {
            "type": "date",
            "format": "basic_date_time"
        },
        "my_string": {
            "type": "text",
            "fields": {
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "my_num": {
            "type": "integer"
        }
    }
}
# );
# assert_eq!(json, mapping);
# }
```

It's also possible to adjust the mapping using the `#[elastic]` attribute.

### Override Default Mapping Properties

You can override the mapping meta properties for an object by providing your own mapping type with `#[elastic(mapping="{TypeName}")]`:

```
# #[macro_use]
# extern crate json_str;
# #[macro_use]
# extern crate serde_derive;
# #[macro_use]
# extern crate elastic_types_derive;
# #[macro_use]
# extern crate elastic_types;
# extern crate serde;
# use elastic_types::prelude::*;
#[derive(Serialize, ElasticType)]
#[elastic(mapping="MyTypeMapping")]
pub struct MyType {
    pub my_date: Date<DefaultDateMapping>,
    pub my_string: String,
    pub my_num: i32
}

#[derive(Default)]
pub struct MyTypeMapping;
impl DocumentMapping for MyTypeMapping {
    //Give your own name to a type
    fn name() -> &'static str { "my_type" }

    fn data_type() -> &'static str { OBJECT_DATATYPE }
}
# fn main() {
# }
```

This will produce the following field mapping:

```
# #[macro_use]
# extern crate json_str;
# #[macro_use]
# extern crate serde_derive;
# #[macro_use]
# extern crate elastic_types_derive;
# #[macro_use]
# extern crate elastic_types;
# extern crate serde;
# extern crate serde_json;
# use elastic_types::prelude::*;
# #[derive(Default, Serialize, Deserialize, ElasticType)]
# #[elastic(mapping="MyTypeMapping")]
# pub struct MyType {
#   pub my_date: Date<DefaultDateMapping>,
#   pub my_string: String,
#   pub my_num: i32
# }
#
# #[derive(Default)]
# pub struct MyTypeMapping;
# impl DocumentMapping for MyTypeMapping {
#   fn name() -> &'static str { "my_type" }
#   fn data_type() -> &'static str { OBJECT_DATATYPE }
# }
# fn main() {
# let mapping = elastic_types::derive::standalone_field_ser(MyTypeMapping).unwrap();
# let json = json_str!(
{
    "type": "object",
    "properties": {
        "my_date": {
            "type": "date",
            "format": "basic_date_time"
        },
        "my_string": {
            "type": "text",
            "fields": {
                "keyword":{
                    "type":"keyword",
                    "ignore_above":256
                }
            }
        },
        "my_num": {
            "type": "integer"
        }
    }
}
# );
# assert_eq!(json, mapping);
# }
```

### Ignore or Rename Fields

You can then serialise type mappings with `#[serde]` attributes:

```
# #[macro_use]
# extern crate json_str;
# #[macro_use]
# extern crate serde_derive;
# #[macro_use]
# extern crate elastic_types_derive;
# #[macro_use]
# extern crate elastic_types;
# extern crate serde;
# use elastic_types::prelude::*;
#[derive(ElasticType, Serialize)]
pub struct MyType {
    #[serde(rename="my_renamed_date")]
    pub my_date: Date<DefaultDateMapping>,
    #[serde(skip_serializing)]
    pub ignored: String,
    pub my_num: i32
}
# fn main() {
# }
```

> NOTE: Fields with a `#[serde(skip_deserializing)]` attribute will still be mapped, because they can
still be indexed in Elasticsearch.

## Limitations

Automatically deriving mapping has the following limitations:

- Generics aren't supported by auto deriving.
So you can't `#[derive(ElasticType)]` on `MyType<T>`.
- Mapping types can't be shared. This is because they need to map the type fields, so are specific to that type.
So you can't share `MyTypeMapping` between `MyType` and `MyOtherType`.

# Links
- [Field Types](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html)
- [Document Types](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html)
*/

pub mod mapping;

mod impls;
pub use self::impls::*;

pub mod prelude {
    /*!
    Includes all types for document types.
    
    This is a convenience module to make it easy to build mappings for multiple types without too many `use` statements.
    */

    pub use super::impls::*;
    pub use super::mapping::*;
}
