Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
d206e26
Initial workflow setup
BobdenOs Jul 30, 2025
ec62acf
Initial version of database level federation
BobdenOs Aug 4, 2025
4de7be0
ignore generated default-env.json file
BobdenOs Aug 4, 2025
e26c703
Update references for rename
BobdenOs Aug 4, 2025
d2ba954
Add service level federation plugin
BobdenOs Aug 4, 2025
2f8dbf6
Use proper resolve function for workspace support
BobdenOs Aug 4, 2025
a54a217
Explicit read permission
BobdenOs Aug 5, 2025
be2326a
Add cf support for synonym federation
BobdenOs Aug 5, 2025
f56f098
Allow switching back to local HANA from cf
BobdenOs Aug 5, 2025
02d74e4
Fix part of UI (#3)
stewsk Aug 7, 2025
f71bd53
Add Data Sphere and scheduled replication support
BobdenOs Aug 9, 2025
54bf4ab
cosmetics
danjoa Aug 12, 2025
68ae982
Merge branch 'main' into cafe
danjoa Aug 12, 2025
6546172
Add sflight rap support
BobdenOs Aug 12, 2025
46aa45e
Switch to generating .env files
BobdenOs Aug 13, 2025
d3a2fba
Adjust env file cleanup to .env files
BobdenOs Aug 13, 2025
decd4a8
Fix Booking page route
BobdenOs Aug 13, 2025
c21a3b7
cleanup package.json
danjoa Aug 14, 2025
c1d39df
Feat: Extend srv-fed capabilities
stefanrudi Aug 14, 2025
f8c2883
Simulate cds-export/import
danjoa Aug 14, 2025
16fa6f2
Using cds-generated @capire/xflights-api
danjoa Aug 14, 2025
713c119
Merge branch 'main' into cafe
danjoa Aug 15, 2025
d8e77bf
Merge branch 'main' into cafe
danjoa Aug 16, 2025
67ba94e
Update model reference for sap.capire.flights.data to use @capire/xfl…
danjoa Aug 17, 2025
1b46477
Introducing @federated annotation
danjoa Aug 18, 2025
bcb44d4
Merge branch 'main' into cafe
danjoa Aug 18, 2025
961fed5
Merge branch 'main' into cafe
danjoa Aug 18, 2025
e9fef64
Re-adding .cdsrc.yaml in cafe branch
danjoa Aug 18, 2025
5bfb565
Service-level Replication
danjoa Aug 18, 2025
d5ccb9f
Added fed-xrv plugin -> doesn't need a profile
danjoa Aug 19, 2025
c16bc19
more cosmetics
danjoa Aug 19, 2025
661c38d
feat(app): Improve expand for srv-fed
stefanrudi Aug 21, 2025
7c4334e
Removed cds.requires entry
danjoa Aug 21, 2025
426b7fd
Merge remote-tracking branch 'origin/main' into cafe
danjoa Aug 21, 2025
0f3608b
Adjust fed-srv plugin for federated annotation
stefanrudi Aug 22, 2025
2a0f100
fix: Label 'datum' -> 'Booking Date'
danjoa Aug 22, 2025
7efd0a9
Adjust handling for flatten assoc in srv-fed for OData
stefanrudi Aug 22, 2025
1d4b642
Remove the unnecessary redirect round trip for all odata requests
BobdenOs Aug 26, 2025
f0299c2
Add xflights-api for abap injection
BobdenOs Aug 26, 2025
1f046f6
Merge branch 'cafe' of https://github.com/capire/xtravels into cafe
BobdenOs Aug 26, 2025
68a3d39
Merge branch 'main' into cafe
danjoa Aug 26, 2025
eff30e8
fix: Adjust service import for rep-srv profile
stefanrudi Aug 27, 2025
d15e154
Merge branch 'main' into cafe
danjoa Aug 28, 2025
1b4581d
Merge branch 'main' into cafe
danjoa Aug 29, 2025
695ea32
Merge branch 'main' into cafe
danjoa Sep 2, 2025
04f6dde
named apis
danjoa Sep 3, 2025
ceb8591
Merge branch 'main' into cafe
danjoa Sep 4, 2025
f3ebdfc
Merge branch 'main' into cafe
danjoa Sep 4, 2025
c545fe3
prep merging to main
danjoa Sep 4, 2025
b60e39b
merged main into current branch
danjoa Sep 4, 2025
6c768cb
Merge branch 'main' into cafe
danjoa Sep 4, 2025
9dbecab
Merge branch 'main' into cafe
danjoa Sep 6, 2025
b29b268
Merge branch 'main' into cafe
danjoa Sep 6, 2025
87cf357
feat: Add periodic refresh of remote data
stefanrudi Oct 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .cdsrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
features:
ieee754compatible: true # REVISIT: Why do we need that ??
"[fed-srv]":
features:
with_mocks: false
requires:
sap.capire.flights.data:
model: "@capire/xflights-api"
credentials:
url: http://localhost:4005/hcql/data/
"[rep-srv]":
features:
with_mocks: false
requires:
sap.capire.flights.data:
kind: odata
model: "db/rep-srv"
credentials:
url: http://localhost:4005/odata/v4/data/
loadOnDemand: true
"[fed-vrt]":
features:
with_mocks: false
requires:
db: hana
sap.capire.flights.data:
kind: odata
credentials:
remote: xflights
schema: XFLIGHTS_XFLIGHTS
supportRealTimeCDC: true
"[fed-syn]":
features:
with_mocks: false
requires:
db: hana
sap.capire.flights.data:
kind: odata
vcap: xflights
credentials:
schema: XFLIGHTS_XFLIGHTS
"[fed-ds]":
features:
with_mocks: false
requires:
db: hana
sap.capire.flights.data:
kind: odata
vcap:
name: xflights-datasphere
credentials:
sql:
names: quoted
"[fed-rap]":
features:
with_mocks: false
requires:
db: hana
rap_v2:
kind: odata
model: db/abap
credentials:
remote: sflight-rap
sql:
names: quoted
service: false
supportRealTimeCDC: false
7 changes: 7 additions & 0 deletions .github/actions/hxe/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM saplabs/hanaexpress:latest

COPY ./start-hdi.sql /usr/sap/HXE/start-hdi.sql
COPY ./setup.sh /setup

# Do initial boot
RUN /setup
54 changes: 54 additions & 0 deletions .github/actions/hxe/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: 'Start HANA'
description: 'Starts an local HANA Express instance for isolated testing'
inputs:
GITHUB_TOKEN:
description: 'Derivative token for using the GitHub REST API'
required: true
outputs:
TAG:
description: "The Image Tag"
value: ${{ steps.find-hxe.outputs.TAG }}
IMAGE_ID:
description: "The Image ID"
value: ${{ steps.find-hxe.outputs.IMAGE_ID }}
runs:
using: "composite"
steps:
- name: Find HXE image
id: find-hxe
shell: bash
run: |
TAG="$(sha1sum ${{ github.action_path }}/* | sha1sum --tag | grep '[^ ]*$' -o)";
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/hanaexpress;
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]');
echo "TAG=${TAG}" >> $GITHUB_OUTPUT;
echo "IMAGE_ID=${IMAGE_ID}" >> $GITHUB_OUTPUT;
GHCR_TOKEN=$(echo ${{ inputs.GITHUB_TOKEN }} | base64);
if
curl -H "Authorization: Bearer ${GHCR_TOKEN}" https://ghcr.io/v2/${{ github.repository_owner }}/hanaexpress/manifests/$TAG | grep "MANIFEST_UNKNOWN";
then
echo "BUILD_HXE=true" >> $GITHUB_OUTPUT
else
echo "BUILD_HXE=false" >> $GITHUB_OUTPUT
fi;
- name: Set up Docker Buildx
if: ${{ steps.find-hxe.outputs.BUILD_HXE == 'true' }}
uses: docker/setup-buildx-action@v3
- name: Build HXE image
if: ${{ steps.find-hxe.outputs.BUILD_HXE == 'true' }}
shell: bash
run: |
echo "${{ inputs.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin;
DOCKER_BUILDKIT=1 docker build -t $IMAGE_ID:$TAG ${{ github.action_path }}/;
docker push $IMAGE_ID:$TAG;
env:
TAG: ${{ steps.find-hxe.outputs.TAG }}
IMAGE_ID: ${{ steps.find-hxe.outputs.IMAGE_ID }}
- name: Start HXE image
shell: bash
run: |
echo "${{ inputs.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin;
{ ${{ github.action_path }}/start.sh; } &
env:
TAG: ${{ steps.find-hxe.outputs.TAG }}
IMAGE_ID: ${{ steps.find-hxe.outputs.IMAGE_ID }}
28 changes: 28 additions & 0 deletions .github/actions/hxe/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Use postgres/example user/password credentials
version: '3.1'

