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 support for PostgreSQL databases #52

Merged
merged 13 commits into from
Nov 29, 2023
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,6 @@ Execute the commands below to build from source.

./gradlew clean build -Pgroups=<Comma separated groups/test cases>

**Tip:** The following groups of test cases are available.

| Groups | Test cases |
|:---------------:|:-----------------------------:|
| basic | basic |
| associations | associations <br> one-to-many |
| composite-keys | composite-keys |

5. To disable some specific test groups:

./gradlew clean build -Pdisable-groups=<Comma separated groups/test cases>
Expand Down
2 changes: 1 addition & 1 deletion ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ graalvmCompatible = true
groupId = "io.ballerina.stdlib"
artifactId = "persist.sql-native"
version = "1.2.1"
path = "../native/build/libs/persist.sql-native-1.2.1.jar"
path = "../native/build/libs/persist.sql-native-1.2.1-SNAPSHOT.jar"

[[platform.java17.dependency]]
groupId = "io.ballerina.stdlib"
Expand Down
2 changes: 1 addition & 1 deletion ballerina/CompilerPlugin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ id = "persist.sql-compiler-plugin"
class = "io.ballerina.stdlib.persist.sql.compiler.PersistSqlCompilerPlugin"

[[dependency]]
path = "../compiler-plugin/build/libs/persist.sql-compiler-plugin-1.2.1.jar"
path = "../compiler-plugin/build/libs/persist.sql-compiler-plugin-1.2.1-SNAPSHOT.jar"

[[dependency]]
path = "./lib/persist-native-1.2.0.jar"
41 changes: 35 additions & 6 deletions ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

[ballerina]
dependencies-toml-version = "2"
distribution-version = "2201.8.0"
distribution-version = "2201.8.3-20231119-151400-9cb79da7"

