Skip to content

Commit

Permalink
Merge pull request #336 from Bhashinee/init
Browse files Browse the repository at this point in the history
Fix the init command
  • Loading branch information
daneshk authored Mar 20, 2024
2 parents 2b352b4 + d31fd83 commit c4e9239
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package io.ballerina.persist.tools;

import io.ballerina.persist.cmd.Init;
import org.testng.annotations.Test;
import picocli.CommandLine;

import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import java.nio.file.Paths;

import static io.ballerina.persist.tools.utils.GeneratedSourcesTestUtils.assertGeneratedSources;

public class ToolingInitTest {
public static final String GENERATED_SOURCES_DIRECTORY = Paths.get("build", "generated-sources")
.toString();
private static final PrintStream errStream = System.err;

@Test(enabled = true)
public void testInitWithDatastore() {
executeInitCommand("tool_test_init_1", "mysql");
assertGeneratedSources("tool_test_init_1");
}

@Test(enabled = true)
public void testInitWithoutArguments() {
executeInitCommand("tool_test_init_1");
assertGeneratedSources("tool_test_init_1");
}

@Test(enabled = true)
public void testInitWithBothDatastoreAndModule() {
executeInitCommand("tool_test_init_1", "mysql", "test_module");
assertGeneratedSources("tool_test_init_1");
}

public static void executeInitCommand(String subDir, String... args) {
Class<?> persistClass;
Path sourcePath = Paths.get(GENERATED_SOURCES_DIRECTORY, subDir);
try {
persistClass = Class.forName("io.ballerina.persist.cmd.Init");
Init persistCmd = (Init) persistClass.getDeclaredConstructor(String.class)
.newInstance(sourcePath.toAbsolutePath().toString());
if (args.length > 1) {
// ballerina persist init --datastore <datastore> --module <module>
new CommandLine(persistCmd).parseArgs("--datastore", args[0], "--module", args[1]);
} else if (args.length == 1) {
// ballerina persist init --datastore <datastore>
new CommandLine(persistCmd).parseArgs("--datastore", args[0]);
} else {
// ballerina persist init
new CommandLine(persistCmd).parseArgs();
}
persistCmd.execute();
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException
| InvocationTargetException e) {
errStream.println(e.getMessage());
}
}
}
75 changes: 19 additions & 56 deletions persist-cli/src/main/java/io/ballerina/persist/cmd/Init.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,22 @@

import io.ballerina.cli.BLauncherCmd;
import io.ballerina.persist.BalException;
import io.ballerina.persist.PersistToolsConstants;
import io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants;
import io.ballerina.projects.util.ProjectUtils;
import picocli.CommandLine;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.ballerina.persist.PersistToolsConstants.COMPONENT_IDENTIFIER;
import static io.ballerina.persist.PersistToolsConstants.MIGRATIONS;
import static io.ballerina.persist.PersistToolsConstants.PERSIST_DIRECTORY;
import static io.ballerina.persist.PersistToolsConstants.SUPPORTED_DB_PROVIDERS;
import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.BAL_EXTENSION;
import static io.ballerina.persist.nodegenerator.syntax.utils.TomlSyntaxUtils.readPackageName;
import static io.ballerina.persist.utils.BalProjectUtils.validateBallerinaProject;

