New versions: Dev (3.15) | Latest (3.14)

Embedded domains

Applies to ❌ Open Source Edition   ✅ Express Edition   ✅ Professional Edition   ✅ Enterprise Edition

A very useful application of embeddable types are DOMAIN types. A DOMAIN type is a combination of:

  • A semantic type name
  • A data type (or other domain type)
  • A default value
  • A CHECK constraint

The combination name/type is enough to describe a semantic type like EMAIL across your schema, much better than e.g. VARCHAR(10). With embedded domains, you can generate a Java type for each domain type, and have that automatically attached to all your columns.

You can turn on the feature like this:

XML (standalone and maven)
Programmatic
Gradle
<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.14.0.xsd">
  <generator>
    <database>

      <!-- Use regular expressions to match the domains that should be replaced by embeddables. -->
      <embeddableDomains>.*</embeddableDomains>
    </database>
  </generator>
</configuration>
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()

      // Use regular expressions to match the domains that should be replaced by embeddables.
      .withEmbeddableDomains(".*")
    )
  )
myConfigurationName(sourceSets.main) {
  generator {
    database {

      // Use regular expressions to match the domains that should be replaced by embeddables.
      embeddableDomains = '.*'
    }
  }
}

As always, when regular expressions are used, they are regular expressions with default flags.

This will automatically produce an embeddable type configuration for each DOMAIN. For example, this schema:

CREATE DOMAIN email AS varchar(100);
CREATE DOMAIN year AS int;

CREATE TABLE user (
  id bigint NOT NULL PRIMARY KEY,
  name varchar(100) NOT NULL,
  email email NOT NULL,
  created year NOT NULL
);

The above would generate the following set of classes (simplified):

public class EmailRecord extends EmbeddableRecordImpl<EmailRecord> {
    public void setValue(String value) { ... }
    public String getValue() { ... }
    public EmailRecord() { ... }
    public EmailRecord(String value) { ... }
}

public class YearRecord extends EmbeddableRecordImpl<YearRecord> {
    public void setValue(Integer value) { ... }
    public Integer getValue() { ... }
    public YearRecord() { ... }
    public YearRecord(Integer value) { ... }
}

These classes are now referenced by embedded fields in the User table and UserRecord record (simplified):

public class User extends TableImpl<UserRecord> {
    public final TableField<UserRecord, Integer> ID;
    public final TableField<UserRecord, String> NAME;
    public final TableField<UserRecord, EmailRecord> EMAIL;
    public final TableField<UserRecord, YearRecord> CREATED;
}

With these generated fields, you can create semantically type safe queries:

create.insertInto(USER)
      .columns(USER.ID, USER.NAME, USER.EMAIL, USER.CREATED)
      .values(1, "domain_user", new EmailRecord("domain@user.com"), new YearRecord(2020))
      .execute();

Feedback

Do you have any feedback about this page? We'd love to hear it!

The jOOQ Logo