You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CLAUDE.md
+12-3Lines changed: 12 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,6 +34,11 @@ npm run hana # Deploy to HANA HDI container ("starwars")
34
34
npm run load # Load Star Wars fixture data (hybrid/HANA profile)
35
35
npm run load_sqlite # Load fixture data into SQLite
36
36
37
+
# Data scraping
38
+
npm run scrape # full run, cache-first (fast — uses committed cache)
39
+
npm run scrape:films # films-only, no episodes (reproduces original dataset)
40
+
npm run scrape:bypass-cache # fetch fresh from Wookieepedia (requires confirmation)
41
+
37
42
# Docs generation
38
43
npm run openapi # Generate OpenAPI docs → docs/
39
44
npm run asyncapi # Generate AsyncAPI docs
@@ -62,13 +67,17 @@ cap/labs/ Hands-on exercises (lab-01 through lab-05)
62
67
63
68
### Domain Model (`cap/db/schema.cds`)
64
69
65
-
Six core entities: **Film**, **People**, **Planet**, **Species**, **Starship**, **Vehicle**. Many-to-many relationships use explicit junction entities (`Film2People`, `Film2Planets`, etc.) with redirected projections in services. All entities use `managed` + `cuid` from `@sap/cds/common`.
70
+
Core entities: **Film**, **People**, **Planet**, **Species**, **Starship**, **Vehicle**, **Show**, **Episode**. Many-to-many relationships use explicit junction entities (`Film2People`, `Film2Planets`, `Episode2People`, `Episode2Planets`, etc.) with redirected projections in services. All entities use `managed` + `cuid` from `@sap/cds/common`.
71
+
72
+
`Episode` is a composition child of `Show` — episodes cascade-delete with their parent show. Five `Episode2*` junction tables (`Episode2People`, `Episode2Planets`, `Episode2Starships`, `Episode2Vehicles`, `Episode2Species`) link episodes to the core entity set.
73
+
74
+
`Show2Planets`, `Show2Starships`, `Show2Vehicles`, and `Show2Species` are CDS `define view` declarations that aggregate over the corresponding `Episode2*` tables rather than being physical tables.
66
75
67
76
Profile-specific extensions live in `cap/db/hana/`, `cap/db/sqlite/`, `cap/db/postgres/`. Always check these when making cross-profile changes.
Six domain services (one per entity): `StarWarsFilm`, `StarWarsPeople`, `StarWarsPlanet`, `StarWarsSpecies`, `StarWarsStarship`, `StarWarsVehicle`. A seventh service, `StarWarsEpisode`, exposes `Episodes` and `Episode2*` junctions as read-only projections (no handler logic required). Protocols: OData v4 (primary), OData v2 (adapter), GraphQL (`/graphql`), REST.
72
81
73
82
**Critical file separation rule:**
74
83
- Service contracts → `*-service.cds`
@@ -123,6 +132,6 @@ GitHub Actions auto-deploys to GitHub Pages on push to `main` when files under `
123
132
124
133
-**CDS modeling**: Preserve namespace and `managed`/`cuid` patterns. Prefer explicit many-to-many junction entities. Keep `Common.ValueList` and `UI.*` patterns consistent.
125
134
-**Breaking changes**: Avoid renames/removals without migration intent. See `docs/value-help-migration.md` for a past breaking-change example.
126
-
-**Data loading**: Use `convertDataLite.js` for SQLite (avoids `SQLITE_BUSY`); use `convertData.js` for HANA (parallel chunk loading).
135
+
-**Data loading**: Use `convertData.js` for all profiles (handles parallel chunk loading; SQLite-safe). The `load_sqlite` npm script invokes this directly.
127
136
-**Generated folders**: `cap/gen/` is auto-generated. After HANA deployment, re-run `npm run build` if `gen/srv` is cleared.
128
137
-**cds-mcp**: When editing CDS files, resolve entity/field definitions with `cds-mcp` before modifying models, and check CAP docs via `cds-mcp` before proposing CDS syntax or API usage.
Copy file name to clipboardExpand all lines: README.md
+71-5Lines changed: 71 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,12 +10,48 @@ The original project was a data set and data model based in Python that exposed
10
10
11
11
The projects described above have fallen out of maintenance but still offered the opportunity for a fun yet challenging learning experience from a non-trivial data model. The many bi-directional, many-to-many relationships with the data provides a good basis for an SAP Cloud Application Programming Model and Fiori Draft UI sample.
12
12
13
+
This project extends the original data set with **TV Shows and streaming series** (The Mandalorian, The Clone Wars, Andor, etc.) scraped live from Wookieepedia, and introduces unified `Media` views that query across both films and shows.
14
+
13
15
### Data Model
14
16
15
17
#### Films
16
18
17
19

18
20
21
+
#### Shows (TV Series & Streaming)
22
+
23
+
The `Show` entity represents all canon Star Wars TV and streaming productions. It shares the same relationship structure as `Film` — each show can be linked to characters, planets, starships, vehicles, and species.
Each show owns a composition of `Episode` records (cascade-delete). The `Episode` entity captures per-episode metadata: `season_number`, `episode_number`, `title`, `air_date`, `director`, `writer`, `runtime` (minutes), and `timeline` (in-universe date, e.g. "19 BBY").
`Show2Planets`, `Show2Starships`, `Show2Vehicles`, and `Show2Species` are **CDS `define view`** declarations that aggregate over the corresponding `Episode2*` tables. They are not physical tables — show-level relationship data is derived from episode-level scraping.
41
+
42
+
#### Unified Media Views
43
+
44
+
Six read-only `UNION ALL` views join `Film` and `Show` data across a single query surface. The relationship views each include a branch for `Episode2*` data so that episode-level associations are surfaced at the media level:
45
+
46
+
| View | Returns |
47
+
| --- | --- |
48
+
|`Media`| All films and shows with a `media_type` discriminator (`'FILM'` / `'SHOW'`) |
49
+
|`MediaCharacters`| All film+show+episode → character relationships |
50
+
|`MediaPlanets`| All film+show+episode → planet relationships |
51
+
|`MediaSpecies`| All film+show+episode → species relationships |
52
+
|`MediaStarships`| All film+show+episode → starship relationships |
53
+
|`MediaVehicles`| All film+show+episode → vehicle relationships |
54
+
19
55
#### People
20
56
21
57

@@ -43,15 +79,45 @@ The projects described above have fallen out of maintenance but still offered th
43
79
44
80
## Download and Installation
45
81
46
-
The original data model and data source files are in in the [oldPython\resources](./oldPython/resources/) folder.
82
+
The rest of the operations can be performed within the [cap](./cap/) folder and there are scripts in the [package.json](./cap/package.json#L20) file for major operations.
83
+
84
+
You can use `npm run build` to perform the cds build and should be run before deployment to HANA or whenever you make changes to the data model.
47
85
48
-
The rest of the operations can be performed within the [cap](./cap/) folder and there are scripts in the [package.json](./cap/package.json#L20) file major operations.
86
+
You can run `npm run hana` to deploy the content to your HANA database. Just be sure from the terminal that you are logged into the cf/xs cli and targeting the Account/Org/Space where you want the content to live. By default this command will create an HDI Container instance named **starwars**. **Note**: due to some strange circumstances in the latest versions of CAP it seems the `/gen/srv` folder is getting cleared after any deployment to HANA. Therefore just execute a `cds build` or `npm run build` after any deployment to restore the `/gen` folder until we find the root cause of this issue.
87
+
88
+
### Data Pipeline
89
+
90
+
Star Wars data is sourced from [Wookieepedia](https://starwars.fandom.com/wiki/Wookieepedia) via a rate-limited MediaWiki API scraper. The pipeline is two steps:
91
+
92
+
**Step 1 — Scrape** (optional — committed cache makes this instantaneous):
93
+
94
+
```bash
95
+
cd cap
96
+
npm run scrape # cache-first run — uses committed cache, completes in seconds
97
+
npm run scrape:films # films-only run (no episodes); reproduces the original SWAPI dataset
98
+
npm run scrape:bypass-cache # fetch fresh data from Wookieepedia (prompts for confirmation)
99
+
```
100
+
101
+
The scraper crawls three levels deep: Show page → Season page → Episode page. It writes nine JSON files to `scripts/data/raw/`:
Cache files (`scripts/data/cache/`) are committed to the repository (~6,469 files), so clones can run `npm run scrape` without any network access. Use `--bypass-cache` only when you need genuinely fresh Wookieepedia data.
105
+
106
+
**Step 2 — Load** into your target database:
107
+
108
+
```bash
109
+
npm run load_sqlite # SQLite (local development)
110
+
npm run load # SAP HANA Cloud (hybrid profile — requires .cdsrc-private.json)
111
+
npm run load_pg # PostgreSQL
112
+
```
49
113
50
-
You can use `npm run build` to perform the cds build and should be ran before deployment to HANA or whenever you make changes to the data model.
114
+
The loading script is [convertData.js](./cap/convertData.js). It reads the raw JSON files and upserts all entities and junction records using CAP CQL.
51
115
52
-
You can run `npm run hana` to deploy the content to your HANA database. Just be sure from the terminal that you are logged into the cf/xs cli and targeting the Account/Org/Space where you want the content to live. By default this command will create an HDI Container instance named **starwars**. **Note**: due to some strange circumstances in the latest versions of CAP it seems the `/gen/srv` folder is getting cleared after any deployment to HANA. Therefore just execute a `cds build` or `npm run build` after any deployment to restore the `/gen` folder until we find the root cause of this issue.
116
+
**Scraped data included:**
53
117
54
-
You can run the command `npm run load`. This command will read the original JSON data files from the source project and load them into your HANA database using Cloud Application Programming Model [CQL](https://cap.cloud.sap/docs/cds/cql). The loading script is [convertData.js](./cap/convertData.js)
The command `npm start` or `cds run` will start the service running locally. It will open the standard CAP test page where you can explore the OData Services or the Fiori UI.
(CDS define view over Episode2* — not physical tables)
83
88
```
84
89
90
+
`define view` in CDS creates a SQL view rather than a physical table. It is the right choice when the data can be fully derived from another entity — there is no value in storing it redundantly. `Show2Planets` (and its siblings) are a concrete example: Wookieepedia show pages list no per-show relationships, but each episode page lists the planets it features. By defining the show-level view as an aggregation over `Episode2Planets`, show-level data is always correct and requires no separate load step.
91
+
85
92
### Service Layer (`srv/*-service.cds`)
86
93
87
94
Services **project** domain entities into API-facing views. The key insight:
Copy file name to clipboardExpand all lines: cap/docs/learning-path.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,6 +22,8 @@ Five progressive milestones, each building on the previous one. Every milestone
22
22
23
23
3. Trace how `Film2People` links `Film` and `People` (M:N relationship).
24
24
25
+
4. Find the `define view` declarations for `Show2Planets`, `Show2Starships`, `Show2Vehicles`, and `Show2Species`. Explain why they are views instead of physical junction tables. (Hint: where does the underlying data actually come from?)
26
+
25
27
**Key files:**`db/schema.cds`
26
28
27
29
**Check your understanding:** Run `npm run test` — all model tests should pass.
@@ -55,7 +57,7 @@ Five progressive milestones, each building on the previous one. Every milestone
**Check your understanding:** Open Swagger UI at `http://localhost:4004/api-docs` and explore the generated spec.
60
+
**Check your understanding:** Open Swagger UI at `http://localhost:4004/api-docs` and explore the generated spec. Then compare `StarWarsEpisode` (`srv/episode-service.cds`) — a read-only service with no `.js` handler at all — with `StarWarsPeople`. Notice that CAP's generic provider handles all CRUD automatically when there is no `on` handler registered.
0 commit comments