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

Introspection Support for Bal Persist #330

Merged
merged 54 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
87129b4
Generate entity module by introspecting database
hasathcharu Jan 30, 2024
2ec490a
Populate Ballerina entities after introspecting database
hasathcharu Jan 31, 2024
cdbc53e
Implement the logic for handling name mapping annotations in Entity
hasathcharu Feb 2, 2024
3cbc43a
Implement the logic for handling type mapping annotations for custom …
hasathcharu Feb 2, 2024
717578c
Implement the logic for handling index annotations in Entity
hasathcharu Feb 6, 2024
5d52cbe
Implement the logic for handling db generated fields in Entity
hasathcharu Feb 7, 2024
92a2bbb
Implement driver resolution for bal persist pull
hasathcharu Feb 7, 2024
c2d6827
Add annotation support for sql annotations in generate command
hasathcharu Feb 8, 2024
b8365c0
Add interactive CLI messages for pull command
hasathcharu Feb 9, 2024
1ac3d9f
Add support for generated annotation post function
hasathcharu Feb 12, 2024
7f3ca24
Remove constants, refactor code and fix a bug where the entity resour…
hasathcharu Feb 12, 2024
e7214a6
Add support for enum types in the introspector
hasathcharu Feb 12, 2024
2239b14
Fix how client api handles relations mapped with new custom foreign k…
hasathcharu Feb 12, 2024
f48a851
Fix the client resource name conflict with table name
hasathcharu Feb 14, 2024
a9b320c
Fix resource name conflict with table name
hasathcharu Feb 14, 2024
a7bf35f
Fix issues and assert that all existing test cases pass
hasathcharu Feb 14, 2024
148d860
Refine the behavior of how sql drivers are resolved
hasathcharu Feb 15, 2024
c3ab596
Add the first new test case along with the assertion logic
hasathcharu Feb 19, 2024
c47aa29
Add two new test cases
hasathcharu Feb 19, 2024
1cd531c
Add model file exists validation
hasathcharu Feb 20, 2024
46b2601
Add new test cases and bug fixes along the way
hasathcharu Feb 20, 2024
724db92
Fix a bug which would cause the foreign key name to be generated inco…
hasathcharu Feb 21, 2024
162f4c2
Add new test cases
hasathcharu Feb 21, 2024
8b65403
Add support to account for ballerina keywords in database field names
hasathcharu Feb 22, 2024
fc16796
Add new test cases and bug fixes along the way
hasathcharu Feb 22, 2024
36e3f29
Add specifications
hasathcharu Feb 25, 2024
9c5573c
Update changelog
hasathcharu Feb 25, 2024
a6453a0
Add more test cases and bug fixes
hasathcharu Feb 26, 2024
d19a191
Add test cases for command line args
hasathcharu Feb 26, 2024
01ecfef
Change how the db credentials are passed to the tool. db credentials …
hasathcharu Feb 26, 2024
86360c9
Update specification
hasathcharu Feb 26, 2024
1adc951
Update build.gradle
hasathcharu Feb 27, 2024
6ff25b6
Restore examples/build.gradle
hasathcharu Feb 27, 2024
efc10e5
Make suggested changes
hasathcharu Feb 28, 2024
d13750e
Refactor how annotations are handled in entity model
hasathcharu Feb 28, 2024
6c3be6a
Add help flag
hasathcharu Feb 29, 2024
f42cae0
Fix singularizer issues and add test cases
hasathcharu Mar 1, 2024
9eb8b7e
Update test cases to pass code quality
hasathcharu Mar 1, 2024
43113ee
Improve CaseConverter and add test cases
hasathcharu Mar 1, 2024
ecd8c48
Refactor SqlScriptUtils to reduce code duplication
hasathcharu Mar 1, 2024
fec7933
Refactor to improve code quality
hasathcharu Mar 4, 2024
e84185d
Make suggested changes
hasathcharu Mar 4, 2024
bb521e0
Update test cases to support new generate command
hasathcharu Mar 5, 2024
588b812
Make suggested changes
hasathcharu Mar 5, 2024
fae6591
Make suggested changes
hasathcharu Mar 6, 2024
01d62b2
Improve Introspector class properties
hasathcharu Mar 6, 2024
97239c6
Add test case to test generated ID fields
hasathcharu Mar 6, 2024
aed1530
Make suggested changes
hasathcharu Mar 8, 2024
56597a3
Fix minor issue on wording
hasathcharu Mar 8, 2024
14a4058
Add support to blob type
hasathcharu Mar 11, 2024
c4ddcd9
Add test case to blob types and update persist lib version
hasathcharu Mar 11, 2024
feef58b
Upgrade persist.sql version and add example for annotations
hasathcharu Mar 13, 2024
e99e5fc
Make suggested changes
hasathcharu Mar 14, 2024
f93f643
Make suggested changes
hasathcharu Mar 14, 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
  •  
  •  
  •  
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ hs_err_pid*

