Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
aramovic79 committed Feb 17, 2025
1 parent ceb64da commit 432d1a9
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 12 deletions.
127 changes: 127 additions & 0 deletions __tests__/__mocks__/dataProductCsn.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
{
"namespace": "sap.capire.incidents",
"definitions": {
"sap.capire.incidents.LocalService": {
"kind": "service",
"@AsyncAPI.Title": "SAP Incident Management",
"@AsyncAPI.SchemaVersion": "1.0",
"@ORD.Extensions.title": "This is Local Service title",
"@DataIntegration.dataProduct.type": "primary"
},
"sap.capire.incidents.LocalService.Entertainment": {
"kind": "entity",
"@ODM.root": true,
"@ODM.entityName": "Cinema",
"@ODM.oid": "id",
"@title": "Cinema Title",
"projection": {
"from": {
"ref": ["sap.cds.demo.Cinema"]
}
},
"elements": {
"id": {
"key": true,
"type": "cds.UUID"
},
"name": {
"type": "cds.String",
"length": 50
},
"location": {
"type": "cds.String",
"length": 100
}
}
},
"sap.capire.incidents.LocalService.Film": {
"kind": "entity",
"@ObjectModel.compositionRoot": true,
"@EntityRelationship.entityType": "sap.sample:Movie",
"@title": "Movie Title",
"projection": {
"from": {
"ref": ["sap.cds.demo.Movie"]
}
},
"elements": {
"id": {
"key": true,
"type": "cds.UUID"
},
"title": {
"type": "cds.String",
"length": 100
},
"genre": {
"type": "cds.String",
"length": 50
},
"duration": {
"type": "cds.Integer"
}
}
},
"sap.capire.incidents.LocalService.TitleChange": {
"kind": "event",
"elements": {
"ID": {
"type": "cds.Integer"
},
"title": {
"@title": "Changed Title",
"type": "cds.String"
}
}
},
"sap.cds.demo.Cinema": {
"kind": "entity",
"@ODM.root": true,
"@ODM.entityName": "Cinema",
"@ODM.oid": "id",
"@title": "Cinema Title",
"elements": {
"id": {
"key": true,
"type": "cds.UUID"
},
"name": {
"type": "cds.String",
"length": 50
},
"location": {
"type": "cds.String",
"length": 100
}
}
},
"sap.cds.demo.Movie": {
"kind": "entity",
"@ObjectModel.compositionRoot": true,
"@EntityRelationship.entityType": "sap.sample:Movie",
"@title": "Movie Title",
"elements": {
"id": {
"key": true,
"type": "cds.UUID"
},
"title": {
"type": "cds.String",
"length": 100
},
"genre": {
"type": "cds.String",
"length": 50
},
"duration": {
"type": "cds.Integer"
}
}
}
},
"meta": {
"creator": "CDS Compiler v5.4.4",
"flavor": "inferred"
},
"$version": "2.0"
}
17 changes: 16 additions & 1 deletion __tests__/mockedCsn.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe("Tests for ORD document generated out of mocked csn files", () => {
});