services:
hana:
image: ${IMAGE_ID}:${TAG}
restart: always
hostname: buildkitsandbox
ulimits:
nofile:
soft: 1048576
hard: 1048576
#sysctls:
# - kernel.shmmax=1073741824
# - net.ipv4.ip_local_port_range='60000 65535'
# - kernel.shmmni=4096
# - kernel.shmall=8388608
ports:
# Currently the only port being used is 39041
- '30041:39041'
# - '30013:39013'
# - '30015:39015'
# - '30041-30045:39041-39045'
# - '1128-1129:1128-1129'
# - '50013-50014:59013-59014'
# - '30030-30033:39030-39033'
# - '51000-51060:51000-51060'
# - '53075:53075'
6 changes: 6 additions & 0 deletions .github/actions/hxe/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/run_hana --agree-to-sap-license --dont-check-system --dont-check-mount-points --master-password Manager1 &

Check warning on line 1 in .github/actions/hxe/setup.sh

View check run for this annotation

In Solidarity / Inclusive Language

Match Found

Please consider an alternative to `master`. Possibilities include: `primary`, `main`, `leader`, `active`, `writer`
Raw output
/\b(?!masterdata|masterdata\w+\b)master/gi
until /check_hana_health -n -e ready-status > /dev/null; do sleep 1; done;
/usr/sap/HXE/HDB90/exe/hdbsql -i 90 -d SYSTEMDB -u SYSTEM -p Manager1 -I /usr/sap/HXE/start-hdi.sql

