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 (.*) STATEMENTEND') 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) } 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 if 'description' in operation: description = operation['description'] statementFinderResult = statementFinder.search(description) if statementFinderResult: statement = statementFinderResult.group(1) if not statementChecker[method].match(statement): raise Exception(f"Invalid statement {statement} for method {method}") 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']: paramsInputType['type'] = CsTypeConverter(paramsInputType['schema']['type']) 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, 'bodyInputType': bodyInputType, 'paramInputTypes': paramInputTypes }) #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))