[[package]]
org = "ballerina"
Expand All @@ -23,7 +23,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "cache"
version = "3.7.0"
version = "3.7.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "constraint"},
Expand Down Expand Up @@ -66,7 +66,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
version = "2.10.0"
version = "2.10.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
Expand Down Expand Up @@ -105,6 +105,7 @@ dependencies = [
org = "ballerina"
name = "jballerina.java"
version = "0.0.0"
scope = "testOnly"
modules = [
{org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"}
]
Expand Down Expand Up @@ -294,7 +295,7 @@ modules = [
[[package]]
org = "ballerina"
name = "sql"
version = "1.11.0"
version = "1.11.1"
dependencies = [
{org = "ballerina", name = "io"},
{org = "ballerina", name = "jballerina.java"},
Expand Down Expand Up @@ -332,6 +333,7 @@ modules = [
org = "ballerina"
name = "time"
version = "2.4.0"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "jballerina.java"}
]
Expand Down Expand Up @@ -385,7 +387,7 @@ modules = [
[[package]]
org = "ballerinax"
name = "mssql"
version = "1.11.0"
version = "1.11.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "crypto"},
Expand Down Expand Up @@ -446,9 +448,36 @@ dependencies = [
{org = "ballerinax", name = "mssql"},
{org = "ballerinax", name = "mssql.driver"},
{org = "ballerinax", name = "mysql"},
{org = "ballerinax", name = "mysql.driver"}
{org = "ballerinax", name = "mysql.driver"},
{org = "ballerinax", name = "postgresql"},
{org = "ballerinax", name = "postgresql.driver"}
]
modules = [
{org = "ballerinax", packageName = "persist.sql", moduleName = "persist.sql"}
]

[[package]]
org = "ballerinax"
name = "postgresql"
version = "1.11.0"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "crypto"},
{org = "ballerina", name = "io"},
{org = "ballerina", name = "jballerina.java"},
{org = "ballerina", name = "sql"},
{org = "ballerina", name = "time"}
]
modules = [
{org = "ballerinax", packageName = "postgresql", moduleName = "postgresql"}
]

[[package]]
org = "ballerinax"
name = "postgresql.driver"
version = "1.5.0"
scope = "testOnly"
modules = [
{org = "ballerinax", packageName = "postgresql.driver", moduleName = "postgresql.driver"}
]

39 changes: 22 additions & 17 deletions ballerina/Module.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

This module provides relation database support for the `bal persist` feature, which provides functionality to store and query data from a relational database conveniently through a data model instead of using SQL query language.

Currently, this package supports only MySQL as the relational database. However, you are planning to add support for other relational databases such as PostgreSQL, Oracle, and Microsoft SQL Server.
Currently, this package supports MySQL, MSSQL, PostgreSQL as the relational database. However, we are also planning to add support for other relational databases such as Oracle.

The MySQL data store is a relational database management system that stores data in tables. The MySQL data store is useful for storing data in a relational format. The MySQL data store is not the default data store for the `bal persist` feature. Therefore, you need to explicitly specify the data store when initializing `bal persist` in your application. as follows,
The MySQL, MSSQL, PostgreSQL data stores are relational database management systems that stores data in tables. None of these data stores is the default data store for the `bal persist` feature. Therefore, you need to explicitly specify the data store when initializing `bal persist` in your application. as follows,

```
$ bal persist init --datastore mysql
$ bal persist init --datastore mssql
$ bal persist init --datastore postgresql
```

## Supported Ballerina Types
Expand All @@ -33,13 +35,13 @@ If you want to map a Ballerina type to a different SQL type or want to change th
## Configuration
You need to set values for the following basic configuration parameters in the `Config.toml` file in your project to use the MySQL data store.

| Parameter | Description |
|:----------:|:-------------------------------------:|
| host | The hostname of the MySQL server. |
| port | The port of the MySQL server. |
| username | The username of the MySQL server. |
| password | The password of the MySQL server. |
| database | The name of the database to be used. |
| Parameter | Description |
|:----------:|:------------------------------------:|
| host | The hostname of the DB server. |
| port | The port of the DB server. |
| username | The username of the DB server. |
| password | The password of the DB server. |
| database | The name of the database to be used. |

The following is a sample `Config.toml` file with the MySQL data store configuration. This is generated by the `bal persist generate` command.

Expand All @@ -52,20 +54,23 @@ password = ""
database = ""
```

Additionally, you can set values for advanced configuration parameters in the `Config.toml` file in your project to use the MySQL data store. Please refer to the [MySQL Connector documentation](https://lib.ballerina.io/ballerinax/mysql/latest) for more information on these parameters.
Additionally, you can set values for advanced configuration parameters in the `Config.toml` file in your project to use the data store. Please refer to the individual connection documentation for more information on these parameters.
- [MySQL Connector documentation](https://lib.ballerina.io/ballerinax/mysql/latest)
- [MSSQL Connector documentation](https://lib.ballerina.io/ballerinax/mssql/latest)
- [PostgreSQL Connector documentation](https://lib.ballerina.io/ballerinax/postgresql/latest)

## How to Setup

### Set up a MySQL server instance
Select one of the methods below to set up a MySQL server.
### Set up a MySQL/MSSQL/PostgreSQL server instance
Select one of the methods below to set up a DB server.

> Tip: Keep the connection and authentication details for connecting to the MySQL server including the hostname, port, username, and password noted down.
> Tip: Keep the connection and authentication details for connecting to the DB server including the hostname, port, username, and password noted down.

* Install a MySQL server on your machine locally by downloading and installing MySQL for different platforms.
* Install a DB server on your machine locally by downloading and installing the server software for different platforms.
* Use a cross-platform web-server solution such as XAMPP or WampServer.
* Use Docker to create a MySQL server deployment.
* Use a cloud-based MySQL solution such as Google’s CloudSQL, Amazon’s RDS for MySQL, or Microsoft’s Azure Database for MySQL.
* Use Docker to create a DB server deployment.
* Use a cloud-based DB solution such as Google’s CloudSQL, Amazon’s RDS, or Microsoft’s Azure Database.

### Run the script to create the database and tables

The `bal persist generate` command generates a script.sql file in the generated directory of your project. This file contains the SQL script to create the tables required for your application. You need to run this script to create the database and tables in the MySQL server using a MySQL client such as MySQL Workbench or the MySQL command line client.
The `bal persist generate` command generates a script.sql file in the generated directory of your project. This file contains the SQL script to create the tables required for your application. You need to run this script to create the database and tables in the DB server using a DB client or a command line client.
48 changes: 27 additions & 21 deletions ballerina/Package.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
## Package overview
# Module Overview

This package provides relation database support for the `bal persist` feature, which provides functionality to store and query data from a relational database conveniently through a data model instead of using SQL query language.
This module provides relation database support for the `bal persist` feature, which provides functionality to store and query data from a relational database conveniently through a data model instead of using SQL query language.

Currently, this package supports only MySQL as the relational database. However, we are planning to add support for other relational databases such as PostgreSQL, Oracle, and Microsoft SQL Server.
Currently, this package supports MySQL, MSSQL, PostgreSQL as the relational database. However, we are also planning to add support for other relational databases such as Oracle.

The MySQL data store is a relational database management system that stores data in tables. The MySQL data store is useful for storing data in a relational format. The MySQL data store is not the default data store for the `bal persist` feature. Therefore, you need to explicitly specify the data store when initializing `bal persist` in your application. as follows,
The MySQL, MSSQL, PostgreSQL data stores are relational database management systems that stores data in tables. None of these data stores is the default data store for the `bal persist` feature. Therefore, you need to explicitly specify the data store when initializing `bal persist` in your application. as follows,

```
$ bal persist init --datastore mysql
$ bal persist init --datastore mssql
$ bal persist init --datastore postgresql
```

## Supported Ballerina Types
Expand All @@ -26,21 +28,22 @@ The following table lists the Ballerina types supported by the MySQL data store
| time:TimeOfDay | TIME |
| time:Utc | TIMESTAMP |
| time:Civil | DATETIME |
| enum | ENUM |

If you want to map a Ballerina type to a different SQL type or want to change the default length of a SQL type, you can change it in the `script.sql` file generated by the `persist generate` command before executing the script.
If you want to map a Ballerina type to a different SQL type or want to change the default length of a SQL type, you can change it in the `script.sql` file generated by the `bal persist generate` command before executing the script.

## Configuration
You need to set values for the following basic configuration parameters in the `Config.toml` file in your project to use the MySQL data store.

| Parameter | Description |
|:----------:|:-------------------------------------:|
| host | The hostname of the MySQL server. |
| port | The port of the MySQL server. |
| username | The username of the MySQL server. |
| password | The password of the MySQL server. |
| database | The name of the database to be used. |
| Parameter | Description |
|:----------:|:------------------------------------:|
| host | The hostname of the DB server. |
| port | The port of the DB server. |
| username | The username of the DB server. |
| password | The password of the DB server. |
| database | The name of the database to be used. |

The following is a sample `Config.toml` file with the MySQL data store configuration. This is generated by the `persist generate` command.
The following is a sample `Config.toml` file with the MySQL data store configuration. This is generated by the `bal persist generate` command.

```toml
[<packageName>.<moduleName>]
Expand All @@ -51,23 +54,26 @@ password = ""
database = ""
```

Additionally, you can set values for the following advanced configuration parameters in the Config.toml file in your project to use the MySQL data store. Please refer to the MySQL Connector documentation for more information on these parameters.
Additionally, you can set values for advanced configuration parameters in the `Config.toml` file in your project to use the data store. Please refer to the individual connection documentation for more information on these parameters.
- [MySQL Connector documentation](https://lib.ballerina.io/ballerinax/mysql/latest)
- [MSSQL Connector documentation](https://lib.ballerina.io/ballerinax/mssql/latest)
- [PostgreSQL Connector documentation](https://lib.ballerina.io/ballerinax/postgresql/latest)

## How to Setup

### Set up a MySQL server instance
Select one of the methods below to set up a MySQL server.
### Set up a MySQL/MSSQL/PostgreSQL server instance
Select one of the methods below to set up a DB server.

> Tip: Keep the connection and authentication details for connecting to the MySQL server including the hostname, port, username, and password noted down.
> Tip: Keep the connection and authentication details for connecting to the DB server including the hostname, port, username, and password noted down.

* Install a MySQL server on your machine locally by downloading and installing MySQL for different platforms.
* Install a DB server on your machine locally by downloading and installing the server software for different platforms.
* Use a cross-platform web-server solution such as XAMPP or WampServer.
* Use Docker to create a MySQL server deployment.
* Use a cloud-based MySQL solution such as Google’s CloudSQL, Amazon’s RDS for MySQL, or Microsoft’s Azure Database for MySQL.
* Use Docker to create a DB server deployment.
* Use a cloud-based DB solution such as Google’s CloudSQL, Amazon’s RDS, or Microsoft’s Azure Database.

### Run the script to create the database and tables

The `bal persist generate` command generates a script.sql file in the generated directory of your project. This file contains the SQL script to create the tables required for your application. You need to run this script to create the database and tables in the MySQL server using a MySQL client such as MySQL Workbench or the MySQL command line client.
The `bal persist generate` command generates a script.sql file in the generated directory of your project. This file contains the SQL script to create the tables required for your application. You need to run this script to create the database and tables in the DB server using a DB client or a command line client.

## Report issues

Expand Down
64 changes: 64 additions & 0 deletions ballerina/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -262,17 +262,81 @@ task stopMSSQLTestDockerContainer() {
}
}

task createPostgreSQLTestDockerImage(type: Exec) {
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
def standardOutput = new ByteArrayOutputStream()
commandLine 'sh', '-c', "docker build -f ${project.projectDir}/tests/resources/postgresql/Dockerfile -t ballerina-persist-postgresql" +
" -q ${project.projectDir}/tests/resources/postgresql"
doLast {
checkExecResult(executionResult, 'Error', standardOutput)
sleep(10 * 1000)
}
}
}

def checkPostgreSQLTestDockerContainerStatus(containerName) {
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
try {
return exec {
commandLine 'sh', '-c', "docker exec ${containerName} psql -U postgres -h localhost -p 5432"
}.exitValue
} catch (all) {
return 1;
}
}
}

task startPostgreSQLTestDockerContainer(type: Exec) {
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
def standardOutput = new ByteArrayOutputStream()
commandLine 'sh', '-c',
"docker run --rm -d --name ballerina-persist-postgresql -p 5432:5432 -d ballerina-persist-postgresql"
def healthCheck = 1;
def counter = 0;
doLast {
checkExecResult(executionResult, 'Error', standardOutput)
while (healthCheck != 0 && counter < 12) {
sleep(5 * 1000)
healthCheck = checkPostgreSQLTestDockerContainerStatus("ballerina-persist-postgresql")
counter = counter + 1;
}
if (healthCheck != 0) {
throw new GradleException("Docker container 'ballerina-persist-postgresql' health test exceeded timeout!")
}
}
}
}

task stopPostgreSQLTestDockerContainer() {
doLast {
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
try {
def stdOut = new ByteArrayOutputStream()
exec {
commandLine 'sh', '-c', "docker stop ballerina-persist-postgresql"
standardOutput = stdOut
}
} catch (all) {
println("Process can safely ignore stopPostgreSQLTestDockerContainer task")
}
}
}
}

updateTomlFiles.dependsOn copyStdlibs
startMySQLTestDockerContainer.dependsOn createMySQLTestDockerImage
startMSSQLTestDockerContainer.dependsOn createMSSQLTestDockerImage
startPostgreSQLTestDockerContainer.dependsOn createPostgreSQLTestDockerImage

build.dependsOn "generatePomFileForMavenPublication"
build.dependsOn ":${packageName}-compiler-plugin:build"
build.dependsOn ":${packageName}-native:build"
build.finalizedBy stopMySQLTestDockerContainer
build.finalizedBy stopMSSQLTestDockerContainer
build.finalizedBy stopPostgreSQLTestDockerContainer

test.dependsOn ":${packageName}-compiler-plugin:build"
test.dependsOn ":${packageName}-native:build"
test.dependsOn startMySQLTestDockerContainer
test.dependsOn startMSSQLTestDockerContainer
test.dependsOn startPostgreSQLTestDockerContainer
16 changes: 14 additions & 2 deletions ballerina/constants.bal
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public final DataSourceSpecifics & readonly MYSQL_SPECIFICS = {
constraintViolationErrorMessage: "a foreign key constraint fails",
duplicateEntryErrorMessage: "Duplicate entry",
duplicateKeyStartIndicator: ".Duplicate entry '",
duplicateKeyEndIndicator: "' for key"
duplicateKeyEndIndicator: "' for key",
columnIdentifier: ""
};

public final DataSourceSpecifics & readonly MSSQL_SPECIFICS = {
Expand All @@ -29,5 +30,16 @@ public final DataSourceSpecifics & readonly MSSQL_SPECIFICS = {
constraintViolationErrorMessage: "conflicted with the FOREIGN KEY constraint",
duplicateEntryErrorMessage: "Cannot insert duplicate key",
duplicateKeyStartIndicator: "The duplicate key value is (",
duplicateKeyEndIndicator: ").."
duplicateKeyEndIndicator: ")..",
columnIdentifier: ""
};

public final DataSourceSpecifics & readonly POSTGRESQL_SPECIFICS = {
quoteOpen: "",
quoteClose: "",
constraintViolationErrorMessage: "violates foreign key constraint",
duplicateEntryErrorMessage: "duplicate key value violates unique constraint",
duplicateKeyStartIndicator: "Detail: Key ",
duplicateKeyEndIndicator: " already exists.",
columnIdentifier: "\""
};
Loading
Loading