All skills
secondsky avatar

/sap-cap-capire

@620a19a
by Eddiesecondsky/sap-skills456 stars
120

SAP Cloud Application Programming Model (CAP) development skill using Capire documentation. Use when: building CAP applications, defining CDS models, implementing services, working with SAP HANA/SQLite/PostgreSQL databases, deploying to SAP BTP Cloud Foundry or Kyma, implementing Fiori UIs, handling authorization, multitenancy, or messaging. Covers CDL/CQL/CSN syntax, Node.js and Java runtimes, event handlers, OData services, and CAP plugins.

Use this Skill: https://skilld.dev/gh/secondsky/sap-skills/sap-cap-capire

This session only. Nothing lands on disk.

referencescdl-syntax.md

≈2.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

CDL (Conceptual Definition Language) Complete Syntax Reference

Source: https://cap.cloud.sap/docs/cds/cdl

Table of Contents

Keywords & Identifiers

  • Keywords are case-insensitive (typically lowercase)
  • Identifiers are case-sensitive; must match /^[$A-Za-z_]\w*$/
  • Delimited identifiers use ![identifier name] syntax (avoid when possible)

Literals & Values

// Booleans
true, false, null

// Numbers
11, 2.4, 1e3, 1.23e-11

// Strings
'single quotes'
`backtick for
multiline strings`

// Records & Arrays
{ key: 'value', nested: { prop: 1 } }
[1, 'two', { three: 4 }]

// Date/Time literals
date'2024-11-22'
time'16:30:00'
timestamp'2024-11-22T16:30:00Z'

Comments

// Line-end comment

/* Block comment
   spanning multiple lines */

/**
 * Doc comment - stored in CSN 'doc' property
 * Supports markdown formatting
 */
entity Books { ... }

Model Organization

Namespaces

namespace my.bookshop;
entity Books { ... }  // Full name: my.bookshop.Books

Contexts

context admin {
  entity Users { ... }  // Full name: my.bookshop.admin.Users
}

Scoped Names

entity Orders { ... }
entity Orders.Items { ... }  // Scoped under Orders

Imports

using my.bookshop.Books from './db/schema';
using { Authors, Genres } from './db/schema';
using { Books as MyBooks } from './db/schema';
using * from './db/schema';  // Import all definitions

Entity Definitions

Basic Entity

entity Books {
  key ID    : UUID;
  title     : String(255) not null;
  descr     : String(5000);
  stock     : Integer default 0;
  price     : Decimal(10,2);
  available : Boolean default true;
}

Structured Elements

type Address {
  street  : String;
  city    : String;
  zipCode : String(10);
  country : Country;
}

entity Customers {
  homeAddress : Address;
  workAddress : Address;
}

Arrayed Types

entity Contacts {
  emails : many String;           // Array of strings
  phones : array of String(20);   // Same as above
  tags   : many { name: String }; // Array of structs
}

Virtual Elements

entity Employees {
  // Not persisted, computed at runtime
  virtual fullName : String @Core.Computed;
}

Calculated Elements

On-read (computed during queries):

entity Employees {
  firstName : String;
  lastName  : String;
  fullName  : String = firstName || ' ' || lastName;
  upperName : String = upper(fullName);
}

Stored (persisted in database):

entity Employees {
  fullName : String = (firstName || ' ' || lastName) stored;
}

Default Values

entity Orders {
  status    : String default 'draft';
  priority  : Integer default 5;
  createdAt : Timestamp default $now;
  createdBy : String default $user;
}

Type References

entity Books {
  title     : String(200);
  subtitle  : type of title;        // Same type as title
}

entity Reviews {
  bookTitle : Books:title;          // Reference Books.title type
}

Constraints

entity Books {
  title : String(200) not null;
  isbn  : String(13) not null unique;
}

// Unique constraints
@assert.unique: {
  isbn: [isbn],
  titleAuthor: [title, author_ID]
}
entity Books { ... }

Enumerations

// String enum
type Status : String enum {
  draft;
  submitted;
  approved;
  rejected = 'REJ';  // Custom value
}

// Integer enum
type Priority : Integer enum {
  low = 1;
  medium = 2;
  high = 3;
}

entity Orders {
  status   : Status default #draft;
  priority : Priority default #medium;
}

Views & Projections

As Select From

entity BooksList as select from Books {
  ID,
  title,
  author.name as authorName,
  stock * price as value : Decimal
} where stock > 0
  order by title;

As Projection On

entity PublicBooks as projection on Books {
  ID, title, descr, author
} excluding { createdBy, modifiedBy };

View with Parameters

entity FilteredBooks(minStock: Integer, maxPrice: Decimal)
  as select from Books
  where stock >= :minStock
    and price <= :maxPrice;

Associations

Managed To-One

entity Books {
  author : Association to Authors;
  // CAP auto-generates foreign key column: author_ID
  // The FK type matches the target's primary key (UUID if Authors uses cuid)
  // No explicit definition needed - CAP handles persistence automatically
}

Managed To-One with Default

entity Orders {
  customer : Association to Customers default 'DEFAULT_CUSTOMER_ID';
}

Unmanaged Association

entity Books {
  author    : Association to Authors on author.ID = author_ID;
  author_ID : UUID;  // Explicit foreign key - REQUIRED for unmanaged associations
  // Unlike managed associations, you must define the FK field yourself
  // and specify the ON condition to join the entities
}