build
.gradle/
target

/target/
!persist-cli-tests/src/resources/test-src/**/target/

# IDEA Files
.idea/
Expand All @@ -44,3 +46,6 @@ bin/
# Ballerina
velocity.log*
*Ballerina.lock

# Jar Dependency Versions
version.properties
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- [Added support for PostgreSQL as a datasource](https://github.com/ballerina-platform/ballerina-standard-library/issues/5829)
- [Integrate the persist code generation to the bal build command](https://github.com/ballerina-platform/ballerina-library/issues/5784)
- [Added introspection support for MySQL databases](https://github.com/ballerina-platform/ballerina-library/issues/6014)
- [Added advanced annotation support for SQL databases](https://github.com/ballerina-platform/ballerina-library/issues/6013)

## [1.2.1] - 2021-11-21

Expand Down
31 changes: 31 additions & 0 deletions docs/spec/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The conforming implementation of the specification is released and included in t
2. [Initializing Persistence Layer in Bal Project](#2-initializing-the-bal-project-with-persistence-layer)
3. [Generating Persistence Derived Types, Clients, and Database Schema](#3-generating-persistence-derived-types-and-clients)
4. [Push Persistence Schema to the Data Provider](#4-push-persistence-schema-to-the-data-provider)
5. [Pull Persistence Schema from the Data Provider](#5-pull-persistence-schema-from-the-data-provider)

## 1. Overview
This specification elaborates on the `Persist CLI Tool` commands.
Expand Down Expand Up @@ -206,3 +207,33 @@ Behaviour of the `push` command,
- User should add the relevant configuration to the Ballerina.toml file.
- The user should have initiated the persistence layer in the project and executed the `generate` command to generate the SQL script.
- If the user invokes the command twice, it will not fail. It will rerun the SQL script against the database.

## 5. Pull Persistence Schema from the Data Provider

```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 database client. 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 |

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.

hasathcharu marked this conversation as resolved.
Show resolved Hide resolved
This command should execute within a Ballerina project.

The `persist` directory is created if it is not already present. If a `model.bal` file is already present in the `persist` directory, it will prompt the user to confirm overwriting the existing `model.bal` file.

Running the `pull` command will,
1. Create a `model.bal` file with the entities and relations based on the introspected schema of the database.
2. Not change the schema of the database in any way.

Behaviour of the `pull` command,
- User should invoke the command within a Ballerina project.
- User should provide the relevant database configuration as command-line arguments.
- The database password is not provided as a command-line argument. The user will be prompted to enter the password.
- If the user invokes the command while a `model.bal` file exists in the `persist` directory, it will prompt the user to confirm overwriting the existing `model.bal` file.
- The user must execute the `generate` command to generate the derived types and client API after running the `pull` command in order to use the client API in the project.
77 changes: 75 additions & 2 deletions examples/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ description = 'Ballerina - Persist Examples'

def ballerinaDist = "${project.buildDir}/ballerina-distribution"
def examples = ["medical-center", "rainier"]
def introspectionExamples = ["hospital"]

configurations {
balTools
Expand Down Expand Up @@ -124,6 +125,14 @@ task copyTestResources() {
}
}
}
copy {
introspectionExamples.each { example ->
into buildDir
into("generated-examples/${example}/") {
from "${example}"
}
}
}
}

}
Expand Down Expand Up @@ -248,6 +257,26 @@ task generateInMemoryExamples {
}
}

task generateIntrospectionExamples {
doLast {
introspectionExamples.each { example ->
try {
exec {
workingDir "${project.projectDir}/build/generated-examples/${example}"
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine 'sh', '-c', "${ballerinaDist}/bin/bal persist generate --datastore=mysql --module=entities"
} else {
commandLine 'cmd', '/c', "${ballerinaDist}/bin/bal.bat persist generate --datastore=mysql --module=entities"
}
}
} catch (Exception e) {
println("Example '${example}' Generation failed: " + e.message)
throw e
}
}
}
}

// task generateGSheetExamples {
// doLast {
// examples.each { example ->
Expand Down Expand Up @@ -306,13 +335,13 @@ def checkExecResult(executionResult, failText, standardOutput) {
task startTestDockerContainer(type: Exec) {
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
def standardOutput = new ByteArrayOutputStream()
commandLine 'sh', '-c', 'docker run --platform linux/amd64 --rm -d --name ballerina-persist-tools-example -e MYSQL_ROOT_PASSWORD="Test123#" -p 3308:3306 -t mysql:8.0.21'
commandLine 'sh', '-c', 'docker run --platform linux/amd64 --rm -d --name ballerina-persist-tools-example -e MYSQL_ROOT_PASSWORD="Test123#" -e MYSQL_DATABASE="hospital" -p 3308:3306 -t mysql:8.0.21'
def healthCheck = 1
def counter = 0
doLast {
checkExecResult(executionResult, 'Error', standardOutput)
while (healthCheck != 0 && counter < 12) {
sleep(60 * 1000)
sleep(30 * 1000)
healthCheck = checkTestDockerContainerStatus('ballerina-persist-tools-example')
counter = counter + 1
}
Expand Down Expand Up @@ -406,6 +435,47 @@ task testInMemoryExamples {
}
}

task testIntrospectionExamples {
dependsOn(startTestDockerContainer)
doLast {
introspectionExamples.each { example ->
try {
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
//this part is not necessary. this is added so that the build will not fail due to the issue with
//mysql connector for ballerina requiring a 'first login' on a different mysql client. This is a
//temporary fix until the issue is resolved.
try {
exec {
workingDir "${project.projectDir}/build/generated-examples/${example}"
commandLine 'sh', '-c', "${ballerinaDist}/bin/bal persist pull --host localhost --database nonexistentdb --user root --port 3308"
standardInput = new ByteArrayInputStream("Test123#\ny\n".getBytes())
}
} catch (Exception ignored) {}
exec {
workingDir "${project.projectDir}/build/generated-examples/${example}"
commandLine 'sh', '-c', "${ballerinaDist}/bin/bal test"
}
} else {
try {
exec {
workingDir "${project.projectDir}/build/generated-examples/${example}"
commandLine 'cmd', '/c', "${ballerinaDist}/bin/bal.bat persist pull --host localhost --database hris --user root --port 3308"
standardInput = new ByteArrayInputStream("Test123#\ny\n".getBytes())
}
} catch (Exception ignored) {}
exec {
workingDir "${project.projectDir}/build/generated-examples/${example}"
commandLine 'cmd', '/c', "${ballerinaDist}/bin/bal.bat test"
}
}
} catch (Exception e) {
println("Example '${example}' Tests failed: " + e.message)
throw e
}
}
}
}

task automateGSheetTable {
doLast {
try {
Expand Down Expand Up @@ -450,13 +520,15 @@ copyPersistTool.dependsOn ":persist-cli:build"
copyTestResources.dependsOn copyPersistTool

initInMemoryExamples.dependsOn copyTestResources
generateIntrospectionExamples.dependsOn copyTestResources
generateInMemoryExamples.dependsOn initInMemoryExamples
testInMemoryExamples.dependsOn generateInMemoryExamples

initDbExamples.dependsOn testInMemoryExamples
generateDbExamples.dependsOn initDbExamples
pushExamples.dependsOn generateDbExamples
testDbExamples.dependsOn pushExamples
testIntrospectionExamples.dependsOn generateIntrospectionExamples

// initGSheetExamples.dependsOn testDbExamples
// generateGSheetExamples.dependsOn initGSheetExamples
Expand All @@ -465,5 +537,6 @@ testDbExamples.dependsOn pushExamples

build.dependsOn testInMemoryExamples
build.dependsOn testDbExamples
build.dependsOn testIntrospectionExamples
//build.dependsOn testGSheetExamples
build.finalizedBy stopTestDockerContainer
16 changes: 16 additions & 0 deletions examples/hospital/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
org = "wso2"
name = "Demo"
version = "0.1.0"
distribution = "2201.8.4"

[build-options]
observabilityIncluded = true

[[platform.java17.repository]]
id="wso2-nexus"
url = "https://maven.wso2.org/nexus/content/groups/public/"

[[platform.java17.repository]]
id="wso2-nexus-snapshot"
url = "https://maven.wso2.org/nexus/content/repositories/snapshots/"
Loading
Loading