Skip to content

Add domain types configuration #4594

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

lsunsi
Copy link

@lsunsi lsunsi commented May 5, 2025

This PR intends to be the point of discussion of a possible feature discussed in #4592.

Concept

Domain types are regular types with some added constraints. Reference.

The current behavior when using them with diesel is that diesel prints the underlying type, which makes sense as a default. As an alternative behavior, this PR proposes that a new type is generated if the user wants to add behavior to the domain type on the application layer.

Details

I'm not entirely happy with the last commit because I had to use "boxed" in order to have two distinct queries in the same variable, which still having to add "if" on the flag. If you can think of a better way to express the logic in diesel I'd love to learn it and change the implementation.

Questions

  1. Should other databases have support or it? I'm not sure if domain types are a pg-only thing, since the information schema is actually a SQL thing from what I can gather. Anyway, I'd enjoy some guidance here as well.
  2. Is a boolean flag enough? The user won't be able to configure which domain types to render, just "all or nothing" behavior. Maybe it'd make sense to allowlist some domain types in the configuration with their postgres name?

@weiznich weiznich requested a review from a team May 5, 2025 12:51
Comment on lines 15 to 17
#[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "posint"))]
pub struct Posint;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just laying some thoughts here (but I'm not sure we should do what's suggested below): this loses information of what the underlying type is, which makes it the responsibility of the user to make sure that serialization is appropriate.

We might want to add this data to the type here, such as a new Domain derive and underling_type = "..." annotation to the SqlType derive, that would implement a corresponding Domain trait, and allow the user to make use of this type in their implementations of FromSql and ToSql (or even make the relevant implementations conditionally on implementations of some new traits that would define the mapping between input rust types and rust types that have ToSql/FromSql<UnderlyingType>) to fully close the door for mistakes here.

If we were to add that later by default, that would be a breaking change for users who already manually define their FromSql/ToSql implementations for these types.

But I'm not sure if that's ever worth the extra maintenance cost within Diesel itself...
Probably that wouldn't be very consistent with Diesel not supporting enums out-of-the-box, where ideally the CLI would also infer enum variants...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I fully agree that some information is being lost here and this should be avoided. I'd be willing to try something along the lines you suggested with some help (since I'm a newbie in this project).

And about this breaking compatibility, is there a way in diesel to add features in an "unstable" manner so it can be worked over multiple releases before being stabilized? If so, maybe we should think of this feature in layers, but I'm not sure about it either.

Copy link
Author

@lsunsi lsunsi May 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ten0 I'm re-reading your comment and I'm positive this is the right path, but I'm not sure how to begin to propose a solution. Is there any pointer you could give me to similar code I could read up on in order to get up to speed on this implementation?

Edit:

Or even, how would the Domain trait look like? From what I can gather, you are suggesting: (1) the cli should output postgres_type = "posint" but also underlying_type = "bigint" for example, and (2) the derive should understand the "underlying type" property and generate a Domain implementation (3) could be used on the actual user-level From/ToSql implementations without messing up the type. Does this tracks or I'm way off mark?

In this situation, the Domain trait would be responsible for carrying the information about the "bigint" which was lost when "postgres_type" was set for the domain name.

(I'm just phrasing it so I can serialize my current understanding haha)

Edit2:

or even make the relevant implementations conditionally on implementations of some new traits that would define the mapping between input rust types and rust types that have ToSql/FromSql

I didn't fully grasp this one but it seems interesting too if you're willing to elaborate

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I'm not sure how to begin to propose a solution

I understand that this comment is blocked on me giving this issue some more thought. I'll come back to you when I have time to do that 😊🙏

For me the main question is whether we even want to do this here:

But I'm not sure if that's ever worth the extra maintenance cost within Diesel itself...
Probably that wouldn't be very consistent with Diesel not supporting enums out-of-the-box, where ideally the CLI would also infer enum variants...

Maybe other reviewers will have an opinion.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, I wasn't trying to pressure you or anything @Ten0 , sorry if it came off this way.

Is there any way we could release something without having stability guarantees on it? Maybe a feature a feature or something, maybe this could relieve some pressure and give us some time to think on this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do currently not have a way to say: This feature is unstable, that by itself would need to be implemented first. That written: I'm not opposed to have something like that as unstable feature that can be explicitly enabled via an unstable.domain_type = true flag in the diesel.toml configuration.

Finally for the actual discussion: Given that domain types often introduce custom requirements on the underlying types it's hard to see how providing the built-in FromSql/ToSql impls for the underlying types would be helpful. I would guess that users ~always want to express these requirements in their rust code as well, so having these impls by default might be not helpful for them.

As for the discussion whether this should be a boolean flag or a list of type names: If somewhat possible I would prefer a list of type names or even a list of type name regexes there so that users can have finer control around where thy want domain types and where not.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @weiznich , thanks for the feedback!

I like the idea of prefixing with unstable, seems like a simpler way to avoid this possible improvement. That said, I'll leave this discussion for when we're comfortable with the PR so we know exactly what implementation we are talking about!

About the list of type names, I updated the implementation on 14cbf02 trying to implement a version of this idea. I think it looks way better than the boolean, do you mind checking it out and giving feedback?

I updated the tests too to reflect usage.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I do anything special for the diesel.toml file to be read on the test? I swear the commit passed the test once but I changed something and can't seem to do it again. haha.

@lsunsi
Copy link
Author

lsunsi commented May 6, 2025

@Ten0 What do you think of instead of a boolean we have a list of type names to be considered as is? The reason I suggest this is that the implementation would look very similar, while adding more control for the users. Instead of all-or-nothing domain types, the user could allowlist the domains they want.

If it makes sense, we could have "true" representing all, and a list representing allowlist, or something along these lines. I'm not sure about it, but I'd like to hear what you think about it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants