Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FromForm flatten attribute #1916

Open
ijackson opened this issue Sep 23, 2021 · 1 comment
Open

FromForm flatten attribute #1916

ijackson opened this issue Sep 23, 2021 · 1 comment
Labels
accepted An accepted request or suggestion request Request for new functionality

Comments

@ijackson
Copy link
Contributor

When using derive, it is often useful to be able to make common structs that contain fields where everything can be done automatically, and then surrounding structs where only some of the things are derived.

To do this, one needs to indicate to each derive macro that the fields of a contained struct should be imported without another level of nesting. #[serde(flatten)], #[row(flatten)]. But unfortunately there is not a #[field(flatten)].

For example, I have this in a work-in-progress webapp:

#[derive(Debug,Serialize)]
struct PageContext {
    #[serde(flatten)] frow: FlightRow,
    hidden_vals: TemplateEnumRadio<IsHidden>,
}

#[derive(Debug,Serialize,FromSqlRow)]
struct FlightRow {
    flight: Flight,
    branch: String,

    hidden: IsHidden,

    webgroup: String,
    main_tree: String,
    template_flight: Option<Flight>,
    basis_flight: Option<Flight>,
    reuse_real_builds: bool,

    xtrees_web: String,
    xtrees_main: String,
    job_patterns: String,

    #[serde(flatten)] #[row(flatten)]
    common: RowUpdateCommon,
}

#[derive(Debug,FromForm)]
struct UpdateForm {
    common: RowUpdateCommon, // this wants to be flatten
}

#[derive(Debug,Serialize,FromForm,FromSqlRow)]
struct RowUpdateCommon {
    email: String,
}

This doesn't work because the generated code expects form submissions containing common.email but the actual form contains only email.

Alternatives Considered

Letting the fields be nested the way FromForm wants doesn't really work, because whether a field ends up in common depends not on anything principled about the system, but simply on whether the automatic handling produced by the derive macros is appropriate.

For now I have to just give up on making this part of my code common, and writing some boilerplate to copy fields from one struct to another.

Additional Context

I'm not convinced that field is a good name for this attribute. Derive macro inert attributes are in a global namespace. I suggest that form would be better. However, it is perhaps too late to change this now.

@ijackson ijackson added the request Request for new functionality label Sep 23, 2021
@SergioBenitez
Copy link
Member

Yeah, this (among others) is something that the derive simply doesn't do at the moment. Implementing it should be fairly straightforward and in fact is what we already do to handle queries. I'd be happy to review a PR implementing this.

As an aside: FromForm is an interesting derive because it's effectively serde specialized to forms. Unfortunately, this specialization (we don't/can't conform to serde's data model) makes it impossible to actually use serde without serious short-comings. In other words, while we'd love to just use serde, it's simply not expressive enough. So we're left effectively recreating serde in many cases, this one considered.

@SergioBenitez SergioBenitez added the accepted An accepted request or suggestion label Sep 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted An accepted request or suggestion request Request for new functionality
Projects
None yet
Development

No branches or pull requests

2 participants