Skip to content

Commit

Permalink
Merge pull request #1587 from lnash94/master-528
Browse files Browse the repository at this point in the history
[master] Remove `types.bal` generation from low level service
  • Loading branch information
lnash94 authored Jan 17, 2024
2 parents fa22934 + cf982ff commit a9eb963
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ public List<GenSrcFile> generateBallerinaService(Path openAPI, String serviceNam
openAPIDef, nullable, preGeneratedTypeDefNodes);
String schemaContent = Formatter.format(
ballerinaSchemaGenerator.generateSyntaxTree()).toSourceCode();
if (!schemaContent.isBlank()) {
if (!schemaContent.isBlank() && !generateWithoutDataBinding) {
sourceFiles.add(new GenSrcFile(GenSrcFile.GenFileType.GEN_SRC, srcPackage, TYPE_FILE_NAME,
(licenseHeader.isBlank() ? DEFAULT_FILE_HEADER : licenseHeader) + schemaContent));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
*/
package io.ballerina.openapi.cmd;

import io.ballerina.cli.launcher.BLauncherException;
import org.testng.Assert;
import org.testng.annotations.Test;
import picocli.CommandLine;

import java.io.IOException;
import java.nio.file.Files;
Expand Down Expand Up @@ -111,4 +113,34 @@ public void testOneOfSchemaGen() throws IOException {
Assert.fail("Service generation for OneOf Schema type failed.");
}
}

@Test(description = "Test for --without-data-binding flag")
public void testWithoutDataBinding() throws IOException {
Path yamlPath = resourceDir.resolve(Paths.get("withoutDataBinding.yaml"));
String[] args = {"--input", yamlPath.toString(), "--without-data-binding", "-o",
this.tmpDir.toString(), "--mode", "service"};
OpenApiCmd cmd = new OpenApiCmd(printStream, this.tmpDir);
new CommandLine(cmd).parseArgs(args);
String output = "";
try {
cmd.execute();
} catch (BLauncherException e) {
output = e.getDetailedMessages().get(0);
}

Path expectedServiceFile = resourceDir.resolve(Paths.get("expected_gen",
"without-data-binding.bal"));
Stream<String> expectedServiceLines = Files.lines(expectedServiceFile);
String expectedService = expectedServiceLines.collect(Collectors.joining("\n"));
expectedServiceLines.close();
Assert.assertFalse(Files.exists(this.tmpDir.resolve("types.bal")));
if (Files.exists(this.tmpDir.resolve("withoutdatabinding_service.bal"))) {
String generatedService = getStringFromFile(this.tmpDir.resolve("withoutdatabinding_service.bal"));
Assert.assertEquals(replaceWhiteSpace(generatedService), replaceWhiteSpace(expectedService),
"Expected content and actual generated content is mismatched for: " + yamlPath);
deleteGeneratedFiles("without-data-binding-service.bal");
} else {
Assert.fail("Service generation for low level service is failed.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// AUTO-GENERATED FILE.
// This file is auto-generated by the Ballerina OpenAPI tool.

import ballerina/http;

listener http:Listener ep0 = new (9090, config = {host: "localhost"});

service /v1 on ep0 {
resource function get coupons/[string couponCode]/[int id]/[string limits](http:Caller caller, http:Request request) returns error? {
}
}
76 changes: 76 additions & 0 deletions openapi-cli/src/test/resources/withoutDataBinding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
openapi: 3.0.1
info:
title: V1
version: 0.1.0
servers:
- url: "{server}:{port}/v1"
variables:
server:
default: http://localhost
port:
default: "9090"
paths:
/coupons/{couponCode}/{id}/{limits}:
get:
operationId: getCoupon
parameters:
- $ref: '#/components/parameters/ngwCouponCodePathParam'
- $ref: '#/components/parameters/ngwCouponCodePathParam02'
- $ref: '#/components/parameters/ngwCouponCodePathParam03'
responses:
'200':
description: Successful operation, coupon was found by requested code
content:
application/json:
schema:
$ref: '#/components/schemas/Cat'
components:
parameters:
ngwCouponCodePathParam:
in: path
name: couponCode
required: true
schema:
$ref: '#/components/schemas/Coupon'
ngwCouponCodePathParam02:
in: path
name: id
required: true
schema:
$ref: '#/components/schemas/Id'
ngwCouponCodePathParam03:
in: path
name: limits
required: true
schema:
type: array
items:
type: integer
schemas:
Coupon:
type: string
Id:
$ref: '#/components/schemas/AddressNo'
AddressNo:
type: integer
Pet:
type: object
properties:
name:
type: string
tag:
type: string
required:
- name
- tag
Cat:
type: object
properties:
name:
type: string
parent:
$ref: '#/components/schemas/Pet'
petType:
$ref: '#/components/schemas/Cat'
required:
- name
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ public static QualifiedNameReferenceNode getQualifiedNameReferenceNode(String mo
* @return - node lists
* @throws BallerinaOpenApiException
*/
public static List<Node> getRelativeResourcePath(String path, Operation operation, List<Node> resourceFunctionDocs)
public static List<Node> getRelativeResourcePath(String path, Operation operation, List<Node> resourceFunctionDocs,
Components components, boolean isWithoutDataBinding)
throws BallerinaOpenApiException {

List<Node> functionRelativeResourcePath = new ArrayList<>();
Expand All @@ -241,7 +242,7 @@ public static List<Node> getRelativeResourcePath(String path, Operation operatio
*/
if (operation.getParameters() != null) {
extractPathParameterDetails(operation, functionRelativeResourcePath, pathNode,
pathParam, resourceFunctionDocs);
pathParam, resourceFunctionDocs, components, isWithoutDataBinding);
}
} else if (!pathNode.isBlank()) {
IdentifierToken idToken = createIdentifierToken(escapeIdentifier(pathNode.trim()));
Expand All @@ -261,7 +262,9 @@ public static List<Node> getRelativeResourcePath(String path, Operation operatio
}

private static void extractPathParameterDetails(Operation operation, List<Node> functionRelativeResourcePath,
String pathNode, String pathParam, List<Node> resourceFunctionDocs)
String pathNode, String pathParam,
List<Node> resourceFunctionDocs,
Components components, boolean isWithoutDataBinding)
throws BallerinaOpenApiException {
// check whether path parameter segment has special character
String[] split = pathNode.split(CLOSE_CURLY_BRACE, 2);
Expand All @@ -281,9 +284,10 @@ private static void extractPathParameterDetails(Operation operation, List<Node>
&& parameter.getIn().equals("path")) {
String paramType;
if (parameter.getSchema().get$ref() != null) {
paramType = getValidName(extractReferenceType(parameter.getSchema().get$ref()), true);
paramType = resolveReferenceType(parameter.getSchema(), components, isWithoutDataBinding,
pathParam);
} else {
paramType = convertOpenAPITypeToBallerina(parameter.getSchema());
paramType = getPathParameterType(parameter.getSchema(), pathParam);
if (paramType.endsWith(NILLABLE)) {
throw new BallerinaOpenApiException("Path parameter value cannot be null.");
}
Expand Down Expand Up @@ -1102,4 +1106,37 @@ public static boolean isIntegerSchema(Schema<?> fieldSchema) {
public static boolean isNumberSchema(Schema<?> fieldSchema) {
return Objects.equals(GeneratorUtils.getOpenAPIType(fieldSchema), NUMBER);
}

public static String resolveReferenceType(Schema<?> schema, Components components, boolean isWithoutDataBinding,
String pathParam) throws BallerinaOpenApiException {
String type = GeneratorUtils.extractReferenceType(schema.get$ref());

if (isWithoutDataBinding) {
Schema<?> referencedSchema = components.getSchemas().get(getValidName(type, true));
if (referencedSchema != null) {
if (referencedSchema.get$ref() != null) {
type = resolveReferenceType(referencedSchema, components, isWithoutDataBinding, pathParam);
} else {
type = getPathParameterType(referencedSchema, pathParam);
}
}
} else {
type = getValidName(type, true);
}
return type;
}

private static String getPathParameterType(Schema<?> typeSchema, String pathParam)
throws BallerinaOpenApiException {
String type;
if (!(isStringSchema(typeSchema) || isNumberSchema(typeSchema) || isBooleanSchema(typeSchema)
|| isIntegerSchema(typeSchema))) {
type = STRING;
LOGGER.warn("unsupported path parameter type found in the parameter `" + pathParam + "`. hence the " +
"parameter type is set to string.");
} else {
type = GeneratorUtils.convertOpenAPITypeToBallerina(typeSchema);
}
return type;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,8 @@ private FunctionDefinitionNode getClientMethodFunctionDefinitionNode(List<Annota

//Generate relative path
NodeList<Node> relativeResourcePath = resourceMode ?
createNodeList(GeneratorUtils.getRelativeResourcePath(path, operation.getValue(), null)) :
createNodeList(GeneratorUtils.getRelativeResourcePath(path, operation.getValue(),
null, openAPI.getComponents(), false)) :
createEmptyNodeList();
return createFunctionDefinitionNode(null,
metadataNode, qualifierList, functionKeyWord, functionName, relativeResourcePath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ private List<Node> applyFiltersForOperations(Filter filter, String path,
filterOperations.contains(operation.getValue().getOperationId().trim()))) {
// getRelative resource path
List<Node> functionRelativeResourcePath = GeneratorUtils.getRelativeResourcePath(path,
operation.getValue(), resourceFunctionDocs);
operation.getValue(), resourceFunctionDocs, openAPI.getComponents(),
generateWithoutDataBinding);
// function call

FunctionDefinitionNode functionDefinitionNode = generateWithoutDataBinding ?
Expand All @@ -261,7 +262,7 @@ private List<Node> applyFiltersForOperations(Filter filter, String path,
} else {
// getRelative resource path
List<Node> relativeResourcePath = GeneratorUtils.getRelativeResourcePath(path, operation.getValue(),
resourceFunctionDocs);
resourceFunctionDocs, openAPI.getComponents(), generateWithoutDataBinding);
// function call
FunctionDefinitionNode resourceFunction = generateWithoutDataBinding ?
generateGenericResourceFunctions(operation,
Expand Down

0 comments on commit a9eb963

Please sign in to comment.