From bfed0407ca3a59209624185a0c2e27ec5446d01a Mon Sep 17 00:00:00 2001 From: Ludwig Stockbauer-Muhr <35834861+stockbal@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:49:49 +0200 Subject: [PATCH] feat: add static property `elements` to entity classes (#345) --- CHANGELOG.md | 1 + lib/components/basedefs.js | 4 ++++ lib/components/wrappers.js | 8 ++++++++ lib/visitor.js | 11 ++++++++++- test/unit/files/elements/model.cds | 19 +++++++++++++++++++ test/unit/files/elements/model.ts | 26 ++++++++++++++++++++++++++ 6 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 test/unit/files/elements/model.cds create mode 100644 test/unit/files/elements/model.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index be0fce05..a17eb11d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## Version 0.28.0 - TBD ### Added - Schema definition for `cds.typer` options in `package.json` and `.cdsrc-*.json` files +- Added a static `elements` property to all entities, which allows access to the `LinkedDefinitions` instance of an entity's elements - Schema definition for `typescript` cds build task. ### Fixed diff --git a/lib/components/basedefs.js b/lib/components/basedefs.js index 763fcf3b..482baa72 100644 --- a/lib/components/basedefs.js +++ b/lib/components/basedefs.js @@ -13,6 +13,10 @@ const timeRegex = '`${number}${number}:${number}${number}:${number}${number}`' const baseDefinitions = new SourceFile('_') // FIXME: this should be a library someday baseDefinitions.addPreamble(` +import { type } from '@sap/cds' + +export type ElementsOf = {[name in keyof Required]: type } + export namespace Association { export type to = T; export namespace to { diff --git a/lib/components/wrappers.js b/lib/components/wrappers.js index d442e5ed..cd9626db 100644 --- a/lib/components/wrappers.js +++ b/lib/components/wrappers.js @@ -17,6 +17,13 @@ const createKey = t => `${base}.Key<${t}>` */ const createKeysOf = t => `${base}.KeysOf<${t}>` +/** + * Wraps type into ElementsOf type. + * @param {string} t - the type name. + * @returns {string} + */ +const createElementsOf = t => `${base}.ElementsOf<${t}>` + /** * Wraps type into association to scalar. * @param {string} t - the singular type name. @@ -102,6 +109,7 @@ module.exports = { createArrayOf, createKey, createKeysOf, + createElementsOf, createObjectOf, createPromiseOf, createUnionOf, diff --git a/lib/visitor.js b/lib/visitor.js index fdac4432..53a20b2d 100644 --- a/lib/visitor.js +++ b/lib/visitor.js @@ -8,7 +8,7 @@ const { SourceFile, FileRepository, Buffer, Path } = require('./file') const { FlatInlineDeclarationResolver, StructuredInlineDeclarationResolver } = require('./components/inline') const { Resolver } = require('./resolution/resolver') const { LOG } = require('./logging') -const { docify, createPromiseOf, createUnionOf, createKeysOf } = require('./components/wrappers') +const { docify, createPromiseOf, createUnionOf, createKeysOf, createElementsOf } = require('./components/wrappers') const { csnToEnumPairs, propertyToInlineEnumName, isInlineEnumType, stringifyEnumType } = require('./components/enum') const { isReferenceType } = require('./components/reference') const { empty } = require('./components/typescript') @@ -167,6 +167,14 @@ class Visitor { buffer.add(`declare static readonly keys: ${createKeysOf(clean)}`) } + /** + * @param {Buffer} buffer - the buffer to write the elements into + * @param {string} clean - the clean name of the entity + */ + #printStaticElements(buffer, clean) { + buffer.add(`declare static readonly elements: ${createElementsOf(clean)}`) + } + /** * Transforms an entity or CDS aspect into a JS aspect (aka mixin). * That is, for an element A we get: @@ -281,6 +289,7 @@ class Visitor { buffer.add(`static readonly kind: 'entity' | 'type' | 'aspect' = '${entity.kind}';`) } this.#printStaticKeys(buffer, clean) + this.#printStaticElements(buffer, clean) this.#printStaticActions(entity, buffer, ancestorInfos, file) }, '};') // end of generated class }, '}') // end of aspect diff --git a/test/unit/files/elements/model.cds b/test/unit/files/elements/model.cds new file mode 100644 index 00000000..f3861866 --- /dev/null +++ b/test/unit/files/elements/model.cds @@ -0,0 +1,19 @@ +namespace elements_test; + +aspect A1 { + A_f1 : String; + A_f2 : String; +} + +entity E1 { + key ID: Integer; + a : String; + b : Integer; +} + +entity E2 : A1 { + key ID: String; + d: Integer; +} + +entity P1 as projection on E2; \ No newline at end of file diff --git a/test/unit/files/elements/model.ts b/test/unit/files/elements/model.ts new file mode 100644 index 00000000..4cbe575d --- /dev/null +++ b/test/unit/files/elements/model.ts @@ -0,0 +1,26 @@ +import cds from '@sap/cds' +import { E1, E2, P1 } from '#cds-models/elements_test' + +E1.elements +E1.elements.ID +E1.elements.a +E1.elements.b +// @ts-expect-error +E1.elements.nonExistent + +E2.elements +E2.elements.d // from entity E1 +E2.elements.A_f1 // from aspect A1 + +// check projection +P1.elements +P1.elements.ID +P1.elements.d +P1.elements.A_f1 +P1.elements.A_f2 + +// check LinkedDefinitions types +E1.elements.a.type +E1.elements.a.kind +E1.elements.a.items +E1.elements.a instanceof cds.builtin.classes.String \ No newline at end of file