lambda-appsync-proc 0.10.0

Procedural macros for the lambda-appsync type-safe AWS AppSync resolver framework
Documentation
Generates Rust types (structs and enums) from a GraphQL schema file.

# Usage

```text
make_types!("path/to/schema.graphql");

// or with options:
make_types!(
    "path/to/schema.graphql",
    type_override = Type.field: CustomType,               // override a field type
    name_override = TypeName: NewTypeName,                // rename a type
    name_override = Type.field: new_field_name,           // rename a field
    name_override = Enum.VARIANT: NewVariant,             // rename an enum variant
    default_traits = MyType: false,                       // disable default traits for a type
    derive = MyType: Default,                             // add an extra derive macro to a type
    derive = MyType: PartialEq,                           // (specify multiple times for multiple derives)
);
```

This is one of three composable macros that together replace the monolithic [appsync_lambda_main!]:

- `make_types!` — generates types (structs for GraphQL `type` and `input`, enums for GraphQL `enum`)
- [make_operation!] — generates the `Operation` enum and dispatch logic
- [make_handlers!] — generates the Lambda handler trait

[make_appsync!] is a convenience macro that combines all three.

# Schema Path Argument

The first argument to this macro must be a string literal containing the path to your GraphQL schema file.
The schema path can be:

- An absolute filesystem path (e.g. "/home/user/project/schema.graphql")
- A relative path, that will be relative to your crate's root directory (e.g. "schema.graphql", "graphql/schema.gql")
- When in a workspace context, the relative path will be relative to the workspace root directory

# Options

- `type_override` — see section below for details
- `name_override` — see section below for details
- `default_traits` — see section below for details
- `derive` — see section below for details

## Type Overrides

The `type_override` option allows overriding the Rust type generated for a struct field:

- `type_override = Type.field: CustomType`

These overrides are only for the Rust code and must be compatible for serialization/deserialization purposes,
i.e. you can use `String` for a GraphQL `ID` but you cannot use a `u32` for a GraphQL `Float`.

Note: operation-level overrides (`Query.op: Type` or `Query.op.arg: Type`) are not relevant here since
`make_types!` does not generate operation types. Use [make_operation!] or [make_appsync!] for those.

## Name Overrides

The `name_override` option supports renaming various schema elements:

- Type/input/enum names: `name_override = TypeName: NewTypeName`
- Field names: `name_override = Type.field: new_field_name`
- Enum variants: `name_override = Enum.VARIANT: NewVariant`

These overrides are only for the Rust code and will not change serialization/deserialization,
i.e. `serde` will rename to the original GraphQL schema name.

Note that when using `name_override`, the macro does not automatically change the case:
you are responsible to provide the appropriate casing or Clippy will complain.

## Default Traits

The `default_traits` option controls whether the macro applies its default set of traits
on a given type:

- `default_traits = TypeName: bool`

The default value is `true`. When set to `false` for a type, none of the default traits are
implemented for that type, giving you the opportunity to implement them yourself.

**Important:** certain traits are required by the generated operation dispatch code regardless
of this setting:

- `serde::Serialize` **must** be implemented on any type used as a return type of a Query or
  Mutation operation.
- `serde::Deserialize` **must** be implemented on any `input` type used as an operation argument.

You are free to disable the default implementations, but you must provide alternative ones —
whether via `derive` entries, manual `impl` blocks, or any other means.

The default traits are:

- **Structs** (GraphQL `type` and `input`): `Debug`, `Clone`, `Serialize`, `Deserialize`
- **Enums** (GraphQL `enum`): `Debug`, `Clone`, `Copy`, `Serialize`, `Deserialize`, `PartialEq`,
  `Eq`, `PartialOrd`, `Ord`, `Hash`, `Display` and `FromStr`

## Additional Derive Macros

The `derive` option allows adding an extra derive macro on top of the default ones for a given
type:

- `derive = TypeName: Trait`

Each `derive` entry adds a single trait. Specify the option multiple times to add several traits:

- `derive = Player: Default`
- `derive = Player: PartialEq`

This is additive: it does not replace the default traits (unless `default_traits` is
set to `false` for the same type, in which case only the explicitly listed traits are derived).

This is useful for deriving traits that the macro does not provide, such as `Default`
on a struct or `PartialEq`.

For enums, `derive = MyEnum: Default` is supported: the first variant declared in the GraphQL
schema becomes the default value.

# What Gets Generated

For each GraphQL `type` (excluding Query, Mutation, and Subscription), with default traits:
```rust,no_run
# use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
# struct FieldType;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeName {
    pub field1: FieldType,
    pub field2: Option<FieldType>,
    // ...
}
```

