Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add introspection support for PostgreSQL and MSSQL data stores #369

Merged
merged 31 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
35962a6
Add columns query and tables query for postgresql
hasathcharu Apr 16, 2024
f67f5e1
Add indexes query for postgresql
hasathcharu Apr 16, 2024
5c814ae
Add indexes foreign key query for postgresql
hasathcharu Apr 17, 2024
b1e2878
Add get enums query
hasathcharu Apr 17, 2024
424df92
Refactor introspect package
hasathcharu Apr 17, 2024
b666887
Create test cases for pull command with postgresql
hasathcharu Apr 18, 2024
4b4a701
Fix driver issues and refine SQL queries
hasathcharu Apr 18, 2024
18a029a
Create test cases for postgresql
hasathcharu Apr 19, 2024
6f6e7fb
Fix failing test cases
hasathcharu Apr 22, 2024
e06be49
Add the MsSqlIntrospector class
hasathcharu Apr 29, 2024
fad9941
Configure MSSQL as a supported datastore
hasathcharu Apr 30, 2024
6dead9d
Add test cases to the output folder
hasathcharu Apr 30, 2024
6715599
WIP -driver issues
hasathcharu Apr 30, 2024
6696a43
Temporary driver issue fix and enum type regex
hasathcharu May 2, 2024
bdbf77b
Create draft test cases for MsSql
hasathcharu May 2, 2024
42882b1
Fix minor issues in test suite
hasathcharu May 2, 2024
ea95b5a
Fix minor bugs encountered during testing for mssql introspection
hasathcharu May 2, 2024
d63ef87
Improve enum support for postgres in introspection
hasathcharu May 3, 2024
ff4d7af
Fix minor issues and enable all tests
hasathcharu May 3, 2024
7ff7156
Add support for BIT data type in MsSql
hasathcharu May 3, 2024
0c2262e
Fix client generation issue
hasathcharu May 3, 2024
1a14dd7
Add test cases
hasathcharu May 3, 2024
4161dca
Fix recreation of unique Index
hasathcharu May 6, 2024
674406b
Fix issue with script.sql
hasathcharu May 6, 2024
72c2882
Fix code quality issues and update changelog
hasathcharu May 6, 2024
28a61ac
Fix failing test cases
hasathcharu May 6, 2024
53f7ce3
Update specification
hasathcharu May 6, 2024
9f0d723
Merge branch 'main' into introspection-mssql
daneshk May 7, 2024
3f72ca1
Fix line ending issues
hasathcharu May 7, 2024
3cfc688
Fix formatting issues
hasathcharu May 7, 2024
359b794
Make suggested changes
hasathcharu May 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
11 changes: 11 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Changed
- Fixes an issue where client API is still generated even if all entities contain unsupported field(s)
- Fixes an issue where unique indexes are declared twice in script.sql in one-to-one associations
- Fixes an issue where the cardinality of the first association is taken as the cardinality of all the other associations between same entities

