2021-12-15 14:58:24 +01:00

187 lines
7.5 KiB
Python

import yaml
from Cheetah.Template import Template
import glob
import argparse
import os
import re
import json
from yaml.loader import SafeLoader
from generateHelper import CsOperationNameConverter, OpenApiExtractRefType, CsTypeConverter
parser = argparse.ArgumentParser(description="generate.py")
parser.add_argument('--apiDefinitionFile', '-a',
help='API definition file. Default: openapi.yaml in the current folder.',
required=False,
default='./openapi.yaml')
parser.add_argument('--errorDefinitionFile', '-e',
help='Error definition file. Default: serviceErrorCodes.yaml in the current folder.',
required=False,
default='./serviceErrorCodes.yaml')
parser.add_argument('--template', '-t',
help="""Template file, templates files must be named as the final output file
with an additional .tmpl extension. Default: all template files recursively from the current folder.""",
required=False,
default="**/*.tmpl")
args = parser.parse_args()
with open(args.apiDefinitionFile) as apiDefinitionFile:
apiDefinition = yaml.load(apiDefinitionFile, Loader=SafeLoader)
with open(args.errorDefinitionFile) as errorDefinitionFile:
errorDefinition = yaml.load(errorDefinitionFile, Loader=SafeLoader)
apiDefinition["GENERATED_SQL_COMMENT"] = """
-- ----------------------------------------
-- THIS FILE HAS BEEN GENERATED
-- DO NOT EDIT MANUALLY
-- ----------------------------------------
"""
apiDefinition["GENERATED_PYTHON_COMMENT"] = """
# -----------------------------------------
# THIS FILE HAS BEEN GENERATED
# DO NOT EDIT MANUALLY
# -----------------------------------------
"""
apiDefinition["GENERATED_YAML_COMMENT"] = """
# -----------------------------------------
# THIS FILE HAS BEEN GENERATED
# DO NOT EDIT MANUALLY
# -----------------------------------------
"""
apiDefinition["GENERATED_TS_COMMENT"] = """
// -----------------------------------------
// THIS FILE HAS BEEN GENERATED
// DO NOT EDIT MANUALLY
// -----------------------------------------
"""
apiDefinition["GENERATED_CS_COMMENT"] = """
// -----------------------------------------
// THIS FILE HAS BEEN GENERATED
// DO NOT EDIT MANUALLY
// -----------------------------------------
"""
os.environ["PACKAGE_NAME"]
apiDefinition["env"] = {
"packagename": os.environ["PACKAGE_NAME"],
"routeprefix": os.environ["ROUTE_PREFIX"]
}
statementFinder = re.compile('STATEMENTBEGIN(\s+)(.+)(\s+)STATEMENTEND', flags=re.DOTALL)
statementCleaner = re.compile('\s+')
statementChecker = {
'get': re.compile('^select', re.IGNORECASE),
'put': re.compile('^update', re.IGNORECASE),
'delete': re.compile('^delete', re.IGNORECASE),
'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():
for (method, operation) in path.items():
print(f"{method=}")
print(f"{CsOperationNameConverter(operation['operationId'])=}")
# if 200 in
content = operation['responses'][200]['content']['application/json']['schema']
if ('type' in content) and (content['type'] == 'array'):
isList = True
resultType = OpenApiExtractRefType(content['items']['$ref'])
else:
isList = False
resultType = OpenApiExtractRefType(content['$ref'])
print(f"{content=}")
print(f"{resultType=}")
description = None
statement = None
bindingByStringReplacement = False
if 'description' in operation:
description = operation['description']
print(f"{description=}")
statementFinderResult = statementFinder.search(description)
if statementFinderResult:
statement = statementCleaner.sub(' ', statementFinderResult.group(2))
print(f"{statement=}")
if not statementChecker[method].match(statement):
raise Exception(f"Invalid statement {statement} for method {method}")
else:
print("no statement")
databaseTagFinderResult = databaseTagFinder.search(description)
if databaseTagFinderResult:
databaseTag = databaseTagFinderResult.group(2)
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:
bodyInputTypeName = OpenApiExtractRefType(operation['requestBody']['content']['application/json']['schema']['$ref'])
bodyInputType = { 'apiName': bodyInputTypeName, 'csName': CsOperationNameConverter(bodyInputTypeName) }
paramInputTypes = []
if 'parameters' in operation:
for paramsInputType in operation['parameters']:
if paramsInputType['schema']['type'] == 'array':
paramsInputType['type'] = CsTypeConverter(paramsInputType['schema']['items']['type'])
paramsInputType['isList'] = True
else:
paramsInputType['type'] = CsTypeConverter(paramsInputType['schema']['type'])
paramsInputType['isList'] = False
del paramsInputType['schema']
paramsInputType['csName'] = CsOperationNameConverter(paramsInputType['name'])
paramInputTypes.append(paramsInputType)
operations.append({
'description': description,
'method':method,
'func':CsOperationNameConverter(operation['operationId']),
'isList': isList,
'resultType': { 'apiName': resultType, 'csName': CsOperationNameConverter(resultType) } if resultType else {},
'allSelector': operation['operationId'].endswith('all'),
'byIdSelector': operation['operationId'].endswith('byid'),
'statement': statement,
'databaseTag': databaseTag,
'bodyInputType': bodyInputType,
'paramInputTypes': paramInputTypes,
'bindingByStringReplacement': bindingByStringReplacement
})
print(f"{operations=}")
apiDefinition["operations"] = operations
types = {}
for (typeName, typeDefinition) in apiDefinition['components']['schemas'].items():
print(f"{typeName=}")
typeProperties = []
for itemName in typeDefinition['properties']:
print(f"{itemName=}")
typeProperties.append({
'sqlName': itemName,
'csName': itemName.capitalize()
})
types[typeName] = {
'sqlName': typeName,
'csName': typeName.capitalize(),
'properties': typeProperties
}
print(f"{types=}")
apiDefinition['types'] = types
print(json.dumps(apiDefinition, indent=4))
print(json.dumps(errorDefinition, indent=4))
for f in glob.glob(args.template, recursive=True):
print(f"process {f}")
tmpl = Template(file=f, searchList=[apiDefinition, errorDefinition])
with open(f[:-5], 'w') as outFile:
outFile.write(str(tmpl))