Coder Social home page Coder Social logo

cds-ts-dispatcher's Introduction

CDS-TS Dispatcher

The goal of CDS-TS-Dispatcher is to significantly reduce the boilerplate code required to implement TS handlers provided by the SAP CAP framework.

Table of Contents

Prerequisites

Install @sap/cds-dk globally:

npm i -g @sap/cds-dk

Installation

Install CDS-TS-Dispatcher - New project

Use the following steps if you want to create a new SAP CAP project.

  1. Create new folder :
mkdir new-sap-cap-project
cd new-sap-cap-project
  1. Initialize the CDS folder structure :
cds init
  1. Add the the following NPM packages :
npm install @dxfrontier/cds-ts-dispatcher @sap/cds express
npm install --save-dev @types/node @cap-js/sqlite typescript
  1. Add a tsconfig.json :
tsc --init
  1. It is recommended to use the following tsconfig.json properties:
{
  "compilerOptions": {
    /* Base Options: */
    "esModuleInterop": true,
    "skipLibCheck": true,
    "allowJs": true,
    "strictPropertyInitialization": false,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "strictNullChecks": true,
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",

    /* Allow decorators */
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,

    /* Strictness */
    "strict": true,

    "lib": ["es2022"],

    "outDir": "./gen/srv"
  },
  "include": ["./srv"]
}
  1. Run the CDS-TS server
cds-ts watch

Install CDS-TS-Dispatcher - Existing project

Use the following steps if you want to add only the @dxfrontier/cds-ts-dispatcher to an existing project :

npm install @dxfrontier/cds-ts-dispatcher

It is recommended to use the following tsconfig.json properties:

{
  "compilerOptions": {
    /* Base Options: */
    "esModuleInterop": true,
    "skipLibCheck": true,
    "allowJs": true,
    "strictPropertyInitialization": false,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "strictNullChecks": true,
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",

    /* Allow decorators */
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,

    /* Strictness */
    "strict": true,

    "lib": ["es2022"],

    "outDir": "./gen/srv"
  },
  "include": ["./srv"]
}

Warning

If below message appears

-----------------------------------------------------------------------
WARNING: Package '@sap/cds' was loaded from different installations: [
 '***/node_modules/@sap/cds/lib/index.js',
 '***/node_modules/@dxfrontier/cds-ts-dispatcher/node_modules/@sap/cds/lib/index.js'
] Rather ensure a single install only to avoid hard-to-resolve errors.
-----------------------------------------------------------------------

Run the following command :

npm install @sap/cds@latest

(back to top)

Generate CDS Typed entities

Option 1 - Recommended

Execute the following commands :

cds add typer
npm install

Tip

If above option is being used, this means whenever we change a .CDS file the changes will be reflected in the generated @cds-models folder.

Option 2

Execute the command :

npx @cap-js/cds-typer "*" --outputDirectory ./srv/util/types/entities
  • Target folder :./srv/util/types/entities - Change to your desired destination folder.

Tip

If above option is being used, you have to run every time the command when you do a change in a .CDS file

Important

Caution

Import always the generated entities from the service folders and not from the index.ts

alt text

For more info see official SAP CDS-Typer page.

(back to top)

Architecture

We recommend adhering to the Controller-Service-Repository design pattern using the following folder structure:

  1. EntityHandler (Controller) - Responsible for managing the REST interface to the business logic implemented in ServiceLogic
  2. ServiceLogic (Service) - Contains business logic implementations
  3. Repository (Repository) - This component is dedicated to handling entity manipulation operations by leveraging the power of CDS-QL.

Controller-Service-Repository suggested folder structure

alt text <= expanded folders => alt text

Usage

CDSDispatcher

CDSDispatcher(entities : Constructable[])

The CDSDispatcher constructor allows you to create an instance for dispatching and managing entities.

Parameters

  • entities (Array): An array of Entity handler(s) (Constructable) that represent the entities in the CDS.

Method

Example

import { CDSDispatcher } from '@dxfrontier/cds-ts-dispatcher';

module.exports = new CDSDispatcher([
  BookHandler,
  ReviewHandler,
  UnboundActionsHandler,
  // ...
]).initialize();

Visual image

(back to top)

Decorators

Class

EntityHandler

@EntityHandler(entity: CDSTyperEntity)

