//! This is an implementation the test factory pattern made to work with [Diesel][].
//!
//! [Diesel]: https://diesel.rs
//!
//! Example usage:
//!
//! ```
//! #[macro_use]
//! extern crate diesel;
//!
//! use diesel_factories::{Association, Factory};
//! use diesel::{pg::PgConnection, prelude::*};
//!
//! // Tell Diesel what our schema is
//! // Note unusual primary key name - see options for derive macro.
//! mod schema {
//! table! {
//! countries (identity) {
//! identity -> Integer,
//! name -> Text,
//! }
//! }
//!
//! table! {
//! cities (id) {
//! id -> Integer,
//! name -> Text,
//! country_id -> Integer,
//! }
//! }
//! }
//!
//! // Our city model
//! #[derive(Clone, Queryable)]
//! struct City {
//! pub id: i32,
//! pub name: String,
//! pub country_id: i32,
//! }
//!
//! #[derive(Clone, Factory)]
//! #[factory(
//! // model type our factory inserts
//! model = City,
//! // table the model belongs to
//! table = crate::schema::cities,
//! // connection type you use. Defaults to `PgConnection`
//! connection = diesel::pg::PgConnection,
//! // type of primary key. Defaults to `i32`
//! id = i32,
//! )]
//! struct CityFactory<'a> {
//! pub name: String,
//! // A `CityFactory` is associated to either an inserted `&'a Country` or a `CountryFactory`
//! // instance.
//! pub country: Association<'a, Country, CountryFactory>,
//! }
//!
//! // We make new factory instances through the `Default` trait
//! impl<'a> Default for CityFactory<'a> {
//! fn default() -> Self {
//! Self {
//! name: "Copenhagen".to_string(),
//! // `default` will return an `Association` with a `CountryFactory`. No inserts happen
//! // here.
//! //
//! // This is the same as `Association::Factory(CountryFactory::default())`.
//! country: Association::default(),
//! }
//! }
//! }
//!
//! // The same setup, but for `Country`
//! #[derive(Clone, Queryable)]
//! struct Country {
//! pub identity: i32,
//! pub name: String,
//! }
//!
//! #[derive(Clone, Factory)]
//! #[factory(
//! model = Country,
//! table = crate::schema::countries,
//! connection = diesel::pg::PgConnection,
//! id = i32,
//! id_name = identity,
//! )]
//! struct CountryFactory {
//! pub name: String,
//! }
//!
//! impl Default for CountryFactory {
//! fn default() -> Self {
//! Self {
//! name: "Denmark".into(),
//! }
//! }
//! }
//!
//! // Usage
//! fn basic_usage() {
//! let con = establish_connection();
//!
//! let city = CityFactory::default().insert(&con);
//! assert_eq!("Copenhagen", city.name);
//!
//! let country = find_country_by_id(city.country_id, &con);
//! assert_eq!("Denmark", country.name);
//!
//! assert_eq!(1, count_cities(&con));
//! assert_eq!(1, count_countries(&con));
//! }
//!
//! fn setting_fields() {
//! let con = establish_connection();
//!
//! let city = CityFactory::default()
//! .name("Amsterdam")
//! .country(CountryFactory::default().name("Netherlands"))
//! .insert(&con);
//! assert_eq!("Amsterdam", city.name);
//!
//! let country = find_country_by_id(city.country_id, &con);
//! assert_eq!("Netherlands", country.name);
//!
//! assert_eq!(1, count_cities(&con));
//! assert_eq!(1, count_countries(&con));
//! }
//!
//! fn multiple_models_with_same_association() {
//! let con = establish_connection();
//!
//! let netherlands = CountryFactory::default()
//! .name("Netherlands")
//! .insert(&con);
//!
//! let amsterdam = CityFactory::default()
//! .name("Amsterdam")
//! .country(&netherlands)
//! .insert(&con);
//!
//! let hague = CityFactory::default()
//! .name("The Hague")
//! .country(&netherlands)
//! .insert(&con);
//!
//! assert_eq!(amsterdam.country_id, hague.country_id);
//!
//! assert_eq!(2, count_cities(&con));
//! assert_eq!(1, count_countries(&con));
//! }
//! #
//! # fn main() {
//! # basic_usage();
//! # setting_fields();
//! # multiple_models_with_same_association();
//! # }
//! # fn establish_connection() -> PgConnection {
//! # use std::env;
//! # let pg_host = env::var("POSTGRES_HOST").unwrap_or_else(|_| "localhost".to_string());
//! # let pg_port = env::var("POSTGRES_PORT").unwrap_or_else(|_| "5432".to_string());
//! # let pg_password = env::var("POSTGRES_PASSWORD").ok();
//! #
//! # let auth = if let Some(pg_password) = pg_password {
//! # format!("postgres:{}@", pg_password)
//! # } else {
//! # String::new()
//! # };
//! #
//! # let database_url = format!(
//! # "postgres://{auth}{host}:{port}/diesel_factories_test",
//! # auth = auth,
//! # host = pg_host,
//! # port = pg_port
//! # );
//! # let con = PgConnection::establish(&database_url).unwrap();
//! # con.begin_test_transaction().unwrap();
//! # con
//! # }
//!
//! // Utility functions just for demo'ing
//! fn count_cities(con: &PgConnection) -> i64 {
//! use crate::schema::cities;
//! use diesel::dsl::count_star;
//! cities::table.select(count_star()).first(con).unwrap()
//! }
//!
//! fn count_countries(con: &PgConnection) -> i64 {
//! use crate::schema::countries;
//! use diesel::dsl::count_star;
//! countries::table.select(count_star()).first(con).unwrap()
//! }
//!
//! fn find_country_by_id(input: i32, con: &PgConnection) -> Country {
//! use crate::schema::countries::dsl::*;
//! countries
//! .filter(identity.eq(&input))
//! .first::<Country>(con)
//! .unwrap()
//! }
//! ```
//!
//! ## `#[derive(Factory)]`
//!
//! ### Attributes
//!
//! These attributes are available on the struct itself inside `#[factory(...)]`.
//!
//! | Name | Description | Example | Default |
//! |---|---|---|---|
//! | `model` | Model type your factory inserts | `City` | None, required |
//! | `table` | Table your model belongs to | `crate::schema::cities` | None, required |
//! | `connection` | The connection type your app uses | `MysqlConnection` | `diesel::pg::PgConnection` |
//! | `id` | The type of your table's primary key | `i64` | `i32` |
//! | `id_name` | The name of your table's primary key column | `identity` | `id` |
//!
//! These attributes are available on association fields inside `#[factory(...)]`.
//!
//! | Name | Description | Example | Default |
//! |---|---|---|---|
//! | `foreign_key_name` | Name of the foreign key column on your model | `country_identity` | `{association_name}_id` |
//!
//! ### Builder methods
//!
//! Besides implementing [`Factory`] for your struct it will also derive builder methods for easily customizing each field. The generated code looks something like this:
//!
//! ```
//! struct CountryFactory {
//! pub name: String,
//! }
//!
//! // This is what gets generated for each field
//! impl CountryFactory {
//! fn name<T: Into<String>>(mut self, new: T) -> Self {
//! self.name = new.into();
//! self
//! }
//! }
//! #
//! # impl Default for CountryFactory {
//! # fn default() -> Self {
//! # CountryFactory { name: String::new() }
//! # }
//! # }
//!
//! // So you can do this
//! CountryFactory::default().name("Amsterdam");
//! ```
//!
//! [`Factory`]: trait.Factory.html
//!
//! ### Builder methods for associations
//!
//! The builder methods generated for `Association` fields are a bit different. If you have a factory like:
//!
//! ```
//! # #![allow(unused_imports)]
//! # include!("../tests/docs_setup.rs");
//! #
//! #[derive(Clone, Factory)]
//! #[factory(
//! model = City,
//! table = crate::schema::cities,
//! )]
//! struct CityFactory<'a> {
//! pub name: String,
//! pub country: Association<'a, Country, CountryFactory>,
//! }
//! #
//! # impl<'a> Default for CityFactory<'a> {
//! # fn default() -> Self {
//! # unimplemented!()
//! # }
//! # }
//! #
//! # fn main() {}
//! ```
//!
//! You'll be able to call `country` either with an owned `CountryFactory`:
//!
//! ```
//! # #![allow(unused_imports)]
//! # include!("../tests/docs_setup.rs");
//! #
//! # #[derive(Clone, Factory)]
//! # #[factory(
//! # model = City,
//! # table = crate::schema::cities,
//! # )]
//! # struct CityFactory<'a> {
//! # pub name: String,
//! # pub country: Association<'a, Country, CountryFactory>,
//! # }
//! #
//! # impl<'a> Default for CityFactory<'a> {
//! # fn default() -> Self {
//! # Self {
//! # name: String::new(), country: Association::default(),
//! # }
//! # }
//! # }
//! #
//! # fn main() {
//! let country_factory = CountryFactory::default();
//! CityFactory::default().country(country_factory);
//! # }
//! ```
//!
//! Or a borrowed `Country`:
//!
//! ```
//! # #![allow(unused_imports)]
//! # include!("../tests/docs_setup.rs");
//! #
//! # #[derive(Clone, Factory)]
//! # #[factory(
//! # model = City,
//! # table = crate::schema::cities,
//! # )]
//! # struct CityFactory<'a> {
//! # pub name: String,
//! # pub country: Association<'a, Country, CountryFactory>,
//! # }
//! #
//! # impl<'a> Default for CityFactory<'a> {
//! # fn default() -> Self {
//! # Self {
//! # name: String::new(), country: Association::default(),
//! # }
//! # }
//! # }
//! #
//! # fn main() {
//! let country = Country { id: 1, name: "Denmark".into() };
//! CityFactory::default().country(&country);
//! # }
//! ```
//!
//! This should prevent bugs where you have multiple factory instances sharing some association that you mutate halfway through a test.
//!
//! ### Optional associations
//!
//! If your model has a nullable association you can do this:
//!
//! ```
//! # #![allow(unused_imports)]
//! # include!("../tests/docs_setup_with_city_factory.rs");
//! #
//! #[derive(Clone, Factory)]
//! #[factory(
//! model = User,
//! table = crate::schema::users,
//! )]
//! struct UserFactory<'a> {
//! pub name: String,
//! pub country: Option<Association<'a, Country, CountryFactory>>,
//! # pub age: i32,
//! # pub home_city: Option<Association<'a, City, CityFactory<'a>>>,
//! # pub current_city: Option<Association<'a, City, CityFactory<'a>>>,
//! }
//!
//! impl<'a> Default for UserFactory<'a> {
//! fn default() -> Self {
//! Self {
//! name: "Bob".into(),
//! country: None,
//! # age: 30,
//! # home_city: None,
//! # current_city: None,
//! }
//! }
//! }
//!
//! # fn main() {
//! // Setting `country` to a `CountryFactory`
//! let country_factory = CountryFactory::default();
//! UserFactory::default().country(Some(country_factory));
//!
//! // Setting `country` to a `Country`
//! let country = Country { id: 1, name: "Denmark".into() };
//! UserFactory::default().country(Some(&country));
//!
//! // Setting `country` to `None`
//! UserFactory::default().country(Option::<CountryFactory>::None);
//! UserFactory::default().country(Option::<&Country>::None);
//! # }
//! ```
//!
//! ### Customizing foreign key names
//!
//! You can customize the name of the foreign key for your associations like so
//!
//! ```
//! # #![allow(unused_imports)]
//! # include!("../tests/docs_setup.rs");
//! #
//! #[derive(Clone, Factory)]
//! #[factory(
//! model = City,
//! table = crate::schema::cities,
//! )]
//! struct CityFactory<'a> {
//! #[factory(foreign_key_name = country_id)]
//! pub country: Association<'a, Country, CountryFactory>,
//! # pub name: String,
//! }
//! #
//! # impl<'a> Default for CityFactory<'a> {
//! # fn default() -> Self {
//! # unimplemented!()
//! # }
//! # }
//! #
//! # fn main() {}
//! ```
use ;
pub use Factory;
/// A "belongs to" association that may or may not have been inserted yet.
///
/// You will normally be using this when setting up "belongs to" associations between models in
/// factories.
/// A generic factory trait.
///
/// You shouldn't ever have to implement this trait yourself. It can be derived using
/// `#[derive(Factory)]`
///
/// See the [root module docs](/) for info on how to use `#[derive(Factory)]`.
static SEQUENCE_COUNTER: AtomicUsize = new;
/// Utility function for generating unique ids or strings in factories.
/// Each time `sequence` gets called, the closure will receive a different number.
///
/// ```
/// use diesel_factories::sequence;
///
/// assert_ne!(
/// sequence(|i| format!("unique-string-{}", i)),
/// sequence(|i| format!("unique-string-{}", i)),
/// );
/// ```