Skip to content

Commit

Permalink
majority rewrite with new arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
NexRX committed Mar 10, 2024
1 parent 9f18320 commit da8d441
Show file tree
Hide file tree
Showing 16 changed files with 1,081 additions and 939 deletions.
22 changes: 11 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,26 @@ license-file = "license.txt"
proc-macro = true

[features]
default = ["builder", "openapi"]
openapi = ["dep:poem-openapi"]
builder = ["dep:typed-builder"]
welds = ["dep:welds"]
default = ["openapi"]
openapi = []
# builder = ["dep:typed-builder"]
# welds = ["dep:welds"]

[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["parsing"] }
proc-macro-error = "1.0.4"


# Supported Crates
poem-openapi = { version = "3.0", features = [
[dev-dependencies]
# # Supported Crates
poem-openapi = { version = "4.0", features = [
"uuid",
"chrono",
], optional = true }

typed-builder = { version = "0.18.0", optional = true }
welds = { version = "0.2.1", default-features = false, optional = true}
proc-macro-error = "1.0.4"
] }
# typed-builder = { version = "0.18.0" }
# welds = { version = "0.3", default-features = false}

[package.metadata.docs.rs]
all-features = true
Expand Down
180 changes: 103 additions & 77 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ New features planned are available [here](https://github.com/NexRX/restructed/is

# Usage

This library requires the `nightly` channel.

Add `restructed` to your projects `Cargo.toml`:

```toml
Expand All @@ -51,8 +49,6 @@ cargo add restructed
Add the import and derive it on the target struct

```rust
use restructed::Models;

#[derive(restructed::Models)]
struct User {
id: i32,
Expand All @@ -65,112 +61,142 @@ And then add attributes for each model you want to create.

```rust
#[derive(restructed::Models)]
#[patch(UserUpdatables, omit(id))] // <-- Wraps all fields in a new struct with Option
#[view(UserId, fields(id))] // <-- Selectively includes fields in a new struct
#[view(UserId, fields(id))] // <-- Simple subset of the deriving structs field
#[patch(UserUpdatables, omit(id))] // <-- Wraps all fields with a Option type inside a new struct
struct User {
id: i32,
username: String,
}
```

Continue reading for the available models and their breakdown.
Continue reading for the available models and their breakdown and arguments in general.


Now anywhere that requires a `T: OrderStoreFilter` will also accept an `&T` or `Arc<T>` where `T` implements `OrderStoreFilter`.
## Common Arguments
These are arguments that can be applied to all models.

## Models
- `name` - The name of the struct the generate [**Required**, **Must be first** e.g. `MyStruct`]
- `fields` [**Only One**]
- `fields` - A _list_ of field names in the original structure to carry over [e.g. `fields(field1, field2, ...)`]
- `omit` - A _list_ of field names in the original structure to omit [e.g. `omit(field1, field2, ...)`]
- `derive` - A _list_ of derivables to derive on the generated struct just like you would normally [e.g. `derive(Clone, Debug, thiserror::Error)`]
- `preset` - A _string literal_ of the preset to use, presets are a set of defaults to apply to a model. *Below is a list of what arguments are composed in a preset.* [e.g. `preset = "none"`]
- **none** - **Default**, does nothing and is the default behaviour
- **write** *['openapi' Feature Flag]* - Designed to only show properties that can be written to.
- `omit` - Applied as a base, any fields with `#[oai(read_only)]` attribute are removed, your fields/omit is applied after
- `option` **patch only** - Arg defaults to `MaybeUndefined`

Each model is defined using an attribute after deriving `Models` and multiple models (of the same kind) can be had with multiple attributes.
- **read** *['openapi' Feature Flag]* - Designed to only show properties that can always be read.
- `omit` - Applied as a base, any fields with `#[oai(write_only)]` attribute are removed, your fields/omit is applied after
- `option` **patch only** - arg defaults to `MaybeUndefined`

### view
- `attributes_with` - A _string literal_ of the attributes to inherit at both struct & field level. *Below is a list of values.* [e.g. `attributes_with = "none"`]
- **none** - Does not consider any attributes [**Default**]
- **oai** *['openapi' Feature Flag]* - Composes all Poem's OpenAPI attributes
- **deriveless** - Composes all attributes but omits the derive attributes
- **all** - Composes all attributes

A selective subset of fields from the original model of the same types. Useful for generating views of a database table, etc. Supports both struct and enums
<br/>

**Arguements:**
# Models
Derivable models via the struct attributes.

- `name` - The name of the struct the generate (**Required**, **Must be first** e.g. `MyStruct`)
- `fields` - A _list_ of field names in the original structure to carry over (**Required**, e.g. `fields(field1, field2, ...)`)
- `derive` - A _list_ of derivables (in scope) to derive on the generated struct (e.g. `derive(Clone, Debug, thiserror::Error)`)
- `default_derives` - A _bool_, if `true` _(default)_ then the a list of derives will be additionally derived. Otherwise, `false` to avoid this (e.g. `default_derives = false`)
## **Patch**
A subset model where every field's type is an option in some way. It's called patch because it reflect a REST / DB patch of the original struct.

**Example:**
#### **Unique Args**
- `option` - A _Identifer_ that allows a different option implementation from supported crates [e.g. `option = MaybeUndefined` (from poem-openapi)]
- **Option** - The standard implementation of Option [**Default**]
- **MaybeUndefined** *['openapi' Feature Flag]* - Use Poem's OpenAPI crate and it's Option implmentation

#### **Example**
```rust
// Original
#[derive(restructed::Models)]
#[view(UserProfile, fields(display_name, bio), derive(Clone), default_derives = false)]
struct User {
id: i32,
display_name: String,
bio: String,
password: String,
}
#[derive(restructed::Models)]
#[patch(UserUpdate, omit(id), option = Option)]
struct User {
id: i32,
display_name: String,
bio: String,
extra: Option<String>,
password: String,
}
```

Generates:

will expand into something like this:
```rust
#[derive(Clone)]
struct UserProfile {
display_name: String,
bio: String,
}
struct UserUpdate {
display_name: Option<String>,
bio: Option<String>,
extra: Option<Option<String>>,
password: Option<String>,
}
```

### patch

A complete subset of fields of the original model wrapped in `Option<T>` with the ability to omit instead select fields. <br/>
I want to note that patch currently doesn't support enums as I don't see the use-case for it. If someone can, feel free to submit a feature request
## **View**
A simple subset of the deriving model/struct.

**Arguements:**

- `name` - The name of the struct the generate (**Required**, **Must be first** e.g. `MyStruct`)
- `omit` - A _list_ of field names in the original structure to omit (e.g. `fields(field1, field2, ...)`)
- `derive` - A _list_ of derivables (in scope) to derive on the generated struct (e.g. `derive(Clone, Debug, thiserror::Error)`)
- `default_derives` - A _bool_, if `true` _(default)_ then the a list of derives will be additionally derived. Otherwise, `false` to avoid this (e.g. `default_derives = false`)

**Example:**
#### **Unique Args**
- N/A

#### **Example**
```rust
// Original
#[derive(restructed::Models)]
#[patch(UserUpdate, omit(id))]
struct User {
id: i32,
display_name: String,
bio: String,
password: String,
}
#[derive(restructed::Models)]
#[view(UserPublic, fields(display_name, bio))]
struct User {
id: i32,
display_name: String,
bio: String,
extra: Option<String>,
password: String,
}
```

Generates:

will expand into something like this:
```rust
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] // <-- Default derives (when *not* disabled)
struct UserUpdate {
display_name: Option<String>,
bio: Option<String>, // MaybeUndefined<String> with feature 'openapi'
password: Option<String>,
}
struct UserPublic {
display_name: String,
bio: String,
}
```

## Crate Features

Links are to other crates GitHub page that are related to the features.<br/>
Only `builder` is enabled by default.

### `openapi`
<br/>

Wraps `Option<T>` from the source struct with `MaybeUndefined<T>` from the [poem-openapi](https://github.com/poem-web/poem/tree/master/poem-openapi) crate in `patch` models. All `oai(...)` attributes are also copied over to the generated struct meaning you keep all validators, etc..
# Complex Example
Just to demonstrate the versitility of this crate, here is an example using all the possible arguments at once using all features.

### `builder`
## Poem OpenAPI
Each attribute is copied over so all your validations are kept

Uses the [typed-builder](https://github.com/idanarye/rust-typed-builder) crate to derive a builder for add a type safe builder for all generated models.
```rust
use restructed::Models;

### `welds`
#[cfg(test)] // For rust_doc test purposes
#[derive(poem::Object, Models)]
#[oai(skip_serializing_if_is_none, rename_all = "camelCase")]
#[patch(UserUpdate, preset = "write", derive(Object))]
#[view(UserProfile, preset = "view", derive(Object))]
#[view(UserNames, preset = "view", derive(Object))]
pub struct User {
#[oai(read_only)]
pub id: u32,
// profile
#[oai(validator(min_length = 3, max_length = 16, pattern = r"^[a-zA-Z0-9_]*$"))]
pub username: String,
#[oai(validator(min_length = 5, max_length = 1024), write_only)]
pub password: String,
#[oai(validator(min_length = 2, max_length = 16, pattern = r"^[a-zA-Z\s]*$"))]
pub name: Option<String>,
#[oai(validator(min_length = 2, max_length = 16, pattern = r"^[a-zA-Z\s]*$"))]
pub surname: Option<String>,
#[oai(read_only)]
pub joined: u64,
}
```

Generates a function to merge changes for returning a `DbState<T>` from the [welds](https://github.com/weldsorm/welds) crate.
<br/>

## Contributions & Bugs
# Crate Features
Links are to other crates GitHub page that are related to the features.<br/>

This is my first self publish proc macro so any feedback and feature request, changes, pull requests are all welcome! <br/>
If you find any bugs do submit a github issue with any relavent information and I'll try to fix it.
## Poem OpenAPI
Enables wrapping `Option<T>` from the source struct with `MaybeUndefined<T>` from the [poem-openapi](https://github.com/poem-web/poem/tree/master/poem-openapi) crate in `patch` models. All `oai(...)` attributes can also be explictly copied over to the generated struct meaning you keep all validators, etc..
105 changes: 0 additions & 105 deletions src/clone.rs

This file was deleted.

Loading

0 comments on commit da8d441

Please sign in to comment.