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

Add "combine" or "merge" operator for models #1292

Open
johanste opened this issue Nov 17, 2022 · 10 comments
Open

Add "combine" or "merge" operator for models #1292

johanste opened this issue Nov 17, 2022 · 10 comments
Labels
design:needed A design request has been raised that needs a proposal feature New feature or request
Milestone

Comments

@johanste
Copy link
Contributor

Something that I have missed is the ability to combine models outside of spread operators. One example of a (unrelated) language is jsonnet's object combine operator (see inheritance and nested field inheritance the sections).

To illustrate a bit what I'm thinking:

model Base {
  id: string;
  etag?: string;
  apiVersion: string;
}

model Overrides {
  id: int32;
  description?: string;
  apiVersion: never;
}

model Combined is Base + Overrides;

/*
// Resulting model:

model Combined {
  id: int32;
  etag?: string;
  apiVersion: never;
  description?: string;
}
*/

As indicated, the resulting model is not a subtype of either operands, the order of attributes could be preserved (although there is an argument to be made that overriding attributes should move later), decorators (not shown) are not merged etc.

I can think of a couple of places in azure core where this would be useful and simplify our life.

Playground Link

@johanste johanste added feature New feature or request design:needed A design request has been raised that needs a proposal labels Nov 17, 2022
@ghost ghost added the Needs Triage label Nov 17, 2022
@timotheeguerin
Copy link
Member

is the goal here not simply just have multiple model is

@johanste
Copy link
Contributor Author

I don't think so. I wouldn't expect decorators on Base or Overrides to be applied to Combined. But I do want the property conflicts that would result in doing:

model Combined {
  ... Base;
  ... Overrides;
}

...with last-in-wins semantics...

@bterlson
Copy link
Member

I am missing something obvious here, but... how is this different from spread?

@timotheeguerin
Copy link
Member

with spread you cannot override properties, here proposal is to have something that would behave like TS object spread

@bterlson
Copy link
Member

Ahh right. I don't remember why we made our spread not allow duplicates, but is that something we could change also? I am allergic to adding yet another composition mechanism.

@timotheeguerin
Copy link
Member

Yeah I think the one thing though is that right now A & B and {...A, ...B} are exactly the same, I feel like A & B shouldn't be overriding(it merge in typescript)

@timotheeguerin
Copy link
Member

Noting that this behavior of overriding is not possible in the typescript type system( as far as I remember), you can override object properties this way but not interface memebers

@bterlson
Copy link
Member

bterlson commented Nov 17, 2022

The type system does allow it in the sense that runtime spreads do the override calculations in the type system, but you can't declare such types (there is an issue tracking it that has been open for some time).

If the only real justification for spread not overriding previous properties is to maintain alignment with intersection, then I would be fine updating spread to override. Intersection should probably intersect same-named properties too, and that would definitely not make sense for spread...

@johanste
Copy link
Contributor Author

johanste commented Oct 1, 2023

One would also have to decide what to do for nested properties. You commonly want json-merge-patch like merge as opposed to replace-at-top-level. And controlling this would be the main reason to introduce another merge operator.

@fuunnx
Copy link

fuunnx commented Dec 19, 2024

Hi, what about somethings like that ?

model Base {
  id: string;
  etag?: string;
  apiVersion: string;
}

// option A1 : new "@override" decorator on the properties (OK, except "override" is not actually a metadata)
model Combined {
  ...Base;
  @override id: int32;
  description?: string; // overriding a non existent property would print an error
  @override apiVersion: never;
}

// option A2 : new "override" keyword on the properties (great, but introduces a new keyword)
model Combined {
  ...Base;
  override id: int32;
  description?: string; // overriding a non existent property would print an error
  override apiVersion: never;
}

// option B1 : new "@override" decorator on the model (not my fav)
@override
model Combined {
  ...Base;
  id: int32;
  description?: string;
  apiVersion: never;
}

// option B2 : new "extends" keyword (not my fav, and introduces a new keyword)
model Combined extends Base {
  id: int32;
  description?: string;
  apiVersion: never;
}

// or something in between ?

Also:

One would also have to decide what to do for nested properties. You commonly want json-merge-patch like merge as opposed to replace-at-top-level. And controlling this would be the main reason to introduce another merge operator.

I could live without as I live without it everyday in the JS ecosystem :D

But yeah, could be great (another keyword ? ^^)


Kindly, in the hope of reviving this discussion for a top needed feature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design:needed A design request has been raised that needs a proposal feature New feature or request
Projects
None yet
Development

No branches or pull requests

6 participants