kill -TERM -- -0
wait
43 changes: 43 additions & 0 deletions .github/actions/hxe/start-hdi.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
DO
BEGIN
DECLARE dbName NVARCHAR(25) = 'HXE';
DECLARE diserverCount INT = 0;
DECLARE dpserverCount INT = 0;

-- Ensures that the HDI is enabled on the system
SELECT COUNT(*) INTO diserverCount FROM SYS_DATABASES.M_SERVICES WHERE SERVICE_NAME = 'diserver' AND DATABASE_NAME = :dbName AND ACTIVE_STATUS = 'YES';
IF diserverCount = 0 THEN
EXEC 'ALTER DATABASE ' || :dbName || ' ADD ''diserver''';
END IF;

-- Ensure that remote sources are enabled on the system
SELECT COUNT(*) INTO dpserverCount FROM SYS_DATABASES.M_SERVICES WHERE SERVICE_NAME = 'dpserver' AND DATABASE_NAME = :dbName AND ACTIVE_STATUS = 'YES';
IF dpserverCount = 0 THEN
EXEC 'ALTER DATABASE ' || :dbName || ' ADD ''dpserver''';
END IF;
END;

-- Grants HDI privileges to SYSTEM
CREATE LOCAL TEMPORARY TABLE #PRIVILEGES LIKE _SYS_DI.TT_API_PRIVILEGES;
INSERT INTO #PRIVILEGES (PRINCIPAL_NAME, PRIVILEGE_NAME, OBJECT_NAME) SELECT 'SYSTEM', PRIVILEGE_NAME, OBJECT_NAME FROM _SYS_DI.T_DEFAULT_DI_ADMIN_PRIVILEGES;
CALL _SYS_DI.GRANT_CONTAINER_GROUP_API_PRIVILEGES('_SYS_DI', #PRIVILEGES, _SYS_DI.T_NO_PARAMETERS, ?, ?, ?);
DROP TABLE #PRIVILEGES;

-- Forces all statistics tables to use NSE
CALL _SYS_STATISTICS.SHARED_ALTER_PAGE_LOADABLE;

-- Selects all tables that are loaded and unloads them from memory
DO
BEGIN
DECLARE v_isbn VARCHAR(20) = '';
DECLARE CURSOR c_cursor1 (v_isbn VARCHAR(20)) FOR
SELECT schema_name,table_name FROM m_cs_tables WHERE loaded != 'NO';

FOR cur_row AS c_cursor1(v_isbn) DO
EXEC 'UNLOAD ' || :cur_row.schema_name || '.' || :cur_row.table_name || ' DELETE PERSISTENT MEMORY';
END FOR;
END;

-- Configure maximum memory allocation to 8192MiB as this does not translate to physical memory
ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'system') SET ('memorymanager', 'global_allocation_limit') = '10240' WITH RECONFIGURE;
ALTER SYSTEM ALTER CONFIGURATION ('indexserver.ini', 'DATABASE', 'HXE') SET ('smart_data_access', 'enable_loopback') = 'TRUE' WITH RECONFIGURE;
2 changes: 2 additions & 0 deletions .github/actions/hxe/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
docker compose -f ci.yml up -d;
docker exec hxe-hana-1 bash -c "until /check_hana_health -n -e ready-status > /dev/null; do sleep 1; done;"
44 changes: 44 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Tests

on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened, auto_merge_enabled]

permissions:
contents: read

# Allow parallel jobs on `main`, so that each commit is tested. For PRs, run only the latest commit.
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
name: Tests
permissions:
packages: write

strategy:
fail-fast: true

steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- run: npm ci
- id: hxe
uses: ./.github/actions/hxe
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# testing
- run: npm test
env:
FORCE_COLOR: true
TAG: ${{ steps.hxe.outputs.TAG }}
IMAGE_ID: ${{ steps.hxe.outputs.IMAGE_ID }}
33 changes: 33 additions & 0 deletions .plugins/abap/cds-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const cds = require('@sap/cds')

if (cds.env.profiles.includes('fed-rap')) {
// Just a little hijack to inject the rap sflight model to xflights model transformation
const resolver = require('@sap/cds-compiler/lib/utils/moduleResolve.js')

const _makeModuleResolver = resolver.makeModuleResolver
resolver.makeModuleResolver = function () {
const ret = _makeModuleResolver.apply(this, arguments)
return {
resolveModule: async function (dep) {
if (dep.module in { '@capire/xflights': 1, '@capire/xflights-api': 1 }) {
return __dirname + '/index.cds'
}
return ret.resolveModule(dep)
}
}
}

const _makeModuleResolverSync = resolver.makeModuleResolverSync
resolver.makeModuleResolverSync = function (a, b, c, d) {
const ret = _makeModuleResolverSync.apply(this, arguments)
return {
resolveModule: function (dep) {
if (dep.module in { '@capire/xflights': 1, '@capire/xflights-api': 1 }) {
return __dirname + '/index.cds'
}
return ret.resolveModule(dep)
}
}
}

}
19 changes: 19 additions & 0 deletions .plugins/abap/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
services:
abap:
# username: SAP* / DEVELOPER
# password: ABAPtr2022#01
image: sapse/abap-cloud-developer-trial:ABAPTRIAL_2022_SP01
restart: always
hostname: vhcala4hci
command:
- -agree-to-sap-license
- -skip-limits-check
ports:
- 3200:3200
- 3300:3300
- 8443:8443
- 30213:30213
- 50000:50000
- 50001:50001
# volumes:
# - "./A4H_Multiple.txt:/opt/sap/ASABAP_license"
71 changes: 71 additions & 0 deletions .plugins/abap/index.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using { sap, sap.common.CodeList } from '@sap/cds/common';
using { rap_v2 as my } from './srv/external/rap-v2';

@odata @rest @hcql @data.product
service sap.capire.flights.data {

// Serve Flights data with inlined connection details
entity Flights as projection on my.Flight {
key ConnectionID as ID,
to_Connection.{
AirlineID as airline_ID,
DepartureAirport as origin_ID,
DestinationAirport as destination_ID,
DepartureTime as departure,
ArrivalTime as arrival,
Distance as distance,
to_DepartureAirport as origin: redirected to Airlines
on $self.origin.ID = $self.origin_ID,
to_DestinationAirport as destination: redirected to Airlines
on $self.destination.ID = $self.destination_ID,
},
key FlightDate as date, // preserve the flight date as a key
PlaneType as aircraft,
Price as price, CurrencyCode as currency_code,
MaximumSeats as maximum_seats,
OccupiedSeats as occupied_seats,
MaximumSeats - OccupiedSeats as free_seats: Integer,
to_Airline as airline: redirected to Airlines on $self.airline_ID = airline.ID,
to_Connection as flight,
};

// Serve Airlines, Airports, and Supplements data as is
entity Airlines as projection on my.Airline {
key AirlineID as ID,
null as icon: LargeBinary,
Name as name,
CurrencyCode as currency_code,
};
entity Airports as projection on my.Airport {
AirportID as ID,
Name as name,
City as city,
CountryCode as country_code,
};
entity Supplements as select from my.Supplement mixin {
type: Association to SupplementTypes on SupplementCategory = type.code;
} into {
key SupplementID as ID,
type,
SupplementCategory as type_code,
to_SupplementText[where LanguageCode = session_context('$user.locale')].Description as descr,
Price as price,
to_Currency as currency,
CurrencyCode as currency_code,
};

entity SupplementTypes : CodeList {
key code : String(2) enum {
Beverage = 'BV';
Meal = 'ML';
Luggage = 'LU';
Extra = 'EX';
}
}

// Serve data for common entities from @sap/cds/common
entity Currencies as projection on sap.common.Currencies;
entity Countries as projection on sap.common.Countries;
entity Languages as projection on sap.common.Languages;

}
2 changes: 2 additions & 0 deletions .plugins/abap/license.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
docker cp ./A4H_Multiple.txt abap-abap-1:/opt/sap/ASABAP_license
docker exec -it abap-abap-1 /usr/local/bin/asabap_license_update
4 changes: 4 additions & 0 deletions .plugins/abap/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "@capire/xflights-abap-api",
"version": "1.0.0"
}
Loading