cap-js / cds-typer

CDS type generator for JavaScript
Apache License 2.0
29 stars 10 forks source link

Always express structured types as flat properties #372

Open daogrady opened 1 month ago

daogrady commented 1 month ago

Fixes internal issue 14369

type Point {
  x: Integer;
  y: Integer;
}

entity Thing {
  position: Point
}

shall result in

class Point {
  x: number
  y: number
}

class Thing {
  position_x: number
  position_y: number
}

instead of

class Thing {
  position: Point
}
stockbal commented 3 weeks ago

Hi @daogrady,

I think this has to be implemented depending on two factors:

Consider the following CDS model:

// /db/datamodel.cds
type Author {
  firstName : String(60);
  lastName  : String(60);
  address   : {
    place   : String(30);
    zip     : String(10);
  };
}

entity Books : cuid {
  title        : String;
  author       : Author;
  otherAuthors : array of Author;  
  inlineAuthor : {
    firstName : String;
    lastName : String;
  };
  inlineAuthors: array of {
    name : String;
    address : {
      place : String;
    }
  };
}

// /srv/cat-service.cds
using {my.bookshop} from '../db/data-model';

service CatalogService {
  @readonly entity Books as projection on bookshop.Books;
} 

This will result in the following OData metadata for the CatalogService:

<Schema Namespace="CatalogService" xmlns="http://docs.oasis-open.org/odata/ns/edm">
    <EntityContainer Name="EntityContainer">
        <EntityType Name="Books">
            <Property Name="title" Type="Edm.String"/>
            <Property Name="authors" Type="Collection(CatalogService.my_bookshop_Author)" Nullable="true"/>
            <Property Name="otherAuthors" Type="Collection(CatalogService.my_bookshop_Author)" Nullable="true"/>
            <Property Name="inlineAuthor_firstName" Type="Edm.String"/>
            <Property Name="inlineAuthor_lastName" Type="Edm.String"/>
            <Property Name="inlineAuthors" Type="Collection(CatalogService.Books_inlineAuthors)" Nullable="true"/>
            <Property Name="author_firstName" Type="Edm.String" MaxLength="60"/>
            <Property Name="author_lastName" Type="Edm.String" MaxLength="60"/>
            <Property Name="author_address_place" Type="Edm.String" MaxLength="30"/>
            <Property Name="author_address_zip" Type="Edm.String" MaxLength="10"/>    
        </EntityType>
        <ComplexType Name="Books_inlineAuthors">
            <Property Name="name" Type="Edm.String"/>
            <Property Name="address" Type="CatalogService.Books_inlineAuthors_address"/>
        </ComplexType>
        <ComplexType Name="Books_inlineAuthors_address">
            <Property Name="place" Type="Edm.String"/>
        </ComplexType>
        <ComplexType Name="my_bookshop_Author">
            <Property Name="firstName" Type="Edm.String" MaxLength="60"/>
            <Property Name="lastName" Type="Edm.String" MaxLength="60"/>
            <Property Name="address" Type="CatalogService.my_bookshop_Author_address"/>
        </ComplexType>
            <ComplexType Name="my_bookshop_Author_address">
            <Property Name="place" Type="Edm.String" MaxLength="30"/>
            <Property Name="zip" Type="Edm.String" MaxLength="10"/>
        </ComplexType>
    </EntityContainer>
</Schema>

According to this, entity elements that are non-arrayed and structured are flattened regardless if they are concrete types or inline. However, elements with arrayed structured types converted into collections of complex types and are therefore kept structured.

The resulting (simplified) types should therefore look something like this:

// class for type Author
class Author {
  firstName: string;
  lastName: string;
  address: {
    place: string;
    zip: string;
  }
}
// class for entity Books
class Book {
  title: string;
  inlineAuthor_firstName: string;
  inlineAuthor_lastName: string;
  inlineAuthors: Array<{
    name: string;
    address: {
      place: string;
    };
  }>;
  otherAuthors: Array<Author>;
  author_firstName: string;
  author_lastName: string;
  author_address_place: string;
  author_address_zip: string;
}
daogrady commented 1 week ago

Hi @stockbal ,

thank you very much for weighing in on this change and pointing out this nuance! 🙂 I will actually shelve this PR for now, as the (internal) issue that prompted this change has been resolved for now, so unless other users run into this (still factually wrong) behaviour, I would like to deprioritise it for now.

Best, Daniel