describe("Tests for ORD document when all the resources are internal", () => {
test("All services are interal: Successfully create ORD Documents without packages, empty apiResources and eventResources lists", () => {
test("All services are internal: Successfully create ORD Documents without packages, empty apiResources and eventResources lists", () => {
const csn = require("./__mocks__/internalResourcesCsn.json");
checkOrdDocument(csn);
});
Expand All @@ -100,4 +100,19 @@ describe("Tests for ORD document generated out of mocked csn files", () => {
expect(document.eventResources[0].ordId).toEqual(expect.stringContaining("CatalogService"));
});
});

describe("Tests for ORD document when service is annotated as a primary Data Product`", () => {
test("Successfully create ORD Documents: ", () => {
const csn = require("./__mocks__/dataProductCsn.json");
const document = ord(csn);

expect(document).not.toBeUndefined();
expect(document.apiResources).toHaveLength(2)
const dataProductApiResources = document.apiResources.filter(resource => resource.implementationStandard === "sap.dp:data-subscription-api:v1");
expect(dataProductApiResources).toHaveLength(1);
expect(dataProductApiResources[0].resourceDefinitions).toHaveLength(1);
expect(dataProductApiResources[0].resourceDefinitions[0]).type === "sap-csn-interop-effective-v1";
});
});

});
8 changes: 8 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ const COMPILER_TYPES = Object.freeze({

const CONTENT_MERGE_KEY = "ordId";

const DATA_PRODUCT_ANNOTATION = "@DataIntegration.dataProduct.type";

const DATA_PRODUCT_TYPE = Object.freeze({
primary: "primary"
});

const DESCRIPTION_PREFIX = "Description for ";

const ENTITY_RELATIONSHIP_ANNOTATION = "@EntityRelationship.entityType";
Expand Down Expand Up @@ -54,6 +60,8 @@ module.exports = {
CDS_ELEMENT_KIND,
COMPILER_TYPES,
CONTENT_MERGE_KEY,
DATA_PRODUCT_ANNOTATION,
DATA_PRODUCT_TYPE,
DESCRIPTION_PREFIX,
ENTITY_RELATIONSHIP_ANNOTATION,
LEVEL,
Expand Down
20 changes: 19 additions & 1 deletion lib/ord.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
const {
CDS_ELEMENT_KIND,
CONTENT_MERGE_KEY,
DATA_PRODUCT_ANNOTATION,
DATA_PRODUCT_TYPE,
ENTITY_RELATIONSHIP_ANNOTATION,
ORD_ODM_ENTITY_NAME_ANNOTATION
} = require('./constants');
const {
createAPIResourceTemplate,
createDataProductAPIResourceTemplate,
createEntityTypeTemplate,
createEntityTypeMappingsItemTemplate,
createEventResourceTemplate,
Expand Down Expand Up @@ -34,6 +37,7 @@ const initializeAppConfig = (csn) => {
const events = [];
const entityTypeTargets = [];
const serviceNames = [];
const dataProducts = [];
const lastUpdate = getRFC3339Date();

const vendorNamespace = "customer";
Expand All @@ -50,6 +54,9 @@ const initializeAppConfig = (csn) => {
case CDS_ELEMENT_KIND.service:
if (!keyDefinition["@cds.external"]) {
serviceNames.push(key);
if (keyDefinition[DATA_PRODUCT_ANNOTATION] === DATA_PRODUCT_TYPE.primary) {
dataProducts.push(keyDefinition);
}
}
break;
// TODO: should be rewritten
Expand Down Expand Up @@ -82,6 +89,7 @@ const initializeAppConfig = (csn) => {
ordNamespace,
eventApplicationNamespace,
packageName,
dataProducts
};
};

Expand Down Expand Up @@ -121,6 +129,13 @@ const _getAPIResources = (csn, appConfig, packageIds) => {
.flatMap((serviceName) => createAPIResourceTemplate(serviceName, csn.definitions[serviceName], appConfig, packageIds))
};

const _getDataProductAPIResources = (appConfig) => {
return appConfig.dataProducts
.flatMap((dataProduct) => {
return createDataProductAPIResourceTemplate(dataProduct);
})
};

const _getEventResources = (csn, appConfig, packageIds) => {
if (appConfig.events.length === 0) return [];
return appConfig.serviceNames
Expand All @@ -145,11 +160,13 @@ function createDefaultORDDocument(linkedCsn, appConfig) {
products: _getProducts(appConfig),
groups: _getGroups(linkedCsn, appConfig),
consumptionBundles: _getConsumptionBundles(appConfig),
apiResources: _getDataProductAPIResources(appConfig)
};

if (_getAPIResources(linkedCsn, appConfig).length && _getEventResources(linkedCsn, appConfig).length) {
ordDocument.packages = _getPackages(ordDocument.policyLevel, appConfig);
}

return ordDocument;
}

Expand All @@ -171,7 +188,8 @@ module.exports = (csn) => {
if (entityTypes.length != 0) {
ordDocument.entityTypes = entityTypes;
}
ordDocument.apiResources = _getAPIResources(linkedCsn, appConfig, packageIds);

ordDocument.apiResources.push(..._getAPIResources(linkedCsn, appConfig, packageIds));
ordDocument.eventResources = _getEventResources(linkedCsn, appConfig, packageIds);
ordDocument = extendCustomORDContentIfExists(appConfig, ordDocument);

Expand Down
49 changes: 39 additions & 10 deletions lib/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function _getTitleFromServiceName(srv) {
*/
function _getEntityVersion(entity) {
const entityVersion = entity.ordId.split(":").pop();
const version = entityVersion.replace("v", "") + ".0.0"; // TODO: version can be stated/overwritten by annotation
const version = entityVersion.replace("v", "") + ".0.0"; // TODO: version can be stated/overwritten by annotation
if (!SEM_VERSION_REGEX.test(version)) {
Logger.warn(`Entity version "${version}" is not a valid semantic version.`);
}
Expand Down Expand Up @@ -244,17 +244,19 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
},
// conditionally setting the entityTypeMappings field based on the presence of entityTypeTargets in appConfig
...(appConfig.entityTypeTargets?.length > 0 &&
{
entityTypeMappings: [
{
entityTypeTargets: appConfig.entityTypeTargets.map(m => { return (
{
entityTypeMappings: [
{
entityTypeTargets: appConfig.entityTypeTargets.map(m => {
return (
{
"ordId" : m.ordId
"ordId": m.ordId
}
)} )
}
]
}),
)
})
}
]
}),
...ordExtensions,
};

Expand All @@ -266,6 +268,32 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
return apiResources;
};

/**
* This is a function creating an API Resource object for each service defined as a data product.
* @returns {Array} An array of objects for the API Resources.
*/
const createDataProductAPIResourceTemplate = (dataProduct) => {
console.log(dataProduct);

return {
apiProtocol: "api",
visibility: RESOURCE_VISIBILITY.internal,
direction: "outbound",
implementationStandard: "sap.dp:data-subscription-api:v1",
entryPoints: [],
resourceDefinitions: [{
type: "sap-csn-interop-effective-v1",
mediaType: "application/json",
url: "<TBD>/Product.csn.json",
accessStrategies: [
{
type: "open"
}
]
}]
}
};

/**
* This is a template function to create Event Resource object for Event Resource Array.
* There can be only one event resource per service because all events are using the same protocol, they are always Cloud Events.
Expand Down Expand Up @@ -323,5 +351,6 @@ module.exports = {
createEntityTypeMappingsItemTemplate,
createGroupsTemplateForService,
createAPIResourceTemplate,
createDataProductAPIResourceTemplate,
createEventResourceTemplate,
};

0 comments on commit 432d1a9

Please sign in to comment.