@sap/xsodata
Version:
Expose data from a HANA database as OData V2 service with help of .xsodata files.
252 lines (210 loc) • 7.49 kB
JavaScript
'use strict';
const sql = require('./sqlStatement');
const sqlTools = require('./sqlTools');
const utils = require('../utils/utils');
const EntityType = require('../model/entityType.js');
exports.createPostStatementsForCreateTmpTables = function (context, asyncDone) {
try {
context.logger.silly(
'createPostStatements',
'createPostStatementsForCreateTmpTables'
);
const dbSegLast = context.oData.dbSegmentLast;
const sqlContext = {
context: context,
netId: context.uniqueNetworkRequestID,
reqId: context.uniqueRequestID,
rId: 1,
dbSegLast: dbSegLast,
systemQueryParameters: context.oData.systemQueryParameters,
};
context.sql = sqlContext;
context.sql.container = dbSegLast.sql.stmContainer =
new sql.PostContainer();
startPostMasterDbSegForCreate(sqlContext);
return asyncDone(null, context);
} catch (err) {
return asyncDone(err, context);
}
};
exports.createPostStatementsForInsert = function (context, asyncDone) {
try {
context.logger.silly(
'createPostStatements',
'createPostStatementsForInsert'
);
const sqlContext = context.sql;
startPostMasterDbSegForInsert(sqlContext);
return asyncDone(null, context);
} catch (err) {
return asyncDone(err, context);
}
};
/**
* Create SQL statements for the master table (=end of resource path)
* @param sqlContext
*/
function startPostMasterDbSegForCreate(sqlContext) {
const dbSeg = sqlContext.dbSegLast;
sqlContext.context.logger.debug(
'createPostStatements',
'startPostMasterDbSegForCreate'
);
dbSeg.sql.rId = sqlTools.rIdToNewTableName(
dbSeg._Alias,
sqlContext.netId,
sqlContext.reqId,
sqlContext.rId++
);
//create statement for master table
dbSeg.sql.stmContainer.createTmp = masterTableCreate(
sqlContext,
dbSeg.sql.rId
);
}
/**
* Create SQL statements for the master table (=end of resource path)
* @param sqlContext
*/
function startPostMasterDbSegForInsert(sqlContext) {
const dbSeg = sqlContext.dbSegLast;
sqlContext.context.logger.debug(
'createPostStatements',
'startPostMasterDbSegForInsert'
);
//create insert statement for master table
dbSeg.sql.stmContainer.insertTmp = masterTableInsertTmp(
sqlContext,
dbSeg.sql.rId
);
//create insert statement for master table
dbSeg.sql.stmContainer.insertReal = masterTableInsert(
sqlContext,
dbSeg.sql.rId
);
//create select statement for master table
dbSeg.sql.stmContainer.select = masterTableSelect(
sqlContext,
dbSeg.sql.rId
);
if (sqlContext.context.db.isExternalHandledConnection === true) {
// We only truncate and delete temp tables when db connection is handled external
// otherwise we will self disconnect and temp tables will be deleted automatically
// Build the truncate statement for created temporary table;
dbSeg.sql.stmContainer.createTmpTruncate = sql.buildTableStatement(
sql.Truncate,
sqlContext,
dbSeg.sql.stmContainer.createTmp.table
);
sqlContext.context.networkContext.cleanSessionTruncateContainer.push(
dbSeg.sql.stmContainer.createTmpTruncate
);
// Build the drop statement for created temporary table;
dbSeg.sql.stmContainer.createTmpDrop = sql.buildTableStatement(
sql.Drop,
sqlContext,
dbSeg.sql.stmContainer.createTmp.table
);
sqlContext.context.networkContext.cleanSessionDropContainer.push(
dbSeg.sql.stmContainer.createTmpDrop
);
}
}
function masterTableCreate(sqlContext, rId) {
const context = sqlContext.context;
const dbSeg = sqlContext.dbSegLast;
const stmCreate = new sql.Create();
context.logger.debug(
'createPostStatements',
'masterTableCreate (ordered selects)'
);
stmCreate.setModifiers([
'local',
'temporary',
dbSeg.entityType.tableStoreType,
]);
stmCreate.setTableName(rId);
const properties = dbSeg.getPropertiesForCreate();
const propertiesDbOrdered = dbSeg.makeDbOrdered(properties);
stmCreate.addProperties(propertiesDbOrdered);
if (dbSeg._ExpandedNavigations.length > 0) {
stmCreate.addProperties(dbSeg.getNavPropertiesForCreate());
}
return stmCreate;
}
function masterTableInsertTmp(sqlContext, rId) {
const context = sqlContext.context;
const dbSeg = sqlContext.dbSegLast;
const stm = new sql.Insert();
context.logger.debug(
'createPostStatements',
'masterTableInsertTmp (ordered selects)'
);
stm.setTableName({ table: rId });
//SELECT
const properties = dbSeg.getQKeyProperties();
const all = properties.concat(dbSeg.getQNonKeyProperties());
const allOrdered = dbSeg.makeDbOrdered(all);
stm.addNames(allOrdered);
//the data is inserted later on
return stm;
}
function masterTableInsert(sqlContext, rId) {
sqlContext.context.logger.debug(
'createPostStatements',
'createPostSQL_Insert_TmpMasterTable (ordered selects)'
);
const dbSeg = sqlContext.dbSegLast;
//subselect
const subSelect = new sql.Select();
subSelect.addSelects(new sql.SelectFormula(null, '*'));
subSelect.setFrom({ schema: null, table: rId, alias: null });
const stm = new sql.Insert();
//SELECT
stm.setTableName(dbSeg.getQTableNameNoAlias());
const properties = dbSeg.getQKeyProperties();
const all = properties.concat(dbSeg.getQNonKeyProperties());
const allOrdered = dbSeg.makeDbOrdered(all);
stm.addNames(allOrdered);
//Values
stm.setSubSelect(subSelect);
return stm;
}
/**
* Create select SQL statement to select from tmp table
* Since a application exit may be used to do the insert into the real table
* and possible create a custom key, we can't select with the client-key from the real table
* so in this case the application has the possiblity to pass the new key back to the client.
* @param sqlContext
* @param rId
* @returns {Select}
*/
function masterTableSelect(sqlContext, rId) {
sqlContext.context.logger.debug(
'createPostStatements',
'masterTableSelect (ordered selects)'
);
const dbSeg = sqlContext.dbSegLast;
const stmSelect = new sql.Select();
stmSelect.addSelect(dbSeg.getQKeyPropertiesWith0123AliasForSelect(true));
let prop = null;
if (
dbSeg.entityType.kind === EntityType.entityKind.calculationView &&
dbSeg.entityType._entityType.parameters &&
dbSeg.entityType._entityType.parameters.viaKey === true
) {
prop = dbSeg.getSelectFragmentsFromAllProperties(true);
} else {
prop = dbSeg.getPropertiesForSelect(true);
}
const propOrdered = dbSeg.makeDbOrdered(prop);
stmSelect.addSelects(propOrdered);
if (dbSeg._ExpandedNavigations.length > 0) {
stmSelect.addSelects(dbSeg.getNavPropertiesForSelect(true));
}
if (utils.isETagRequired(sqlContext.context, dbSeg)) {
sql._addETagToSelect(dbSeg, stmSelect, rId);
}
stmSelect.setFrom({ schema: null, table: rId, alias: null });
return stmSelect;
}