The @EntityHandler decorator is utilized at the class-level to annotate a class with the specific entity that will be used in all handlers.

Parameters

  • entity (CDSTyperEntity): A specialized class generated using the CDS-Typer.

Example

import { EntityHandler } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@EntityHandler(MyEntity)
class CustomerHandler {
  ...
  constructor() {}
  ...

Note

MyEntity was generated using CDS-Typer and imported in the class.

(back to top)

ServiceLogic

@ServiceLogic()

The @ServiceLogic decorator is utilized at the class-level to annotate a class as a specialized class containing only business logic.

When applying ServiceLogic decorator, the class becomes eligible to be used with Inject decorator for Dependency injection

Example

import { ServiceLogic } from '@dxfrontier/cds-ts-dispatcher';

@ServiceLogic()
class CustomerService {
  ...
  constructor() {}
  ...

(back to top)

Repository

@Repository()

The @Repository decorator is utilized as a class-level annotation that designates a particular class as a specialized Repository.

When applying Repository decorator, the class becomes eligible to be used with Inject decorator for Dependency injection

import { Repository } from '@dxfrontier/cds-ts-dispatcher';

@Repository()
class CustomerRepository {
  ...
  constructor() {}
  ...
[Optional] - BaseRepository

The BaseRepository was designed to reduce the boilerplate code required to implement data access layer for persistance entities.

It simplifies the implementation by offering a set of ready-to-use actions for interacting with the database. These actions include:

  • .create(): Create new records in the database.
  • .findAll(): Retrieve all records from the database.
  • .find(): Query the database to find specific data.
  • .delete(): Remove records from the database.
  • .exists(): Check the existence of data in the database.
  • ... and many other actions

To get started, refer to the official documentation BaseRepository. Explore the capabilities it offers and enhance your data access layer with ease.

Example

import { Repository } from '@dxfrontier/cds-ts-dispatcher';
import { BaseRepository } from '@dxfrontier/cds-ts-repository';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@Repository()
class CustomerRepository extends BaseRepository<MyEntity> {
  constructor() {
    super(MyEntity);
  }

  public async aMethod() {
    const created = this.create(...)
    const createdMany = this.createMany(...)
    const updated = this.update(...)
    // ...
  }
}

Note

MyEntity was generated using CDS-Typer and imported in the class.

(back to top)

UnboundActions

@UnboundActions()

The @UnboundActions decorator is utilized at the class-level to annotate a class as a specialized class which will be used only for Unbound actions.

Example

import { UnboundActions } from '@dxfrontier/cds-ts-dispatcher';

@UnboundActions()
class UnboundActionsHandler {
  ...
  constructor() {}
  // all unbound actions
  ...

Imported it in the CDSDispatcher

import { CDSDispatcher } from '@dxfrontier/cds-ts-dispatcher';

module.exports = new CDSDispatcher([UnboundActionsHandler, ...]).initialize();

Note

The reason behind introducing a distinct decorator for Unbound actions stems from the fact that these actions are not associated with any specific Entity but instead these actions belongs to the Service itself.

(back to top)

Fields

Inject

@Inject(serviceIdentifier: ServiceIdentifierOrFunc<unknown>)

The @Inject decorator is utilized as a field-level decorator and allows you to inject dependencies into your classes.

Parameters

  • serviceIdentifier(ServiceIdentifierOrFunc<unknown>): A Class representing the service to inject.

Example

import { EntityHandler, Inject, SRV, Service } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@EntityHandler(MyEntity)
class CustomerHandler {
  ...
  @Inject(CustomerService) private customerService: CustomerService
  @Inject(SRV) private srv: Service
  ...
  constructor() {}
  ...

Note

MyEntity was generated using CDS-Typer and imported in the class.

(back to top)

Inject SRV

@Inject(SRV) private srv: Service

This specialized @Inject can be used as a constant in @ServiceLogic, @Repository, @EntityHandler and @UnboundActions classes, it can be accessed trough this.srv and contains the CDS srv for further enhancements.

Example

import { EntityHandler, Inject, SRV, Service } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@EntityHandler(MyEntity)
// OR @ServiceLogic()
// OR @Repository()
// OR @UnboundActions
class CustomerHandler { // OR CustomerService, CustomerRepository
  ...
  @Inject(SRV) private srv: Service
  ...
  constructor() {}
  ...

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

Methods - active entity

Before

Use @BeforeCreate(), @BeforeRead(), @BeforeUpdate(), @BeforeDelete() to register handlers to run before .on handlers, frequently used for validating user input.

The handlers receive one argument:

