diff --git a/core/src/main/java/google/registry/schema/tmch/ClaimsList.java b/core/src/main/java/google/registry/schema/tmch/ClaimsList.java
new file mode 100644
index 000000000..3ef3135dc
--- /dev/null
+++ b/core/src/main/java/google/registry/schema/tmch/ClaimsList.java
@@ -0,0 +1,96 @@
+// Copyright 2019 The Nomulus Authors. All Rights Reserved.
+//
+// Licensed 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.
+
+package google.registry.schema.tmch;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.time.ZonedDateTime;
+import java.util.Map;
+import java.util.Optional;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.Table;
+
+/**
+ * A list of TMCH claims labels and their associated claims keys.
+ *
+ *
Note that the primary key of this entity is {@link #revisionId}, which is auto-generated by
+ * the database. So, if a retry of insertion happens after the previous attempt unexpectedly
+ * succeeds, we will end up with having two exact same claims list with only different {@link
+ * #revisionId}. However, this is not an actual problem because we only use the claims list with
+ * highest {@link #revisionId}.
+ */
+@Entity
+@Table(name = "ClaimsList")
+public class ClaimsList {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "revision_id")
+ private Long revisionId;
+
+ @Column(name = "creation_timestamp", nullable = false)
+ private ZonedDateTime creationTimestamp;
+
+ @ElementCollection
+ @CollectionTable(
+ name = "ClaimsEntry",
+ joinColumns = @JoinColumn(name = "revision_id", referencedColumnName = "revision_id"))
+ @MapKeyColumn(name = "domain_label", nullable = false)
+ @Column(name = "claim_key", nullable = false)
+ private Map labelsToKeys;
+
+ private ClaimsList(ZonedDateTime creationTimestamp, Map labelsToKeys) {
+ this.creationTimestamp = creationTimestamp;
+ this.labelsToKeys = labelsToKeys;
+ }
+
+ // Hibernate requires this default constructor.
+ private ClaimsList() {}
+
+ /** Constructs a {@link ClaimsList} object. */
+ public static ClaimsList create(
+ ZonedDateTime creationTimestamp, Map labelsToKeys) {
+ return new ClaimsList(creationTimestamp, labelsToKeys);
+ }
+
+ /** Returns the revision id of this claims list, or throws exception if it is null. */
+ public Long getRevisionId() {
+ checkState(
+ revisionId != null, "revisionId is null because it is not persisted in the database");
+ return revisionId;
+ }
+
+ /** Returns the creation time of this claims list. */
+ public ZonedDateTime getCreationTimestamp() {
+ return creationTimestamp;
+ }
+
+ /** Returns an {@link Map} mapping domain label to its lookup key. */
+ public Map getLabelsToKeys() {
+ return labelsToKeys;
+ }
+
+ /** Returns the claim key for a given domain if there is one, empty otherwise. */
+ public Optional getClaimKey(String label) {
+ return Optional.ofNullable(labelsToKeys.get(label));
+ }
+}
diff --git a/db/src/main/resources/sql/schema/claims_list.sql b/db/src/main/resources/sql/schema/claims_list.sql
new file mode 100644
index 000000000..c73ccadb2
--- /dev/null
+++ b/db/src/main/resources/sql/schema/claims_list.sql
@@ -0,0 +1,27 @@
+-- Copyright 2019 The Nomulus Authors. All Rights Reserved.
+--
+-- Licensed 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 `ClaimsList` (
+ revision_id BIGSERIAL NOT NULL,
+ creation_timestamp TIMESTAMPTZ NOT NULL,
+ PRIMARY KEY (revision_id)
+);
+
+CREATE TABLE `ClaimsEntry` (
+ revision_id BIGSERIAL NOT NULL,
+ claim_key TEXT NOT NULL,
+ domain_label TEXT NOT NULL,
+ PRIMARY KEY (revision_id, domain_label),
+ FOREIGN KEY (revision_id) REFERENCES `ClaimsList`(revision_id)
+);
diff --git a/settings.gradle b/settings.gradle
index 9b2d11de8..e229618ad 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -28,6 +28,7 @@ if (pluginsUrl) {
rootProject.name = 'nomulus'
include 'core'
+include 'db'
include 'prober'
include 'proxy'
include 'third_party'