### Added
- [Add introspection support for PostgreSQL databases](https://github.com/ballerina-platform/ballerina-library/issues/6333)
- [Add introspection support for MSSQL databases](https://github.com/ballerina-platform/ballerina-library/issues/6460)

## [1.3.0] - 2024-05-03

### Changed
- [Refactor migrate command and test cases to support more scenarios](https://github.com/ballerina-platform/ballerina-library/issues/6189)
- [Fix a bug in the `migrate` command where tables with `@sql:Name` annotations are recreated](https://github.com/ballerina-platform/ballerina-library/issues/6374)
Expand Down
16 changes: 8 additions & 8 deletions docs/spec/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
_Owners_: @daneshk @sahanHe
_Reviewers_: @daneshk
_Created_: 2022/07/26
_Updated_: 2024/04/10
_Updated_: 2024/05/06
_Edition_: Swan Lake

## Introduction
Expand Down Expand Up @@ -214,13 +214,13 @@ Behaviour of the `push` command,
```bash
bal persist pull --datastore mysql --host localhost --port 3306 --user root --database persist
```
| Command Parameter | Description | Mandatory | Default Value |
|:-----------------:|:--------------------------------------------------------------------------------:|:---------:|:-------------:|
| --datastore | used to indicate the preferred data store. Currently, only 'mysql' is supported. | No | mysql |
| --host | used to indicate the database host | Yes | None |
| --port | used to indicate the database port | No | 3306 |
| --user | used to indicate the database user | Yes | None |
| --database | used to indicate the database name | Yes | None |
| Command Parameter | Description | Mandatory | Default Value |
|:-----------------:|:---------------------------------------------------------------------------------------:|:---------:|:------------------:|
| --datastore | used to indicate the preferred data store. supports `mysql`, `postgresql`, and `mssql`. | No | mysql |
| --host | used to indicate the database host | Yes | None |
| --port | used to indicate the database port | No | datastore specific |
| --user | used to indicate the database user | Yes | None |
| --database | used to indicate the database name | Yes | None |

This command will introspect the schema of the database and create a `model.bal` file with the entities and relations based on the schema of the database. The database configuration should be provided as command-line arguments.

Expand Down
5 changes: 0 additions & 5 deletions examples/hospital_unsupported/Ballerina.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,3 @@ url = "https://maven.wso2.org/nexus/content/groups/public/"
id="wso2-nexus-snapshot"
url = "https://maven.wso2.org/nexus/content/repositories/snapshots/"

[[platform.java17.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "persist.sql-native"
version = "1.3.0-SNAPSHOT"

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,25 @@ public void testGenerateIgnoreSQLAnnotationsForRedis() {
assertGeneratedSources("tool_test_generate_104_redis");
}

@Test(enabled = true)
@Description("There are entities with 'sql' annotations")
public void testGenerateWithAllUnsupportedEntities() {
updateOutputBallerinaToml("tool_test_generate_105");
executeGenerateCommand("tool_test_generate_105", "mysql", "entities");
assertGeneratedSources("tool_test_generate_105");
}

@Test(enabled = true)
@Description("The model has a one-to-one relation where the unique index name is managed")
public void testGenerateEntitiesWithUniqueIndexAnnotatedForeignKeys() {
String subDir = "tool_test_generate_106";
updateOutputBallerinaToml(subDir);
executeGenerateCommand(subDir, "mysql", "entities");
executeGenerateCommand(subDir, "mssql", "mssql_entities");
executeGenerateCommand(subDir, "postgresql", "postgresql_entities");
assertGeneratedSources(subDir);
}

private void updateOutputBallerinaToml(String fileName) {
String tomlFileName = "Ballerina.toml";
Path filePath = Paths.get("src", "test", "resources", "test-src", "output", fileName, tomlFileName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
import java.util.ArrayList;
import java.util.Locale;

import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.CREATE_DATABASE_SQL_FORMAT;
import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.DROP_DATABASE_SQL_FORMAT;
import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.JDBC_URL_WITH_DATABASE_MSSQL;
import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.JDBC_URL_WITH_DATABASE_MYSQL;
import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.JDBC_URL_WITH_DATABASE_POSTGRESQL;
import static io.ballerina.persist.tools.utils.GeneratedSourcesTestUtils.GENERATED_SOURCES_DIRECTORY;
import static io.ballerina.persist.tools.utils.GeneratedSourcesTestUtils.INPUT_RESOURCES_DIRECTORY;
import static io.ballerina.projects.util.ProjectConstants.BALLERINA_TOML;
Expand Down Expand Up @@ -201,17 +206,50 @@ private static void validateTable(Connection connection, PersistTable persistTab
}
}

public static void createFromDatabaseScript(String packageName, String datasource,
public static void resetPostgreSqlDatabase(DatabaseConfiguration dbConfig, boolean recreate) {

String url = String.format(JDBC_URL_WITH_DATABASE_POSTGRESQL, "postgresql", dbConfig.getHost(),
dbConfig.getPort(), "postgres");
resetDatabase(dbConfig, recreate, url);
}

public static void resetMsSqlDatabase(DatabaseConfiguration dbConfig, boolean recreate) {

String url = String.format(JDBC_URL_WITH_DATABASE_MSSQL,
PersistToolsConstants.SupportedDataSources.MSSQL_DB_ALT, dbConfig.getHost(), dbConfig.getPort(),
"master");
resetDatabase(dbConfig, recreate, url);
}

private static void resetDatabase(DatabaseConfiguration dbConfig, boolean recreate, String url) {
try (Connection connection = DriverManager.getConnection(url, dbConfig.getUsername(), dbConfig.getPassword())) {
try (Statement statement = connection.createStatement()) {
statement.execute(String.format(DROP_DATABASE_SQL_FORMAT, dbConfig.getDatabase()));
if (recreate) {
statement.execute(String.format(CREATE_DATABASE_SQL_FORMAT, dbConfig.getDatabase()));
}
statement.executeBatch();
PrintStream outStream = System.out;
outStream.println("Database reset successfully");
}
} catch (SQLException e) {
errStream.println("Failed to reset database: " + e.getMessage());
}
}

public static void createFromDatabaseScript(String packageName, String datastore,
DatabaseConfiguration dbConfig) {
Path sourcePath = Paths.get(INPUT_RESOURCES_DIRECTORY, packageName);

String url;
if (datasource.equals(PersistToolsConstants.SupportedDataSources.MSSQL_DB)) {
url = String.format("jdbc:sqlserver://%s:%s", dbConfig.getHost(), dbConfig.getPort());
} else if (datasource.equals(PersistToolsConstants.SupportedDataSources.POSTGRESQL_DB)) {
url = String.format("jdbc:postgresql://%s:%s/", dbConfig.getHost(), dbConfig.getPort());
if (datastore.equals(PersistToolsConstants.SupportedDataSources.MSSQL_DB)) {
url = String.format(JDBC_URL_WITH_DATABASE_MSSQL, PersistToolsConstants.SupportedDataSources.MSSQL_DB_ALT,
dbConfig.getHost(), dbConfig.getPort(), dbConfig.getDatabase());
} else if (datastore.equals(PersistToolsConstants.SupportedDataSources.POSTGRESQL_DB)) {
url = String.format(JDBC_URL_WITH_DATABASE_POSTGRESQL, "postgresql", dbConfig.getHost(),
dbConfig.getPort(), dbConfig.getDatabase());
} else {
url = String.format("jdbc:mysql://%s:%s", dbConfig.getHost(), dbConfig.getPort());
url = String.format(JDBC_URL_WITH_DATABASE_MYSQL, "mysql", dbConfig.getHost(), dbConfig.getPort(), "mysql");
}

try (Connection connection = DriverManager.getConnection(url, dbConfig.getUsername(), dbConfig.getPassword())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
distribution = "2201.8.4"
name = "tool_test_generate_105"
org = "wso2"
version = "0.1.0"

[build-options]
observabilityIncluded = true

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/io;

public function main() {
io:println("Hello, World!");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/persist as _;
import ballerinax/persist.sql;

public enum UserGender {
MALE,
FEMALE
}

public type User record {|
readonly int id;
string name;
UserGender gender;
string nic;
decimal? salary;
Car[] cars;
Car? drives;
//Unsupported[set('a','b','c')] setType;
|};

public type Car record {|
readonly int id;
string name;
string model;
@sql:Index {name: ["ownerId"]}
int ownerId;
@sql:Relation {keys: ["ownerId"]}
User owner;
@sql:Name {value: "DRIVER_ID"}
int driverId;
@sql:Relation {keys: ["driverId"]}
User driver;
//Unsupported[set('a','b','c')] setType;
|};
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
distribution = "2201.8.4"
name = "tool_test_generate_106"
org = "wso2"
version = "0.1.0"

[build-options]
observabilityIncluded = true


Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/io;

public function main() {
io:println("Hello, World!");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/persist as _;
import ballerinax/persist.sql;


public type User record {|
readonly int id;
string name;
string nic;
decimal? salary;
Car? drives;
|};

public type Car record {|
readonly int id;
string name;
string model;
@sql:UniqueIndex
int driverId;
@sql:Relation {keys: ["driverId"]}
User driver;
|};

public type User2 record {|
readonly int id;
readonly string nic;
string name;
decimal? salary;
Car2? drives;
|};

public type Car2 record {|
readonly int id;
string name;
string model;
@sql:UniqueIndex {name: "driver_idx"}
int driverId;
@sql:UniqueIndex {name: "driver_idx"}
string driverNic;
@sql:Relation {keys: ["driverId", "driverNic"]}
User2 driver;
|};
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
distribution = "2201.8.4"
name = "tool_test_pull_28_postgresql"
org = "wso2"
version = "0.1.0"

[build-options]
observabilityIncluded = true

[[platform.java17.dependency]]
artifactId = "persist.sql-native"
groupId = "io.ballerina.stdlib"
version = "1.2.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/io;

public function main() {
io:println("Hello, World!");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-- Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
--
-- WSO2 LLC. licenses this file to you under the Apache License,
-- Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.

CREATE TABLE "User" (
"id" INT NOT NULL,
"name" VARCHAR(191) NOT NULL,
"gender" VARCHAR(6) CHECK ("gender" IN ('MALE', 'FEMALE')) NOT NULL,
"nic" VARCHAR(191) NOT NULL,
"salary" DECIMAL(65,30) NOT NULL,
PRIMARY KEY("id")
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
distribution = "2201.8.4"
name = "tool_test_pull_29_postgresql"
org = "wso2"
version = "0.1.0"

[build-options]
observabilityIncluded = true

[[platform.java17.dependency]]
artifactId = "persist.sql-native"
groupId = "io.ballerina.stdlib"
version = "1.2.0"
Loading
Loading