/**
Expand Down Expand Up @@ -85,55 +78,13 @@ public void execute() {
return;
}

if (datastore == null) {
datastore = PersistToolsConstants.SupportedDataSources.IN_MEMORY_TABLE;
} else if (!SUPPORTED_DB_PROVIDERS.contains(datastore)) {
errStream.printf("ERROR: the persist layer supports one of data stores: %s" +
". but found '%s' datasource.%n", Arrays.toString(SUPPORTED_DB_PROVIDERS.toArray()), datastore);
return;
}

if (Files.isDirectory(Paths.get(sourcePath, PERSIST_DIRECTORY, MIGRATIONS))) {
errStream.println("ERROR: reinitializing persistence after executing the migrate command is not " +
"permitted. please remove the migrations directory within the persist directory and try " +
"executing the command again.");
return;
}

if (datastore.equals(PersistToolsConstants.SupportedDataSources.GOOGLE_SHEETS)) {
errStream.printf(BalSyntaxConstants.EXPERIMENTAL_NOTICE, "The support for Google Sheets data store " +
"is currently an experimental feature, and its behavior may be subject to change in future " +
"releases." + System.lineSeparator());
}

Path projectPath = Paths.get(sourcePath);
try {
validateBallerinaProject(projectPath);
} catch (BalException e) {
errStream.println(e.getMessage());
return;
}
String packageName;
try {
packageName = readPackageName(this.sourcePath);
} catch (BalException e) {
errStream.println(e.getMessage());
return;
}
if (module == null) {
module = packageName;
} else {
module = module.replaceAll("\"", "");
}
if (!ProjectUtils.validateModuleName(module)) {
errStream.println("ERROR: invalid module name : '" + module + "' :\n" +
"module name can only contain alphanumerics, underscores and periods");
return;
} else if (!ProjectUtils.validateNameLength(module)) {
errStream.println("ERROR: invalid module name : '" + module + "' :\n" +
"maximum length of module name is 256 characters");
return;
}

Path persistDirPath = Paths.get(this.sourcePath, PERSIST_DIRECTORY);
if (!Files.exists(persistDirPath)) {
Expand Down Expand Up @@ -171,13 +122,25 @@ public void execute() {
return;
}
}
errStream.println("Initialized the package for persistence.");
errStream.println(System.lineSeparator() + "Next steps:");

errStream.println("- Define your data model in \"persist/model.bal\".");
errStream.println("- Run \"bal persist generate\" to generate persist client and " +
"entity types for your data model.");

if (datastore != null || module != null) {
errStream.println("The behavior of the `bal persist init` command has been updated starting " +
"from Ballerina update 09.");
errStream.println("Now, you no longer need to provide any parameters. The command will exclusively " +
"create the `persist` directory in the project's root directory. This directory contains the " +
"data model definition file (`model.bal`) for the project." + System.lineSeparator());
errStream.println("If you have any questions or need further assistance, refer to the updated " +
"documentation.");
} else {
errStream.println("Initialized the package for persistence.");
errStream.println(System.lineSeparator() + "Next steps:");

errStream.println("1. Define your data model in \"persist/model.bal\".");
errStream.println("2. Execute `bal persist add --datastore <datastore> --module <module>` to add an" +
" entry to \"Ballerina.toml\" for integrating code generation with the package build process.");
errStream.println("OR");
errStream.println("Execute `bal persist generate --datastore <datastore> --module <module>` for " +
"a one-time generation of the client.");
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ OPTIONS
The name of the module to initialize the persistence layer. If not specified, the default module will be used.
--datastore <store type>
The type of the datastore to be used for persistence.
The supported datastores are 'inmemory', 'mysql', 'mssql', 'postgresql', and 'googlesheets'.
The supported datastores are 'inmemory', 'mysql', 'mssql', 'postgresql', 'googlesheets' and 'redis'.
If not specified, the 'inmemory' datastore will be used as the default.
-h, --help
Print the usage details of all commands.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,28 @@ NAME
bal persist generate - Generate the client API based on the data model.

SYNOPSIS
bal persist generate [<-h> | <--help>]
bal persist generate [--module <module name>]
[--datastore <store type>]
[<-h> | <--help>]

DESCRIPTION
Generate the client API and SQL script based on the data model defined in the `persist` directory.
The generated API can be used to query and manipulate the persistent data in the application.
The generated SQL script can be used to create the database tables.

OPTIONS
--module <module name>
The name of the module to initialize the persistence layer. If not specified, the default module will be used.
--datastore <store type>
The type of the datastore to be used for persistence.
The supported datastores are 'inmemory', 'mysql', 'mssql', 'postgresql', 'googlesheets', and 'redis'.
-h, --help
Print the usage details of all commands.

EXAMPLES
Print the usage details of the `bal persist generate` command.
$ bal persist generate --help

Generate client objects for the model definition file inside persist directory.
$ bal persist generate
$ bal persist generate --module persist --datastore mysql

26 changes: 21 additions & 5 deletions persist-cli/src/main/resources/cli-help/ballerina-persist.help
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ DESCRIPTION
data persistence in a Ballerina package. This step creates the required
directories and configuration files. For example:

$ bal persist init
$ bal persist add

Define the application's data model as the next step. Use the generated
definition file in the "persist" directory to define the data model
Expand All @@ -31,11 +31,25 @@ DESCRIPTION
Department department;
|};

Then, generate the client API based on the data model. Use the generated
API to query and manipulate the persistent data in the application.
Then, generate the client API based on the data model. You can use the `bal build` command to generate the client.
This process will automatically regenerate the client whenever you modify the data model during project builds.
Use the generated API to query and manipulate the persistent data in the application.
For example:

$ bal persist generate
$ bal build

Apart from the above commands, the following commands are also available:

$ bal persist init

This command initializes the package for persistence.
This command will create a new directory named 'persist' in the project directory. The 'persist' directory will
contain empty model definition file which can be used to define the data model of the Ballerina project.

$ bal persist generate --module persist --datastore mysql

This command generates the client API based on the data model defined in the "persist" directory. Usually used
for one time generation of the client.

OPTIONS
-h, --help
Expand All @@ -44,7 +58,9 @@ OPTIONS
BALLERINA COMMANDS
The below is a list of available subcommands:

init Initialize the package for persistence
add Initialize the package for persistence and integrate the client generation to
the `bal build` command.
init Initialize the package for persistence and create the "persist" directory and data model file.
generate Generate the client API based on the data model defined in the "persist" directory

Use 'bal persist <command> --help' for more information on a specific command.

0 comments on commit c4e9239

Please sign in to comment.