In this lesson, we will cover some of the Java and unit-testing integrations.
These lessons will be more showing examples vs. doing exercises due to time constraints. We aim to prepare fuller kata exercises in future.
(Please run kata-files/lesson1/kata-step4.sh or .bat as a pre-requisite for this example)
The class ExampleDbUnitTest.java shows a unit test with Obevo. Note the APIs for doing deployments and table verifications.
There is a twist - we do have the ability to do some translations of traditional DBMS platforms to in-memory. As of this moment, here is the list. (DB2 and Sybase are more mature implementations of the translation functionality).
From | To |
---|---|
DB2 | HSQL |
DB2 | H2 |
Sybase ASE | HSQL |
Sybase ASE | H2 |
PostgreSQL | HSQL |
For more information, see here. We are aiming to post more design information as well on this.
In summary, the general implementation algorithm:
- Create user-defined types with the in-memory implementation whose name matches the traditional DBMS (e.g. create a TEXT field as VARCHAR(255))
- Enabling any translation functionalities in the in-memory platform (though these are never 100%)
- Leveraging some basic ASTs to remove any complex SQLs after CREATE TABLE or column statements
To try out this functionality in action:
- Modify Account.sql to add "with oids" at the end of the CREATE TABLE statement. This is a PostgreSQL-specific SQL statement.
create table Account (
...
) with oids
GO
-
Run ExampleDbUnitTest using system-config-hsql.xml as the input. This defines an original HSQLDB implementation, and thus you'll see the test fail as there is no translation invoked.
-
Now change ExampleDbUnitTest to specify system-config-postgresql.xml as the input and rerun the test. You will see that it passes.
Let's now dive into an example using Hibernate. Similar to how we implemented reverse-engineering from an existing database, we can reverse-engineer from a Hibernate model as well.
Run HibernateRevengExample.java to try this out.
- Can work with Hibernate 3, 4, or 5
- Can work with annotated Java class or a config read from a file
- Can work with Envers
We've configured the example to write the generated DDLs to src/main/database/lesson/orm
- You can run HibernateExample.java to try out such a test.
- Our example Java model is in src/main/java and the obevo.lesson.orm package
- The sample model is similar in function to the model in Lesson 1
Though we can reverse-engineer directly from a Hibernate model, we do not want that reverse-engineering to directly overwrite a file maintained for deployment, as that violates the rule we have around not modifying stateful //// CHANGE entries. However, a Hibernate model may change, and we'd want those changes reflected in our model. Is there a way to enforce this lookup?
We can do this w/ leveraging .baseline files and the BaselineValidator API.
The baseline file represents the "latest"/"full" version of the DDL that we should compare the full content of the //// CHANGE entries against.
- We can do this on a per-object basis; no need to do it on an all-or-nothing basis
To enable this:
- Create a .baseline file that has the latest version
- Run the BaselineValidator API and ensure that you have no breaks.
- OrmLessonPart3.java has an example of this usage.
Let's try this out on an example in our code:
- Add a new field "nickname" to the Hibernate model
public class Person {
// ...
@Column(name = "nickname")
private String nickname;
// ...
- Run OrmLessonPart3.java, and you should see some breaks emitted.
Inspect Person.sql and Person.baseline.sql to see the differences: Person.baseline.sql will have the nickname field
ObjectCompareBreak[objectCompareBreakSide=RIGHT,compareSubject=DaColumnImpl[column=PUBLIC.COMPANY.PERSON.FIELD]]
ObjectCompareBreak[objectCompareBreakSide=RIGHT,compareSubject=DaColumnImpl[column=PUBLIC.COMPANY.PERSON_AUD.FIELD]]
- Add the nickname field to Person.sql to get it in sync
//// CHANGE name=field
alter table Person
add column field varchar(255)
GO
//// CHANGE name=field_AUD
alter table Person_AUD
add column field varchar(255)
GO
- Rerun OrmLessonPart3.java - you should see no breaks
For more information, see the documentation on ORM DDL Generation and Baseline DDL Validation.
In the kata example, we have left in a break on-purpose in TABLE_B so that you can see these feature first-hand (the error looks like the snippet below). Give it a shot to fix this (i.e. add an ALTER command on TABLE_B to get it in line with the baseline)