1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! `bluejay-typegen` is a crate for generating Rust types from GraphQL schemas and queries.
//!
//! ### Usage
//! The [`typegen`] macro generates Rust types from a GraphQL schema and any number of queries.
//! The macro must decorate a module, and the module must contain a type alias for each custom scalar defined in the schema.
//! All shared types for the schema (input object, enums) are generated within the module.
//!
//! #### Arguments
//! The macro takes one positional argument, followed by a series of optional named arguments.
//! The positional argument can be either a string literal pointing to a file containing the schema in SDL format (path relative to the `Cargo.toml` of the crate where the macro is used),
//! or DSL code defining the schema directly in the macro invocation, enclosed within square brackets.
//! The optional named arguments are:
//! - `borrow`: A boolean indicating whether the generated types should borrow strings from the input JSON value instead of owning them. Defaults to `false`.
//! - `codec`: A string literal specifying the codec to use for serializing and deserializing values.
//!   Must be one of `"serde"` or `"miniserde"`. Defaults to `"serde"` when the `serde` feature is enabled, otherwise `"miniserde"` when the `miniserde` feature is enabled.
//!   When `"miniserde"` is used, `borrow` must be `false` as `miniserde` does not support borrowing strings.
//!
//! #### Queries
//! Within the module defining the schema definition, a submodule can be defined for any number of executable documents.
//! This can be done by decorating the submodule with `#[query(...)]` where the argument follows the same convention as the positional argument of the macro.
//! For each operation and fragment definition in the query document, a corresponding Rust type is generated. If an anonymous operation is defined, the type is named `Root`.
//! See [type path pattern](#type-path-pattern) for more information on how the path for a given type is determined.
//!
//! ### Example
//! ```
//! #[bluejay_typegen::typegen([
//!   scalar UnsignedInt
//!
//!   enum Position {
//!     WING
//!     CENTRE
//!     DEFENCE
//!   }
//!
//!   type Skater {
//!     name: String!
//!     position: Position!
//!     age: UnsignedInt!
//!     stats: [SkaterStat!]!
//!   }
//!
//!   type SkaterStat {
//!     goals: UnsignedInt!
//!   }
//!
//!   type Goalie {
//!     name: String!
//!     age: UnsignedInt!
//!     stats: [GoalieStat!]!
//!   }
//!
//!   type GoalieStat {
//!     wins: UnsignedInt!
//!   }
//!
//!   union Player = Skater | Goalie
//!
//!   type Query {
//!     player: Player!
//!   }
//! ], borrow = true)]
//! mod schema {
//!     type UnsignedInt = u32;
//!
//!     #[query([
//!       query Player {
//!         player {
//!           __typename
//!           ...on Skater {
//!             name
//!             age
//!             position
//!             stats { goals }
//!           }
//!           ...on Goalie {
//!             name
//!             age
//!             stats { wins }
//!           }
//!         }
//!       }
//!     ])]
//!     pub mod query {}
//! }
//!
//! let value = serde_json::json!({
//!     "player": {
//!         "__typename": "Skater",
//!         "name": "Auston Matthews",
//!         "age": 25,
//!         "position": "CENTRE",
//!         "stats": [
//!             {
//!                 "goals": 60
//!             },
//!         ],
//!     },
//! }).to_string();
//!
//! let result: schema::query::Player = serde_json::from_str(&value).expect("Error parsing value");
//!
//! assert_eq!(
//!     schema::query::Player {
//!         player: schema::query::player::Player::Skater {
//!             name: "Auston Matthews".into(),
//!             age: 25,
//!             position: schema::Position::Centre,
//!             stats: vec![schema::query::player::player::skater::Stats { goals: 60 }],
//!         },
//!     },
//!     result,
//! );
//! ```
//!
//! ### Limitations
//! - A query cannot contain a fragment definition with the same name as an operation definition
//! - A schema module must contain exactly one type alias for each custom scalar defined in the schema, so that the type alias can be used in the generated Rust types
//! - Within the scope of an object type, the selection set must not contain any inline fragments and must either:
//!     - Contain at least one field selection, or
//!     - Contain exactly one fragment spread
//! - Within the scope of an interface type, the selection set must not contain any inline fragments and must either:
//!     - Contain at least one field selection, or
//!     - Contain exactly one fragment spread, where the target type of the fragment spread is either the interface type itself or an interface that the interface type implements
//! - Within the scope of a union type, the selection set must:
//!     - Contain an unaliased field selection of `__typename` as the first selection in the set, and no other field selections, and
//!     - Not contain any fragment spreads, and
//!     - Not contain multiple inline fragments targeting any object type in the union type, and
//!     - Not contain any inline fragments targeting types that are not a member of the union type
//!
//! ### Type path pattern
//! The path for a given type in the generated Rust types is determined by the following rules:
//! - If the type is a custom scalar, enum, or input type, the path is `schema_module::TypeName`. For example, the `Position` enum in the example above has the path `schema::Position`.
//! - If the type is an operation root type, the path is `schema_module::query_module::OperationName`. For example, the `Player` type for the `Player` query root in the example above has the path `schema::query::Player`.
//! - If the type is an anonymous operation root type, the path is `schema_module::query_module::Root`
//! - If the type is a nested object type, the path is nested under the path of the parent object type, like `schema_module::query_module::operation_name::TypeName`. For example, the `Player` Rust enum type for the `player` field in the example above has the path `schema::query::player::Player`. And the `Stats` Rust struct type for the `stats` field in the `Skater` arm of the `Player` enum has the path `schema::query::player::player::skater::Stats`.
//! - If the type is a fragment definition, the path is `schema_module::query_module::FragmentName`, with all nested types following the same pattern as operation types, e.g. at `schema_module::query_module::fragment_name::TypeName`.

pub use bluejay_typegen_macro::typegen;

#[cfg(feature = "serde")]
pub use srd as serde;

#[cfg(feature = "miniserde")]
pub use mnsrd as miniserde;