string replacement, better exception names

This commit is contained in:
Wolfgang Hottgenroth 2021-12-15 14:58:24 +01:00
parent 7b039b4fa4
commit 0f4c509b13
5 changed files with 90 additions and 22 deletions

View File

@ -71,13 +71,29 @@ namespace com.krohne.genericdatabaseapiservice.Services {
public interface IDbService { public interface IDbService {
Task<List<TOUT>> ReadBySelect<TIN, TOUT>(string databaseTag, string selectStatement, bool justOne, TIN input); Task<List<TOUT>> ReadBySelect<TIN, TOUT>(string databaseTag, string selectStatement, bool justOne, TIN input, bool bindingByStringReplacement);
} }
public class DbServiceException : Exception {} public class DbServiceException : Exception {
public class NoDataFoundException : DbServiceException {} public DbServiceException(string msg): base(msg) { }
public class TooMuchDataFoundException : DbServiceException {} public DbServiceException(): base() { }
public class UnsupportedDataTypeException: DbServiceException {} }
public class NoDataFoundException : DbServiceException {
public NoDataFoundException(string msg): base(msg) { }
public NoDataFoundException(): base() { }
}
public class TooMuchDataFoundException : DbServiceException {
public TooMuchDataFoundException(string msg): base(msg) { }
public TooMuchDataFoundException(): base() { }
}
public class UnsupportedDataTypeException: DbServiceException {
public UnsupportedDataTypeException(string msg): base(msg) { }
public UnsupportedDataTypeException(): base() { }
}
public class StringReplacementNotAllowedException: DbServiceException {
public StringReplacementNotAllowedException(string msg): base(msg) { }
public StringReplacementNotAllowedException(): base() { }
}
public class DbService : IDbService { public class DbService : IDbService {
private readonly IConfiguration Configuration; private readonly IConfiguration Configuration;
@ -90,7 +106,7 @@ namespace com.krohne.genericdatabaseapiservice.Services {
DbInfoService = dbInfoService; DbInfoService = dbInfoService;
} }
async public Task<List<TOUT>> ReadBySelect<TIN, TOUT>(string databaseTag, string selectStatement, bool justOne, TIN input) { async public Task<List<TOUT>> ReadBySelect<TIN, TOUT>(string databaseTag, string selectStatement, bool justOne, TIN input, bool bindingByStringReplacement) {
var itemList = new List<TOUT>(); var itemList = new List<TOUT>();
var databaseConnInfo = DbInfoService.GetInfoStringByTag(databaseTag); var databaseConnInfo = DbInfoService.GetInfoStringByTag(databaseTag);
@ -101,8 +117,12 @@ namespace com.krohne.genericdatabaseapiservice.Services {
using (var conn = new MySqlConnection(databaseConnInfo)) { using (var conn = new MySqlConnection(databaseConnInfo)) {
await conn.OpenAsync(); await conn.OpenAsync();
bool commandTextSet = false;
using (var cmd = conn.CreateCommand()) { using (var cmd = conn.CreateCommand()) {
if (! bindingByStringReplacement) {
cmd.CommandText = selectStatement; cmd.CommandText = selectStatement;
commandTextSet = true;
}
if (input != null){ if (input != null){
foreach (var propertyInfo in typeof(TIN).GetProperties()) { foreach (var propertyInfo in typeof(TIN).GetProperties()) {
Logger.LogInformation("Input Property name: {0} {1} ", propertyInfo.Name, propertyInfo.PropertyType); Logger.LogInformation("Input Property name: {0} {1} ", propertyInfo.Name, propertyInfo.PropertyType);
@ -117,6 +137,9 @@ namespace com.krohne.genericdatabaseapiservice.Services {
var p2 = new StringBuilder(); var p2 = new StringBuilder();
var sep = ""; var sep = "";
foreach (var x in p1) { foreach (var x in p1) {
if (! (x is int || x is long)) {
throw new StringReplacementNotAllowedException();
}
Logger.LogInformation("x: {0}", x); Logger.LogInformation("x: {0}", x);
p2.Append(sep); p2.Append(sep);
p2.Append(x); p2.Append(x);
@ -124,8 +147,21 @@ namespace com.krohne.genericdatabaseapiservice.Services {
} }
var p3 = p2.ToString(); var p3 = p2.ToString();
Logger.LogInformation("Input Value: p3:{0} typ:{1} isList:{2}", p3, typ, isList); Logger.LogInformation("Input Value: p3:{0} typ:{1} isList:{2}", p3, typ, isList);
cmd.Parameters.AddWithValue(dma.Name, p3); if (bindingByStringReplacement) {
if (commandTextSet) {
throw new StringReplacementNotAllowedException("string replacement only allowed for numeric parameters");
}
var processedStatement = selectStatement.Replace(String.Format("@{0}", dma.Name), p3);
cmd.CommandText = processedStatement;
commandTextSet = true;
Logger.LogInformation("Statement after replacement is {0}", processedStatement);
} else { } else {
cmd.Parameters.AddWithValue(dma.Name, p3);
}
} else {
if (bindingByStringReplacement) {
throw new StringReplacementNotAllowedException("string replacement only allowed to handle lists of parameters");
}
Logger.LogInformation("Input Value: {0} {1} {2}", value, typ, isList); Logger.LogInformation("Input Value: {0} {1} {2}", value, typ, isList);
cmd.Parameters.AddWithValue(dma.Name, value); cmd.Parameters.AddWithValue(dma.Name, value);
} }
@ -154,6 +190,11 @@ namespace com.krohne.genericdatabaseapiservice.Services {
var value = reader.GetInt32(ordinal); var value = reader.GetInt32(ordinal);
propertyInfo.SetValue(item, value); propertyInfo.SetValue(item, value);
Logger.LogInformation("Output Value:{0}", (System.Int32)value); Logger.LogInformation("Output Value:{0}", (System.Int32)value);
} else if (propertyInfo.PropertyType == typeof(System.Int64) ||
propertyInfo.PropertyType == typeof(System.Nullable<System.Int64>)) {
var value = reader.GetInt64(ordinal);
propertyInfo.SetValue(item, value);
Logger.LogInformation("Output Value:{0}", (System.Int64)value);
} else if (propertyInfo.PropertyType == typeof(System.DateTime)) { } else if (propertyInfo.PropertyType == typeof(System.DateTime)) {
var value = reader.GetDateTime(ordinal); var value = reader.GetDateTime(ordinal);
propertyInfo.SetValue(item, value); propertyInfo.SetValue(item, value);
@ -164,7 +205,7 @@ namespace com.krohne.genericdatabaseapiservice.Services {
propertyInfo.SetValue(item, value); propertyInfo.SetValue(item, value);
Logger.LogInformation("Output Value:{0}", value); Logger.LogInformation("Output Value:{0}", value);
} else { } else {
throw new UnsupportedDataTypeException(); throw new UnsupportedDataTypeException(String.Format("{0}", propertyInfo.PropertyType));
} }
} }
itemList.Add(item); itemList.Add(item);

View File

@ -77,6 +77,7 @@ statementChecker = {
'post': re.compile('^insert', re.IGNORECASE) 'post': re.compile('^insert', re.IGNORECASE)
} }
databaseTagFinder = re.compile('DATABASETAGBEGIN(\s+)(\S+)(\s+)DATABASETAGEND', flags=re.DOTALL) databaseTagFinder = re.compile('DATABASETAGBEGIN(\s+)(\S+)(\s+)DATABASETAGEND', flags=re.DOTALL)
bindingHintFinder = re.compile('BINDINGHINTBEGIN(\s+)(\S+)(\s+)BINDINGHINTEND', flags=re.DOTALL)
operations = [] operations = []
for path in apiDefinition['paths'].values(): for path in apiDefinition['paths'].values():
@ -95,6 +96,7 @@ for path in apiDefinition['paths'].values():
print(f"{resultType=}") print(f"{resultType=}")
description = None description = None
statement = None statement = None
bindingByStringReplacement = False
if 'description' in operation: if 'description' in operation:
description = operation['description'] description = operation['description']
print(f"{description=}") print(f"{description=}")
@ -112,6 +114,12 @@ for path in apiDefinition['paths'].values():
print(f"{databaseTag=}") print(f"{databaseTag=}")
else: else:
print("no databasetag") print("no databasetag")
bindingHintFinderResult = bindingHintFinder.search(description)
if bindingHintFinderResult:
bindingHint = bindingHintFinderResult.group(2)
print(f"{bindingHint=}")
bindingByStringReplacement = bindingHint == 'stringreplacement'
print(f"{bindingByStringReplacement=}")
bodyInputType = {} bodyInputType = {}
if 'requestBody' in operation: if 'requestBody' in operation:
@ -143,7 +151,8 @@ for path in apiDefinition['paths'].values():
'statement': statement, 'statement': statement,
'databaseTag': databaseTag, 'databaseTag': databaseTag,
'bodyInputType': bodyInputType, 'bodyInputType': bodyInputType,
'paramInputTypes': paramInputTypes 'paramInputTypes': paramInputTypes,
'bindingByStringReplacement': bindingByStringReplacement
}) })
print(f"{operations=}") print(f"{operations=}")
apiDefinition["operations"] = operations apiDefinition["operations"] = operations

View File

@ -168,6 +168,9 @@ paths:
DATABASETAGBEGIN DATABASETAGBEGIN
pdb_el_reader1 pdb_el_reader1
DATABASETAGEND DATABASETAGEND
BINDINGHINTBEGIN
stringreplacement
BINDINGHINTEND
STATEMENTBEGIN STATEMENTBEGIN
SELECT SELECT
sn.seriennummer AS serialNumber sn.seriennummer AS serialNumber
@ -184,7 +187,7 @@ paths:
LEFT JOIN ems ON sn.seriennummer = ems.Seriennummer LEFT JOIN ems ON sn.seriennummer = ems.Seriennummer
LEFT JOIN modulindex ON sn.seriennummer = modulindex.sn_lp LEFT JOIN modulindex ON sn.seriennummer = modulindex.sn_lp
WHERE WHERE
FIND_IN_SET(sn.seriennummer, @serialNumbers) != 0 sn.seriennummer in (@serialNumbers)
STATEMENTEND STATEMENTEND
``` ```
parameters: parameters:
@ -194,7 +197,7 @@ paths:
schema: schema:
type: array type: array
items: items:
type: integer type: string
responses: responses:
200: 200:
description: Here are your pcbItem items description: Here are your pcbItem items
@ -242,6 +245,12 @@ components:
offensiveData: offensiveData:
description: Input data which causes this error description: Input data which causes this error
type: string type: string
caughtException:
description: caught exception as a string
type: string
caughtExceptionMessage:
description: message of caught exception
type: string
# -------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------
baseItem: baseItem:
description: Selected columns of the stammdaten table from pdb_el description: Selected columns of the stammdaten table from pdb_el
@ -389,9 +398,10 @@ components:
nullable: true nullable: true
articleCode: articleCode:
type: integer type: integer
format: int64
nullable: true nullable: true
bomIndex: bomIndex:
type: integer type: string
nullable: true nullable: true
hasEmsUpdate: hasEmsUpdate:
type: boolean type: boolean

View File

@ -126,6 +126,12 @@ paramInput#slurp
#else #else
null#slurp null#slurp
#end if #end if
, #slurp
#if $operation['bindingByStringReplacement']
true#slurp
#else
false#slurp
#end if
); );
return new ObjectResult(res#slurp return new ObjectResult(res#slurp
#if not $operation['isList'] #if not $operation['isList']
@ -138,13 +144,10 @@ null#slurp
var err = new ErrorResultObject(); var err = new ErrorResultObject();
err.ErrorCode = $errDef['ErrorCode']; err.ErrorCode = $errDef['ErrorCode'];
err.ServiceErrorCode = $errDef['ServiceErrorCode']; err.ServiceErrorCode = $errDef['ServiceErrorCode'];
err.ErrorMessage = #slurp err.ErrorMessage = "$errDef['ErrorMessage']";
#if $errDef['ErrorMessage'] == 'INSERT_EXCEPTION_MESSAGE'
ex.ToString();
#else
"$errDef['ErrorMessage']";
#end if
err.ErrorInfoURL = "$errDef['ErrorInfoURL']"; err.ErrorInfoURL = "$errDef['ErrorInfoURL']";
err.CaughtException = ex.ToString();
err.CaughtExceptionMessage = ex.Message;
err.OffensiveData = #slurp err.OffensiveData = #slurp
#if $operation['bodyInputType'] #if $operation['bodyInputType']
Newtonsoft.Json.JsonConvert.SerializeObject($operation['bodyInputType']['apiName'], Newtonsoft.Json.Formatting.Indented); Newtonsoft.Json.JsonConvert.SerializeObject($operation['bodyInputType']['apiName'], Newtonsoft.Json.Formatting.Indented);

View File

@ -20,9 +20,14 @@ Exceptions:
ServiceErrorCode: 10004 ServiceErrorCode: 10004
ErrorMessage: the database tag mentioned in the API spec is not configured on the server, review the server configuration ErrorMessage: the database tag mentioned in the API spec is not configured on the server, review the server configuration
ErrorInfoURL: https://google.com ErrorInfoURL: https://google.com
- Exception: StringReplacementNotAllowedException
ErrorCode: 500
ServiceErrorCode: 10005
ErrorMessage: parameter binding by string replacement is not allowed for this select, review the openapi specifiction
ErrorInfoURL: https://google.com
# Make sure "Exception: Exception" is the last entry in the list # Make sure "Exception: Exception" is the last entry in the list
- Exception: Exception - Exception: Exception
ErrorCode: 500 ErrorCode: 500
ServiceErrorCode: 10000 ServiceErrorCode: 10000
ErrorMessage: INSERT_EXCEPTION_MESSAGE ErrorMessage: catch-all message
ErrorInfoURL: https://google.com ErrorInfoURL: https://google.com