{"id":21450938,"url":"https://github.com/soontao/cds-change-log","last_synced_at":"2025-07-09T13:38:28.330Z","repository":{"id":51970551,"uuid":"470051117","full_name":"Soontao/cds-change-log","owner":"Soontao","description":"Change Log Best Practice for CAP CDS","archived":false,"fork":false,"pushed_at":"2024-10-23T17:38:44.000Z","size":878,"stargazers_count":2,"open_issues_count":13,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-24T22:54:29.347Z","etag":null,"topics":["cap","cds","changelog","sap"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Soontao.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-15T07:33:01.000Z","updated_at":"2023-03-10T01:10:36.000Z","dependencies_parsed_at":"2024-03-19T00:28:03.968Z","dependency_job_id":"93f95897-baf2-4d87-afc0-c65ae43542e4","html_url":"https://github.com/Soontao/cds-change-log","commit_stats":{"total_commits":226,"total_committers":4,"mean_commits":56.5,"dds":0.415929203539823,"last_synced_commit":"261e49c1e18b9253df3d27f99712e8f5d5ca83e3"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":"Soontao/ts-project-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Soontao%2Fcds-change-log","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Soontao%2Fcds-change-log/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Soontao%2Fcds-change-log/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Soontao%2Fcds-change-log/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Soontao","download_url":"https://codeload.github.com/Soontao/cds-change-log/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225998797,"owners_count":17557473,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cap","cds","changelog","sap"],"created_at":"2024-11-23T04:17:15.055Z","updated_at":"2024-11-23T04:17:15.798Z","avatar_url":"https://github.com/Soontao.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CDS Change Log\n\n\u003e provide the `ChangeLog` best practice for SAP CAP nodejs runtime\n\n[![node-test](https://github.com/Soontao/cds-change-log/actions/workflows/nodejs.yml/badge.svg)](https://github.com/Soontao/cds-change-log/actions/workflows/nodejs.yml)\n[![npm](https://img.shields.io/npm/v/cds-change-log)](https://www.npmjs.com/package/cds-change-log)\n![NPM](https://img.shields.io/npm/l/cds-change-log)\n![node-lts](https://img.shields.io/node/v-lts/cds-change-log)\n\n[![codecov](https://codecov.io/gh/Soontao/cds-change-log/branch/main/graph/badge.svg?token=kKkSYJyTfG)](https://codecov.io/gh/Soontao/cds-change-log)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Soontao_cds-change-log\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Soontao_cds-change-log)\n[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=Soontao_cds-change-log\u0026metric=security_rating)](https://sonarcloud.io/summary/new_code?id=Soontao_cds-change-log)\n![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/npm/cds-change-log)\n\n## Get Started\n\n\u003e `package.json`\n\n```json\n{\n  \"cds\": {\n    \"plugins\": {\n      \"cds-change-log\": {\n        \"impl\": \"cds-change-log\"\n      }\n    }\n  }\n}\n```\n\n\u003e `entity.cds`\n\n- **MUST** `using from 'cds-change-log'` statement in CDS model\n- **MUST** annotating `@cds.changelog.enabled` on elements\n- **MUST** annotating at the root/raw `entity` level, annotations on `projection`/`view` will not work\n- **MUST** have at least one **PRIMARY KEY**\n\n```groovy\nusing {cap.community.common} from 'cds-change-log'\n\nentity People : cuid, managed, customManaged {\n  Name       : String(255);\n  Age        : Integer;\n  changeLogs : Association to many common.ChangeLog\n                 on  changeLogs.entityKey  = $self.ID\n                 and changeLogs.entityName = 'People';\n}\n\n// mark in entity and field elements level\n// annotation in another place, you can put it into entity definition directly\nannotate People with {\n  Age  @cds.changelog.enabled;\n  Name @cds.changelog.enabled;\n};\n```\n\n\u003e `create and update objects`\n\n```js\nlet response = await axios.post(\"/sample/Peoples\", { Name: \"Theo Sun 2\", Age: 39 })\nconst { ID } = response.data\nawait axios.patch(`/sample/Peoples(${ID})`, { Name: \"Theo Sun 9\", Age: 12 })\n```\n\n\u003e `generated change logs`\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick to expand sample logs\u003c/summary\u003e\n\n```js\n[\n  {\n    ID: \"595b3604-d7dd-434f-962c-1e70e92bd775\",\n    actionAt: \"2022-03-17T04:20:41.402Z\",\n    actionBy: \"anonymous\",\n    entityName: \"People\",\n    entityKey: \"0e926ff2-53ad-4cd9-9569-ad2147dad0bc\",\n    action: \"Create\",\n    Items: [\n      {\n        sequence: 0,\n        Parent_ID: \"595b3604-d7dd-434f-962c-1e70e92bd775\",\n        attributeKey: \"Name\",\n        attributeNewValue: \"Theo Sun 2\",\n        attributeOldValue: null,\n      },\n      {\n        sequence: 1,\n        Parent_ID: \"595b3604-d7dd-434f-962c-1e70e92bd775\",\n        attributeKey: \"Age\",\n        attributeNewValue: \"39\",\n        attributeOldValue: null,\n      },\n    ],\n  },\n  {\n    ID: \"55bca8b8-1e79-4c9b-8bc9-1a013bf3cf39\",\n    actionAt: \"2022-03-17T04:20:41.461Z\",\n    actionBy: \"anonymous\",\n    entityName: \"People\",\n    entityKey: \"0e926ff2-53ad-4cd9-9569-ad2147dad0bc\",\n    action: \"Update\",\n    Items: [\n      {\n        sequence: 0,\n        Parent_ID: \"55bca8b8-1e79-4c9b-8bc9-1a013bf3cf39\",\n        attributeKey: \"Name\",\n        attributeNewValue: \"Theo Sun 9\",\n        attributeOldValue: \"Theo Sun 2\",\n      },\n      {\n        sequence: 1,\n        Parent_ID: \"55bca8b8-1e79-4c9b-8bc9-1a013bf3cf39\",\n        attributeKey: \"Age\",\n        attributeNewValue: \"12\",\n        attributeOldValue: \"39\",\n      },\n    ],\n  },\n]\n```\n\u003c/details\u003e\n\n\n\n### Custom Type Primary Key\n\n\u003e if you want to use `Integer` or other cds built-in type as primary key\n\n`entity.cds`\n\n```groovy\n@cds.changelog.enabled\nentity Order : managed { // a sample entity\n  key ID     : Integer; // use Integer as key, not out-of-box UUID\n      @cds.changelog.enabled\n      Amount : Decimal;\n};\n```\n\n`extension.cds`\n\n```groovy\n// remember using this file from your project root\nusing {cap.community.common.ChangeLog} from 'cds-change-log';\n\nextend ChangeLog with {\n\n  // add a new column 'entityKeyInteger' for integer key\n  @cds.changelog.extension.entityKey\n  // this column will be used when entity use `Integer` as primary key\n  // MUST add the `cds.` prefix for built-in types\n  @cds.changelog.extension.for.type : cds.Integer \n  entityKeyInteger : Integer;\n  \n};\n\n```\n\n### Multi Primary Keys on target entity\n\n\u003e if you want to **manually** specify the data storage for entity keys\n\n`entity.cds`\n\n```groovy\n@cds.changelog.enabled\nentity PeopleOrderForProduct {\n      // store key to ChangeLog.entityKeyInteger\n      @cds.changelog.extension.key.target : 'entityKeyInteger'\n  key OrderID  : Integer;\n      // store key to ChangeLog.entityKey\n      @cds.changelog.extension.key.target : 'entityKey'\n  key PeopleID : UUID;\n      @cds.changelog.enabled\n      Amount   : Decimal;\n}\n```\n\n## Features\n\n- [x] single `CUD` OData requests \n- [x] multi `CUD` CQL\n- [x] all `Update/Delete` CQL (without `where`)\n- [x] aspect support\n- [x] localization support\n- [x] custom type key (e.g. Integer) support\n  - [x] metadata cache\n- [x] multi primary key support\n- [x] extension field support\n- [ ] draft mode (`draftActivate`)\n  - [x] simple single entity\n  - [ ] localization\n- [ ] key relation cache\n- [ ] built-in FE UI Annotations\n- [ ] save change logs in async mode\n- [ ] benchmark test\n- [ ] subscribe change log event\n- [ ] validation at startup\n- [ ] skip/warn log for `Blob`\n- [ ] secondary storage like mongo/s3\n- [ ] readable identifier support\n- [ ] association/composition support\n  - [ ] annotation `@cds.changelog.to`\n- [ ] Samples\n  - [ ] localized data sample\n  - [ ] for fiori elements\n  - [ ] rows to columns table records\n\n## [CHANGELOG](./CHANGELOG.md)\n\n## [LICENSE](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoontao%2Fcds-change-log","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoontao%2Fcds-change-log","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoontao%2Fcds-change-log/lists"}