To-Many Association

entity Authors {
  books : Association to many Books on books.author = $self;
}

Many-to-Many (via Link Entity)

entity Books {
  categories : Association to many Book2Category on categories.book = $self;
}

entity Categories {
  books : Association to many Book2Category on books.category = $self;
}

entity Book2Category {
  key book     : Association to Books;
  key category : Association to Categories;
}

Infix Filters on Associations

entity Authors {
  // Filter: only books with stock > 0
  availableBooks : Association to many Books on availableBooks.author = $self
                   and availableBooks.stock > 0;
}

// In projections
entity AuthorDetails as projection on Authors {
  *,
  books[stock > 0] as availableBooks,
  books[1: favorite = true] as favoriteBook  // 1: reduces to single
}

Compositions

Basic Composition

entity Orders {
  key ID : UUID;
  Items  : Composition of many OrderItems on Items.order = $self;
}

entity OrderItems {
  key ID    : UUID;
  order     : Association to Orders;
  product   : Association to Products;
  quantity  : Integer;
}

Managed Composition (Inline)

entity Orders {
  key ID : UUID;
  Items  : Composition of many {
    key pos      : Integer;
    product      : Association to Products;
    quantity     : Integer;
    price        : Decimal(10,2);
  };
}
// Auto-creates: entity Orders.Items { ... }

Managed Composition (Named Aspect)

aspect OrderItem {
  key pos  : Integer;
  product  : Association to Products;
  quantity : Integer;
}

entity Orders {
  key ID : UUID;
  Items  : Composition of many OrderItem;
}

Annotations

Syntax Variations

@title: 'Books'
@description: 'All books in the catalog'
entity Books { ... }

// Multiple on same line
@readonly @cds.persistence.skip
entity TempData { ... }

// Grouped
@(
  title: 'Books',
  description: 'All books',
  UI.HeaderInfo: { TypeName: 'Book' }
)
entity Books { ... }

Annotation Values

@flag                        // true (default)
@enabled: true               // boolean
@count: 42                   // integer
@rate: 3.14                  // decimal
@label: 'Hello'              // string
@status: #active             // symbol/enum
@items: [1, 2, 3]            // array
@config: { a: 1, b: 2 }      // record
@expr: (price * quantity)    // expression

Element-Level Annotations

entity Books {
  @title: 'Book Title'
  @mandatory
  title : String;

  @readonly
  @Core.Computed
  totalValue : Decimal;
}

Annotation Propagation

Annotations propagate through:

  • Type inheritance
  • Views and projections
  • Association navigation

Stop propagation with null:

annotate ChildEntity with {
  field @parentAnnotation: null
}

Aspects

Define Aspect

aspect tracked {
  createdAt  : Timestamp @cds.on.insert: $now;
  createdBy  : String(255) @cds.on.insert: $user;
  modifiedAt : Timestamp @cds.on.insert: $now @cds.on.update: $now;
  modifiedBy : String(255) @cds.on.insert: $user @cds.on.update: $user;
}

Apply Aspect (Shortcut Includes)

entity Books : tracked {
  key ID : UUID;
  title  : String;
}

Extend Directive

extend Books with {
  newField   : String;
  otherField : Integer;
}

extend Books with tracked;

extend Books:price with @title: 'Price';

Annotate Directive

annotate Books with @title: 'Books';

annotate Books with {
  title @title: 'Book Title';
  price @Measures.Unit: currency_code;
}

Services

Service Definition

service CatalogService @(path: '/catalog') {
  entity Books as projection on my.Books;
  entity Authors as projection on my.Authors;
}

Multiple Protocols

@protocol: ['odata', 'rest']
service MultiProtocolService { ... }

Bound Actions/Functions

service OrderService {
  entity Orders { ... } actions {
    action confirm();
    action cancel(reason: String);
    function getTotal() returns Decimal;
  };
}

Unbound Actions/Functions

service UtilityService {
  action sendNotification(to: String, message: String);
  function calculateTax(amount: Decimal, region: String) returns Decimal;
}

Custom Events

service OrderService {
  event OrderCreated {
    orderID   : UUID;
    customer  : String;
    total     : Decimal;
    timestamp : Timestamp;
  }

  event OrderCancelled : projection on OrderCreated {
    orderID, reason: String
  }
}

Internal Services

@protocol: 'none'  // No external access
service InternalService { ... }

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The analyzed skill is a reference and template package providing guidance for SAP Cloud Application Programming Model (CAP) development, configuration, data privacy, and testing. It contains no executable scripts, hardcoded credentials, or malicious behavior.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    12/34 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 620a19a. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated 2 months ago
Other metadata
metadata
{
  "maintainer": "Eduard Jiglau",
  "maintainer_email": "hello@sap-ai-skills.com",
  "website": "https://sap-ai-skills.com",
  "version": "2.4.1",
  "last_verified": "2026-02-22",
  "cap_version": "@sap/cds 9.7.x",
  "mcp_version": "@cap-js/mcp-server 0.0.5",
  "lsp_version": "@sap/cds-lsp 9.7.x"
}

README badge

README badge for secondsky/sap-skills/sap-cap-capire