For each GraphQL `input`, with default traits:
```rust,no_run
# use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
# struct FieldType;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputName {
    pub field1: FieldType,
    // ...
}
```

For each GraphQL `enum`, with default traits:
```rust,no_run
# use serde::{Serialize, Deserialize};

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EnumName {
    Variant1,
    Variant2,
    // ...
}
```

Each generated enum also gets:
- `const COUNT: usize` — number of variants
- `const fn all() -> [Self; Self::COUNT]` — array of all variants
- `const fn index(self) -> usize` — index of the variant (useful for array indexing)
- `Display` impl (when `default_traits` is `true`, displays the original GraphQL name)
- `FromStr` impl (when `default_traits` is `true`, parses from the original GraphQL name)

# GraphQL to Rust Type Mapping

| GraphQL | Rust |
|---------|------|
| `String` | `String` |
| `ID` | `lambda_appsync::ID` |
| `Int` | `i32` |
| `Float` | `f64` |
| `Boolean` | `bool` |
| `AWSEmail` | `lambda_appsync::AWSEmail` |
| `AWSPhone` | `lambda_appsync::AWSPhone` |
| `AWSTimestamp` | `lambda_appsync::AWSTimestamp` |
| `AWSDate` | `lambda_appsync::AWSDate` |
| `AWSTime` | `lambda_appsync::AWSTime` |
| `AWSDateTime` | `lambda_appsync::AWSDateTime` |
| `AWSJSON` | `serde_json::Value` |
| `AWSURL` | `lambda_appsync::AWSUrl` |
| `AWSIPAddress` | `core::net::IpAddr` |
| `[T]` (list) | `Vec<T>` |
| nullable | `Option<T>` |
| Custom type | The generated Rust struct/enum |

# Use Case: Shared Types Crate

The primary use case for `make_types!` alone (vs [make_appsync!]) is when you want to share
GraphQL types across multiple crates — e.g., a shared library crate for types and separate
binary crates for different Lambda functions:

```text
my-project/
├── schema.graphql
├── shared-types/     # lib crate using make_types!
│   └── src/lib.rs
├── lambda-a/         # bin crate using make_operation! + make_handlers!
│   └── src/main.rs
└── lambda-b/         # another bin crate
    └── src/main.rs
```

When using `name_override` with `make_types!` in a multi-crate setup, you must use the same
overrides in [make_operation!] so that operation signatures reference the correct renamed types.

# Examples

## Basic usage:
```rust,no_run
# mod sub {
lambda_appsync::make_types!("schema.graphql");
# }
# fn main() {}
```

## With type overrides:
```rust,no_run
# mod sub {
lambda_appsync::make_types!(
    "schema.graphql",
    // Use String instead of the default lambda_appsync::ID
    type_override = Player.id: String,
);
# }
# fn main() {}
```

## With name overrides:
```rust,no_run
# mod sub {
lambda_appsync::make_types!(
    "schema.graphql",
    // Rename the Player struct
    name_override = Player: GqlPlayer,
    // Rename a field
    name_override = Player.name: email,
    // Rename an enum variant
    name_override = Team.PYTHON: Snake,
);
# }
# fn main() {}
```

## Combined overrides:
```rust,no_run
# mod sub {
lambda_appsync::make_types!(
    "schema.graphql",
    type_override = Player.id: String,
    name_override = Player: GqlPlayer,
);
# }
# fn main() {}
```

## Disable default derivations for a type:
```rust,no_run
# mod sub {
lambda_appsync::make_types!(
    "schema.graphql",
    // Player will have no derive macros — implement them yourself
    default_traits = Player: false,
);
# }
# fn main() {}
```

## Add extra derive macros to a type:
```rust,no_run
# mod sub {
lambda_appsync::make_types!(
    "schema.graphql",
    // Add Default and PartialEq on top of the default derives
    derive = Team: Default,
    derive = Player: Default,
    derive = Player: PartialEq,
);
# }
# fn main() {}
```

## Combine default_traits and derive:
```rust,no_run
# mod sub {
lambda_appsync::make_types!(
    "schema.graphql",
    derive = Team: Default,
    // Disable defaults and provide only the derives you need
    default_traits = Player: false,
    derive = Player: Debug,
    derive = Player: Default,
);
# }
# fn main() {}
```

This macro generates **only** types (structs and enums). It does not generate the `Operation` enum
or Lambda handler code. Use [make_operation!] for operations and [make_handlers!] for the handler,
or [make_appsync!] for all three at once.