Skip to content

Commit

Permalink
Merge branch 'main' into fix-performance-issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Sv7enNowitzki authored Oct 22, 2024
2 parents 677ec05 + 36de362 commit e8a25f7
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 5 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ a [CDS plugin](https://cap.cloud.sap/docs/node.js/cds-plugins#cds-plugin-package
>
> See the changelog for a full list of changes
> [!Warning]
>
>Currently, change-tracking is not fully compatible with the [@sap/cds-mtxs](https://www.npmjs.com/package/@sap/cds-mtxs) package which is used to provide extensibility and [CAP Feature Toggles](https://cap.cloud.sap/docs/guides/extensibility/feature-toggles#enable-feature-toggles).
>
>When using multi-tenancy with MTX, the generated facets and associations will not be present in the metadata provided by the service. Therefore, it will not work out of the box.
>Until this gap in MTX is closed, we suggest using the `@changelog.disable_assoc` ([see here](#disable-association-to-changes-generation)) for all tracked entities and to add the association and facet manually to the service entity.

### Table of Contents

Expand Down Expand Up @@ -574,6 +581,7 @@ this.on("UpdateActivationStatus", async (req) =>

The reason is that: Application level services are by design the only place where business logic is enforced. This by extension means, that it also is the only point where e.g. change-tracking would be enabled. The underlying method used to do change tracking is `req.diff` which is responsible to read the necessary before-image from the database, and this method is not available on DB level.


## Contributing

This project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://github.com/cap-js/change-tracking/issues). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](CONTRIBUTING.md).
Expand Down
41 changes: 41 additions & 0 deletions lib/change-log.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ const { localizeLogFields } = require("./localization")
const isRoot = "change-tracking-isRootEntity"


function formatDecimal(str, scale) {
if (typeof str === "number" && !isNaN(str)) {
str = String(str);
} else return str;

if (scale > 0) {
let parts = str.split(".");
let decimalPart = parts[1] || "";

while (decimalPart.length < scale) {
decimalPart += "0";
}

return `${parts[0]}.${decimalPart}`;
}

return str;
}

const _getRootEntityPathVals = function (txContext, entity, entityKey) {
const serviceEntityPathVals = []
const entityIDs = _getEntityIDs(txContext.params)
Expand Down Expand Up @@ -317,6 +336,28 @@ function _trackedChanges4 (srv, target, diff) {
const eleParentKeys = element.parent.keys
if (from === to) return

/**
*
* HANA driver always filling up the defined decimal places with zeros,
* need to skip the change log if the value is not changed.
* Example:
* entity Books : cuid {
* price : Decimal(11, 4);
* }
* When price is updated from 3000.0000 to 3000,
* the change log should not be created.
*/
if (
row._op === "update" &&
element.type === "cds.Decimal" &&
cds.db.kind === "hana" &&
typeof to === "number"
) {
const scaleNum = element.scale || 0;
if (from === formatDecimal(to, scaleNum))
return;
}

/**
*
* For the Inline entity such as Items,
Expand Down
4 changes: 2 additions & 2 deletions tests/bookshop/db/data/sap.capire.bookshop-Books.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ID;title;descr;isUsed;author_ID;stock;price;genre_ID;bookStore_ID
9d703c23-54a8-4eff-81c1-cdce6b8376b1;Wuthering Heights;"Wuthering Heights, Emily Brontë's only novel, was published in 1847 under the pseudonym ""Ellis Bell"". It was written between October 1845 and June 1846. Wuthering Heights and Anne Brontë's Agnes Grey were accepted by publisher Thomas Newby before the success of their sister Charlotte's novel Jane Eyre. After Emily's death, Charlotte edited the manuscript of Wuthering Heights and arranged for the edited version to be published as a posthumous second edition in 1850.";true;d4d4a1b3-5b83-4814-8a20-f039af6f0387;12;11.11;11;64625905-c234-4d0d-9bc1-283ee8946770
9d703c23-54a8-4eff-81c1-cdce6b8376b1;Wuthering Heights;"Wuthering Heights, Emily Brontë's only novel, was published in 1847 under the pseudonym ""Ellis Bell"". It was written between October 1845 and June 1846. Wuthering Heights and Anne Brontë's Agnes Grey were accepted by publisher Thomas Newby before the success of their sister Charlotte's novel Jane Eyre. After Emily's death, Charlotte edited the manuscript of Wuthering Heights and arranged for the edited version to be published as a posthumous second edition in 1850.";true;d4d4a1b3-5b83-4814-8a20-f039af6f0387;12;3000.0000;11;64625905-c234-4d0d-9bc1-283ee8946770
676059d4-8851-47f1-b558-3bdc461bf7d5;Jane Eyre;"Jane Eyre /ɛər/ (originally published as Jane Eyre: An Autobiography) is a novel by English writer Charlotte Brontë, published under the pen name ""Currer Bell"", on 16 October 1847, by Smith, Elder & Co. of London. The first American edition was published the following year by Harper & Brothers of New York. Primarily a bildungsroman, Jane Eyre follows the experiences of its eponymous heroine, including her growth to adulthood and her love for Mr. Rochester, the brooding master of Thornfield Hall. The novel revolutionised prose fiction in that the focus on Jane's moral and spiritual development is told through an intimate, first-person narrative, where actions and events are coloured by a psychological intensity. The book contains elements of social criticism, with a strong sense of Christian morality at its core and is considered by many to be ahead of its time because of Jane's individualistic character and how the novel approaches the topics of class, sexuality, religion and feminism.";true;47f97f40-4f41-488a-b10b-a5725e762d5e;11;12.34;11;5ab2a87b-3a56-4d97-a697-7af72334a384
42bc7997-f6ce-4ae9-8a64-ee5e02ef1087;The Raven;"""The Raven"" is a narrative poem by American writer Edgar Allan Poe. First published in January 1845, the poem is often noted for its musicality, stylized language, and supernatural atmosphere. It tells of a talking raven's mysterious visit to a distraught lover, tracing the man's slow fall into madness. The lover, often identified as being a student, is lamenting the loss of his love, Lenore. Sitting on a bust of Pallas, the raven seems to further distress the protagonist with its constant repetition of the word ""Nevermore"". The poem makes use of folk, mythological, religious, and classical references.";true;5c30d395-db0a-4095-bd7e-d4de34646607;333;13.13;16;5ab2a87b-3a56-4d97-a697-7af72334a384
9297e4ea-396e-47a4-8815-cd4622dea8b1;Eleonora;"""Eleonora"" is a short story by Edgar Allan Poe, first published in 1842 in Philadelphia in the literary annual The Gift. It is often regarded as somewhat autobiographical and has a relatively ""happy"" ending.";true;5c30d395-db0a-4095-bd7e-d4de34646607;555;14;16;8aaed432-8336-4b0d-be7e-3ef1ce7f13ea
574c8add-0ee3-4175-ab62-ca09a92c723c;Catweazle;Catweazle is a British fantasy television series, starring Geoffrey Bayldon in the title role, and created by Richard Carpenter for London Weekend Television. The first series, produced and directed by Quentin Lawrence, was screened in the UK on ITV in 1970. The second series, directed by David Reid and David Lane, was shown in 1971. Each series had thirteen episodes, most but not all written by Carpenter, who also published two books based on the scripts.;true;a45da28a-7f55-4b53-8a63-48b61132d1b9;22;15;13;8aaed432-8336-4b0d-be7e-3ef1ce7f13ea
574c8add-0ee3-4175-ab62-ca09a92c723c;Catweazle;Catweazle is a British fantasy television series, starring Geoffrey Bayldon in the title role, and created by Richard Carpenter for London Weekend Television. The first series, produced and directed by Quentin Lawrence, was screened in the UK on ITV in 1970. The second series, directed by David Reid and David Lane, was shown in 1971. Each series had thirteen episodes, most but not all written by Carpenter, who also published two books based on the scripts.;true;a45da28a-7f55-4b53-8a63-48b61132d1b9;22;15;13;8aaed432-8336-4b0d-be7e-3ef1ce7f13ea
2 changes: 1 addition & 1 deletion tests/bookshop/db/schema.cds
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ entity Books : managed, cuid {
@title : '{i18n>books.genre}'
genre : Association to Genres;
stock : Integer;
price : Decimal;
price : Decimal(11, 4);
isUsed : Boolean;
image : LargeBinary @Core.MediaType : 'image/png';
@title : '{i18n>books.bookType}'
Expand Down
18 changes: 16 additions & 2 deletions tests/integration/fiori-draft-enabled.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,14 @@ describe("change log integration test", () => {
});

it("2.2 Child entity update - should log basic data type changes (ERP4SMEPREPWORKAPPPLAT-32 ERP4SMEPREPWORKAPPPLAT-613)", async () => {
cds.services.AdminService.entities.Books.elements.price["@changelog"] = true;

const action = PATCH.bind({}, `/odata/v4/admin/Books(ID=9d703c23-54a8-4eff-81c1-cdce6b8376b1,IsActiveEntity=false)`, {
title: "new title",
author_ID: "47f97f40-4f41-488a-b10b-a5725e762d5e",
genre_ID: 16,
isUsed: false
isUsed: false,
price: 3000
});
await utils.apiAction("admin", "BookStores", "64625905-c234-4d0d-9bc1-283ee8946770", "AdminService", action);
const bookChanges = await adminService.run(
Expand Down Expand Up @@ -345,6 +348,17 @@ describe("change log integration test", () => {
expect(isUsedChange.valueChangedFrom).to.equal("true");
expect(isUsedChange.valueChangedTo).to.equal("false");

// The current price is 3000.0000, and update operation via OData service is price: 3000. In this case, a changelog should not be generated.
const priceChanges = await adminService.run(
SELECT.from(ChangeView).where({
entity: "sap.capire.bookshop.Books",
attribute: "price",
})
);

expect(priceChanges.length).to.equal(0);

delete cds.services.AdminService.entities.Books.elements.price["@changelog"];
});

it("2.3 Child entity delete - should log basic data type changes (ERP4SMEPREPWORKAPPPLAT-32 ERP4SMEPREPWORKAPPPLAT-613)", async () => {
Expand Down Expand Up @@ -605,7 +619,7 @@ describe("change log integration test", () => {
expect(titleChanges.length).to.equal(1);

const titleChange = titleChanges[0];
expect(titleChange.objectID).to.equal("11.11, new title, 12");
expect(titleChange.objectID).to.equal("3000, new title, 12");

cds.services.AdminService.entities.Books["@changelog"] = [
{ "=": "title" },
Expand Down

0 comments on commit e8a25f7

Please sign in to comment.