@sap/cds-compiler
Version:
CDS (Core Data Services) compiler and backends
136 lines (117 loc) • 5.22 kB
JavaScript
;
const { setProp, isBetaEnabled } = require('../../base/model');
const { hasPersistenceSkipAnnotation } = require('../../model/csnUtils');
const sqlServiceAnnotation = '@protocol';
/**
* Find all entities in SQL services and mark them with an annotation and
* remember them in a symbol property for easier processing in toSql-rendering.
*
* @param {CSN.Model} csn
* @param {CSN.Options} options
* @returns {Function}
*/
function processSqlServices(csn, options) {
setProp(csn, '$sqlServiceEntities', Object.create(null));
setProp(csn, '$dummyServiceEntities', Object.create(null));
setProp(csn, '$dataProductEntities', Object.create(null));
return function findAndMarkSqlServiceArtifacts(artifact, artifactName) {
const { sqlServiceName, dummyServiceName, dataProductServiceName } = isEntityInSqlService(artifact, artifactName, csn, options);
if (sqlServiceName?.length > 0)
setProp(artifact, '$sqlService', sqlServiceName);
if (dummyServiceName?.length > 0)
setProp(artifact, '$dummyService', dummyServiceName);
if (dataProductServiceName?.length > 0)
setProp(artifact, '$dataProductService', dataProductServiceName);
};
}
/**
*
* @param {CSN.Artifact} artifact
* @returns {boolean}
*/
function isSqlService(artifact) {
return artifact.kind === 'service' && artifact[sqlServiceAnnotation] === 'sql';
}
/**
* Checks if the given artifact is an external ABAP SQL service.
*
* @param {object} artifact - The artifact to check.
* @param {CSN.Options} options
* @returns {boolean} - Returns true if the artifact is an external ABAP SQL service, otherwise false.
*/
function isDummyService(artifact, options) {
return isBetaEnabled(options, 'sqlServiceDummies') && artifact.kind === 'service' && artifact['@cds.external'] && artifact[sqlServiceAnnotation] === 'dummy';
}
/**
* Determines if an artifact is part of a SQL service or an external ABAP SQL service.
*
* @param {object} artifact - The artifact to check.
* @param {string} artifactName - The name of the artifact.
* @param {object} csn - The CSN (Core Schema Notation) object containing definitions.
* @param {CSN.Options} options
* @returns {object} An object containing the names of the SQL service and external ABAP SQL service, if found.
*/
function isEntityInSqlService(artifact, artifactName, csn, options) {
const result = { sqlServiceName: undefined, dummyServiceName: undefined, dataProductServiceName: undefined };
if (artifact.kind !== 'entity' || !artifactName.includes('.') || hasPersistenceSkipAnnotation(artifact))
return result;
const nameParts = artifactName.split('.');
for (let i = nameParts.length - 1; i >= 0; i--) {
const possibleServiceName = nameParts.slice(0, i).join('.');
if (!csn.definitions[possibleServiceName])
continue;
const definition = csn.definitions[possibleServiceName];
if (isSqlService(definition))
result.sqlServiceName = possibleServiceName;
if (isDummyService(definition, options))
result.dummyServiceName = possibleServiceName;
if (isDataProductService(definition, options))
result.dataProductServiceName = possibleServiceName;
// We don't allow nested services/contexts - if we find one, we don't need to keep searching
if (definition.kind === 'service' || definition.kind === 'context')
return result;
}
return result;
}
/**
* Creates a dummy ABAP SQL service for the given artifact if it is marked as an external ABAP SQL service.
* The dummy service is a copy of the original artifact with certain properties removed.
* The dummy service is then added to the CSN (Core Schema Notation) definitions.
*
* @param {object} artifact - The artifact to create a dummy service for.
* @param {string} artifactName - The name of the artifact.
* @param {object} csn - The Core Schema Notation (CSN) object where the dummy service will be added.
* @param {object} messageFunctions
* @param {Function} messageFunctions.error
*/
function createServiceDummy(artifact, artifactName, csn, { error }) {
if (!artifact.$dummyService)
return;
artifact['@cds.persistence.exists'] = true;
artifact.$ignore = true;
const dummy = { ...artifact };
delete dummy['@cds.persistence.exists'];
delete dummy.$ignore;
if (csn.definitions[`dummy.${ artifactName }`])
error(null, [ 'definitions', artifactName ], { name: `dummy.${ artifactName }` }, 'Generated artifact name $(NAME) conflicts with existing entity');
else
csn.definitions[`dummy.${ artifactName }`] = dummy;
}
/**
* Determines if the given artifact is a data product service.
*
* @param {object} artifact - The artifact to evaluate.
* @param {object} options - The options object containing feature flags.
* @returns {boolean} - Returns `true` if the artifact is a data product service, otherwise `false`.
*/
function isDataProductService(artifact, options) {
return isBetaEnabled(options, 'projectionViews') && artifact.kind === 'service' && artifact['@DataIntegration.dataproduct.type'] === 'primary';
}
module.exports = {
processSqlServices,
isSqlService,
isDummyService,
isDataProductService,
sqlServiceAnnotation,
createServiceDummy,
};