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,14 +71,30 @@ namespace com.krohne.genericdatabaseapiservice.Services {
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 NoDataFoundException : DbServiceException {}
public class TooMuchDataFoundException : DbServiceException {}
public class UnsupportedDataTypeException: DbServiceException {}
public class DbServiceException : Exception {
public DbServiceException(string msg): base(msg) { }
public DbServiceException(): base() { }
}
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 {
private readonly IConfiguration Configuration;
private readonly ILogger<DbService> Logger;
@ -90,7 +106,7 @@ namespace com.krohne.genericdatabaseapiservice.Services {
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 databaseConnInfo = DbInfoService.GetInfoStringByTag(databaseTag);
@ -101,8 +117,12 @@ namespace com.krohne.genericdatabaseapiservice.Services {
using (var conn = new MySqlConnection(databaseConnInfo)) {
await conn.OpenAsync();
bool commandTextSet = false;
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = selectStatement;
if (! bindingByStringReplacement) {
cmd.CommandText = selectStatement;
commandTextSet = true;
}
if (input != null){
foreach (var propertyInfo in typeof(TIN).GetProperties()) {
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 sep = "";
foreach (var x in p1) {
if (! (x is int || x is long)) {
throw new StringReplacementNotAllowedException();
}
Logger.LogInformation("x: {0}", x);
p2.Append(sep);
p2.Append(x);
@ -124,8 +147,21 @@ namespace com.krohne.genericdatabaseapiservice.Services {
}
var p3 = p2.ToString();
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 {
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);
cmd.Parameters.AddWithValue(dma.Name, value);
}
@ -154,6 +190,11 @@ namespace com.krohne.genericdatabaseapiservice.Services {
var value = reader.GetInt32(ordinal);
propertyInfo.SetValue(item, 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)) {
var value = reader.GetDateTime(ordinal);
propertyInfo.SetValue(item, value);
@ -164,7 +205,7 @@ namespace com.krohne.genericdatabaseapiservice.Services {
propertyInfo.SetValue(item, value);
Logger.LogInformation("Output Value:{0}", value);
} else {
throw new UnsupportedDataTypeException();
throw new UnsupportedDataTypeException(String.Format("{0}", propertyInfo.PropertyType));
}
}
itemList.Add(item);

View File

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

View File

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

View File

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

View File

@ -20,9 +20,14 @@ Exceptions:
ServiceErrorCode: 10004
ErrorMessage: the database tag mentioned in the API spec is not configured on the server, review the server configuration
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
- Exception: Exception
ErrorCode: 500
ServiceErrorCode: 10000
ErrorMessage: INSERT_EXCEPTION_MESSAGE
ErrorMessage: catch-all message
ErrorInfoURL: https://google.com