From ae62400224a13f0e9a31da3772bdea8f5058f592 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Wed, 3 Dec 2025 14:40:17 +0530 Subject: [PATCH 1/9] [Automated] Update the native jar versions --- persist-tool/BalTool.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/persist-tool/BalTool.toml b/persist-tool/BalTool.toml index 5575aaf67..4d2fe57fa 100644 --- a/persist-tool/BalTool.toml +++ b/persist-tool/BalTool.toml @@ -3,3 +3,6 @@ id = "persist" [[dependency]] path = "../persist-cli/build/libs/persist-cli-1.8.0-SNAPSHOT.jar" + +[[dependency]] +path = "../persist-core/build/libs/persist-core-1.8.0-SNAPSHOT.jar" From f079bc81492eda4da4f8a71a3bb747eccd131191 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Wed, 3 Dec 2025 14:53:14 +0530 Subject: [PATCH 2/9] Add support for init parameters in persistence layer configuration --- .../java/io/ballerina/persist/cmd/Add.java | 36 +++-- .../io/ballerina/persist/cmd/Generate.java | 32 ++-- .../persist/cmd/PersistCodeGeneratorTool.java | 22 +-- .../resources/persist-options-schema.json | 5 +- .../persist/PersistToolsConstants.java | 1 + .../persist/components/Function.java | 15 ++ .../nodegenerator/SourceGenerator.java | 42 +++-- .../syntax/clients/DbClientSyntax.java | 145 +++++++++++++----- .../syntax/constants/BalSyntaxConstants.java | 2 +- .../constants/SyntaxTokenConstants.java | 1 + .../syntax/sources/DbSyntaxTree.java | 12 +- 11 files changed, 214 insertions(+), 99 deletions(-) diff --git a/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java b/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java index 9f89ad88a..d80618d30 100644 --- a/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java +++ b/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java @@ -58,9 +58,7 @@ import static io.ballerina.persist.utils.BalProjectUtils.validateTestDatastore; import static io.ballerina.projects.util.ProjectConstants.BALLERINA_TOML; -@CommandLine.Command( - name = "add", - description = "Initialize the persistence layer in the Ballerina project.") +@CommandLine.Command(name = "add", description = "Initialize the persistence layer in the Ballerina project.") public class Add implements BLauncherCmd { private static final PrintStream errStream = System.err; @@ -68,26 +66,30 @@ public class Add implements BLauncherCmd { private final String sourcePath; - @CommandLine.Option(names = {"-h", "--help"}, hidden = true) + @CommandLine.Option(names = { "-h", "--help" }, hidden = true) private boolean helpFlag; - @CommandLine.Option(names = {"--datastore"}) + @CommandLine.Option(names = { "--datastore" }) private String datastore; - @CommandLine.Option(names = {"--module"}) + @CommandLine.Option(names = { "--module" }) private String module; - @CommandLine.Option(names = {"--id"}, description = "ID for the generated Ballerina client") + @CommandLine.Option(names = { "--id" }, description = "ID for the generated Ballerina client") private String id; - @CommandLine.Option(names = {"--test-datastore"}, description = "Test data store for the " + + @CommandLine.Option(names = { "--test-datastore" }, description = "Test data store for the " + "generated Ballerina client") private String testDatastore; - @CommandLine.Option(names = {"--eager-loading"}, hidden = true, description = "Enable eager loading to return " + + @CommandLine.Option(names = { "--eager-loading" }, hidden = true, description = "Enable eager loading to return " + "arrays instead of streams for get-all methods") private boolean eagerLoading; + @CommandLine.Option(names = { "--init-params" }, hidden = true, description = "Use init parameters instead of " + + "configurables") + private boolean initParams; + public Add() { this(""); } @@ -125,7 +127,7 @@ public void execute() { String moduleNameWithPackage = validateAndProcessModule(packageName, module); createDefaultClientId(); String syntaxTree = updateBallerinaToml(Paths.get(this.sourcePath, BALLERINA_TOML), - moduleNameWithPackage, datastore, testDatastore, eagerLoading, id); + moduleNameWithPackage, datastore, testDatastore, eagerLoading, initParams, id); FileUtils.writeToTargetFile(syntaxTree, Paths.get(sourcePath, BALLERINA_TOML).toAbsolutePath().toString()); createPersistDirectoryIfNotExists(); @@ -151,7 +153,7 @@ public void execute() { * Method to update the Ballerina.toml with persist tool configurations. */ private String updateBallerinaToml(Path tomlPath, String module, String datastore, String testDatastore, - boolean eagerLoading, String id) + boolean eagerLoading, boolean initParams, String id) throws BalException, IOException { TomlSyntaxUtils.NativeDependency dependency = getDependencyConfig(datastore, testDatastore); TomlSyntaxUtils.ConfigDeclaration declaration = getConfigDeclaration(tomlPath, dependency); @@ -165,7 +167,7 @@ private String updateBallerinaToml(Path tomlPath, String module, String datastor moduleMembers = moduleMembers.add(SampleNodeGenerator.createTableArray( PersistToolsConstants.PERSIST_TOOL_CONFIG, null)); moduleMembers = populateBallerinaNodeList(moduleMembers, module, datastore, testDatastore, - eagerLoading, id); + eagerLoading, initParams, id); moduleMembers = BalProjectUtils.addNewLine(moduleMembers, 1); } Token eofToken = AbstractNodeFactory.createIdentifierToken(""); @@ -176,7 +178,7 @@ private String updateBallerinaToml(Path tomlPath, String module, String datastor private static NodeList populateBallerinaNodeList( NodeList moduleMembers, String module, String dataStore, - String testDatastore, boolean eagerLoading, String id) { + String testDatastore, boolean eagerLoading, boolean initParams, String id) { moduleMembers = moduleMembers.add(SampleNodeGenerator.createStringKV("id", id, null)); moduleMembers = moduleMembers.add(SampleNodeGenerator.createStringKV("targetModule", module, null)); moduleMembers = moduleMembers.add(SampleNodeGenerator.createStringKV("options.datastore", dataStore, null)); @@ -188,6 +190,10 @@ private static NodeList populateBallerinaNodeList moduleMembers = moduleMembers.add(SampleNodeGenerator.createBooleanKV("options.eagerLoading", true, null)); } + if (initParams) { + moduleMembers = moduleMembers.add(SampleNodeGenerator.createBooleanKV("options.initParams", + true, null)); + } moduleMembers = moduleMembers.add(SampleNodeGenerator.createStringKV("filePath", "persist/model.bal", null)); return moduleMembers; } @@ -219,8 +225,8 @@ private String validateAndProcessModule(String packageName, String module) throw "maximum length of module name is 256 characters", module)); } } - return Objects.isNull(module) ? packageName : - String.format("%s.%s", packageName.replaceAll("\"", ""), + return Objects.isNull(module) ? packageName + : String.format("%s.%s", packageName.replaceAll("\"", ""), module.replaceAll("\"", "")); } diff --git a/persist-cli/src/main/java/io/ballerina/persist/cmd/Generate.java b/persist-cli/src/main/java/io/ballerina/persist/cmd/Generate.java index 7303d6fa5..763731354 100644 --- a/persist-cli/src/main/java/io/ballerina/persist/cmd/Generate.java +++ b/persist-cli/src/main/java/io/ballerina/persist/cmd/Generate.java @@ -53,14 +53,12 @@ import static io.ballerina.projects.util.ProjectConstants.BALLERINA_TOML; /** - * This Class implements the `persist generate` command in Ballerina persist-tool. + * This Class implements the `persist generate` command in Ballerina + * persist-tool. * * @since 0.1.0 */ -@CommandLine.Command( - name = "generate", - description = "Generate Ballerina client object for the entity." -) +@CommandLine.Command(name = "generate", description = "Generate Ballerina client object for the entity.") public class Generate implements BLauncherCmd { @@ -78,23 +76,27 @@ public Generate(String sourcePath) { this.sourcePath = sourcePath; } - @CommandLine.Option(names = {"-h", "--help"}, hidden = true) + @CommandLine.Option(names = { "-h", "--help" }, hidden = true) private boolean helpFlag; - @CommandLine.Option(names = {"--module"}) + @CommandLine.Option(names = { "--module" }) private String module; - @CommandLine.Option(names = {"--datastore"}) + @CommandLine.Option(names = { "--datastore" }) private String datastore; - @CommandLine.Option(names = {"--test-datastore"}, description = "Test data store for the " + + @CommandLine.Option(names = { "--test-datastore" }, description = "Test data store for the " + "generated Ballerina client") private String testDatastore; - @CommandLine.Option(names = {"--eager-loading"}, hidden = true, description = "Enable eager loading to return " + + @CommandLine.Option(names = { "--eager-loading" }, hidden = true, description = "Enable eager loading to return " + "arrays instead of streams for get-all methods") private boolean eagerLoading; + @CommandLine.Option(names = { "--init-params" }, hidden = true, description = "Use init parameters instead of " + + "configurables") + private boolean initParams; + @Override public void execute() { Path generatedSourceDirPath; @@ -216,7 +218,7 @@ public void execute() { } try { - schemaFilePath = BalProjectUtils.getSchemaFilePath(this.sourcePath); + schemaFilePath = BalProjectUtils.getSchemaFilePath(this.sourcePath); } catch (BalException e) { errStream.println(e.getMessage()); return; @@ -251,7 +253,7 @@ public void execute() { } } SourceGenerator sourceCreator = new SourceGenerator(sourcePath, generatedSourceDirPath, - moduleNameWithPackage, entityModule, eagerLoading); + moduleNameWithPackage, entityModule, eagerLoading, initParams); try { switch (datastore) { case PersistToolsConstants.SupportedDataSources.MYSQL_DB: @@ -275,7 +277,7 @@ public void execute() { datastore, e.getMessage())); return; } - errStream.println("Persist client and entity types generated successfully in the " + module + " directory."); + errStream.println("Persist client and entity types generated successfully in the " + module + " directory."); if (testDatastore != null) { try { @@ -323,8 +325,8 @@ public void printLongDesc(StringBuilder out) { @Override public void printUsage(StringBuilder stringBuilder) { - stringBuilder.append(" ballerina " + PersistToolsConstants.COMPONENT_IDENTIFIER + " generate"). - append(System.lineSeparator()); + stringBuilder.append(" ballerina " + PersistToolsConstants.COMPONENT_IDENTIFIER + " generate") + .append(System.lineSeparator()); } public static boolean hasPersistConfig(Path configPath) throws BalException { diff --git a/persist-cli/src/main/java/io/ballerina/persist/cmd/PersistCodeGeneratorTool.java b/persist-cli/src/main/java/io/ballerina/persist/cmd/PersistCodeGeneratorTool.java index 414185f0d..9671d31db 100644 --- a/persist-cli/src/main/java/io/ballerina/persist/cmd/PersistCodeGeneratorTool.java +++ b/persist-cli/src/main/java/io/ballerina/persist/cmd/PersistCodeGeneratorTool.java @@ -75,6 +75,7 @@ public void execute(ToolContext toolContext) { Path projectPath = toolContext.currentPackage().project().sourceRoot(); Path generatedSourceDirPath = Paths.get(projectPath.toString(), BalSyntaxConstants.GENERATED_SOURCE_DIRECTORY); boolean eagerLoading = false; + boolean initParams = false; try { BalProjectUtils.validateBallerinaProject(projectPath); packageName = TomlSyntaxUtils.readPackageName(projectPath.toString()); @@ -84,10 +85,12 @@ public void execute(ToolContext toolContext) { path); targetModule = ballerinaTomlConfig.get(TARGET_MODULE).trim(); datastore = ballerinaTomlConfig.get(OPTION_DATASTORE).trim(); - testDatastore = ballerinaTomlConfig.get(OPTION_TEST_DATASTORE) == null ? null : - ballerinaTomlConfig.get(OPTION_TEST_DATASTORE).trim(); + testDatastore = ballerinaTomlConfig.get(OPTION_TEST_DATASTORE) == null ? null + : ballerinaTomlConfig.get(OPTION_TEST_DATASTORE).trim(); eagerLoading = ballerinaTomlConfig.get(PersistToolsConstants.OPTION_EAGER_LOADING) != null && Boolean.parseBoolean(ballerinaTomlConfig.get(PersistToolsConstants.OPTION_EAGER_LOADING).trim()); + initParams = ballerinaTomlConfig.get(PersistToolsConstants.OPTION_INIT_PARAMS) != null && + Boolean.parseBoolean(ballerinaTomlConfig.get(PersistToolsConstants.OPTION_INIT_PARAMS).trim()); validateDatastore(datastore); validateTestDatastore(datastore, testDatastore); @@ -117,7 +120,7 @@ public void execute(ToolContext toolContext) { FileUtils.writeToTargetFile(syntaxTree, path.toAbsolutePath().toString()); createGeneratedSourceDirIfNotExists(generatedSourceDirPath); generateSources(datastore, entityModule, targetModule, projectPath, generatedSourceDirPath, - eagerLoading); + eagerLoading, initParams); generateTestSources(testDatastore, entityModule, targetModule, projectPath, generatedSourceDirPath); String modelHashVal = getHashValue(schemaFilePath); Path cachePath = toolContext.cachePath(); @@ -213,20 +216,21 @@ private void printExperimentalFeatureInfo(String datastore) { private void validateEntityModule(Module entityModule, Path schemaFilePath) throws BalException { if (entityModule.getEntityMap().isEmpty()) { throw new BalException(String.format("the model definition file(%s) does not contain any " + - "entity definition.", schemaFilePath.getFileName())); + "entity definition.", schemaFilePath.getFileName())); } } private void createGeneratedSourceDirIfNotExists(Path generatedSourceDirPath) throws IOException { if (!Files.exists(generatedSourceDirPath)) { - Files.createDirectories(generatedSourceDirPath.toAbsolutePath()); + Files.createDirectories(generatedSourceDirPath.toAbsolutePath()); } } private void generateSources(String datastore, Module entityModule, String targetModule, Path projectPath, - Path generatedSourceDirPath, boolean eagerLoading) throws BalException { + Path generatedSourceDirPath, boolean eagerLoading, boolean initParams) + throws BalException { SourceGenerator sourceCreator = new SourceGenerator(projectPath.toString(), generatedSourceDirPath, - targetModule, entityModule, eagerLoading); + targetModule, entityModule, eagerLoading, initParams); switch (datastore) { case PersistToolsConstants.SupportedDataSources.MYSQL_DB: case PersistToolsConstants.SupportedDataSources.MSSQL_DB: @@ -247,7 +251,7 @@ private void generateSources(String datastore, Module entityModule, String targe } private void generateTestSources(String testDatastore, Module entityModule, String targetModule, - Path projectPath, Path generatedSourceDirPath) { + Path projectPath, Path generatedSourceDirPath) { if (testDatastore != null) { try { SourceGenerator sourceCreator = new SourceGenerator(projectPath.toString(), generatedSourceDirPath, @@ -260,7 +264,7 @@ private void generateTestSources(String testDatastore, Module entityModule, Stri } private static void createDiagnostics(ToolContext toolContext, PersistToolsConstants.DiagnosticMessages error, - Location location, String... args) { + Location location, String... args) { String message = String.format(error.getDescription(), (Object[]) args); DiagnosticInfo diagnosticInfo = new DiagnosticInfo(error.getCode(), message, error.getSeverity()); diff --git a/persist-cli/src/main/resources/persist-options-schema.json b/persist-cli/src/main/resources/persist-options-schema.json index 61d59848e..b738e280a 100644 --- a/persist-cli/src/main/resources/persist-options-schema.json +++ b/persist-cli/src/main/resources/persist-options-schema.json @@ -10,7 +10,10 @@ }, "eagerLoading": { "type": "boolean" + }, + "initParams": { + "type": "boolean" } }, "additionalProperties": false -} +} \ No newline at end of file diff --git a/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java b/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java index 8f7097592..6b4afa736 100644 --- a/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java +++ b/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java @@ -60,6 +60,7 @@ private PersistToolsConstants() {} public static final String OPTION_DATASTORE = "options.datastore"; public static final String OPTION_TEST_DATASTORE = "options.testDatastore"; public static final String OPTION_EAGER_LOADING = "options.eagerLoading"; + public static final String OPTION_INIT_PARAMS = "options.initParams"; public static final String MIGRATIONS = "migrations"; public static final String BALLERINA_MYSQL_DRIVER_NAME = "ballerinax/mysql.driver"; public static final String BALLERINA_MSSQL_DRIVER_NAME = "ballerinax/mssql.driver"; diff --git a/persist-core/src/main/java/io/ballerina/persist/components/Function.java b/persist-core/src/main/java/io/ballerina/persist/components/Function.java index 58cb9bfb6..db7a3843c 100644 --- a/persist-core/src/main/java/io/ballerina/persist/components/Function.java +++ b/persist-core/src/main/java/io/ballerina/persist/components/Function.java @@ -136,6 +136,21 @@ public void addDefaultableParameter(Node typeName, String name, Node defaultValu ); } + public void addIncludedParameter(Node typeName, String name) { + if (parameters.size() > 0) { + parameters.add(SyntaxTokenConstants.SYNTAX_TREE_COMMA); + } + NodeList annotations = NodeFactory.createEmptyNodeList(); + parameters.add( + NodeFactory.createIncludedRecordParameterNode( + annotations, + SyntaxTokenConstants.SYNTAX_TREE_ASTERISK, + typeName, + AbstractNodeFactory.createIdentifierToken(name) + ) + ); + } + public void addReturns(TypeDescriptorNode node) { returnTypeDescriptorNode = getReturnTypeDescriptorNode(node); } diff --git a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/SourceGenerator.java b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/SourceGenerator.java index cfd8999e3..534d34d17 100644 --- a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/SourceGenerator.java +++ b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/SourceGenerator.java @@ -67,19 +67,21 @@ public class SourceGenerator { private final Path generatedSourceDirPath; private final Module entityModule; private final boolean eagerLoading; + private final boolean initParams; public SourceGenerator(String sourcePath, Path generatedSourceDirPath, String moduleNameWithPackageName, - Module entityModule) { - this(sourcePath, generatedSourceDirPath, moduleNameWithPackageName, entityModule, false); + Module entityModule) { + this(sourcePath, generatedSourceDirPath, moduleNameWithPackageName, entityModule, false, false); } public SourceGenerator(String sourcePath, Path generatedSourceDirPath, String moduleNameWithPackageName, - Module entityModule, boolean eagerLoading) { + Module entityModule, boolean eagerLoading, boolean initParams) { this.sourcePath = sourcePath; this.moduleNameWithPackageName = moduleNameWithPackageName; this.entityModule = entityModule; this.generatedSourceDirPath = generatedSourceDirPath; this.eagerLoading = eagerLoading; + this.initParams = initParams; } public void createDbModel() throws BalException { @@ -101,14 +103,17 @@ private void addModelFile(SyntaxTree syntaxTree, Path path, String moduleName) t public void createDbSources(String datasource) throws BalException { DbSyntaxTree dbSyntaxTree = new DbSyntaxTree(); try { - addDataSourceConfigBalFile(this.generatedSourceDirPath, BalSyntaxConstants.PATH_DB_CONFIGURATION_BAL_FILE, - dbSyntaxTree.getDataStoreConfigSyntax(datasource)); - addConfigTomlFile(this.sourcePath, dbSyntaxTree.getConfigTomlSyntax( + if (!this.initParams) { + addDataSourceConfigBalFile(this.generatedSourceDirPath, + BalSyntaxConstants.PATH_DB_CONFIGURATION_BAL_FILE, + dbSyntaxTree.getDataStoreConfigSyntax(datasource)); + addConfigTomlFile(this.sourcePath, dbSyntaxTree.getConfigTomlSyntax( this.moduleNameWithPackageName, datasource), this.moduleNameWithPackageName); + } addDataTypesBalFile(dbSyntaxTree.getDataTypesSyntax(entityModule), this.generatedSourceDirPath.resolve(persistTypesBal).toAbsolutePath(), this.moduleNameWithPackageName); - addClientFile(dbSyntaxTree.getClientSyntax(entityModule, datasource, this.eagerLoading), + addClientFile(dbSyntaxTree.getClientSyntax(entityModule, datasource, this.eagerLoading, this.initParams), this.generatedSourceDirPath.resolve(persistClientBal).toAbsolutePath(), this.moduleNameWithPackageName); addSqlScriptFile(this.entityModule.getModuleName(), @@ -125,14 +130,15 @@ public void createTestDataSources(String testDatastore) throws BalException { addClientFile(dbSyntaxTree.getTestClientSyntax(entityModule), this.generatedSourceDirPath.resolve("persist_test_client.bal").toAbsolutePath(), this.moduleNameWithPackageName); - addTestInitFile(dbSyntaxTree.getTestInitSyntax(SqlScriptUtils. - generateSqlScript(this.entityModule.getEntityMap().values(), testDatastore)), + addTestInitFile( + dbSyntaxTree.getTestInitSyntax( + SqlScriptUtils.generateSqlScript(this.entityModule.getEntityMap().values(), testDatastore)), this.generatedSourceDirPath.resolve("persist_test_init.bal").toAbsolutePath()); } else { InMemorySyntaxTree inMemorySyntaxTree = new InMemorySyntaxTree(); addClientFile(inMemorySyntaxTree.getTestClientSyntax(entityModule), - this.generatedSourceDirPath.resolve("persist_test_client.bal").toAbsolutePath(), - this.moduleNameWithPackageName); + this.generatedSourceDirPath.resolve("persist_test_client.bal").toAbsolutePath(), + this.moduleNameWithPackageName); } } @@ -140,8 +146,11 @@ public void createTestDataSources(String testDatastore) throws BalException { public void createRedisSources() throws BalException { RedisSyntaxTree redisSyntaxTree = new RedisSyntaxTree(); try { - addDataSourceConfigBalFile(this.generatedSourceDirPath, BalSyntaxConstants.PATH_DB_CONFIGURATION_BAL_FILE, - redisSyntaxTree.getDataStoreConfigSyntax()); + if (!this.initParams) { + addDataSourceConfigBalFile(this.generatedSourceDirPath, + BalSyntaxConstants.PATH_DB_CONFIGURATION_BAL_FILE, + redisSyntaxTree.getDataStoreConfigSyntax()); + } addConfigTomlFile(this.sourcePath, redisSyntaxTree.getConfigTomlSyntax( this.moduleNameWithPackageName), this.moduleNameWithPackageName); addDataTypesBalFile(redisSyntaxTree.getDataTypesSyntax(this.entityModule), @@ -173,8 +182,11 @@ public void createInMemorySources() throws BalException { public void createGSheetSources() throws BalException { GSheetSyntaxTree gSheetSyntaxTree = new GSheetSyntaxTree(); try { - addDataSourceConfigBalFile(this.generatedSourceDirPath, - BalSyntaxConstants.PATH_SHEET_CONFIGURATION_BAL_FILE, gSheetSyntaxTree.getDataStoreConfigSyntax()); + if (!this.initParams) { + addDataSourceConfigBalFile(this.generatedSourceDirPath, + BalSyntaxConstants.PATH_SHEET_CONFIGURATION_BAL_FILE, + gSheetSyntaxTree.getDataStoreConfigSyntax()); + } addConfigTomlFile(this.sourcePath, gSheetSyntaxTree.getConfigTomlSyntax(this.moduleNameWithPackageName), this.moduleNameWithPackageName); addDataTypesBalFile(gSheetSyntaxTree.getDataTypesSyntax(entityModule), diff --git a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java index fa7ad5684..0bfba0792 100644 --- a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java +++ b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java @@ -66,18 +66,26 @@ public class DbClientSyntax implements ClientSyntax { private final String initDbClientMethodTemplate; private final String dataSource; private final boolean eagerLoading; + private final boolean initParams; public DbClientSyntax(Module entityModule, String datasource) throws BalException { - this(entityModule, datasource, false); + this(entityModule, datasource, false, false); } public DbClientSyntax(Module entityModule, String datasource, boolean eagerLoading) throws BalException { + this(entityModule, datasource, eagerLoading, false); + } + + public DbClientSyntax(Module entityModule, String datasource, boolean eagerLoading, boolean initParams) + throws BalException { this.entityModule = entityModule; this.dataSource = datasource; - this.dbNamePrefix = SUPPORTED_VIA_JDBC_CONNECTOR.contains(datasource) ? - PersistToolsConstants.SupportedDataSources.JDBC : datasource; - this.importPackage = SUPPORTED_VIA_JDBC_CONNECTOR.contains(datasource) ? - JDBC_CONNECTOR_MODULE_NAME : datasource; + this.initParams = initParams; + this.dbNamePrefix = SUPPORTED_VIA_JDBC_CONNECTOR.contains(datasource) + ? PersistToolsConstants.SupportedDataSources.JDBC + : datasource; + this.importPackage = SUPPORTED_VIA_JDBC_CONNECTOR.contains(datasource) ? JDBC_CONNECTOR_MODULE_NAME + : datasource; switch (datasource) { case PersistToolsConstants.SupportedDataSources.MYSQL_DB -> { @@ -147,7 +155,65 @@ public FunctionDefinitionNode getInitFunction(Module entityModule) { init.addQualifiers(new String[] { BalSyntaxConstants.KEYWORD_PUBLIC, BalSyntaxConstants.KEYWORD_ISOLATED }); init.addReturns(TypeDescriptor.getOptionalTypeDescriptorNode(BalSyntaxConstants.EMPTY_STRING, BalSyntaxConstants.PERSIST_ERROR)); - init.addStatement(NodeParser.parseStatement(String.format(this.initDbClientMethodTemplate, this.dbNamePrefix))); + + if (initParams) { + // Add individual parameters based on datasource type + switch (dataSource) { + case PersistToolsConstants.SupportedDataSources.MYSQL_DB -> { + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "host"); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("int"), "port"); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "user"); + init.addRequiredParameter( + TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "password"); + init.addRequiredParameter( + TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "database"); + init.addDefaultableParameter( + TypeDescriptor.getQualifiedNameReferenceNode(this.dbNamePrefix, "Options"), + "connectionOptions", + NodeParser.parseExpression("{}")); + } + case PersistToolsConstants.SupportedDataSources.POSTGRESQL_DB, + PersistToolsConstants.SupportedDataSources.MSSQL_DB -> { + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "host"); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("int"), "port"); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "user"); + init.addRequiredParameter( + TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "password"); + init.addRequiredParameter( + TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "database"); + init.addDefaultableParameter( + TypeDescriptor.getQualifiedNameReferenceNode(this.dbNamePrefix, "Options"), + "connectionOptions", + NodeParser.parseExpression("{}")); + init.addDefaultableParameter( + TypeDescriptor.getOptionalTypeDescriptorNode("", "string"), + "defaultSchema", + NodeParser.parseExpression("()")); + } + case PersistToolsConstants.SupportedDataSources.H2_DB -> { + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "url"); + init.addDefaultableParameter( + TypeDescriptor.getOptionalTypeDescriptorNode("", "string"), + "user", + NodeParser.parseExpression("()")); + init.addDefaultableParameter( + TypeDescriptor.getOptionalTypeDescriptorNode("", "string"), + "password", + NodeParser.parseExpression("()")); + init.addDefaultableParameter( + TypeDescriptor.getQualifiedNameReferenceNode(this.dbNamePrefix, "Options"), + "connectionOptions", + NodeParser.parseExpression("{}")); + } + default -> throw new IllegalStateException("Unsupported datasource: " + dataSource); + } + init.addStatement(NodeParser.parseStatement(String.format(this.initDbClientMethodTemplate, + this.dbNamePrefix))); + } else { + // Original behavior with configurables + init.addStatement(NodeParser.parseStatement(String.format(this.initDbClientMethodTemplate, + this.dbNamePrefix))); + } IfElse errorCheck = new IfElse(NodeParser.parseExpression(String.format( BalSyntaxConstants.RESULT_IS_BALLERINA_ERROR, BalSyntaxConstants.DB_CLIENT))); errorCheck.addIfStatement(NodeParser.parseStatement(String.format(BalSyntaxConstants.RETURN_ERROR, @@ -196,8 +262,8 @@ public FunctionDefinitionNode getInitFunction(Module entityModule) { if (persistClientMap.length() != 0) { persistClientMap.append(BalSyntaxConstants.COMMA_WITH_NEWLINE); } - String constantName = BalSyntaxUtils.stripEscapeCharacter(BalSyntaxUtils. - getStringWithUnderScore(entity.getEntityName())); + String constantName = BalSyntaxUtils + .stripEscapeCharacter(BalSyntaxUtils.getStringWithUnderScore(entity.getEntityName())); if (CUSTOM_SCHEMA_SUPPORTED_DB_PROVIDERS.contains(dataSource)) { persistClientMap.append(String.format(BalSyntaxConstants.PERSIST_CLIENT_MAP_ELEMENT_WITH_SCHEMA, constantName, constantName, this.dbSpecifics)); @@ -213,9 +279,8 @@ public FunctionDefinitionNode getInitFunction(Module entityModule) { @Override public FunctionDefinitionNode getGetFunction(Entity entity) { - String template = this.eagerLoading ? - BalSyntaxConstants.EXTERNAL_SQL_GET_METHOD_LIST_TEMPLATE : - BalSyntaxConstants.EXTERNAL_SQL_GET_METHOD_TEMPLATE; + String template = this.eagerLoading ? BalSyntaxConstants.EXTERNAL_SQL_GET_METHOD_LIST_TEMPLATE + : BalSyntaxConstants.EXTERNAL_SQL_GET_METHOD_TEMPLATE; FunctionDefinitionNode functionNode = (FunctionDefinitionNode) NodeParser.parseObjectMember( String.format(template, entity.getClientResourceName(), @@ -389,44 +454,44 @@ private Node generateMetadataRecord(Module entityModule) { if (Objects.equals(associatedEntityField.getFieldName(), associatedEntityField.getFieldColumnName())) { associateFieldMetaData.append(String.format((field.isArrayType() ? "\"%s[]" : "\"%s") + - BalSyntaxConstants.ASSOCIATED_FIELD_TEMPLATE, + BalSyntaxConstants.ASSOCIATED_FIELD_TEMPLATE, BalSyntaxUtils.stripEscapeCharacter(field.getFieldName()), BalSyntaxUtils.stripEscapeCharacter(associatedEntityField.getFieldName()), BalSyntaxUtils.stripEscapeCharacter(field.getFieldName()), BalSyntaxUtils.stripEscapeCharacter(associatedEntityField.getFieldName()))); } else { associateFieldMetaData.append(String.format((field.isArrayType() ? "\"%s[]" : "\"%s") + - BalSyntaxConstants.ASSOCIATED_FIELD_TEMPLATE_MAPPED, + BalSyntaxConstants.ASSOCIATED_FIELD_TEMPLATE_MAPPED, BalSyntaxUtils.stripEscapeCharacter(field.getFieldName()), BalSyntaxUtils.stripEscapeCharacter(associatedEntityField.getFieldName()), BalSyntaxUtils.stripEscapeCharacter(field.getFieldName()), BalSyntaxUtils.stripEscapeCharacter(associatedEntityField.getFieldName()), - BalSyntaxUtils.stripEscapeCharacter(associatedEntityField.getFieldColumnName()) - )); + BalSyntaxUtils + .stripEscapeCharacter(associatedEntityField.getFieldColumnName()))); } } else { if (associatedEntityField.getRelation().isOwner()) { - for (Relation.Key key : associatedEntityField.getRelation().getKeyColumns()) { - if (associateFieldMetaData.length() != 0) { - associateFieldMetaData.append(BalSyntaxConstants.COMMA_WITH_NEWLINE); - } - if (Objects.equals(key.getField(), key.getColumnName())) { - associateFieldMetaData.append(String.format((field.isArrayType() ? - "\"%s[]" : "\"%s") + - BalSyntaxConstants.ASSOCIATED_FIELD_TEMPLATE, - field.getFieldName(), key.getField(), - BalSyntaxUtils.stripEscapeCharacter(field.getFieldName()), - BalSyntaxUtils.stripEscapeCharacter(key.getField()))); - } else { - associateFieldMetaData.append(String.format((field.isArrayType() ? - "\"%s[]" : "\"%s") + - BalSyntaxConstants.ASSOCIATED_FIELD_TEMPLATE_MAPPED, - field.getFieldName(), key.getField(), - BalSyntaxUtils.stripEscapeCharacter(field.getFieldName()), - BalSyntaxUtils.stripEscapeCharacter(key.getField()), - BalSyntaxUtils.stripEscapeCharacter(key.getColumnName()))); - } + for (Relation.Key key : associatedEntityField.getRelation().getKeyColumns()) { + if (associateFieldMetaData.length() != 0) { + associateFieldMetaData.append(BalSyntaxConstants.COMMA_WITH_NEWLINE); + } + if (Objects.equals(key.getField(), key.getColumnName())) { + associateFieldMetaData.append(String.format( + (field.isArrayType() ? "\"%s[]" : "\"%s") + + BalSyntaxConstants.ASSOCIATED_FIELD_TEMPLATE, + field.getFieldName(), key.getField(), + BalSyntaxUtils.stripEscapeCharacter(field.getFieldName()), + BalSyntaxUtils.stripEscapeCharacter(key.getField()))); + } else { + associateFieldMetaData.append(String.format( + (field.isArrayType() ? "\"%s[]" : "\"%s") + + BalSyntaxConstants.ASSOCIATED_FIELD_TEMPLATE_MAPPED, + field.getFieldName(), key.getField(), + BalSyntaxUtils.stripEscapeCharacter(field.getFieldName()), + BalSyntaxUtils.stripEscapeCharacter(key.getField()), + BalSyntaxUtils.stripEscapeCharacter(key.getColumnName()))); } + } } } } @@ -467,8 +532,9 @@ private Node generateMetadataRecord(Module entityModule) { } mapBuilder.append(String.format(BalSyntaxConstants.METADATA_RECORD_ELEMENT_TEMPLATE, - BalSyntaxUtils.stripEscapeCharacter((BalSyntaxUtils. - getStringWithUnderScore(entity.getEntityName()))), entityMetaData)); + BalSyntaxUtils.stripEscapeCharacter( + (BalSyntaxUtils.getStringWithUnderScore(entity.getEntityName()))), + entityMetaData)); } Node node; @@ -535,7 +601,7 @@ private String getJoinMetaData(Entity entity) { } private static void addFunctionBodyToPostResource(Function create, List primaryKeys, - String tableName, String parameterType) { + String tableName, String parameterType) { create.addStatement(NodeParser.parseStatement(BalSyntaxConstants.SQL_CLIENT_DECLARATION)); String getPersistClientStatement = String.format(BalSyntaxConstants.GET_PERSIST_CLIENT, @@ -545,8 +611,7 @@ private static void addFunctionBodyToPostResource(Function create, List imports = dbClientSyntax.getImports(); NodeList moduleMembers = dbClientSyntax.getConstantVariables(); From a5cfcb2f10ad410315f279c388da81cb2021774d Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Wed, 3 Dec 2025 15:03:41 +0530 Subject: [PATCH 3/9] Rename init parameters option to --with-init-params for consistency --- persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java | 4 ++-- .../src/main/java/io/ballerina/persist/cmd/Generate.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java b/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java index d80618d30..7841e1fd9 100644 --- a/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java +++ b/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java @@ -86,8 +86,8 @@ public class Add implements BLauncherCmd { "arrays instead of streams for get-all methods") private boolean eagerLoading; - @CommandLine.Option(names = { "--init-params" }, hidden = true, description = "Use init parameters instead of " + - "configurables") + @CommandLine.Option(names = { "--with-init-params" }, hidden = true, description = "Use init parameters instead" + + " of configurables") private boolean initParams; public Add() { diff --git a/persist-cli/src/main/java/io/ballerina/persist/cmd/Generate.java b/persist-cli/src/main/java/io/ballerina/persist/cmd/Generate.java index 763731354..390600eba 100644 --- a/persist-cli/src/main/java/io/ballerina/persist/cmd/Generate.java +++ b/persist-cli/src/main/java/io/ballerina/persist/cmd/Generate.java @@ -93,8 +93,8 @@ public Generate(String sourcePath) { "arrays instead of streams for get-all methods") private boolean eagerLoading; - @CommandLine.Option(names = { "--init-params" }, hidden = true, description = "Use init parameters instead of " + - "configurables") + @CommandLine.Option(names = { "--with-init-params" }, hidden = true, description = "Use init parameters instead" + + " of configurables") private boolean initParams; @Override From 17966149bdaa8e15c1f0a7e633cccc22bff35a9d Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 5 Dec 2025 10:16:38 +0530 Subject: [PATCH 4/9] Add test cases --- .../persist/tools/ToolingAddTest.java | 50 ++ .../persist/tools/ToolingGenerateTest.java | 74 +++ .../Ballerina.toml | 5 + .../persist/model.bal | 7 + .../Ballerina.toml | 5 + .../persist/model.bal | 7 + .../Ballerina.toml | 5 + .../persist/model.bal | 7 + .../Ballerina.toml | 5 + .../persist/model.bal | 7 + .../Ballerina.toml | 5 + .../persist/model.bal | 7 + .../Ballerina.toml | 5 + .../persist/model.bal | 7 + .../Ballerina.toml | 5 + .../persist/model.bal | 7 + .../Ballerina.toml | 5 + .../persist/model.bal | 7 + .../Ballerina.toml | 5 + .../persist/model.bal | 32 ++ .../Ballerina.toml | 5 + .../persist/model.bal | 35 ++ .../Ballerina.toml | 5 + .../Config.toml | 7 + .../persist/model.bal | 7 + .../Ballerina.toml | 5 + .../persist/model.bal | 8 + .../Ballerina.toml | 14 + .../persist/model.bal | 7 + .../Ballerina.toml | 14 + .../persist/model.bal | 7 + .../Ballerina.toml | 14 + .../persist/model.bal | 7 + .../Ballerina.toml | 14 + .../persist/model.bal | 7 + .../Ballerina.toml | 11 + .../modules/entities/persist_client.bal | 138 ++++++ .../modules/entities/persist_types.bal | 26 ++ .../modules/entities/script.sql | 15 + .../persist/model.bal | 7 + .../target/Persist.toml | 3 + .../Ballerina.toml | 11 + .../modules/entities/persist_client.bal | 157 +++++++ .../modules/entities/persist_types.bal | 26 ++ .../modules/entities/script.sql | 15 + .../persist/model.bal | 7 + .../target/Persist.toml | 3 + .../Ballerina.toml | 11 + .../modules/entities/persist_client.bal | 157 +++++++ .../modules/entities/persist_types.bal | 26 ++ .../modules/entities/script.sql | 15 + .../persist/model.bal | 7 + .../target/Persist.toml | 3 + .../Ballerina.toml | 11 + .../modules/entities/persist_client.bal | 138 ++++++ .../modules/entities/persist_types.bal | 26 ++ .../modules/entities/script.sql | 15 + .../persist/model.bal | 7 + .../target/Persist.toml | 3 + .../Ballerina.toml | 11 + .../modules/entities/persist_client.bal | 410 +++++++++++++++++ .../modules/entities/persist_types.bal | 126 +++++ .../modules/entities/script.sql | 46 ++ .../persist/model.bal | 32 ++ .../target/Persist.toml | 3 + .../Ballerina.toml | 11 + .../modules/entities/persist_client.bal | 435 ++++++++++++++++++ .../modules/entities/persist_types.bal | 134 ++++++ .../modules/entities/script.sql | 48 ++ .../persist/model.bal | 35 ++ .../target/Persist.toml | 3 + .../Ballerina.toml | 11 + .../Config.toml | 7 + .../modules/entities/persist_client.bal | 138 ++++++ .../modules/entities/persist_types.bal | 26 ++ .../modules/entities/script.sql | 15 + .../persist/model.bal | 7 + .../target/Persist.toml | 3 + .../Ballerina.toml | 11 + .../persist/model.bal | 8 + .../target/Persist.toml | 3 + 81 files changed, 2774 insertions(+) create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_add_22_init_params_mysql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_add_22_init_params_mysql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_add_23_init_params_postgresql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_add_23_init_params_postgresql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_add_24_init_params_mssql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_add_24_init_params_mssql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_add_25_init_params_h2/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_add_25_init_params_h2/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_118_init_params_mysql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_118_init_params_mysql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_119_init_params_postgresql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_119_init_params_postgresql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_120_init_params_mssql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_120_init_params_mssql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_121_init_params_h2/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_121_init_params_h2/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_122_init_params_relationships/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_122_init_params_relationships/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_123_init_params_multiple_entities/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_123_init_params_multiple_entities/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/Config.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_125_init_params_negative_invalid_model/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_125_init_params_negative_invalid_model/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_client.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_types.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/script.sql create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/target/Persist.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_client.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_types.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/script.sql create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/target/Persist.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_client.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_types.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/script.sql create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/target/Persist.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_client.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_types.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/script.sql create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/target/Persist.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_client.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_types.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/script.sql create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/target/Persist.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_client.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_types.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/script.sql create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/target/Persist.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/Config.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_client.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_types.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/script.sql create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/target/Persist.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/Ballerina.toml create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/persist/model.bal create mode 100644 persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/target/Persist.toml diff --git a/persist-cli-tests/src/test/java/io/ballerina/persist/tools/ToolingAddTest.java b/persist-cli-tests/src/test/java/io/ballerina/persist/tools/ToolingAddTest.java index 15c7e6bd6..e4ce376a1 100644 --- a/persist-cli-tests/src/test/java/io/ballerina/persist/tools/ToolingAddTest.java +++ b/persist-cli-tests/src/test/java/io/ballerina/persist/tools/ToolingAddTest.java @@ -259,6 +259,56 @@ public void testAddWithEagerLoadingUnsupportedDatastore() throws ClassNotFoundEx assertGeneratedSources("tool_test_add_21"); } + @Test + @Description("Test add command with --with-init-params flag for MySQL datastore") + public void testAddWithInitParamsMySQL() throws ClassNotFoundException, NoSuchMethodException, + InvocationTargetException, InstantiationException, IllegalAccessException { + Class persistClass = Class.forName("io.ballerina.persist.cmd.Add"); + Add persistCmd = (Add) persistClass.getDeclaredConstructor(String.class).newInstance(Paths + .get(GENERATED_SOURCES_DIRECTORY, "tool_test_add_22_init_params_mysql").toAbsolutePath().toString()); + new CommandLine(persistCmd).parseArgs("--datastore", "mysql", "--module", "entities", "--with-init-params"); + persistCmd.execute(); + assertGeneratedSources("tool_test_add_22_init_params_mysql"); + } + + @Test + @Description("Test add command with --with-init-params flag for PostgreSQL datastore") + public void testAddWithInitParamsPostgreSQL() throws ClassNotFoundException, NoSuchMethodException, + InvocationTargetException, InstantiationException, IllegalAccessException { + Class persistClass = Class.forName("io.ballerina.persist.cmd.Add"); + Add persistCmd = (Add) persistClass.getDeclaredConstructor(String.class) + .newInstance(Paths.get(GENERATED_SOURCES_DIRECTORY, "tool_test_add_23_init_params_postgresql") + .toAbsolutePath().toString()); + new CommandLine(persistCmd).parseArgs("--datastore", "postgresql", "--module", "entities", + "--with-init-params"); + persistCmd.execute(); + assertGeneratedSources("tool_test_add_23_init_params_postgresql"); + } + + @Test + @Description("Test add command with --with-init-params flag for MSSQL datastore") + public void testAddWithInitParamsMSSQL() throws ClassNotFoundException, NoSuchMethodException, + InvocationTargetException, InstantiationException, IllegalAccessException { + Class persistClass = Class.forName("io.ballerina.persist.cmd.Add"); + Add persistCmd = (Add) persistClass.getDeclaredConstructor(String.class).newInstance(Paths + .get(GENERATED_SOURCES_DIRECTORY, "tool_test_add_24_init_params_mssql").toAbsolutePath().toString()); + new CommandLine(persistCmd).parseArgs("--datastore", "mssql", "--module", "entities", "--with-init-params"); + persistCmd.execute(); + assertGeneratedSources("tool_test_add_24_init_params_mssql"); + } + + @Test + @Description("Test add command with --with-init-params flag for H2 datastore") + public void testAddWithInitParamsH2() throws ClassNotFoundException, NoSuchMethodException, + InvocationTargetException, InstantiationException, IllegalAccessException { + Class persistClass = Class.forName("io.ballerina.persist.cmd.Add"); + Add persistCmd = (Add) persistClass.getDeclaredConstructor(String.class).newInstance( + Paths.get(GENERATED_SOURCES_DIRECTORY, "tool_test_add_25_init_params_h2").toAbsolutePath().toString()); + new CommandLine(persistCmd).parseArgs("--datastore", "h2", "--module", "entities", "--with-init-params"); + persistCmd.execute(); + assertGeneratedSources("tool_test_add_25_init_params_h2"); + } + private void executeCommand(String subDir) { Class persistClass; Path sourcePath = Paths.get(GENERATED_SOURCES_DIRECTORY, subDir); diff --git a/persist-cli-tests/src/test/java/io/ballerina/persist/tools/ToolingGenerateTest.java b/persist-cli-tests/src/test/java/io/ballerina/persist/tools/ToolingGenerateTest.java index ffd393061..6d7b43b61 100644 --- a/persist-cli-tests/src/test/java/io/ballerina/persist/tools/ToolingGenerateTest.java +++ b/persist-cli-tests/src/test/java/io/ballerina/persist/tools/ToolingGenerateTest.java @@ -1133,6 +1133,80 @@ public void testGenerateWithEagerLoadingMSSQL() { assertGeneratedSources("tool_test_generate_117"); } + @Test(enabled = true) + @Description("Test generate command with --with-init-params flag for MySQL datastore") + public void testGenerateWithInitParamsMySQL() { + updateOutputBallerinaToml("tool_test_generate_118_init_params_mysql"); + executeGenerateCommand("tool_test_generate_118_init_params_mysql", + "--datastore", "mysql", "--module", "entities", "--with-init-params"); + assertGeneratedSources("tool_test_generate_118_init_params_mysql"); + } + + @Test(enabled = true) + @Description("Test generate command with --with-init-params flag for PostgreSQL datastore") + public void testGenerateWithInitParamsPostgreSQL() { + updateOutputBallerinaToml("tool_test_generate_119_init_params_postgresql"); + executeGenerateCommand("tool_test_generate_119_init_params_postgresql", + "--datastore", "postgresql", "--module", "entities", "--with-init-params"); + assertGeneratedSources("tool_test_generate_119_init_params_postgresql"); + } + + @Test(enabled = true) + @Description("Test generate command with --with-init-params flag for MSSQL datastore") + public void testGenerateWithInitParamsMSSQL() { + updateOutputBallerinaToml("tool_test_generate_120_init_params_mssql"); + executeGenerateCommand("tool_test_generate_120_init_params_mssql", + "--datastore", "mssql", "--module", "entities", "--with-init-params"); + assertGeneratedSources("tool_test_generate_120_init_params_mssql"); + } + + @Test(enabled = true) + @Description("Test generate command with --with-init-params flag for H2 datastore") + public void testGenerateWithInitParamsH2() { + updateOutputBallerinaToml("tool_test_generate_121_init_params_h2"); + executeGenerateCommand("tool_test_generate_121_init_params_h2", + "--datastore", "h2", "--module", "entities", "--with-init-params"); + assertGeneratedSources("tool_test_generate_121_init_params_h2"); + } + + @Test(enabled = true) + @Description("Test generate command with --with-init-params flag for MySQL with relationships") + public void testGenerateWithInitParamsRelationships() { + updateOutputBallerinaToml("tool_test_generate_122_init_params_relationships"); + executeGenerateCommand("tool_test_generate_122_init_params_relationships", + "--datastore", "mysql", "--module", "entities", "--with-init-params"); + assertGeneratedSources("tool_test_generate_122_init_params_relationships"); + } + + @Test(enabled = true) + @Description("Test generate command with --with-init-params flag for PostgreSQL with multiple entities") + public void testGenerateWithInitParamsMultipleEntities() { + updateOutputBallerinaToml("tool_test_generate_123_init_params_multiple_entities"); + executeGenerateCommand("tool_test_generate_123_init_params_multiple_entities", + "--datastore", "postgresql", "--module", "entities", "--with-init-params"); + assertGeneratedSources("tool_test_generate_123_init_params_multiple_entities"); + } + + @Test(enabled = true) + @Description("Test generate command with --with-init-params flag when Config.toml exists " + + "(should ignore Config.toml)") + public void testGenerateWithInitParamsWithConfig() { + updateOutputBallerinaToml("tool_test_generate_124_init_params_with_config"); + executeGenerateCommand("tool_test_generate_124_init_params_with_config", + "--datastore", "mysql", "--module", "entities", "--with-init-params"); + assertGeneratedSources("tool_test_generate_124_init_params_with_config"); + } + + @Test(enabled = true) + @Description("Test generate command with --with-init-params flag with invalid model (missing readonly on key)") + public void testGenerateWithInitParamsInvalidModel() { + updateOutputBallerinaToml("tool_test_generate_125_init_params_negative_invalid_model"); + assertGeneratedSourcesNegative("tool_test_generate_125_init_params_negative_invalid_model", GENERATE, + new String[]{"modules/entities/persist_client.bal", "modules/entities/persist_types.bal", + "modules/entities/script.sql"}, + "--datastore", "mysql", "--module", "entities", "--with-init-params"); + } + private void updateOutputBallerinaToml(String fileName) { String tomlFileName = "Ballerina.toml"; Path filePath = Paths.get("src", "test", "resources", "test-src", "output", fileName, tomlFileName); diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_22_init_params_mysql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_22_init_params_mysql/Ballerina.toml new file mode 100644 index 000000000..7be631285 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_22_init_params_mysql/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_add_init_params_mysql" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_22_init_params_mysql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_22_init_params_mysql/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_22_init_params_mysql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_23_init_params_postgresql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_23_init_params_postgresql/Ballerina.toml new file mode 100644 index 000000000..55991d498 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_23_init_params_postgresql/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_add_init_params_postgresql" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_23_init_params_postgresql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_23_init_params_postgresql/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_23_init_params_postgresql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_24_init_params_mssql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_24_init_params_mssql/Ballerina.toml new file mode 100644 index 000000000..56419a26d --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_24_init_params_mssql/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_add_init_params_mssql" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_24_init_params_mssql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_24_init_params_mssql/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_24_init_params_mssql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_25_init_params_h2/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_25_init_params_h2/Ballerina.toml new file mode 100644 index 000000000..b68c8894d --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_25_init_params_h2/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_add_init_params_h2" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_25_init_params_h2/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_25_init_params_h2/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_add_25_init_params_h2/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_118_init_params_mysql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_118_init_params_mysql/Ballerina.toml new file mode 100644 index 000000000..97a3394a8 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_118_init_params_mysql/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_init_params_mysql" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_118_init_params_mysql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_118_init_params_mysql/persist/model.bal new file mode 100644 index 000000000..939ce72fc --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_118_init_params_mysql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type User record {| + readonly int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_119_init_params_postgresql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_119_init_params_postgresql/Ballerina.toml new file mode 100644 index 000000000..a76b2c657 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_119_init_params_postgresql/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_init_params_postgresql" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_119_init_params_postgresql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_119_init_params_postgresql/persist/model.bal new file mode 100644 index 000000000..939ce72fc --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_119_init_params_postgresql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type User record {| + readonly int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_120_init_params_mssql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_120_init_params_mssql/Ballerina.toml new file mode 100644 index 000000000..01d88611a --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_120_init_params_mssql/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_init_params_mssql" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_120_init_params_mssql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_120_init_params_mssql/persist/model.bal new file mode 100644 index 000000000..939ce72fc --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_120_init_params_mssql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type User record {| + readonly int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_121_init_params_h2/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_121_init_params_h2/Ballerina.toml new file mode 100644 index 000000000..3ee513ad6 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_121_init_params_h2/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_init_params_h2" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_121_init_params_h2/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_121_init_params_h2/persist/model.bal new file mode 100644 index 000000000..939ce72fc --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_121_init_params_h2/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type User record {| + readonly int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_122_init_params_relationships/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_122_init_params_relationships/Ballerina.toml new file mode 100644 index 000000000..5e1aa99b8 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_122_init_params_relationships/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_relationships_init_params" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_122_init_params_relationships/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_122_init_params_relationships/persist/model.bal new file mode 100644 index 000000000..59479a8ed --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_122_init_params_relationships/persist/model.bal @@ -0,0 +1,32 @@ +import ballerina/persist as _; + +type Customer record {| + readonly int id; + string name; + string email; + Order[] orders; +|}; + +type Order record {| + readonly int id; + string orderNumber; + decimal totalAmount; + Customer customer; + OrderItem[] items; +|}; + +type OrderItem record {| + readonly int id; + int quantity; + decimal price; + Order 'order; + Product product; +|}; + +type Product record {| + readonly int id; + string name; + string description; + decimal price; + OrderItem[] orderItems; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_123_init_params_multiple_entities/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_123_init_params_multiple_entities/Ballerina.toml new file mode 100644 index 000000000..8b5f100f1 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_123_init_params_multiple_entities/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_multiple_entities" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_123_init_params_multiple_entities/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_123_init_params_multiple_entities/persist/model.bal new file mode 100644 index 000000000..7986be5ff --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_123_init_params_multiple_entities/persist/model.bal @@ -0,0 +1,35 @@ +import ballerina/persist as _; +import ballerina/time; + +type Employee record {| + readonly string empNo; + string firstName; + string lastName; + time:Date birthDate; + string gender; + time:Date hireDate; + Department department; + Workspace? workspace; +|}; + +type Workspace record {| + readonly string workspaceId; + string workspaceType; + Building location; + Employee employee; +|}; + +type Building record {| + readonly string buildingCode; + string city; + string state; + string country; + string postalCode; + Workspace[] workspaces; +|}; + +type Department record {| + readonly string deptNo; + string deptName; + Employee[] employees; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/Ballerina.toml new file mode 100644 index 000000000..13c7274b8 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_init_params_with_config" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/Config.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/Config.toml new file mode 100644 index 000000000..9714d6148 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/Config.toml @@ -0,0 +1,7 @@ +# This Config.toml should be ignored when --with-init-params is used +[test.persist_init_params_with_config] +host = "localhost" +port = 3306 +user = "root" +password = "root" +database = "testdb" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_124_init_params_with_config/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_125_init_params_negative_invalid_model/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_125_init_params_negative_invalid_model/Ballerina.toml new file mode 100644 index 000000000..f793202e6 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_125_init_params_negative_invalid_model/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "test" +name = "persist_init_params_negative_invalid" +version = "0.1.0" +distribution = "2201.13.0" diff --git a/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_125_init_params_negative_invalid_model/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_125_init_params_negative_invalid_model/persist/model.bal new file mode 100644 index 000000000..59b076f97 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/input/tool_test_generate_125_init_params_negative_invalid_model/persist/model.bal @@ -0,0 +1,8 @@ +import ballerina/persist as _; + +// Invalid model - missing readonly on key field +type User record {| + int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/Ballerina.toml new file mode 100644 index 000000000..6c7486dd7 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/Ballerina.toml @@ -0,0 +1,14 @@ +[package] +org = "test" +name = "persist_add_init_params_mysql" +version = "0.1.0" +distribution = "2201.13.0" + +[[tool.persist]] +id = "generate-db-client" +targetModule = "persist_add_init_params_mysql.entities" +options.datastore = "mysql" +options.initParams = true +filePath = "persist/model.bal" + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/Ballerina.toml new file mode 100644 index 000000000..25c7c5dc1 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/Ballerina.toml @@ -0,0 +1,14 @@ +[package] +org = "test" +name = "persist_add_init_params_postgresql" +version = "0.1.0" +distribution = "2201.13.0" + +[[tool.persist]] +id = "generate-db-client" +targetModule = "persist_add_init_params_postgresql.entities" +options.datastore = "postgresql" +options.initParams = true +filePath = "persist/model.bal" + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/Ballerina.toml new file mode 100644 index 000000000..e068f99e2 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/Ballerina.toml @@ -0,0 +1,14 @@ +[package] +org = "test" +name = "persist_add_init_params_mssql" +version = "0.1.0" +distribution = "2201.13.0" + +[[tool.persist]] +id = "generate-db-client" +targetModule = "persist_add_init_params_mssql.entities" +options.datastore = "mssql" +options.initParams = true +filePath = "persist/model.bal" + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/Ballerina.toml new file mode 100644 index 000000000..01eb34ec4 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/Ballerina.toml @@ -0,0 +1,14 @@ +[package] +org = "test" +name = "persist_add_init_params_h2" +version = "0.1.0" +distribution = "2201.13.0" + +[[tool.persist]] +id = "generate-db-client" +targetModule = "persist_add_init_params_h2.entities" +options.datastore = "h2" +options.initParams = true +filePath = "persist/model.bal" + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/Ballerina.toml new file mode 100644 index 000000000..26f553483 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "test" +name = "persist_init_params_mysql" +version = "0.1.0" +distribution = "2201.13.0" + +[[platform.java21.dependency]] +groupId = "io.ballerina.stdlib" +artifactId = "persist.sql-native" +version = "1.6.0" + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_client.bal new file mode 100644 index 000000000..c1397f3b5 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_client.bal @@ -0,0 +1,138 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +import ballerina/jballerina.java; +import ballerina/persist; +import ballerina/sql; +import ballerinax/mysql; +import ballerinax/mysql.driver as _; +import ballerinax/persist.sql as psql; + +const USER = "users"; + +# MySQL persist client. +public isolated client class Client { + *persist:AbstractPersistClient; + + private final mysql:Client dbClient; + + private final map persistClients; + + private final record {|psql:SQLMetadata...;|} & readonly metadata = { + [USER]: { + entityName: "User", + tableName: "User", + fieldMetadata: { + id: {columnName: "id"}, + name: {columnName: "name"}, + email: {columnName: "email"} + }, + keyFields: ["id"] + } + }; + + public isolated function init(string host, int port, string user, string password, string database, mysql:Options connectionOptions = {}) returns persist:Error? { + mysql:Client|error dbClient = new (host = host, user = user, password = password, database = database, port = port, options = connectionOptions); + if dbClient is error { + return error(dbClient.message()); + } + self.dbClient = dbClient; + self.persistClients = {[USER]: check new (dbClient, self.metadata.get(USER), psql:MYSQL_SPECIFICS)}; + } + + # Get rows from User table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get users(UserTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "query" + } external; + + # Get row from User table. + # + # + id - The value of the primary key field id + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get users/[int id](UserTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "queryOne" + } external; + + # Insert rows into User table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post users(UserInsert[] data) returns int[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from UserInsert inserted in data + select inserted.id; + } + + # Update row in User table. + # + # + id - The value of the primary key field id + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put users/[int id](UserUpdate value) returns User|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runUpdateQuery(id, value); + return self->/users/[id].get(); + } + + # Delete row from User table. + # + # + id - The value of the primary key field id + # + return - The deleted record or an error + isolated resource function delete users/[int id]() returns User|persist:Error { + User result = check self->/users/[id].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runDeleteQuery(id); + return result; + } + + # Execute a custom SQL query and return results. + # + # + sqlQuery - The SQL query to execute + # + rowType - Defines the structure of the result rows + # + return - A collection of result rows or an error + remote isolated function queryNativeSQL(sql:ParameterizedQuery sqlQuery, typedesc rowType = <>) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor" + } external; + + # Execute a custom SQL command (INSERT, UPDATE, DELETE, etc.). + # + # + sqlQuery - The SQL command to execute + # + return - The execution result or an error + remote isolated function executeNativeSQL(sql:ParameterizedQuery sqlQuery) returns psql:ExecutionResult|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor" + } external; + + # Close the database client and release connections. + # + # + return - An error if closing fails + public isolated function close() returns persist:Error? { + error? result = self.dbClient.close(); + if result is error { + return error(result.message()); + } + return result; + } +} + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_types.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_types.bal new file mode 100644 index 000000000..4056af713 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_types.bal @@ -0,0 +1,26 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +public type User record {| + readonly int id; + string name; + string email; +|}; + +public type UserOptionalized record {| + int id?; + string name?; + string email?; +|}; + +public type UserTargetType typedesc; + +public type UserInsert User; + +public type UserUpdate record {| + string name?; + string email?; +|}; + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/script.sql b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/script.sql new file mode 100644 index 000000000..8de0bbe52 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/script.sql @@ -0,0 +1,15 @@ +-- AUTO-GENERATED FILE. + +-- This file is an auto-generated file by Ballerina persistence layer for model. +-- Please verify the generated scripts and execute them against the target DB server. + +DROP TABLE IF EXISTS `User`; + +CREATE TABLE `User` ( + `id` INT NOT NULL, + `name` VARCHAR(191) NOT NULL, + `email` VARCHAR(191) NOT NULL, + PRIMARY KEY(`id`) +); + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/persist/model.bal new file mode 100644 index 000000000..939ce72fc --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type User record {| + readonly int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/target/Persist.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/target/Persist.toml new file mode 100644 index 000000000..aa256e31f --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/target/Persist.toml @@ -0,0 +1,3 @@ +[[tool.persist]] +options.datastore = "mysql" +module = "persist_init_params_mysql.entities" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/Ballerina.toml new file mode 100644 index 000000000..9df4f9b7c --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "test" +name = "persist_init_params_postgresql" +version = "0.1.0" +distribution = "2201.13.0" + +[[platform.java21.dependency]] +groupId = "io.ballerina.stdlib" +artifactId = "persist.sql-native" +version = "1.6.0" + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_client.bal new file mode 100644 index 000000000..cb8270523 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_client.bal @@ -0,0 +1,157 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +import ballerina/jballerina.java; +import ballerina/persist; +import ballerina/sql; +import ballerinax/persist.sql as psql; +import ballerinax/postgresql; +import ballerinax/postgresql.driver as _; + +const USER = "users"; + +# PostgreSQL persist client. +public isolated client class Client { + *persist:AbstractPersistClient; + + private final postgresql:Client dbClient; + + private final map persistClients; + + private final record {|psql:SQLMetadata...;|} metadata = { + [USER]: { + entityName: "User", + tableName: "User", + fieldMetadata: { + id: {columnName: "id"}, + name: {columnName: "name"}, + email: {columnName: "email"} + }, + keyFields: ["id"] + } + }; + + public isolated function init(string host, int port, string user, string password, string database, postgresql:Options connectionOptions = {}, string? defaultSchema = ()) returns persist:Error? { + postgresql:Client|error dbClient = new (host = host, username = user, password = password, database = database, port = port, options = connectionOptions); + if dbClient is error { + return error(dbClient.message()); + } + self.dbClient = dbClient; + if defaultSchema != () { + lock { + foreach string key in self.metadata.keys() { + psql:SQLMetadata metadata = self.metadata.get(key); + if metadata.schemaName == () { + metadata.schemaName = defaultSchema; + } + map? joinMetadataMap = metadata.joinMetadata; + if joinMetadataMap == () { + continue; + } + foreach [string, psql:JoinMetadata] [_, joinMetadata] in joinMetadataMap.entries() { + if joinMetadata.refSchema == () { + joinMetadata.refSchema = defaultSchema; + } + } + } + } + } + self.persistClients = {[USER]: check new (dbClient, self.metadata.get(USER).cloneReadOnly(), psql:POSTGRESQL_SPECIFICS)}; + } + + # Get rows from User table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get users(UserTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "query" + } external; + + # Get row from User table. + # + # + id - The value of the primary key field id + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get users/[int id](UserTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "queryOne" + } external; + + # Insert rows into User table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post users(UserInsert[] data) returns int[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from UserInsert inserted in data + select inserted.id; + } + + # Update row in User table. + # + # + id - The value of the primary key field id + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put users/[int id](UserUpdate value) returns User|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runUpdateQuery(id, value); + return self->/users/[id].get(); + } + + # Delete row from User table. + # + # + id - The value of the primary key field id + # + return - The deleted record or an error + isolated resource function delete users/[int id]() returns User|persist:Error { + User result = check self->/users/[id].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runDeleteQuery(id); + return result; + } + + # Execute a custom SQL query and return results. + # + # + sqlQuery - The SQL query to execute + # + rowType - Defines the structure of the result rows + # + return - A collection of result rows or an error + remote isolated function queryNativeSQL(sql:ParameterizedQuery sqlQuery, typedesc rowType = <>) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor" + } external; + + # Execute a custom SQL command (INSERT, UPDATE, DELETE, etc.). + # + # + sqlQuery - The SQL command to execute + # + return - The execution result or an error + remote isolated function executeNativeSQL(sql:ParameterizedQuery sqlQuery) returns psql:ExecutionResult|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor" + } external; + + # Close the database client and release connections. + # + # + return - An error if closing fails + public isolated function close() returns persist:Error? { + error? result = self.dbClient.close(); + if result is error { + return error(result.message()); + } + return result; + } +} + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_types.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_types.bal new file mode 100644 index 000000000..4056af713 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_types.bal @@ -0,0 +1,26 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +public type User record {| + readonly int id; + string name; + string email; +|}; + +public type UserOptionalized record {| + int id?; + string name?; + string email?; +|}; + +public type UserTargetType typedesc; + +public type UserInsert User; + +public type UserUpdate record {| + string name?; + string email?; +|}; + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/script.sql b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/script.sql new file mode 100644 index 000000000..e36cedbcb --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/script.sql @@ -0,0 +1,15 @@ +-- AUTO-GENERATED FILE. + +-- This file is an auto-generated file by Ballerina persistence layer for model. +-- Please verify the generated scripts and execute them against the target DB server. + +DROP TABLE IF EXISTS "User"; + +CREATE TABLE "User" ( + "id" INT NOT NULL, + "name" VARCHAR(191) NOT NULL, + "email" VARCHAR(191) NOT NULL, + PRIMARY KEY("id") +); + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/persist/model.bal new file mode 100644 index 000000000..939ce72fc --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type User record {| + readonly int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/target/Persist.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/target/Persist.toml new file mode 100644 index 000000000..9442cedf0 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/target/Persist.toml @@ -0,0 +1,3 @@ +[[tool.persist]] +options.datastore = "postgresql" +module = "persist_init_params_postgresql.entities" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/Ballerina.toml new file mode 100644 index 000000000..624cfe9c9 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "test" +name = "persist_init_params_mssql" +version = "0.1.0" +distribution = "2201.13.0" + +[[platform.java21.dependency]] +groupId = "io.ballerina.stdlib" +artifactId = "persist.sql-native" +version = "1.6.0" + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_client.bal new file mode 100644 index 000000000..a498b543c --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_client.bal @@ -0,0 +1,157 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +import ballerina/jballerina.java; +import ballerina/persist; +import ballerina/sql; +import ballerinax/mssql; +import ballerinax/mssql.driver as _; +import ballerinax/persist.sql as psql; + +const USER = "users"; + +# MSSQL persist client. +public isolated client class Client { + *persist:AbstractPersistClient; + + private final mssql:Client dbClient; + + private final map persistClients; + + private final record {|psql:SQLMetadata...;|} metadata = { + [USER]: { + entityName: "User", + tableName: "User", + fieldMetadata: { + id: {columnName: "id"}, + name: {columnName: "name"}, + email: {columnName: "email"} + }, + keyFields: ["id"] + } + }; + + public isolated function init(string host, int port, string user, string password, string database, mssql:Options connectionOptions = {}, string? defaultSchema = ()) returns persist:Error? { + mssql:Client|error dbClient = new (host = host, user = user, password = password, database = database, port = port, options = connectionOptions); + if dbClient is error { + return error(dbClient.message()); + } + self.dbClient = dbClient; + if defaultSchema != () { + lock { + foreach string key in self.metadata.keys() { + psql:SQLMetadata metadata = self.metadata.get(key); + if metadata.schemaName == () { + metadata.schemaName = defaultSchema; + } + map? joinMetadataMap = metadata.joinMetadata; + if joinMetadataMap == () { + continue; + } + foreach [string, psql:JoinMetadata] [_, joinMetadata] in joinMetadataMap.entries() { + if joinMetadata.refSchema == () { + joinMetadata.refSchema = defaultSchema; + } + } + } + } + } + self.persistClients = {[USER]: check new (dbClient, self.metadata.get(USER).cloneReadOnly(), psql:MSSQL_SPECIFICS)}; + } + + # Get rows from User table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get users(UserTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MSSQLProcessor", + name: "query" + } external; + + # Get row from User table. + # + # + id - The value of the primary key field id + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get users/[int id](UserTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MSSQLProcessor", + name: "queryOne" + } external; + + # Insert rows into User table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post users(UserInsert[] data) returns int[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from UserInsert inserted in data + select inserted.id; + } + + # Update row in User table. + # + # + id - The value of the primary key field id + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put users/[int id](UserUpdate value) returns User|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runUpdateQuery(id, value); + return self->/users/[id].get(); + } + + # Delete row from User table. + # + # + id - The value of the primary key field id + # + return - The deleted record or an error + isolated resource function delete users/[int id]() returns User|persist:Error { + User result = check self->/users/[id].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runDeleteQuery(id); + return result; + } + + # Execute a custom SQL query and return results. + # + # + sqlQuery - The SQL query to execute + # + rowType - Defines the structure of the result rows + # + return - A collection of result rows or an error + remote isolated function queryNativeSQL(sql:ParameterizedQuery sqlQuery, typedesc rowType = <>) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MSSQLProcessor" + } external; + + # Execute a custom SQL command (INSERT, UPDATE, DELETE, etc.). + # + # + sqlQuery - The SQL command to execute + # + return - The execution result or an error + remote isolated function executeNativeSQL(sql:ParameterizedQuery sqlQuery) returns psql:ExecutionResult|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MSSQLProcessor" + } external; + + # Close the database client and release connections. + # + # + return - An error if closing fails + public isolated function close() returns persist:Error? { + error? result = self.dbClient.close(); + if result is error { + return error(result.message()); + } + return result; + } +} + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_types.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_types.bal new file mode 100644 index 000000000..4056af713 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_types.bal @@ -0,0 +1,26 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +public type User record {| + readonly int id; + string name; + string email; +|}; + +public type UserOptionalized record {| + int id?; + string name?; + string email?; +|}; + +public type UserTargetType typedesc; + +public type UserInsert User; + +public type UserUpdate record {| + string name?; + string email?; +|}; + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/script.sql b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/script.sql new file mode 100644 index 000000000..5f3053264 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/script.sql @@ -0,0 +1,15 @@ +-- AUTO-GENERATED FILE. + +-- This file is an auto-generated file by Ballerina persistence layer for model. +-- Please verify the generated scripts and execute them against the target DB server. + +DROP TABLE IF EXISTS [User]; + +CREATE TABLE [User] ( + [id] INT NOT NULL, + [name] VARCHAR(191) NOT NULL, + [email] VARCHAR(191) NOT NULL, + PRIMARY KEY([id]) +); + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/persist/model.bal new file mode 100644 index 000000000..939ce72fc --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type User record {| + readonly int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/target/Persist.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/target/Persist.toml new file mode 100644 index 000000000..9b4551f73 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/target/Persist.toml @@ -0,0 +1,3 @@ +[[tool.persist]] +options.datastore = "mssql" +module = "persist_init_params_mssql.entities" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/Ballerina.toml new file mode 100644 index 000000000..a0ef144a5 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "test" +name = "persist_init_params_h2" +version = "0.1.0" +distribution = "2201.13.0" + +[[platform.java21.dependency]] +groupId = "io.ballerina.stdlib" +artifactId = "persist.sql-native" +version = "1.6.0" + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_client.bal new file mode 100644 index 000000000..9ae618d8d --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_client.bal @@ -0,0 +1,138 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +import ballerina/jballerina.java; +import ballerina/persist; +import ballerina/sql; +import ballerinax/h2.driver as _; +import ballerinax/java.jdbc; +import ballerinax/persist.sql as psql; + +const USER = "users"; + +# H2 persist client. +public isolated client class Client { + *persist:AbstractPersistClient; + + private final jdbc:Client dbClient; + + private final map persistClients; + + private final record {|psql:SQLMetadata...;|} & readonly metadata = { + [USER]: { + entityName: "User", + tableName: "User", + fieldMetadata: { + id: {columnName: "id"}, + name: {columnName: "name"}, + email: {columnName: "email"} + }, + keyFields: ["id"] + } + }; + + public isolated function init(string url, string? user = (), string? password = (), jdbc:Options connectionOptions = {}) returns persist:Error? { + jdbc:Client|error dbClient = new (url = url, user = user, password = password, options = connectionOptions); + if dbClient is error { + return error(dbClient.message()); + } + self.dbClient = dbClient; + self.persistClients = {[USER]: check new (dbClient, self.metadata.get(USER), psql:H2_SPECIFICS)}; + } + + # Get rows from User table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get users(UserTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.H2Processor", + name: "query" + } external; + + # Get row from User table. + # + # + id - The value of the primary key field id + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get users/[int id](UserTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.H2Processor", + name: "queryOne" + } external; + + # Insert rows into User table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post users(UserInsert[] data) returns int[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from UserInsert inserted in data + select inserted.id; + } + + # Update row in User table. + # + # + id - The value of the primary key field id + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put users/[int id](UserUpdate value) returns User|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runUpdateQuery(id, value); + return self->/users/[id].get(); + } + + # Delete row from User table. + # + # + id - The value of the primary key field id + # + return - The deleted record or an error + isolated resource function delete users/[int id]() returns User|persist:Error { + User result = check self->/users/[id].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(USER); + } + _ = check sqlClient.runDeleteQuery(id); + return result; + } + + # Execute a custom SQL query and return results. + # + # + sqlQuery - The SQL query to execute + # + rowType - Defines the structure of the result rows + # + return - A collection of result rows or an error + remote isolated function queryNativeSQL(sql:ParameterizedQuery sqlQuery, typedesc rowType = <>) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.H2Processor" + } external; + + # Execute a custom SQL command (INSERT, UPDATE, DELETE, etc.). + # + # + sqlQuery - The SQL command to execute + # + return - The execution result or an error + remote isolated function executeNativeSQL(sql:ParameterizedQuery sqlQuery) returns psql:ExecutionResult|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.H2Processor" + } external; + + # Close the database client and release connections. + # + # + return - An error if closing fails + public isolated function close() returns persist:Error? { + error? result = self.dbClient.close(); + if result is error { + return error(result.message()); + } + return result; + } +} + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_types.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_types.bal new file mode 100644 index 000000000..4056af713 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_types.bal @@ -0,0 +1,26 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +public type User record {| + readonly int id; + string name; + string email; +|}; + +public type UserOptionalized record {| + int id?; + string name?; + string email?; +|}; + +public type UserTargetType typedesc; + +public type UserInsert User; + +public type UserUpdate record {| + string name?; + string email?; +|}; + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/script.sql b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/script.sql new file mode 100644 index 000000000..e36cedbcb --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/script.sql @@ -0,0 +1,15 @@ +-- AUTO-GENERATED FILE. + +-- This file is an auto-generated file by Ballerina persistence layer for model. +-- Please verify the generated scripts and execute them against the target DB server. + +DROP TABLE IF EXISTS "User"; + +CREATE TABLE "User" ( + "id" INT NOT NULL, + "name" VARCHAR(191) NOT NULL, + "email" VARCHAR(191) NOT NULL, + PRIMARY KEY("id") +); + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/persist/model.bal new file mode 100644 index 000000000..939ce72fc --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type User record {| + readonly int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/target/Persist.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/target/Persist.toml new file mode 100644 index 000000000..17d9dee3d --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/target/Persist.toml @@ -0,0 +1,3 @@ +[[tool.persist]] +options.datastore = "h2" +module = "persist_init_params_h2.entities" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/Ballerina.toml new file mode 100644 index 000000000..d05f913d7 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "test" +name = "persist_relationships_init_params" +version = "0.1.0" +distribution = "2201.13.0" + +[[platform.java21.dependency]] +groupId = "io.ballerina.stdlib" +artifactId = "persist.sql-native" +version = "1.6.0" + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_client.bal new file mode 100644 index 000000000..c1b77ec7b --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_client.bal @@ -0,0 +1,410 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +import ballerina/jballerina.java; +import ballerina/persist; +import ballerina/sql; +import ballerinax/mysql; +import ballerinax/mysql.driver as _; +import ballerinax/persist.sql as psql; + +const CUSTOMER = "customers"; +const ORDER = "orders"; +const ORDER_ITEM = "orderitems"; +const PRODUCT = "products"; + +# MySQL persist client. +public isolated client class Client { + *persist:AbstractPersistClient; + + private final mysql:Client dbClient; + + private final map persistClients; + + private final record {|psql:SQLMetadata...;|} & readonly metadata = { + [CUSTOMER]: { + entityName: "Customer", + tableName: "Customer", + fieldMetadata: { + id: {columnName: "id"}, + name: {columnName: "name"}, + email: {columnName: "email"}, + "orders[].id": {relation: {entityName: "orders", refField: "id"}}, + "orders[].orderNumber": {relation: {entityName: "orders", refField: "orderNumber"}}, + "orders[].totalAmount": {relation: {entityName: "orders", refField: "totalAmount"}}, + "orders[].customerId": {relation: {entityName: "orders", refField: "customerId"}} + }, + keyFields: ["id"], + joinMetadata: {orders: {entity: Order, fieldName: "orders", refTable: "Order", refColumns: ["customerId"], joinColumns: ["id"], 'type: psql:MANY_TO_ONE}} + }, + [ORDER]: { + entityName: "Order", + tableName: "Order", + fieldMetadata: { + id: {columnName: "id"}, + orderNumber: {columnName: "orderNumber"}, + totalAmount: {columnName: "totalAmount"}, + customerId: {columnName: "customerId"}, + "customer.id": {relation: {entityName: "customer", refField: "id"}}, + "customer.name": {relation: {entityName: "customer", refField: "name"}}, + "customer.email": {relation: {entityName: "customer", refField: "email"}}, + "items[].id": {relation: {entityName: "items", refField: "id"}}, + "items[].quantity": {relation: {entityName: "items", refField: "quantity"}}, + "items[].price": {relation: {entityName: "items", refField: "price"}}, + "items[].orderId": {relation: {entityName: "items", refField: "orderId"}}, + "items[].productId": {relation: {entityName: "items", refField: "productId"}} + }, + keyFields: ["id"], + joinMetadata: { + customer: {entity: Customer, fieldName: "customer", refTable: "Customer", refColumns: ["id"], joinColumns: ["customerId"], 'type: psql:ONE_TO_MANY}, + items: {entity: OrderItem, fieldName: "items", refTable: "OrderItem", refColumns: ["orderId"], joinColumns: ["id"], 'type: psql:MANY_TO_ONE} + } + }, + [ORDER_ITEM]: { + entityName: "OrderItem", + tableName: "OrderItem", + fieldMetadata: { + id: {columnName: "id"}, + quantity: {columnName: "quantity"}, + price: {columnName: "price"}, + orderId: {columnName: "orderId"}, + productId: {columnName: "productId"}, + "order.id": {relation: {entityName: "order", refField: "id"}}, + "order.orderNumber": {relation: {entityName: "order", refField: "orderNumber"}}, + "order.totalAmount": {relation: {entityName: "order", refField: "totalAmount"}}, + "'order.customerId": {relation: {entityName: "order", refField: "customerId"}}, + "product.id": {relation: {entityName: "product", refField: "id"}}, + "product.name": {relation: {entityName: "product", refField: "name"}}, + "product.description": {relation: {entityName: "product", refField: "description"}}, + "product.price": {relation: {entityName: "product", refField: "price"}} + }, + keyFields: ["id"], + joinMetadata: { + 'order: {entity: Order, fieldName: "'order", refTable: "Order", refColumns: ["id"], joinColumns: ["orderId"], 'type: psql:ONE_TO_MANY}, + product: {entity: Product, fieldName: "product", refTable: "Product", refColumns: ["id"], joinColumns: ["productId"], 'type: psql:ONE_TO_MANY} + } + }, + [PRODUCT]: { + entityName: "Product", + tableName: "Product", + fieldMetadata: { + id: {columnName: "id"}, + name: {columnName: "name"}, + description: {columnName: "description"}, + price: {columnName: "price"}, + "orderItems[].id": {relation: {entityName: "orderItems", refField: "id"}}, + "orderItems[].quantity": {relation: {entityName: "orderItems", refField: "quantity"}}, + "orderItems[].price": {relation: {entityName: "orderItems", refField: "price"}}, + "orderItems[].orderId": {relation: {entityName: "orderItems", refField: "orderId"}}, + "orderItems[].productId": {relation: {entityName: "orderItems", refField: "productId"}} + }, + keyFields: ["id"], + joinMetadata: {orderItems: {entity: OrderItem, fieldName: "orderItems", refTable: "OrderItem", refColumns: ["productId"], joinColumns: ["id"], 'type: psql:MANY_TO_ONE}} + } + }; + + public isolated function init(string host, int port, string user, string password, string database, mysql:Options connectionOptions = {}) returns persist:Error? { + mysql:Client|error dbClient = new (host = host, user = user, password = password, database = database, port = port, options = connectionOptions); + if dbClient is error { + return error(dbClient.message()); + } + self.dbClient = dbClient; + self.persistClients = { + [CUSTOMER]: check new (dbClient, self.metadata.get(CUSTOMER), psql:MYSQL_SPECIFICS), + [ORDER]: check new (dbClient, self.metadata.get(ORDER), psql:MYSQL_SPECIFICS), + [ORDER_ITEM]: check new (dbClient, self.metadata.get(ORDER_ITEM), psql:MYSQL_SPECIFICS), + [PRODUCT]: check new (dbClient, self.metadata.get(PRODUCT), psql:MYSQL_SPECIFICS) + }; + } + + # Get rows from Customer table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get customers(CustomerTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "query" + } external; + + # Get row from Customer table. + # + # + id - The value of the primary key field id + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get customers/[int id](CustomerTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "queryOne" + } external; + + # Insert rows into Customer table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post customers(CustomerInsert[] data) returns int[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(CUSTOMER); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from CustomerInsert inserted in data + select inserted.id; + } + + # Update row in Customer table. + # + # + id - The value of the primary key field id + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put customers/[int id](CustomerUpdate value) returns Customer|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(CUSTOMER); + } + _ = check sqlClient.runUpdateQuery(id, value); + return self->/customers/[id].get(); + } + + # Delete row from Customer table. + # + # + id - The value of the primary key field id + # + return - The deleted record or an error + isolated resource function delete customers/[int id]() returns Customer|persist:Error { + Customer result = check self->/customers/[id].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(CUSTOMER); + } + _ = check sqlClient.runDeleteQuery(id); + return result; + } + + # Get rows from Order table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get orders(OrderTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "query" + } external; + + # Get row from Order table. + # + # + id - The value of the primary key field id + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get orders/[int id](OrderTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "queryOne" + } external; + + # Insert rows into Order table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post orders(OrderInsert[] data) returns int[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(ORDER); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from OrderInsert inserted in data + select inserted.id; + } + + # Update row in Order table. + # + # + id - The value of the primary key field id + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put orders/[int id](OrderUpdate value) returns Order|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(ORDER); + } + _ = check sqlClient.runUpdateQuery(id, value); + return self->/orders/[id].get(); + } + + # Delete row from Order table. + # + # + id - The value of the primary key field id + # + return - The deleted record or an error + isolated resource function delete orders/[int id]() returns Order|persist:Error { + Order result = check self->/orders/[id].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(ORDER); + } + _ = check sqlClient.runDeleteQuery(id); + return result; + } + + # Get rows from OrderItem table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get orderitems(OrderItemTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "query" + } external; + + # Get row from OrderItem table. + # + # + id - The value of the primary key field id + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get orderitems/[int id](OrderItemTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "queryOne" + } external; + + # Insert rows into OrderItem table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post orderitems(OrderItemInsert[] data) returns int[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(ORDER_ITEM); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from OrderItemInsert inserted in data + select inserted.id; + } + + # Update row in OrderItem table. + # + # + id - The value of the primary key field id + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put orderitems/[int id](OrderItemUpdate value) returns OrderItem|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(ORDER_ITEM); + } + _ = check sqlClient.runUpdateQuery(id, value); + return self->/orderitems/[id].get(); + } + + # Delete row from OrderItem table. + # + # + id - The value of the primary key field id + # + return - The deleted record or an error + isolated resource function delete orderitems/[int id]() returns OrderItem|persist:Error { + OrderItem result = check self->/orderitems/[id].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(ORDER_ITEM); + } + _ = check sqlClient.runDeleteQuery(id); + return result; + } + + # Get rows from Product table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get products(ProductTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "query" + } external; + + # Get row from Product table. + # + # + id - The value of the primary key field id + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get products/[int id](ProductTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "queryOne" + } external; + + # Insert rows into Product table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post products(ProductInsert[] data) returns int[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(PRODUCT); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from ProductInsert inserted in data + select inserted.id; + } + + # Update row in Product table. + # + # + id - The value of the primary key field id + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put products/[int id](ProductUpdate value) returns Product|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(PRODUCT); + } + _ = check sqlClient.runUpdateQuery(id, value); + return self->/products/[id].get(); + } + + # Delete row from Product table. + # + # + id - The value of the primary key field id + # + return - The deleted record or an error + isolated resource function delete products/[int id]() returns Product|persist:Error { + Product result = check self->/products/[id].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(PRODUCT); + } + _ = check sqlClient.runDeleteQuery(id); + return result; + } + + # Execute a custom SQL query and return results. + # + # + sqlQuery - The SQL query to execute + # + rowType - Defines the structure of the result rows + # + return - A collection of result rows or an error + remote isolated function queryNativeSQL(sql:ParameterizedQuery sqlQuery, typedesc rowType = <>) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor" + } external; + + # Execute a custom SQL command (INSERT, UPDATE, DELETE, etc.). + # + # + sqlQuery - The SQL command to execute + # + return - The execution result or an error + remote isolated function executeNativeSQL(sql:ParameterizedQuery sqlQuery) returns psql:ExecutionResult|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor" + } external; + + # Close the database client and release connections. + # + # + return - An error if closing fails + public isolated function close() returns persist:Error? { + error? result = self.dbClient.close(); + if result is error { + return error(result.message()); + } + return result; + } +} + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_types.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_types.bal new file mode 100644 index 000000000..4f92de9e8 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_types.bal @@ -0,0 +1,126 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +public type Customer record {| + readonly int id; + string name; + string email; + +|}; + +public type CustomerOptionalized record {| + int id?; + string name?; + string email?; +|}; + +public type CustomerWithRelations record {| + *CustomerOptionalized; + OrderOptionalized[] orders?; +|}; + +public type CustomerTargetType typedesc; + +public type CustomerInsert Customer; + +public type CustomerUpdate record {| + string name?; + string email?; +|}; + +public type Order record {| + readonly int id; + string orderNumber; + decimal totalAmount; + int customerId; + +|}; + +public type OrderOptionalized record {| + int id?; + string orderNumber?; + decimal totalAmount?; + int customerId?; +|}; + +public type OrderWithRelations record {| + *OrderOptionalized; + CustomerOptionalized customer?; + OrderItemOptionalized[] items?; +|}; + +public type OrderTargetType typedesc; + +public type OrderInsert Order; + +public type OrderUpdate record {| + string orderNumber?; + decimal totalAmount?; + int customerId?; +|}; + +public type OrderItem record {| + readonly int id; + int quantity; + decimal price; + int orderId; + int productId; +|}; + +public type OrderItemOptionalized record {| + int id?; + int quantity?; + decimal price?; + int orderId?; + int productId?; +|}; + +public type OrderItemWithRelations record {| + *OrderItemOptionalized; + OrderOptionalized 'order?; + ProductOptionalized product?; +|}; + +public type OrderItemTargetType typedesc; + +public type OrderItemInsert OrderItem; + +public type OrderItemUpdate record {| + int quantity?; + decimal price?; + int orderId?; + int productId?; +|}; + +public type Product record {| + readonly int id; + string name; + string description; + decimal price; + +|}; + +public type ProductOptionalized record {| + int id?; + string name?; + string description?; + decimal price?; +|}; + +public type ProductWithRelations record {| + *ProductOptionalized; + OrderItemOptionalized[] orderItems?; +|}; + +public type ProductTargetType typedesc; + +public type ProductInsert Product; + +public type ProductUpdate record {| + string name?; + string description?; + decimal price?; +|}; + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/script.sql b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/script.sql new file mode 100644 index 000000000..ad5bc8972 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/script.sql @@ -0,0 +1,46 @@ +-- AUTO-GENERATED FILE. + +-- This file is an auto-generated file by Ballerina persistence layer for model. +-- Please verify the generated scripts and execute them against the target DB server. + +DROP TABLE IF EXISTS `OrderItem`; +DROP TABLE IF EXISTS `Order`; +DROP TABLE IF EXISTS `Product`; +DROP TABLE IF EXISTS `Customer`; + +CREATE TABLE `Customer` ( + `id` INT NOT NULL, + `name` VARCHAR(191) NOT NULL, + `email` VARCHAR(191) NOT NULL, + PRIMARY KEY(`id`) +); + +CREATE TABLE `Product` ( + `id` INT NOT NULL, + `name` VARCHAR(191) NOT NULL, + `description` VARCHAR(191) NOT NULL, + `price` DECIMAL(65,30) NOT NULL, + PRIMARY KEY(`id`) +); + +CREATE TABLE `Order` ( + `id` INT NOT NULL, + `orderNumber` VARCHAR(191) NOT NULL, + `totalAmount` DECIMAL(65,30) NOT NULL, + `customerId` INT NOT NULL, + FOREIGN KEY(`customerId`) REFERENCES `Customer`(`id`), + PRIMARY KEY(`id`) +); + +CREATE TABLE `OrderItem` ( + `id` INT NOT NULL, + `quantity` INT NOT NULL, + `price` DECIMAL(65,30) NOT NULL, + `orderId` INT NOT NULL, + FOREIGN KEY(`orderId`) REFERENCES `Order`(`id`), + `productId` INT NOT NULL, + FOREIGN KEY(`productId`) REFERENCES `Product`(`id`), + PRIMARY KEY(`id`) +); + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/persist/model.bal new file mode 100644 index 000000000..59479a8ed --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/persist/model.bal @@ -0,0 +1,32 @@ +import ballerina/persist as _; + +type Customer record {| + readonly int id; + string name; + string email; + Order[] orders; +|}; + +type Order record {| + readonly int id; + string orderNumber; + decimal totalAmount; + Customer customer; + OrderItem[] items; +|}; + +type OrderItem record {| + readonly int id; + int quantity; + decimal price; + Order 'order; + Product product; +|}; + +type Product record {| + readonly int id; + string name; + string description; + decimal price; + OrderItem[] orderItems; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/target/Persist.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/target/Persist.toml new file mode 100644 index 000000000..811cbe6ac --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/target/Persist.toml @@ -0,0 +1,3 @@ +[[tool.persist]] +options.datastore = "mysql" +module = "persist_relationships_init_params.entities" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/Ballerina.toml new file mode 100644 index 000000000..ef3e2b085 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "test" +name = "persist_multiple_entities" +version = "0.1.0" +distribution = "2201.13.0" + +[[platform.java21.dependency]] +groupId = "io.ballerina.stdlib" +artifactId = "persist.sql-native" +version = "1.6.0" + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_client.bal new file mode 100644 index 000000000..ecdbe4a0e --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_client.bal @@ -0,0 +1,435 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +import ballerina/jballerina.java; +import ballerina/persist; +import ballerina/sql; +import ballerinax/persist.sql as psql; +import ballerinax/postgresql; +import ballerinax/postgresql.driver as _; + +const EMPLOYEE = "employees"; +const WORKSPACE = "workspaces"; +const BUILDING = "buildings"; +const DEPARTMENT = "departments"; + +# PostgreSQL persist client. +public isolated client class Client { + *persist:AbstractPersistClient; + + private final postgresql:Client dbClient; + + private final map persistClients; + + private final record {|psql:SQLMetadata...;|} metadata = { + [EMPLOYEE]: { + entityName: "Employee", + tableName: "Employee", + fieldMetadata: { + empNo: {columnName: "empNo"}, + firstName: {columnName: "firstName"}, + lastName: {columnName: "lastName"}, + birthDate: {columnName: "birthDate"}, + gender: {columnName: "gender"}, + hireDate: {columnName: "hireDate"}, + departmentDeptNo: {columnName: "departmentDeptNo"}, + "department.deptNo": {relation: {entityName: "department", refField: "deptNo"}}, + "department.deptName": {relation: {entityName: "department", refField: "deptName"}}, + "workspace.workspaceId": {relation: {entityName: "workspace", refField: "workspaceId"}}, + "workspace.workspaceType": {relation: {entityName: "workspace", refField: "workspaceType"}}, + "workspace.locationBuildingCode": {relation: {entityName: "workspace", refField: "locationBuildingCode"}}, + "workspace.employeeEmpNo": {relation: {entityName: "workspace", refField: "employeeEmpNo"}} + }, + keyFields: ["empNo"], + joinMetadata: { + department: {entity: Department, fieldName: "department", refTable: "Department", refColumns: ["deptNo"], joinColumns: ["departmentDeptNo"], 'type: psql:ONE_TO_MANY}, + workspace: {entity: Workspace, fieldName: "workspace", refTable: "Workspace", refColumns: ["employeeEmpNo"], joinColumns: ["empNo"], 'type: psql:ONE_TO_ONE} + } + }, + [WORKSPACE]: { + entityName: "Workspace", + tableName: "Workspace", + fieldMetadata: { + workspaceId: {columnName: "workspaceId"}, + workspaceType: {columnName: "workspaceType"}, + locationBuildingCode: {columnName: "locationBuildingCode"}, + employeeEmpNo: {columnName: "employeeEmpNo"}, + "location.buildingCode": {relation: {entityName: "location", refField: "buildingCode"}}, + "location.city": {relation: {entityName: "location", refField: "city"}}, + "location.state": {relation: {entityName: "location", refField: "state"}}, + "location.country": {relation: {entityName: "location", refField: "country"}}, + "location.postalCode": {relation: {entityName: "location", refField: "postalCode"}}, + "employee.empNo": {relation: {entityName: "employee", refField: "empNo"}}, + "employee.firstName": {relation: {entityName: "employee", refField: "firstName"}}, + "employee.lastName": {relation: {entityName: "employee", refField: "lastName"}}, + "employee.birthDate": {relation: {entityName: "employee", refField: "birthDate"}}, + "employee.gender": {relation: {entityName: "employee", refField: "gender"}}, + "employee.hireDate": {relation: {entityName: "employee", refField: "hireDate"}}, + "employee.departmentDeptNo": {relation: {entityName: "employee", refField: "departmentDeptNo"}} + }, + keyFields: ["workspaceId"], + joinMetadata: { + location: {entity: Building, fieldName: "location", refTable: "Building", refColumns: ["buildingCode"], joinColumns: ["locationBuildingCode"], 'type: psql:ONE_TO_MANY}, + employee: {entity: Employee, fieldName: "employee", refTable: "Employee", refColumns: ["empNo"], joinColumns: ["employeeEmpNo"], 'type: psql:ONE_TO_ONE} + } + }, + [BUILDING]: { + entityName: "Building", + tableName: "Building", + fieldMetadata: { + buildingCode: {columnName: "buildingCode"}, + city: {columnName: "city"}, + state: {columnName: "state"}, + country: {columnName: "country"}, + postalCode: {columnName: "postalCode"}, + "workspaces[].workspaceId": {relation: {entityName: "workspaces", refField: "workspaceId"}}, + "workspaces[].workspaceType": {relation: {entityName: "workspaces", refField: "workspaceType"}}, + "workspaces[].locationBuildingCode": {relation: {entityName: "workspaces", refField: "locationBuildingCode"}}, + "workspaces[].employeeEmpNo": {relation: {entityName: "workspaces", refField: "employeeEmpNo"}} + }, + keyFields: ["buildingCode"], + joinMetadata: {workspaces: {entity: Workspace, fieldName: "workspaces", refTable: "Workspace", refColumns: ["locationBuildingCode"], joinColumns: ["buildingCode"], 'type: psql:MANY_TO_ONE}} + }, + [DEPARTMENT]: { + entityName: "Department", + tableName: "Department", + fieldMetadata: { + deptNo: {columnName: "deptNo"}, + deptName: {columnName: "deptName"}, + "employees[].empNo": {relation: {entityName: "employees", refField: "empNo"}}, + "employees[].firstName": {relation: {entityName: "employees", refField: "firstName"}}, + "employees[].lastName": {relation: {entityName: "employees", refField: "lastName"}}, + "employees[].birthDate": {relation: {entityName: "employees", refField: "birthDate"}}, + "employees[].gender": {relation: {entityName: "employees", refField: "gender"}}, + "employees[].hireDate": {relation: {entityName: "employees", refField: "hireDate"}}, + "employees[].departmentDeptNo": {relation: {entityName: "employees", refField: "departmentDeptNo"}} + }, + keyFields: ["deptNo"], + joinMetadata: {employees: {entity: Employee, fieldName: "employees", refTable: "Employee", refColumns: ["departmentDeptNo"], joinColumns: ["deptNo"], 'type: psql:MANY_TO_ONE}} + } + }; + + public isolated function init(string host, int port, string user, string password, string database, postgresql:Options connectionOptions = {}, string? defaultSchema = ()) returns persist:Error? { + postgresql:Client|error dbClient = new (host = host, username = user, password = password, database = database, port = port, options = connectionOptions); + if dbClient is error { + return error(dbClient.message()); + } + self.dbClient = dbClient; + if defaultSchema != () { + lock { + foreach string key in self.metadata.keys() { + psql:SQLMetadata metadata = self.metadata.get(key); + if metadata.schemaName == () { + metadata.schemaName = defaultSchema; + } + map? joinMetadataMap = metadata.joinMetadata; + if joinMetadataMap == () { + continue; + } + foreach [string, psql:JoinMetadata] [_, joinMetadata] in joinMetadataMap.entries() { + if joinMetadata.refSchema == () { + joinMetadata.refSchema = defaultSchema; + } + } + } + } + } + self.persistClients = { + [EMPLOYEE]: check new (dbClient, self.metadata.get(EMPLOYEE).cloneReadOnly(), psql:POSTGRESQL_SPECIFICS), + [WORKSPACE]: check new (dbClient, self.metadata.get(WORKSPACE).cloneReadOnly(), psql:POSTGRESQL_SPECIFICS), + [BUILDING]: check new (dbClient, self.metadata.get(BUILDING).cloneReadOnly(), psql:POSTGRESQL_SPECIFICS), + [DEPARTMENT]: check new (dbClient, self.metadata.get(DEPARTMENT).cloneReadOnly(), psql:POSTGRESQL_SPECIFICS) + }; + } + + # Get rows from Employee table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get employees(EmployeeTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "query" + } external; + + # Get row from Employee table. + # + # + empNo - The value of the primary key field empNo + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get employees/[string empNo](EmployeeTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "queryOne" + } external; + + # Insert rows into Employee table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post employees(EmployeeInsert[] data) returns string[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(EMPLOYEE); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from EmployeeInsert inserted in data + select inserted.empNo; + } + + # Update row in Employee table. + # + # + empNo - The value of the primary key field empNo + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put employees/[string empNo](EmployeeUpdate value) returns Employee|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(EMPLOYEE); + } + _ = check sqlClient.runUpdateQuery(empNo, value); + return self->/employees/[empNo].get(); + } + + # Delete row from Employee table. + # + # + empNo - The value of the primary key field empNo + # + return - The deleted record or an error + isolated resource function delete employees/[string empNo]() returns Employee|persist:Error { + Employee result = check self->/employees/[empNo].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(EMPLOYEE); + } + _ = check sqlClient.runDeleteQuery(empNo); + return result; + } + + # Get rows from Workspace table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get workspaces(WorkspaceTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "query" + } external; + + # Get row from Workspace table. + # + # + workspaceId - The value of the primary key field workspaceId + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get workspaces/[string workspaceId](WorkspaceTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "queryOne" + } external; + + # Insert rows into Workspace table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post workspaces(WorkspaceInsert[] data) returns string[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(WORKSPACE); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from WorkspaceInsert inserted in data + select inserted.workspaceId; + } + + # Update row in Workspace table. + # + # + workspaceId - The value of the primary key field workspaceId + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put workspaces/[string workspaceId](WorkspaceUpdate value) returns Workspace|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(WORKSPACE); + } + _ = check sqlClient.runUpdateQuery(workspaceId, value); + return self->/workspaces/[workspaceId].get(); + } + + # Delete row from Workspace table. + # + # + workspaceId - The value of the primary key field workspaceId + # + return - The deleted record or an error + isolated resource function delete workspaces/[string workspaceId]() returns Workspace|persist:Error { + Workspace result = check self->/workspaces/[workspaceId].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(WORKSPACE); + } + _ = check sqlClient.runDeleteQuery(workspaceId); + return result; + } + + # Get rows from Building table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get buildings(BuildingTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "query" + } external; + + # Get row from Building table. + # + # + buildingCode - The value of the primary key field buildingCode + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get buildings/[string buildingCode](BuildingTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "queryOne" + } external; + + # Insert rows into Building table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post buildings(BuildingInsert[] data) returns string[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(BUILDING); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from BuildingInsert inserted in data + select inserted.buildingCode; + } + + # Update row in Building table. + # + # + buildingCode - The value of the primary key field buildingCode + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put buildings/[string buildingCode](BuildingUpdate value) returns Building|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(BUILDING); + } + _ = check sqlClient.runUpdateQuery(buildingCode, value); + return self->/buildings/[buildingCode].get(); + } + + # Delete row from Building table. + # + # + buildingCode - The value of the primary key field buildingCode + # + return - The deleted record or an error + isolated resource function delete buildings/[string buildingCode]() returns Building|persist:Error { + Building result = check self->/buildings/[buildingCode].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(BUILDING); + } + _ = check sqlClient.runDeleteQuery(buildingCode); + return result; + } + + # Get rows from Department table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get departments(DepartmentTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "query" + } external; + + # Get row from Department table. + # + # + deptNo - The value of the primary key field deptNo + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get departments/[string deptNo](DepartmentTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor", + name: "queryOne" + } external; + + # Insert rows into Department table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post departments(DepartmentInsert[] data) returns string[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(DEPARTMENT); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from DepartmentInsert inserted in data + select inserted.deptNo; + } + + # Update row in Department table. + # + # + deptNo - The value of the primary key field deptNo + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put departments/[string deptNo](DepartmentUpdate value) returns Department|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(DEPARTMENT); + } + _ = check sqlClient.runUpdateQuery(deptNo, value); + return self->/departments/[deptNo].get(); + } + + # Delete row from Department table. + # + # + deptNo - The value of the primary key field deptNo + # + return - The deleted record or an error + isolated resource function delete departments/[string deptNo]() returns Department|persist:Error { + Department result = check self->/departments/[deptNo].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(DEPARTMENT); + } + _ = check sqlClient.runDeleteQuery(deptNo); + return result; + } + + # Execute a custom SQL query and return results. + # + # + sqlQuery - The SQL query to execute + # + rowType - Defines the structure of the result rows + # + return - A collection of result rows or an error + remote isolated function queryNativeSQL(sql:ParameterizedQuery sqlQuery, typedesc rowType = <>) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor" + } external; + + # Execute a custom SQL command (INSERT, UPDATE, DELETE, etc.). + # + # + sqlQuery - The SQL command to execute + # + return - The execution result or an error + remote isolated function executeNativeSQL(sql:ParameterizedQuery sqlQuery) returns psql:ExecutionResult|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.PostgreSQLProcessor" + } external; + + # Close the database client and release connections. + # + # + return - An error if closing fails + public isolated function close() returns persist:Error? { + error? result = self.dbClient.close(); + if result is error { + return error(result.message()); + } + return result; + } +} + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_types.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_types.bal new file mode 100644 index 000000000..7dbf828f5 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_types.bal @@ -0,0 +1,134 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +import ballerina/time; + +public type Employee record {| + readonly string empNo; + string firstName; + string lastName; + time:Date birthDate; + string gender; + time:Date hireDate; + string departmentDeptNo; + +|}; + +public type EmployeeOptionalized record {| + string empNo?; + string firstName?; + string lastName?; + time:Date birthDate?; + string gender?; + time:Date hireDate?; + string departmentDeptNo?; +|}; + +public type EmployeeWithRelations record {| + *EmployeeOptionalized; + DepartmentOptionalized department?; + WorkspaceOptionalized workspace?; +|}; + +public type EmployeeTargetType typedesc; + +public type EmployeeInsert Employee; + +public type EmployeeUpdate record {| + string firstName?; + string lastName?; + time:Date birthDate?; + string gender?; + time:Date hireDate?; + string departmentDeptNo?; +|}; + +public type Workspace record {| + readonly string workspaceId; + string workspaceType; + string locationBuildingCode; + string employeeEmpNo; +|}; + +public type WorkspaceOptionalized record {| + string workspaceId?; + string workspaceType?; + string locationBuildingCode?; + string employeeEmpNo?; +|}; + +public type WorkspaceWithRelations record {| + *WorkspaceOptionalized; + BuildingOptionalized location?; + EmployeeOptionalized employee?; +|}; + +public type WorkspaceTargetType typedesc; + +public type WorkspaceInsert Workspace; + +public type WorkspaceUpdate record {| + string workspaceType?; + string locationBuildingCode?; + string employeeEmpNo?; +|}; + +public type Building record {| + readonly string buildingCode; + string city; + string state; + string country; + string postalCode; + +|}; + +public type BuildingOptionalized record {| + string buildingCode?; + string city?; + string state?; + string country?; + string postalCode?; +|}; + +public type BuildingWithRelations record {| + *BuildingOptionalized; + WorkspaceOptionalized[] workspaces?; +|}; + +public type BuildingTargetType typedesc; + +public type BuildingInsert Building; + +public type BuildingUpdate record {| + string city?; + string state?; + string country?; + string postalCode?; +|}; + +public type Department record {| + readonly string deptNo; + string deptName; + +|}; + +public type DepartmentOptionalized record {| + string deptNo?; + string deptName?; +|}; + +public type DepartmentWithRelations record {| + *DepartmentOptionalized; + EmployeeOptionalized[] employees?; +|}; + +public type DepartmentTargetType typedesc; + +public type DepartmentInsert Department; + +public type DepartmentUpdate record {| + string deptName?; +|}; + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/script.sql b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/script.sql new file mode 100644 index 000000000..ab6085c4b --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/script.sql @@ -0,0 +1,48 @@ +-- AUTO-GENERATED FILE. + +-- This file is an auto-generated file by Ballerina persistence layer for model. +-- Please verify the generated scripts and execute them against the target DB server. + +DROP TABLE IF EXISTS "Workspace"; +DROP TABLE IF EXISTS "Employee"; +DROP TABLE IF EXISTS "Department"; +DROP TABLE IF EXISTS "Building"; + +CREATE TABLE "Building" ( + "buildingCode" VARCHAR(191) NOT NULL, + "city" VARCHAR(191) NOT NULL, + "state" VARCHAR(191) NOT NULL, + "country" VARCHAR(191) NOT NULL, + "postalCode" VARCHAR(191) NOT NULL, + PRIMARY KEY("buildingCode") +); + +CREATE TABLE "Department" ( + "deptNo" VARCHAR(191) NOT NULL, + "deptName" VARCHAR(191) NOT NULL, + PRIMARY KEY("deptNo") +); + +CREATE TABLE "Employee" ( + "empNo" VARCHAR(191) NOT NULL, + "firstName" VARCHAR(191) NOT NULL, + "lastName" VARCHAR(191) NOT NULL, + "birthDate" DATE NOT NULL, + "gender" VARCHAR(191) NOT NULL, + "hireDate" DATE NOT NULL, + "departmentDeptNo" VARCHAR(191) NOT NULL, + FOREIGN KEY("departmentDeptNo") REFERENCES "Department"("deptNo"), + PRIMARY KEY("empNo") +); + +CREATE TABLE "Workspace" ( + "workspaceId" VARCHAR(191) NOT NULL, + "workspaceType" VARCHAR(191) NOT NULL, + "locationBuildingCode" VARCHAR(191) NOT NULL, + FOREIGN KEY("locationBuildingCode") REFERENCES "Building"("buildingCode"), + "employeeEmpNo" VARCHAR(191) UNIQUE NOT NULL, + FOREIGN KEY("employeeEmpNo") REFERENCES "Employee"("empNo"), + PRIMARY KEY("workspaceId") +); + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/persist/model.bal new file mode 100644 index 000000000..7986be5ff --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/persist/model.bal @@ -0,0 +1,35 @@ +import ballerina/persist as _; +import ballerina/time; + +type Employee record {| + readonly string empNo; + string firstName; + string lastName; + time:Date birthDate; + string gender; + time:Date hireDate; + Department department; + Workspace? workspace; +|}; + +type Workspace record {| + readonly string workspaceId; + string workspaceType; + Building location; + Employee employee; +|}; + +type Building record {| + readonly string buildingCode; + string city; + string state; + string country; + string postalCode; + Workspace[] workspaces; +|}; + +type Department record {| + readonly string deptNo; + string deptName; + Employee[] employees; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/target/Persist.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/target/Persist.toml new file mode 100644 index 000000000..68a0125e9 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/target/Persist.toml @@ -0,0 +1,3 @@ +[[tool.persist]] +options.datastore = "postgresql" +module = "persist_multiple_entities.entities" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/Ballerina.toml new file mode 100644 index 000000000..a10af110b --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "test" +name = "persist_init_params_with_config" +version = "0.1.0" +distribution = "2201.13.0" + +[[platform.java21.dependency]] +groupId = "io.ballerina.stdlib" +artifactId = "persist.sql-native" +version = "1.6.0" + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/Config.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/Config.toml new file mode 100644 index 000000000..9714d6148 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/Config.toml @@ -0,0 +1,7 @@ +# This Config.toml should be ignored when --with-init-params is used +[test.persist_init_params_with_config] +host = "localhost" +port = 3306 +user = "root" +password = "root" +database = "testdb" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_client.bal new file mode 100644 index 000000000..995b2455e --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_client.bal @@ -0,0 +1,138 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +import ballerina/jballerina.java; +import ballerina/persist; +import ballerina/sql; +import ballerinax/mysql; +import ballerinax/mysql.driver as _; +import ballerinax/persist.sql as psql; + +const PRODUCT = "products"; + +# MySQL persist client. +public isolated client class Client { + *persist:AbstractPersistClient; + + private final mysql:Client dbClient; + + private final map persistClients; + + private final record {|psql:SQLMetadata...;|} & readonly metadata = { + [PRODUCT]: { + entityName: "Product", + tableName: "Product", + fieldMetadata: { + id: {columnName: "id"}, + name: {columnName: "name"}, + price: {columnName: "price"} + }, + keyFields: ["id"] + } + }; + + public isolated function init(string host, int port, string user, string password, string database, mysql:Options connectionOptions = {}) returns persist:Error? { + mysql:Client|error dbClient = new (host = host, user = user, password = password, database = database, port = port, options = connectionOptions); + if dbClient is error { + return error(dbClient.message()); + } + self.dbClient = dbClient; + self.persistClients = {[PRODUCT]: check new (dbClient, self.metadata.get(PRODUCT), psql:MYSQL_SPECIFICS)}; + } + + # Get rows from Product table. + # + # + targetType - Defines which fields to retrieve from the results + # + whereClause - SQL WHERE clause to filter the results (e.g., `column_name = value`) + # + orderByClause - SQL ORDER BY clause to sort the results (e.g., `column_name ASC`) + # + limitClause - SQL LIMIT clause to limit the number of results (e.g., `10`) + # + groupByClause - SQL GROUP BY clause to group the results (e.g., `column_name`) + # + return - A collection of matching records or an error + isolated resource function get products(ProductTargetType targetType = <>, sql:ParameterizedQuery whereClause = ``, sql:ParameterizedQuery orderByClause = ``, sql:ParameterizedQuery limitClause = ``, sql:ParameterizedQuery groupByClause = ``) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "query" + } external; + + # Get row from Product table. + # + # + id - The value of the primary key field id + # + targetType - Defines which fields to retrieve from the result + # + return - The matching record or an error + isolated resource function get products/[int id](ProductTargetType targetType = <>) returns targetType|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor", + name: "queryOne" + } external; + + # Insert rows into Product table. + # + # + data - A list of records to be inserted + # + return - The primary key value(s) of the inserted rows or an error + isolated resource function post products(ProductInsert[] data) returns int[]|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(PRODUCT); + } + _ = check sqlClient.runBatchInsertQuery(data); + return from ProductInsert inserted in data + select inserted.id; + } + + # Update row in Product table. + # + # + id - The value of the primary key field id + # + value - The record containing updated field values + # + return - The updated record or an error + isolated resource function put products/[int id](ProductUpdate value) returns Product|persist:Error { + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(PRODUCT); + } + _ = check sqlClient.runUpdateQuery(id, value); + return self->/products/[id].get(); + } + + # Delete row from Product table. + # + # + id - The value of the primary key field id + # + return - The deleted record or an error + isolated resource function delete products/[int id]() returns Product|persist:Error { + Product result = check self->/products/[id].get(); + psql:SQLClient sqlClient; + lock { + sqlClient = self.persistClients.get(PRODUCT); + } + _ = check sqlClient.runDeleteQuery(id); + return result; + } + + # Execute a custom SQL query and return results. + # + # + sqlQuery - The SQL query to execute + # + rowType - Defines the structure of the result rows + # + return - A collection of result rows or an error + remote isolated function queryNativeSQL(sql:ParameterizedQuery sqlQuery, typedesc rowType = <>) returns stream = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor" + } external; + + # Execute a custom SQL command (INSERT, UPDATE, DELETE, etc.). + # + # + sqlQuery - The SQL command to execute + # + return - The execution result or an error + remote isolated function executeNativeSQL(sql:ParameterizedQuery sqlQuery) returns psql:ExecutionResult|persist:Error = @java:Method { + 'class: "io.ballerina.stdlib.persist.sql.datastore.MySQLProcessor" + } external; + + # Close the database client and release connections. + # + # + return - An error if closing fails + public isolated function close() returns persist:Error? { + error? result = self.dbClient.close(); + if result is error { + return error(result.message()); + } + return result; + } +} + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_types.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_types.bal new file mode 100644 index 000000000..e1fdee58c --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_types.bal @@ -0,0 +1,26 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. + +// This file is an auto-generated file by Ballerina persistence layer for model. +// It should not be modified by hand. + +public type Product record {| + readonly int id; + string name; + decimal price; +|}; + +public type ProductOptionalized record {| + int id?; + string name?; + decimal price?; +|}; + +public type ProductTargetType typedesc; + +public type ProductInsert Product; + +public type ProductUpdate record {| + string name?; + decimal price?; +|}; + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/script.sql b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/script.sql new file mode 100644 index 000000000..364b15f5d --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/script.sql @@ -0,0 +1,15 @@ +-- AUTO-GENERATED FILE. + +-- This file is an auto-generated file by Ballerina persistence layer for model. +-- Please verify the generated scripts and execute them against the target DB server. + +DROP TABLE IF EXISTS `Product`; + +CREATE TABLE `Product` ( + `id` INT NOT NULL, + `name` VARCHAR(191) NOT NULL, + `price` DECIMAL(65,30) NOT NULL, + PRIMARY KEY(`id`) +); + + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/persist/model.bal new file mode 100644 index 000000000..668f2c465 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/persist/model.bal @@ -0,0 +1,7 @@ +import ballerina/persist as _; + +type Product record {| + readonly int id; + string name; + decimal price; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/target/Persist.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/target/Persist.toml new file mode 100644 index 000000000..ced82da46 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/target/Persist.toml @@ -0,0 +1,3 @@ +[[tool.persist]] +options.datastore = "mysql" +module = "persist_init_params_with_config.entities" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/Ballerina.toml new file mode 100644 index 000000000..ec04baeda --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "test" +name = "persist_init_params_negative_invalid" +version = "0.1.0" +distribution = "2201.13.0" + +[[platform.java21.dependency]] +groupId = "io.ballerina.stdlib" +artifactId = "persist.sql-native" +version = "1.6.0" + diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/persist/model.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/persist/model.bal new file mode 100644 index 000000000..59b076f97 --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/persist/model.bal @@ -0,0 +1,8 @@ +import ballerina/persist as _; + +// Invalid model - missing readonly on key field +type User record {| + int id; + string name; + string email; +|}; diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/target/Persist.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/target/Persist.toml new file mode 100644 index 000000000..e69dabe5c --- /dev/null +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_125_init_params_negative_invalid_model/target/Persist.toml @@ -0,0 +1,3 @@ +[[tool.persist]] +options.datastore = "mysql" +module = "persist_init_params_negative_invalid.entities" From aa71faf7c748116e1734d26ac3272ffbc16e4a63 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 5 Dec 2025 12:01:09 +0530 Subject: [PATCH 5/9] Add documentation generation for init function --- .../syntax/clients/DbClientSyntax.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java index 0bfba0792..b749eb5c4 100644 --- a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java +++ b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java @@ -274,6 +274,13 @@ public FunctionDefinitionNode getInitFunction(Module entityModule) { } init.addStatement(NodeParser.parseStatement(String.format( BalSyntaxConstants.PERSIST_CLIENT_TEMPLATE, persistClientMap))); + + // Add documentation if init parameters are used + if (initParams) { + String doc = createInitMethodDocumentation(dataSource); + init.addDocumentation(BalSyntaxUtils.createMarkdownDocumentationNode(doc)); + } + return init.getFunctionDefinitionNode(); } @@ -640,4 +647,46 @@ private static void addFunctionBodyToPostResource(Function create, List + String.format("Initialize the persist client with MySQL database connection parameters.%n%n" + + "+ host - Database server host%n" + + "+ port - Database server port%n" + + "+ user - Database username%n" + + "+ password - Database password%n" + + "+ database - Database name%n" + + "+ connectionOptions - Additional MySQL connection options%n" + + "+ return - An error if initialization fails"); + case PersistToolsConstants.SupportedDataSources.POSTGRESQL_DB -> + String.format("Initialize the persist client with PostgreSQL database connection parameters.%n%n" + + "+ host - Database server host%n" + + "+ port - Database server port%n" + + "+ user - Database username%n" + + "+ password - Database password%n" + + "+ database - Database name%n" + + "+ connectionOptions - Additional PostgreSQL connection options%n" + + "+ defaultSchema - Default schema name for the database%n" + + "+ return - An error if initialization fails"); + case PersistToolsConstants.SupportedDataSources.MSSQL_DB -> + String.format("Initialize the persist client with MSSQL database connection parameters.%n%n" + + "+ host - Database server host%n" + + "+ port - Database server port%n" + + "+ user - Database username%n" + + "+ password - Database password%n" + + "+ database - Database name%n" + + "+ connectionOptions - Additional MSSQL connection options%n" + + "+ defaultSchema - Default schema name for the database%n" + + "+ return - An error if initialization fails"); + case PersistToolsConstants.SupportedDataSources.H2_DB -> + String.format("Initialize the persist client with H2 database connection parameters.%n%n" + + "+ url - JDBC URL for the H2 database%n" + + "+ user - Database username (optional)%n" + + "+ password - Database password (optional)%n" + + "+ connectionOptions - Additional H2 connection options%n" + + "+ return - An error if initialization fails"); + default -> throw new IllegalStateException("Unsupported datasource: " + dataSource); + }; + } } From 2114cd1503e23fc0a7f859d883a71693fa6fe124 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 5 Dec 2025 12:01:16 +0530 Subject: [PATCH 6/9] Fix test cases --- .../modules/entities/persist_client.bal | 9 +++++++++ .../modules/entities/persist_client.bal | 10 ++++++++++ .../modules/entities/persist_client.bal | 10 ++++++++++ .../modules/entities/persist_client.bal | 7 +++++++ .../modules/entities/persist_client.bal | 9 +++++++++ .../modules/entities/persist_client.bal | 10 ++++++++++ .../modules/entities/persist_client.bal | 9 +++++++++ 7 files changed, 64 insertions(+) diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_client.bal index c1397f3b5..3355694b0 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_client.bal +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_118_init_params_mysql/modules/entities/persist_client.bal @@ -33,6 +33,15 @@ public isolated client class Client { } }; + # Initialize the persist client with MySQL database connection parameters. + # + # + host - Database server host + # + port - Database server port + # + user - Database username + # + password - Database password + # + database - Database name + # + connectionOptions - Additional MySQL connection options + # + return - An error if initialization fails public isolated function init(string host, int port, string user, string password, string database, mysql:Options connectionOptions = {}) returns persist:Error? { mysql:Client|error dbClient = new (host = host, user = user, password = password, database = database, port = port, options = connectionOptions); if dbClient is error { diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_client.bal index cb8270523..cbe25f601 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_client.bal +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_119_init_params_postgresql/modules/entities/persist_client.bal @@ -33,6 +33,16 @@ public isolated client class Client { } }; + # Initialize the persist client with PostgreSQL database connection parameters. + # + # + host - Database server host + # + port - Database server port + # + user - Database username + # + password - Database password + # + database - Database name + # + connectionOptions - Additional PostgreSQL connection options + # + defaultSchema - Default schema name for the database + # + return - An error if initialization fails public isolated function init(string host, int port, string user, string password, string database, postgresql:Options connectionOptions = {}, string? defaultSchema = ()) returns persist:Error? { postgresql:Client|error dbClient = new (host = host, username = user, password = password, database = database, port = port, options = connectionOptions); if dbClient is error { diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_client.bal index a498b543c..743738f5f 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_client.bal +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_120_init_params_mssql/modules/entities/persist_client.bal @@ -33,6 +33,16 @@ public isolated client class Client { } }; + # Initialize the persist client with MSSQL database connection parameters. + # + # + host - Database server host + # + port - Database server port + # + user - Database username + # + password - Database password + # + database - Database name + # + connectionOptions - Additional MSSQL connection options + # + defaultSchema - Default schema name for the database + # + return - An error if initialization fails public isolated function init(string host, int port, string user, string password, string database, mssql:Options connectionOptions = {}, string? defaultSchema = ()) returns persist:Error? { mssql:Client|error dbClient = new (host = host, user = user, password = password, database = database, port = port, options = connectionOptions); if dbClient is error { diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_client.bal index 9ae618d8d..8eef45159 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_client.bal +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_121_init_params_h2/modules/entities/persist_client.bal @@ -33,6 +33,13 @@ public isolated client class Client { } }; + # Initialize the persist client with H2 database connection parameters. + # + # + url - JDBC URL for the H2 database + # + user - Database username (optional) + # + password - Database password (optional) + # + connectionOptions - Additional H2 connection options + # + return - An error if initialization fails public isolated function init(string url, string? user = (), string? password = (), jdbc:Options connectionOptions = {}) returns persist:Error? { jdbc:Client|error dbClient = new (url = url, user = user, password = password, options = connectionOptions); if dbClient is error { diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_client.bal index c1b77ec7b..8632d7732 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_client.bal +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_122_init_params_relationships/modules/entities/persist_client.bal @@ -105,6 +105,15 @@ public isolated client class Client { } }; + # Initialize the persist client with MySQL database connection parameters. + # + # + host - Database server host + # + port - Database server port + # + user - Database username + # + password - Database password + # + database - Database name + # + connectionOptions - Additional MySQL connection options + # + return - An error if initialization fails public isolated function init(string host, int port, string user, string password, string database, mysql:Options connectionOptions = {}) returns persist:Error? { mysql:Client|error dbClient = new (host = host, user = user, password = password, database = database, port = port, options = connectionOptions); if dbClient is error { diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_client.bal index ecdbe4a0e..e36adabf8 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_client.bal +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_123_init_params_multiple_entities/modules/entities/persist_client.bal @@ -111,6 +111,16 @@ public isolated client class Client { } }; + # Initialize the persist client with PostgreSQL database connection parameters. + # + # + host - Database server host + # + port - Database server port + # + user - Database username + # + password - Database password + # + database - Database name + # + connectionOptions - Additional PostgreSQL connection options + # + defaultSchema - Default schema name for the database + # + return - An error if initialization fails public isolated function init(string host, int port, string user, string password, string database, postgresql:Options connectionOptions = {}, string? defaultSchema = ()) returns persist:Error? { postgresql:Client|error dbClient = new (host = host, username = user, password = password, database = database, port = port, options = connectionOptions); if dbClient is error { diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_client.bal b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_client.bal index 995b2455e..f3c6db9b1 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_client.bal +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_generate_124_init_params_with_config/modules/entities/persist_client.bal @@ -33,6 +33,15 @@ public isolated client class Client { } }; + # Initialize the persist client with MySQL database connection parameters. + # + # + host - Database server host + # + port - Database server port + # + user - Database username + # + password - Database password + # + database - Database name + # + connectionOptions - Additional MySQL connection options + # + return - An error if initialization fails public isolated function init(string host, int port, string user, string password, string database, mysql:Options connectionOptions = {}) returns persist:Error? { mysql:Client|error dbClient = new (host = host, user = user, password = password, database = database, port = port, options = connectionOptions); if dbClient is error { From e67e000c9fb64b6bc3ca45dc4dede922307e05c3 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 5 Dec 2025 12:04:46 +0530 Subject: [PATCH 7/9] Update changelog --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index ab0af4f7e..8551bac2c 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Add documentation for generated client](https://github.com/ballerina-platform/ballerina-library/issues/8467) - [Support eager loading for get all methods in generated client](https://github.com/ballerina-platform/ballerina-library/issues/8488) - [Add support for selecting tables in ballerina persist pull command](https://github.com/ballerina-platform/ballerina-library/issues/8468) +- [Add support for individual init parameters support in persist clients](https://github.com/ballerina-platform/ballerina-library/issues/8505) ### Changed - [Fix an SQL script generation order issue when there are multiple associations](https://github.com/ballerina-platform/ballerina-library/issues/7921) From 7ec0cc3b81fd436bb1850e9e654226b3a5d96b32 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 5 Dec 2025 12:23:46 +0530 Subject: [PATCH 8/9] Address sonar cloud issues --- .../persist/PersistToolsConstants.java | 2 + .../syntax/clients/DbClientSyntax.java | 58 +++++++++++-------- .../syntax/clients/DbMockClientSyntax.java | 17 ++++-- .../syntax/sources/GSheetSyntaxTree.java | 5 +- .../syntax/sources/InMemorySyntaxTree.java | 5 +- 5 files changed, 55 insertions(+), 32 deletions(-) diff --git a/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java b/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java index 6b4afa736..41aff0a87 100644 --- a/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java +++ b/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java @@ -73,6 +73,8 @@ private PersistToolsConstants() {} public static final String CACHE_FILE = "persist-cache.txt"; public static final String UNSUPPORTED_TYPE = "Unsupported"; public static final String UNSUPPORTED_TYPE_COMMENT_START = "//" + UNSUPPORTED_TYPE + "["; + public static final String OPTIONS = "Options"; + public static final String CONNECTION_OPTIONS = "connectionOptions"; public static final Set SUPPORTED_DB_PROVIDERS = Set.of(SupportedDataSources.MYSQL_DB, SupportedDataSources.MSSQL_DB, SupportedDataSources.IN_MEMORY_TABLE, diff --git a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java index b749eb5c4..5e8cf3894 100644 --- a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java +++ b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbClientSyntax.java @@ -45,8 +45,20 @@ import java.util.List; import java.util.Objects; +import static io.ballerina.persist.PersistToolsConstants.BallerinaTypes.INT; +import static io.ballerina.persist.PersistToolsConstants.BallerinaTypes.STRING; +import static io.ballerina.persist.PersistToolsConstants.CONNECTION_OPTIONS; import static io.ballerina.persist.PersistToolsConstants.CUSTOM_SCHEMA_SUPPORTED_DB_PROVIDERS; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_DATABASE; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_DEFAULT_SCHEMA; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_HOST; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_PASSWORD; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_PORT; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_URL; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_USER; +import static io.ballerina.persist.PersistToolsConstants.EMPTY_VALUE; import static io.ballerina.persist.PersistToolsConstants.JDBC_CONNECTOR_MODULE_NAME; +import static io.ballerina.persist.PersistToolsConstants.OPTIONS; import static io.ballerina.persist.PersistToolsConstants.SUPPORTED_VIA_JDBC_CONNECTOR; import static io.ballerina.persist.nodegenerator.syntax.utils.BalSyntaxUtils.EntityType.TABLE; @@ -160,49 +172,49 @@ public FunctionDefinitionNode getInitFunction(Module entityModule) { // Add individual parameters based on datasource type switch (dataSource) { case PersistToolsConstants.SupportedDataSources.MYSQL_DB -> { - init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "host"); - init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("int"), "port"); - init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "user"); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), KEY_HOST); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode(INT), KEY_PORT); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), KEY_USER); init.addRequiredParameter( - TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "password"); + TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), KEY_PASSWORD); init.addRequiredParameter( - TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "database"); + TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), KEY_DATABASE); init.addDefaultableParameter( - TypeDescriptor.getQualifiedNameReferenceNode(this.dbNamePrefix, "Options"), - "connectionOptions", + TypeDescriptor.getQualifiedNameReferenceNode(this.dbNamePrefix, OPTIONS), + CONNECTION_OPTIONS, NodeParser.parseExpression("{}")); } case PersistToolsConstants.SupportedDataSources.POSTGRESQL_DB, PersistToolsConstants.SupportedDataSources.MSSQL_DB -> { - init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "host"); - init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("int"), "port"); - init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "user"); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), KEY_HOST); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode(INT), KEY_PORT); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), KEY_USER); init.addRequiredParameter( - TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "password"); + TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), KEY_PASSWORD); init.addRequiredParameter( - TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "database"); + TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), KEY_DATABASE); init.addDefaultableParameter( - TypeDescriptor.getQualifiedNameReferenceNode(this.dbNamePrefix, "Options"), - "connectionOptions", + TypeDescriptor.getQualifiedNameReferenceNode(this.dbNamePrefix, OPTIONS), + CONNECTION_OPTIONS, NodeParser.parseExpression("{}")); init.addDefaultableParameter( - TypeDescriptor.getOptionalTypeDescriptorNode("", "string"), - "defaultSchema", + TypeDescriptor.getOptionalTypeDescriptorNode(EMPTY_VALUE, STRING), + KEY_DEFAULT_SCHEMA, NodeParser.parseExpression("()")); } case PersistToolsConstants.SupportedDataSources.H2_DB -> { - init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), "url"); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), KEY_URL); init.addDefaultableParameter( - TypeDescriptor.getOptionalTypeDescriptorNode("", "string"), - "user", + TypeDescriptor.getOptionalTypeDescriptorNode(EMPTY_VALUE, STRING), + KEY_USER, NodeParser.parseExpression("()")); init.addDefaultableParameter( - TypeDescriptor.getOptionalTypeDescriptorNode("", "string"), - "password", + TypeDescriptor.getOptionalTypeDescriptorNode(EMPTY_VALUE, STRING), + KEY_PASSWORD, NodeParser.parseExpression("()")); init.addDefaultableParameter( - TypeDescriptor.getQualifiedNameReferenceNode(this.dbNamePrefix, "Options"), - "connectionOptions", + TypeDescriptor.getQualifiedNameReferenceNode(this.dbNamePrefix, OPTIONS), + CONNECTION_OPTIONS, NodeParser.parseExpression("{}")); } default -> throw new IllegalStateException("Unsupported datasource: " + dataSource); diff --git a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbMockClientSyntax.java b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbMockClientSyntax.java index 1dae02b1d..c7b375cf7 100644 --- a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbMockClientSyntax.java +++ b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/clients/DbMockClientSyntax.java @@ -36,6 +36,13 @@ import io.ballerina.persist.nodegenerator.syntax.constants.SyntaxTokenConstants; import io.ballerina.persist.nodegenerator.syntax.utils.BalSyntaxUtils; +import static io.ballerina.persist.PersistToolsConstants.BallerinaTypes.STRING; +import static io.ballerina.persist.PersistToolsConstants.CONNECTION_OPTIONS; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_PASSWORD; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_URL; +import static io.ballerina.persist.PersistToolsConstants.DBConfigs.KEY_USER; +import static io.ballerina.persist.PersistToolsConstants.OPTIONS; + public class DbMockClientSyntax implements ClientSyntax { private final String dbNamePrefix; private final String dbSpecifics; @@ -71,16 +78,16 @@ public FunctionDefinitionNode getInitFunction(Module entityModule) { init.addQualifiers(new String[] { BalSyntaxConstants.KEYWORD_PUBLIC, BalSyntaxConstants.KEYWORD_ISOLATED }); init.addReturns(TypeDescriptor.getOptionalTypeDescriptorNode(BalSyntaxConstants.EMPTY_STRING, BalSyntaxConstants.PERSIST_ERROR)); - init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode("string"), - "url"); + init.addRequiredParameter(TypeDescriptor.getBuiltinSimpleNameReferenceNode(STRING), + KEY_URL); init.addDefaultableParameter(TypeDescriptor.getOptionalTypeDescriptorNode(BalSyntaxConstants.EMPTY_STRING, - "string"), "user", NodeFactory.createNilLiteralNode( + STRING), KEY_USER, NodeFactory.createNilLiteralNode( SyntaxTokenConstants.SYNTAX_TREE_OPEN_PAREN, SyntaxTokenConstants.SYNTAX_TREE_CLOSE_PAREN)); init.addDefaultableParameter(TypeDescriptor.getOptionalTypeDescriptorNode(BalSyntaxConstants.EMPTY_STRING, - "string"), "password", NodeFactory.createNilLiteralNode( + STRING), KEY_PASSWORD, NodeFactory.createNilLiteralNode( SyntaxTokenConstants.SYNTAX_TREE_OPEN_PAREN, SyntaxTokenConstants.SYNTAX_TREE_CLOSE_PAREN)); init.addDefaultableParameter(TypeDescriptor.getOptionalTypeDescriptorNode("jdbc", - "Options"), "connectionOptions", NodeFactory.createNilLiteralNode( + OPTIONS), CONNECTION_OPTIONS, NodeFactory.createNilLiteralNode( SyntaxTokenConstants.SYNTAX_TREE_OPEN_PAREN, SyntaxTokenConstants.SYNTAX_TREE_CLOSE_PAREN)); init.addStatement(NodeParser.parseStatement(String.format(this.initDbClientMethodTemplate, this.dbNamePrefix))); IfElse errorCheck = new IfElse(NodeParser.parseExpression(String.format( diff --git a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/sources/GSheetSyntaxTree.java b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/sources/GSheetSyntaxTree.java index 2f85a1308..f71b05e2b 100644 --- a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/sources/GSheetSyntaxTree.java +++ b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/sources/GSheetSyntaxTree.java @@ -49,6 +49,7 @@ import java.util.Locale; import java.util.Map; +import static io.ballerina.persist.PersistToolsConstants.BallerinaTypes.STRING; import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.CLIENT_NAME; /** @@ -99,7 +100,7 @@ public io.ballerina.compiler.syntax.tree.SyntaxTree getClientSyntax(Module entit BalSyntaxConstants.KEYWORD_ISOLATED }); query.addReturns(TypeDescriptor.getSimpleNameReferenceNode("record{}[]|persist:Error")); query.addRequiredParameter(TypeDescriptor.getSimpleNameReferenceNode("record{}"), "value"); - query.addRequiredParameter(TypeDescriptor.getArrayTypeDescriptorNode("string"), + query.addRequiredParameter(TypeDescriptor.getArrayTypeDescriptorNode(STRING), BalSyntaxConstants.KEYWORD_FIELDS); query.addStatement(NodeParser.parseStatement(entry.getValue())); clientObject.addMember(query.getFunctionDefinitionNode(), true); @@ -182,7 +183,7 @@ private FunctionDefinitionNode[] createQueryFunction(Entity entity) { query.addQualifiers(new String[] { BalSyntaxConstants.KEYWORD_PRIVATE, BalSyntaxConstants.KEYWORD_ISOLATED }); query.addReturns(TypeDescriptor.getSimpleNameReferenceNode(BalSyntaxConstants.QUERY_RETURN + "|" + BalSyntaxConstants.PERSIST_ERROR)); - query.addRequiredParameter(TypeDescriptor.getArrayTypeDescriptorNode("string"), + query.addRequiredParameter(TypeDescriptor.getArrayTypeDescriptorNode(STRING), BalSyntaxConstants.KEYWORD_FIELDS); Function queryOne = new Function(String.format(BalSyntaxConstants.QUERY_ONE, nameInCamelCase), diff --git a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/sources/InMemorySyntaxTree.java b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/sources/InMemorySyntaxTree.java index 5ac955770..f43d924c1 100644 --- a/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/sources/InMemorySyntaxTree.java +++ b/persist-core/src/main/java/io/ballerina/persist/nodegenerator/syntax/sources/InMemorySyntaxTree.java @@ -43,6 +43,7 @@ import java.util.List; import java.util.Locale; +import static io.ballerina.persist.PersistToolsConstants.BallerinaTypes.STRING; import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.CLIENT_NAME; import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.IN_MEMORY_CLIENT_NAME; @@ -117,7 +118,7 @@ private static io.ballerina.compiler.syntax.tree.SyntaxTree getSyntaxTree( query.addQualifiers(new String[] { BalSyntaxConstants.KEYWORD_ISOLATED }); query.addReturns(TypeDescriptor.getSimpleNameReferenceNode("record{}[]")); query.addRequiredParameter(TypeDescriptor.getSimpleNameReferenceNode("record{}"), "value"); - query.addRequiredParameter(TypeDescriptor.getArrayTypeDescriptorNode("string"), + query.addRequiredParameter(TypeDescriptor.getArrayTypeDescriptorNode(STRING), BalSyntaxConstants.KEYWORD_FIELDS); query.addStatement(NodeParser.parseStatement(queryMethod.getMethodBody())); functionsList.add(query.getFunctionDefinitionNode()); @@ -157,7 +158,7 @@ private static FunctionDefinitionNode[] createQueryFunctions(Entity entity) { SyntaxKind.OBJECT_METHOD_DEFINITION); query.addQualifiers(new String[] { BalSyntaxConstants.KEYWORD_ISOLATED }); query.addReturns(TypeDescriptor.getSimpleNameReferenceNode(BalSyntaxConstants.QUERY_RETURN)); - query.addRequiredParameter(TypeDescriptor.getArrayTypeDescriptorNode("string"), + query.addRequiredParameter(TypeDescriptor.getArrayTypeDescriptorNode(STRING), BalSyntaxConstants.KEYWORD_FIELDS); query.addStatement(NodeParser.parseStatement(clonedTables)); From d8b6399fca718f8ccc583dcdeda1da950aa6006e Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Mon, 8 Dec 2025 13:41:17 +0530 Subject: [PATCH 9/9] Add review suggestions --- .../output/tool_test_add_22_init_params_mysql/Ballerina.toml | 2 +- .../tool_test_add_23_init_params_postgresql/Ballerina.toml | 2 +- .../output/tool_test_add_24_init_params_mssql/Ballerina.toml | 2 +- .../output/tool_test_add_25_init_params_h2/Ballerina.toml | 2 +- persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java | 2 +- persist-cli/src/main/resources/persist-options-schema.json | 2 +- .../main/java/io/ballerina/persist/PersistToolsConstants.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/Ballerina.toml index 6c7486dd7..eb2997f3c 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/Ballerina.toml +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_22_init_params_mysql/Ballerina.toml @@ -8,7 +8,7 @@ distribution = "2201.13.0" id = "generate-db-client" targetModule = "persist_add_init_params_mysql.entities" options.datastore = "mysql" -options.initParams = true +options.withInitParams = true filePath = "persist/model.bal" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/Ballerina.toml index 25c7c5dc1..d51d9d399 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/Ballerina.toml +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_23_init_params_postgresql/Ballerina.toml @@ -8,7 +8,7 @@ distribution = "2201.13.0" id = "generate-db-client" targetModule = "persist_add_init_params_postgresql.entities" options.datastore = "postgresql" -options.initParams = true +options.withInitParams = true filePath = "persist/model.bal" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/Ballerina.toml index e068f99e2..2d6ee1211 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/Ballerina.toml +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_24_init_params_mssql/Ballerina.toml @@ -8,7 +8,7 @@ distribution = "2201.13.0" id = "generate-db-client" targetModule = "persist_add_init_params_mssql.entities" options.datastore = "mssql" -options.initParams = true +options.withInitParams = true filePath = "persist/model.bal" diff --git a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/Ballerina.toml b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/Ballerina.toml index 01eb34ec4..d8a1dba52 100644 --- a/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/Ballerina.toml +++ b/persist-cli-tests/src/test/resources/test-src/output/tool_test_add_25_init_params_h2/Ballerina.toml @@ -8,7 +8,7 @@ distribution = "2201.13.0" id = "generate-db-client" targetModule = "persist_add_init_params_h2.entities" options.datastore = "h2" -options.initParams = true +options.withInitParams = true filePath = "persist/model.bal" diff --git a/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java b/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java index 7841e1fd9..fa5bb1cb6 100644 --- a/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java +++ b/persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java @@ -191,7 +191,7 @@ private static NodeList populateBallerinaNodeList true, null)); } if (initParams) { - moduleMembers = moduleMembers.add(SampleNodeGenerator.createBooleanKV("options.initParams", + moduleMembers = moduleMembers.add(SampleNodeGenerator.createBooleanKV("options.withInitParams", true, null)); } moduleMembers = moduleMembers.add(SampleNodeGenerator.createStringKV("filePath", "persist/model.bal", null)); diff --git a/persist-cli/src/main/resources/persist-options-schema.json b/persist-cli/src/main/resources/persist-options-schema.json index b738e280a..3d858b4c0 100644 --- a/persist-cli/src/main/resources/persist-options-schema.json +++ b/persist-cli/src/main/resources/persist-options-schema.json @@ -16,4 +16,4 @@ } }, "additionalProperties": false -} \ No newline at end of file +} diff --git a/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java b/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java index 41aff0a87..ba3494b5e 100644 --- a/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java +++ b/persist-core/src/main/java/io/ballerina/persist/PersistToolsConstants.java @@ -60,7 +60,7 @@ private PersistToolsConstants() {} public static final String OPTION_DATASTORE = "options.datastore"; public static final String OPTION_TEST_DATASTORE = "options.testDatastore"; public static final String OPTION_EAGER_LOADING = "options.eagerLoading"; - public static final String OPTION_INIT_PARAMS = "options.initParams"; + public static final String OPTION_INIT_PARAMS = "options.withInitParams"; public static final String MIGRATIONS = "migrations"; public static final String BALLERINA_MYSQL_DRIVER_NAME = "ballerinax/mysql.driver"; public static final String BALLERINA_MSSQL_DRIVER_NAME = "ballerinax/mssql.driver";