  • req of type TypedRequest

See also the official SAP JS CDS-Before event

Note

If @odata.draft.enabled: true to manage event handlers for draft version you can use @BeforeCreateDraft(), BeforeReadDraft(), @BeforeUpdateDraft(), @BeforeDeleteDraft()

(back to top)

BeforeCreate

@BeforeCreate()

It is important to note that decorator @BeforeCreate() will be triggered based on the EntityHandler argument => MyEntity

Example

import { BeforeCreate, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeCreate()
public async beforeCreateMethod(req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('CREATE', MyEntity, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

BeforeRead

@BeforeRead()

It is important to note that decorator @BeforeRead() will be triggered based on the EntityHandler argument => MyEntity

Example

import { BeforeRead, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeRead()
public async beforeReadMethod(req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('READ', MyEntity, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

BeforeUpdate

@BeforeUpdate()

It is important to note that decorator @BeforeUpdate() will be triggered based on the EntityHandler argument => MyEntity

Example

import { BeforeUpdate, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeUpdate()
public async beforeUpdateMethod(req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('UPDATE', MyEntity, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

BeforeDelete

@BeforeDelete()

It is important to note that decorator @BeforeDelete() will be triggered based on the EntityHandler argument => MyEntity

Example

import { BeforeDelete, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeDelete()
public async beforeDeleteMethod(req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('DELETE', MyEntity, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

After

Use @AfterCreate(), @AfterRead(), @AfterUpdate(), @AfterDelete() register handlers to run after the .on handlers, frequently used to enrich outbound data.

The handlers receive two arguments:

  • results (for @AfterRead): An array of type MyEntity[].
  • result (for @AfterUpdate and @AfterCreate): An object of type MyEntity.
  • deleted (for @AfterDelete): A boolean indicating whether the entity was deleted.
  • req: An object of type TypedRequest.

See also the official SAP JS CDS-After event

Note

If @odata.draft.enabled: true to manage event handlers for draft version you can use @AfterCreateDraft(), AfterReadDraft(), @AfterUpdateDraft(), @AfterDeleteDraft()

(back to top)

AfterCreate

@AfterCreate()

It is important to note that decorator @AfterCreate() will be triggered based on the EntityHandler argument => MyEntity

Example

import { AfterCreate, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterCreate()
public async afterCreateMethod(results: MyEntity, req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('CREATE', MyEntity, async (result, req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

AfterRead

@AfterRead()

Example

It is important to note that decorator @AfterRead() will be triggered based on the EntityHandler argument MyEntity

import { AfterRead, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterRead()
public async afterReadMethod(results: MyEntity[], req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('READ', MyEntity, async (results, req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

AfterUpdate

@AfterUpdate()

It is important to note that decorator @AfterUpdate() will be triggered based on the EntityHandler argument => MyEntity

Example

import { AfterUpdate, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterUpdate()
public async afterUpdateMethod(result: MyEntity, req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('UPDATE', MyEntity, async (result, req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

AfterDelete

@AfterDelete()

It is important to note that decorator @AfterDelete() will be triggered based on the EntityHandler argument => MyEntity

Example

import { AfterDelete, Request} from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterDelete()
public async afterDeleteMethod(deleted: boolean, req: Request) {
  // ...
}

Equivalent to 'JS'

this.after('DELETE', MyEntity, async (deleted, req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

On

Use @OnCreate(), @OnRead(), @OnUpdate(), @OnDelete(), OnAction(), @OnFunction(), @OnBoundAction(), @OnBoundFunction() handlers to fulfill requests, e.g. by reading/writing data from/to databases handlers.

The handlers receive two arguments:

  • req of type TypedRequest
  • next of type Function

See also the official SAP JS CDS-On event

Note

If @odata.draft.enabled: true to manage event handlers for draft version you can use @OnCreateDraft(), @OnReadDraft(), @OnUpdateDraft(), @OnDeleteDraft(), @OnBoundActionDraft(), @OnBoundFunctionDraft()

(back to top)

OnCreate

@OnCreate()

It is important to note that decorator @OnCreate() will be triggered based on the EntityHandler argument => MyEntity

Example

import { OnCreate, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnCreate()
public async onCreateMethod(req: TypedRequest<MyEntity>, next: Function) {
  // ...
}

Equivalent to 'JS'

this.on('CREATE', MyEntity, async (req, next) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

OnRead

@OnRead()

It is important to note that decorator @OnRead() will be triggered based on the EntityHandler argument => MyEntity

Example

import { OnRead, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnRead()
public async onReadMethod(req: TypedRequest<MyEntity>, next: Function) {
  // ...
}

Equivalent to 'JS'

this.on('READ', MyEntity, async (req, next) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

OnUpdate

@OnUpdate()

It is important to note that decorator @OnUpdate() will be triggered based on the EntityHandler argument => MyEntity

Example

import { OnUpdate, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnUpdate()
public async onUpdateMethod(req: TypedRequest<MyEntity>, next: Function) {
  // ...
}

Equivalent to 'JS'

this.on('UPDATE', MyEntity, async (req, next) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

OnDelete

@OnDelete()

It is important to note that decorator @OnDelete() will be triggered based on the EntityHandler argument => MyEntity

Example

import { OnDelete, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnDelete()
public async onDeleteMethod(req: TypedRequest<MyEntity>, next: Function) {
  // ...
}

Equivalent to 'JS'

this.on('DELETE', MyEntity, async (req, next) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

OnAction

@OnAction(name : CdsAction)

Parameters

  • name (CdsAction) : Representing the CDS action defined in the CDS file

Example

import { OnAction, ActionRequest, ActionReturn } from "@dxfrontier/cds-ts-dispatcher";
import { AnAction } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnAction(AnAction)
public async onActionMethod(req: ActionRequest<typeof AnAction>, next: Function): ActionReturn<typeof AnAction> {
  // ...
}

Equivalent to 'JS'

this.on(AnAction, async (req, next) => {
  // ...
});

Note

AnAction was generated using CDS-Typer and imported in the the class.

(back to top)

OnFunction

@OnFunction(name : CdsFunction)

Parameters

  • name (CdsFunction) : Representing the CDS action defined in the CDS file.

Example

import { OnFunction, ActionRequest, ActionReturn } from "@dxfrontier/cds-ts-dispatcher";
import { AFunction } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnFunction(AFunction)
public async onFunctionMethod(req: ActionRequest<typeof AFunction>, next: Function): ActionReturn<typeof AFunction> {
  // ...
}

Equivalent to 'JS'

this.on(AFunction, async (req) => {
  // ...
});

Note

AFunction was generated using CDS-Typer and imported in the the class.

(back to top)

OnBoundAction

@OnBoundAction(name : CdsAction)

It is important to note that decorator @OnBoundAction() will be triggered based on the EntityHandler argument => MyEntity

Parameters

  • name (CdsAction) : Representing the CDS action defined in the CDS file.

Example

import { OnBoundAction, ActionRequest, ActionReturn } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnBoundAction(MyEntity.actions.AnAction)
public async onActionMethod(req: ActionRequest<typeof MyEntity.actions.AnAction>, next: Function): ActionReturn<typeof MyEntity.actions.AnAction> {
  // ...
}

Equivalent to 'JS'

this.on(MyEntity.actions.AnAction, MyEntity, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

OnBoundFunction

@OnBoundFunction(name : CdsFunction)

It is important to note that decorator @OnBoundFunction() will be triggered based on the EntityHandler argument => MyEntity

Parameters

  • name (CdsFunction) : Representing the CDS action defined in the CDS file.

Example

import { OnBoundFunction, ActionRequest, ActionReturn } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnBoundFunction(MyEntity.actions.AFunction)
public async onFunctionMethod(req: ActionRequest<typeof MyEntity.actions.AFunction>, next: Function): ActionReturn<typeof MyEntity.actions.AFunction> {
  // ...
}

Equivalent to 'JS'

this.on(MyEntity.actions.AFunction, MyEntity, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

Methods : draft entity

Before

Use @BeforeNewDraft(), @BeforeCancelDraft(), @BeforeEditDraft(), @BeforeSaveDraft(), @BeforeCreateDraft(), @BeforeReadDraft(), @BeforeUpdateDraft(), @BeforeDeleteDraft() to register handlers to run before .on handlers, frequently used for validating user input.

The handlers receive one argument:

  • req of type TypedRequest

See also the official SAP JS CDS-Before event

BeforeNewDraft

@BeforeNewDraft()

Use this decorator when you want to validate inputs before a new draft is created.

It is important to note that decorator @BeforeNewDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { BeforeNewDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeNewDraft()
public async beforeCreateDraftMethod(req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('NEW', MyEntity.drafts, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

BeforeCancelDraft

@BeforeCancelDraft()

Use this decorator when you want to validate inputs before a draft is discarded.

It is important to note that decorator @BeforeCancelDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { BeforeCancelDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeCancelDraft()
public async beforeCancelDraftMethod(req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('CANCEL', MyEntity.drafts, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

BeforeEditDraft

@BeforeEditDraft()

Use this decorator when you want to validate inputs when a new draft is created from an active instance.

It is important to note that decorator @BeforeEditDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { BeforeEditDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeEditDraft()
public async beforeEditDraftMethod(req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('EDIT', MyEntity, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

BeforeSaveDraft

@BeforeSaveDraft()

Use this decorator when you want to validate inputs when active entity is changed.

It is important to note that decorator @BeforeSaveDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { BeforeSaveDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeSaveDraft()
public async beforeSaveDraftMethod(req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('SAVE', MyEntity, async (req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

After

Use @AfterNewDraft(), @AfterCancelDraft(), @AfterEditDraft(), @AfterSaveDraft(), @AfterCreateDraft(), @AfterReadDraft(), @AfterUpdateDraft(), @AfterDeleteDraft() register handlers to run after the .on handlers, frequently used to enrich outbound data. The handlers receive two arguments:

The results from the preceding .on handler, with the following types:

  • results (of type MyEntity[]) for @AfterRead

  • result (of type MyEntity) for @AfterUpdate and @AfterCreate

  • deleted (of type boolean) for @AfterDelete

  • req of type TypedRequest

See also the official SAP JS CDS-After event

AfterNewDraft

@AfterNewDraft()

Use this decorator when you want to enhance outbound data when a new draft is created.

It is important to note that decorator @AfterNewDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { AfterNewDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterNewDraft()
public async afterNewDraftMethod(results: MyEntity, req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('NEW', MyEntity.drafts, async (results, req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

AfterCancelDraft

@AfterCancelDraft()

Use this decorator when you want to enhance outbound data when a draft is discarded.

It is important to note that decorator @AfterCancelDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { AfterCancelDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterCancelDraft()
public async afterCancelDraftMethod(results: MyEntity, req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('CANCEL', MyEntity.drafts, async (results, req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

AfterEditDraft

@AfterEditDraft()

Use this decorator when you want to enhance outbound data when a new draft is created from an active instance.

It is important to note that decorator @AfterEditDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { AfterEditDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterEditDraft()
public async afterEditDraftMethod(results: MyEntity, req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('EDIT', MyEntity, async (results, req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

AfterSaveDraft

@AfterSaveDraft()

Use this decorator when you want to enhance outbound data when the active entity is changed.

It is important to note that decorator @AfterSaveDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { AfterSaveDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterSaveDraft()
public async afterSaveDraftMethod(results: MyEntity, req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('SAVE', MyEntity, async (results, req) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

On

Use @OnNewDraft(), @OnCancelDraft(), @OnCancelDraft(), @OnSaveDraft(), @OnReadDraft(), @OnUpdateDraft(), @OnCreateDraft(), @OnDeleteDraft(), @OnBoundActionDraft(), @OnBoundFunctionDraft() handlers to support for both, active and draft entities.

The handlers receive two arguments:

  • req of type TypedRequest
  • next of type Function

See Official SAP Fiori-draft

OnNewDraft

@OnNewDraft()

This decorator will be triggered when a new draft is created.

It is important to note that decorator @OnNewDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { OnNewDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnNewDraft()
public async onNewDraft(req: TypedRequest<MyEntity>, next: Function) {
  // ...
}

Equivalent to 'JS'

this.on('NEW', MyEntity.drafts, async (req, next) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

OnCancelDraft

@OnCancelDraft()

This decorator will be triggered when a draft is cancelled.

It is important to note that decorator @OnCancelDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { OnCancelDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnCancelDraft()
public async onCancelDraft(req: TypedRequest<MyEntity>, next: Function) {
  // ...
}

Equivalent to 'JS'

this.on('CANCEL', MyEntity.drafts, async (req, next) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

OnEditDraft

@OnEditDraft()

This decorator will be triggered when a new draft is created from an active instance

It is important to note that decorator @OnEditDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { OnEditDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnEditDraft()
public async onEditDraft(req: TypedRequest<MyEntity>, next: Function) {
  // ...
}

Equivalent to 'JS'

this.on('EDIT', MyEntity, async (req, next) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

OnSaveDraft

@OnSaveDraft()

This decorator will be triggered when the active entity is changed

It is important to note that decorator @OnSaveDraft() will be triggered based on the EntityHandler argument => MyEntity

Example

import { OnSaveDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnSaveDraft()
public async onSaveDraft(req: TypedRequest<MyEntity>, next: Function) {
  // ...
}

Equivalent to 'JS'

this.on('SAVE', MyEntity, async (req, next) => {
  // ...
});

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

Other draft handlers

All active entity On, Before, After events have also a Draft variant.

Note

Except the @OnAction(), @OnFunction() as this are bound to the service and not to an entity.

(back to top)

Method : SingleInstanceCapable

@SingleInstanceCapable()

The @SingleInstanceCapable() decorator is applied at the method level to indicate that all decorators used in conjunction with this decorator will handle both single instance and entity set requests, this behaves like a switch when the REQUEST is entity set and single instance, so you can manage different behavior.

Complementary Decorator Actions

@SingleInstanceCapable can be used together with the following decorator actions :

Examples

Example 1 : Handling single instance request

import { AfterRead, SingleInstanceCapable, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterRead()
@SingleInstanceCapable()
public async singeInstanceMethodAndEntitySet(results : MyEntity[], req: TypedRequest<MyEntity>, isSingleInstance: boolean) {
  if(isSingleInstance) {
    // This will be executed only when single instance read is performed
    // isSingleInstance flag will be `true`
    return this.customerService.handleSingleInstance(req)
  }
}

Example 2 : Differing behavior for single instance and entity set requests

@AfterRead()
@SingleInstanceCapable()
@BeforeRead()
public async singeInstanceMethodAndEntitySet(results : MyEntity[], req: TypedRequest<MyEntity>, isSingleInstance: boolean) {
  if(isSingleInstance) {
    // This method will be executed for 'AfterRead` single instance
    return this.customerService.handleSingleInstance(req)
  }

  // This method will be executed for `BeforeRead` both cases : single instance & entity set
  return this.customerService.handleEntitySet(req)
}

Note

MyEntity was generated using CDS-Typer and imported in the the class.

(back to top)

Deployment to BTP using MTA

  1. Add mta.yaml to your project using the following command :
cds add mta
  1. Install npm-run-all package:
npm install --save-dev npm-run-all
  1. Modify your package.json by adding the following scripts:
"build:cds": "echo 'STEP 1 : Build CDS' && cds build --production",
"build:ts": "echo 'STEP 2 : Transpile TS => JS' && tsc",
"build:srv:clean:ts": "echo 'Step 3: Clean TS files from srv folder' && find gen/srv/srv -type f -name '*.ts' -delete",

"build:production": "run-s build:cds build:ts build:srv:clean:ts"
  1. Modify mta.yaml as follows :
- builder: custom
  commands:
    - npm ci
    - npm run build:production
    - npx @cap-js/cds-typer "*" --outputDirectory gen/srv/@cds-models
  • npm ci - Will do a clean install
  • npm run build:production - will run the package.json script command for CDS build and transpilation of TS to JS
  • npx @cap-js/cds-typer "*" --outputDirectory gen/srv/@cds-models - will make sure the @cds-models are generated.
  1. Run to produce the .mtar file
mbt build
  1. Deploy your mtar to BTP

Examples

Find here a collection of samples for the CDS-TS-Dispatcher-Samples

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

Licence

Copyright (c) 2023 DXFrontier

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Authors

(back to top)

cds-ts-dispatcher's People

Contributors

dragolea avatar sblessing avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.