2021-11-18 19:27:39 +01:00
|
|
|
import yaml
|
|
|
|
from Cheetah.Template import Template
|
|
|
|
import glob
|
|
|
|
import argparse
|
|
|
|
import os
|
2021-11-19 12:39:46 +01:00
|
|
|
import re
|
2021-11-22 19:07:46 +01:00
|
|
|
import json
|
2021-11-18 19:27:39 +01:00
|
|
|
from yaml.loader import SafeLoader
|
2021-11-22 19:07:46 +01:00
|
|
|
from generateHelper import CsOperationNameConverter, OpenApiExtractRefType, CsTypeConverter
|
2021-11-18 19:27:39 +01:00
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(description="generate.py")
|
2021-11-19 12:39:46 +01:00
|
|
|
parser.add_argument('--apiDefinitionFile', '-a',
|
2021-11-18 19:27:39 +01:00
|
|
|
help='API definition file. Default: openapi.yaml in the current folder.',
|
|
|
|
required=False,
|
|
|
|
default='./openapi.yaml')
|
2021-12-02 11:59:10 +01:00
|
|
|
parser.add_argument('--errorDefinitionFile', '-e',
|
|
|
|
help='Error definition file. Default: serviceErrorCodes.yaml in the current folder.',
|
|
|
|
required=False,
|
|
|
|
default='./serviceErrorCodes.yaml')
|
2021-11-18 19:27:39 +01:00
|
|
|
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()
|
|
|
|
|
|
|
|
|
2021-11-19 12:39:46 +01:00
|
|
|
with open(args.apiDefinitionFile) as apiDefinitionFile:
|
|
|
|
apiDefinition = yaml.load(apiDefinitionFile, Loader=SafeLoader)
|
2021-12-02 11:59:10 +01:00
|
|
|
with open(args.errorDefinitionFile) as errorDefinitionFile:
|
|
|
|
errorDefinition = yaml.load(errorDefinitionFile, Loader=SafeLoader)
|
|
|
|
|
2021-11-18 19:27:39 +01:00
|
|
|
|
|
|
|
|
2021-11-19 12:39:46 +01:00
|
|
|
apiDefinition["GENERATED_SQL_COMMENT"] = """
|
2021-11-18 19:27:39 +01:00
|
|
|
-- ----------------------------------------
|
|
|
|
-- THIS FILE HAS BEEN GENERATED
|
|
|
|
-- DO NOT EDIT MANUALLY
|
|
|
|
-- ----------------------------------------
|
|
|
|
"""
|
2021-11-19 12:39:46 +01:00
|
|
|
apiDefinition["GENERATED_PYTHON_COMMENT"] = """
|
2021-11-18 19:27:39 +01:00
|
|
|
# -----------------------------------------
|
|
|
|
# THIS FILE HAS BEEN GENERATED
|
|
|
|
# DO NOT EDIT MANUALLY
|
|
|
|
# -----------------------------------------
|
|
|
|
"""
|
2021-11-19 12:39:46 +01:00
|
|
|
apiDefinition["GENERATED_YAML_COMMENT"] = """
|
2021-11-18 19:27:39 +01:00
|
|
|
# -----------------------------------------
|
|
|
|
# THIS FILE HAS BEEN GENERATED
|
|
|
|
# DO NOT EDIT MANUALLY
|
|
|
|
# -----------------------------------------
|
|
|
|
"""
|
2021-11-19 12:39:46 +01:00
|
|
|
apiDefinition["GENERATED_TS_COMMENT"] = """
|
2021-11-18 19:27:39 +01:00
|
|
|
// -----------------------------------------
|
|
|
|
// THIS FILE HAS BEEN GENERATED
|
|
|
|
// DO NOT EDIT MANUALLY
|
|
|
|
// -----------------------------------------
|
|
|
|
"""
|
2021-11-19 12:39:46 +01:00
|
|
|
apiDefinition["GENERATED_CS_COMMENT"] = """
|
2021-11-18 19:27:39 +01:00
|
|
|
// -----------------------------------------
|
|
|
|
// THIS FILE HAS BEEN GENERATED
|
|
|
|
// DO NOT EDIT MANUALLY
|
|
|
|
// -----------------------------------------
|
|
|
|
"""
|
|
|
|
|
2021-11-26 16:36:07 +01:00
|
|
|
os.environ["PACKAGE_NAME"]
|
|
|
|
apiDefinition["env"] = {
|
|
|
|
"packagename": os.environ["PACKAGE_NAME"],
|
|
|
|
"routeprefix": os.environ["ROUTE_PREFIX"]
|
|
|
|
}
|
2021-12-14 14:02:00 +01:00
|
|
|
statementFinder = re.compile('STATEMENTBEGIN(\s+)(.+)(\s+)STATEMENTEND', flags=re.DOTALL)
|
|
|
|
statementCleaner = re.compile('\s+')
|
2021-11-19 12:39:46 +01:00
|
|
|
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)
|
|
|
|
}
|
2021-12-14 14:02:00 +01:00
|
|
|
databaseTagFinder = re.compile('DATABASETAGBEGIN(\s+)(\S+)(\s+)DATABASETAGEND', flags=re.DOTALL)
|
2021-12-15 14:58:24 +01:00
|
|
|
bindingHintFinder = re.compile('BINDINGHINTBEGIN(\s+)(\S+)(\s+)BINDINGHINTEND', flags=re.DOTALL)
|
2021-11-18 19:27:39 +01:00
|
|
|
|
|
|
|
operations = []
|
2021-11-19 12:39:46 +01:00
|
|
|
for path in apiDefinition['paths'].values():
|
2021-11-18 19:27:39 +01:00
|
|
|
for (method, operation) in path.items():
|
2021-12-14 14:02:00 +01:00
|
|
|
print(f"{method=}")
|
|
|
|
print(f"{CsOperationNameConverter(operation['operationId'])=}")
|
2021-11-19 12:39:46 +01:00
|
|
|
# if 200 in
|
2021-11-18 19:27:39 +01:00
|
|
|
content = operation['responses'][200]['content']['application/json']['schema']
|
|
|
|
if ('type' in content) and (content['type'] == 'array'):
|
|
|
|
isList = True
|
2021-11-19 12:39:46 +01:00
|
|
|
resultType = OpenApiExtractRefType(content['items']['$ref'])
|
2021-11-18 19:27:39 +01:00
|
|
|
else:
|
|
|
|
isList = False
|
2021-11-19 12:39:46 +01:00
|
|
|
resultType = OpenApiExtractRefType(content['$ref'])
|
2021-12-14 14:02:00 +01:00
|
|
|
print(f"{content=}")
|
|
|
|
print(f"{resultType=}")
|
2021-11-19 12:39:46 +01:00
|
|
|
description = None
|
|
|
|
statement = None
|
2021-12-15 14:58:24 +01:00
|
|
|
bindingByStringReplacement = False
|
2021-11-19 12:39:46 +01:00
|
|
|
if 'description' in operation:
|
|
|
|
description = operation['description']
|
2021-12-14 14:02:00 +01:00
|
|
|
print(f"{description=}")
|
2021-11-19 12:39:46 +01:00
|
|
|
statementFinderResult = statementFinder.search(description)
|
|
|
|
if statementFinderResult:
|
2021-12-14 14:02:00 +01:00
|
|
|
statement = statementCleaner.sub(' ', statementFinderResult.group(2))
|
|
|
|
print(f"{statement=}")
|
2021-11-19 12:39:46 +01:00
|
|
|
if not statementChecker[method].match(statement):
|
|
|
|
raise Exception(f"Invalid statement {statement} for method {method}")
|
2021-12-14 14:02:00 +01:00
|
|
|
else:
|
|
|
|
print("no statement")
|
2021-12-06 17:46:58 +01:00
|
|
|
databaseTagFinderResult = databaseTagFinder.search(description)
|
|
|
|
if databaseTagFinderResult:
|
2021-12-14 14:02:00 +01:00
|
|
|
databaseTag = databaseTagFinderResult.group(2)
|
|
|
|
print(f"{databaseTag=}")
|
|
|
|
else:
|
|
|
|
print("no databasetag")
|
2021-12-15 14:58:24 +01:00
|
|
|
bindingHintFinderResult = bindingHintFinder.search(description)
|
|
|
|
if bindingHintFinderResult:
|
|
|
|
bindingHint = bindingHintFinderResult.group(2)
|
|
|
|
print(f"{bindingHint=}")
|
|
|
|
bindingByStringReplacement = bindingHint == 'stringreplacement'
|
|
|
|
print(f"{bindingByStringReplacement=}")
|
2021-11-19 12:39:46 +01:00
|
|
|
|
2021-11-22 19:07:46 +01:00
|
|
|
bodyInputType = {}
|
2021-11-19 12:39:46 +01:00
|
|
|
if 'requestBody' in operation:
|
2021-11-22 19:07:46 +01:00
|
|
|
bodyInputTypeName = OpenApiExtractRefType(operation['requestBody']['content']['application/json']['schema']['$ref'])
|
|
|
|
bodyInputType = { 'apiName': bodyInputTypeName, 'csName': CsOperationNameConverter(bodyInputTypeName) }
|
2021-11-25 14:49:08 +01:00
|
|
|
|
|
|
|
paramInputTypes = []
|
2021-11-22 19:07:46 +01:00
|
|
|
if 'parameters' in operation:
|
|
|
|
for paramsInputType in operation['parameters']:
|
2021-12-14 18:11:57 +01:00
|
|
|
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
|
2021-11-22 19:07:46 +01:00
|
|
|
del paramsInputType['schema']
|
2021-11-25 14:49:08 +01:00
|
|
|
paramsInputType['csName'] = CsOperationNameConverter(paramsInputType['name'])
|
|
|
|
paramInputTypes.append(paramsInputType)
|
2021-11-22 19:07:46 +01:00
|
|
|
|
|
|
|
|
2021-11-18 19:27:39 +01:00
|
|
|
operations.append({
|
2021-11-19 12:39:46 +01:00
|
|
|
'description': description,
|
2021-11-18 19:27:39 +01:00
|
|
|
'method':method,
|
|
|
|
'func':CsOperationNameConverter(operation['operationId']),
|
|
|
|
'isList': isList,
|
2021-11-19 12:39:46 +01:00
|
|
|
'resultType': { 'apiName': resultType, 'csName': CsOperationNameConverter(resultType) } if resultType else {},
|
|
|
|
'allSelector': operation['operationId'].endswith('all'),
|
|
|
|
'byIdSelector': operation['operationId'].endswith('byid'),
|
|
|
|
'statement': statement,
|
2021-12-06 17:46:58 +01:00
|
|
|
'databaseTag': databaseTag,
|
2021-11-22 19:07:46 +01:00
|
|
|
'bodyInputType': bodyInputType,
|
2021-12-15 14:58:24 +01:00
|
|
|
'paramInputTypes': paramInputTypes,
|
|
|
|
'bindingByStringReplacement': bindingByStringReplacement
|
2021-11-19 12:39:46 +01:00
|
|
|
})
|
2021-12-14 14:02:00 +01:00
|
|
|
print(f"{operations=}")
|
2021-11-19 12:39:46 +01:00
|
|
|
apiDefinition["operations"] = operations
|
|
|
|
|
|
|
|
types = {}
|
|
|
|
for (typeName, typeDefinition) in apiDefinition['components']['schemas'].items():
|
2021-12-14 14:02:00 +01:00
|
|
|
print(f"{typeName=}")
|
2021-11-19 12:39:46 +01:00
|
|
|
typeProperties = []
|
|
|
|
for itemName in typeDefinition['properties']:
|
2021-12-14 14:02:00 +01:00
|
|
|
print(f"{itemName=}")
|
2021-11-19 12:39:46 +01:00
|
|
|
typeProperties.append({
|
|
|
|
'sqlName': itemName,
|
|
|
|
'csName': itemName.capitalize()
|
2021-11-18 19:27:39 +01:00
|
|
|
})
|
2021-11-19 12:39:46 +01:00
|
|
|
types[typeName] = {
|
|
|
|
'sqlName': typeName,
|
|
|
|
'csName': typeName.capitalize(),
|
|
|
|
'properties': typeProperties
|
|
|
|
}
|
2021-12-14 14:02:00 +01:00
|
|
|
print(f"{types=}")
|
2021-11-19 12:39:46 +01:00
|
|
|
apiDefinition['types'] = types
|
2021-11-18 19:27:39 +01:00
|
|
|
|
2021-11-22 19:07:46 +01:00
|
|
|
print(json.dumps(apiDefinition, indent=4))
|
2021-12-02 11:59:10 +01:00
|
|
|
print(json.dumps(errorDefinition, indent=4))
|
2021-11-18 19:27:39 +01:00
|
|
|
for f in glob.glob(args.template, recursive=True):
|
|
|
|
print(f"process {f}")
|
2021-12-02 11:59:10 +01:00
|
|
|
tmpl = Template(file=f, searchList=[apiDefinition, errorDefinition])
|
2021-11-18 19:27:39 +01:00
|
|
|
with open(f[:-5], 'w') as outFile:
|
|
|
|
outFile.write(str(tmpl))
|
|
|
|
|
|
|
|
|