Skip to content

Commit

Permalink
Implement multi-schema support
Browse files Browse the repository at this point in the history
  • Loading branch information
philipp-kleber-avelios committed Nov 28, 2024
1 parent 87529c4 commit 8c972cf
Show file tree
Hide file tree
Showing 18 changed files with 667 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@ public abstract class HibernateDatabase extends AbstractJdbcDatabase {
protected Dialect dialect;

private boolean indexesForForeignKeys = false;
public static final String DEFAULT_SCHEMA = "HIBERNATE";
public static final String DEFAULT_DEFAULT_CATALOG_NAME = "HIBERNATE";
public static final String DEFAULT_DEFAULT_SCHEMA_NAME = "HIBERNATE";
public static final String HIBERNATE_TEMP_USE_JDBC_METADATA_DEFAULTS = "hibernate.temp.use_jdbc_metadata_defaults";

public HibernateDatabase() {
setDefaultCatalogName(DEFAULT_SCHEMA);
setDefaultSchemaName(DEFAULT_SCHEMA);
}
public HibernateDatabase() { }

public boolean requiresPassword() {
return false;
Expand Down Expand Up @@ -295,23 +293,28 @@ public boolean supportsTablespaces() {
}

@Override
protected String getConnectionCatalogName() throws DatabaseException {
return getDefaultCatalogName();
protected String getConnectionCatalogName() {
return DEFAULT_DEFAULT_CATALOG_NAME;
}

@Override
protected String getConnectionSchemaName() {
return getDefaultSchemaName();
return DEFAULT_DEFAULT_SCHEMA_NAME;
}

@Override
public String getDefaultSchemaName() {
return DEFAULT_SCHEMA;
final String defaultSchemaName = super.getDefaultSchemaName();
if (defaultSchemaName != null) {
return defaultSchemaName;
}

return DEFAULT_DEFAULT_SCHEMA_NAME;
}

@Override
public String getDefaultCatalogName() {
return DEFAULT_SCHEMA;
return DEFAULT_DEFAULT_CATALOG_NAME;
}

@Override
Expand All @@ -334,6 +337,9 @@ public boolean supportsCatalogs() {
return true;
}

@Override
public void setDefaultCatalogName(String defaultCatalogName) { }

/**
* Used by hibernate to ensure no database access is performed.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package liquibase.ext.hibernate.snapshot;

import liquibase.Scope;
import liquibase.exception.DatabaseException;
import liquibase.snapshot.DatabaseSnapshot;
import liquibase.snapshot.InvalidExampleException;
Expand All @@ -18,7 +19,12 @@ public SchemaSnapshotGenerator() {

@Override
protected DatabaseObject snapshotObject(DatabaseObject example, DatabaseSnapshot snapshot) throws DatabaseException, InvalidExampleException {
return new Schema(snapshot.getDatabase().getDefaultCatalogName(), snapshot.getDatabase().getDefaultSchemaName()).setDefault(true);
Schema schema = new Schema(example.getSchema().getCatalog(), example.getSchema().getName());
if (snapshot.getDatabase().getDefaultSchemaName() != null && snapshot.getDatabase().getDefaultSchemaName().equalsIgnoreCase(schema.getName())) {
schema.setDefault(true);
}

return schema;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ protected void addTo(DatabaseObject foundObject, DatabaseSnapshot snapshot) thro
Schema schema = (Schema) foundObject;
HibernateDatabase database = (HibernateDatabase) snapshot.getDatabase();
for (org.hibernate.boot.model.relational.Namespace namespace : database.getMetadata().getDatabase().getNamespaces()) {
boolean namespaceMatchesSchema = (namespace.getName().getSchema() != null && namespace.getName().getSchema().matches(foundObject.getName()))
|| (namespace.getName().getSchema() == null && ((Schema) foundObject).isDefault());
if (!namespaceMatchesSchema) {
continue;
}

for (org.hibernate.boot.model.relational.Sequence sequence : namespace.getSequences()) {
schema.addDatabaseObject(new Sequence()
.setName(sequence.getName().getSequenceName().getText())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
import liquibase.structure.core.Table;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.generator.Generator;
import org.hibernate.mapping.*;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.SimpleValue;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -38,13 +41,21 @@ protected DatabaseObject snapshotObject(DatabaseObject example, DatabaseSnapshot
return example;
}

Table table = new Table().setName(hibernateTable.getName());
Scope.getCurrentScope().getLog(getClass()).info("Found table " + table.getName());
boolean schemaMatches = (example.getSchema().getName() != null && example.getSchema().getName().equalsIgnoreCase(hibernateTable.getSchema()))
|| (example.getSchema().isDefault() && hibernateTable.getSchema() == null);
if (!schemaMatches) {
Scope.getCurrentScope().getLog(getClass()).info("Skipping table " + hibernateTable.getName() + " for schema " + example.getSchema().getName() + ", because it is part of another one.");
return null;
}

Table table = new Table();
table.setName(hibernateTable.getName());
table.setSchema(example.getSchema());
if (hibernateTable.getComment() != null && !hibernateTable.getComment().isEmpty()) {
table.setRemarks(hibernateTable.getComment());
}

Scope.getCurrentScope().getLog(getClass()).info("Found table " + example.getSchema().getName() + "." + table.getName());
return table;
}

Expand Down Expand Up @@ -115,7 +126,6 @@ protected void addTo(DatabaseObject foundObject, DatabaseSnapshot snapshot) thro
private void addDatabaseObjectToSchema(org.hibernate.mapping.Table join, Schema schema, DatabaseSnapshot snapshot) throws DatabaseException, InvalidExampleException {
Table joinTable = new Table().setName(join.getName());
joinTable.setSchema(schema);
Scope.getCurrentScope().getLog(getClass()).info("Found table " + joinTable.getName());
schema.addDatabaseObject(snapshotObject(joinTable, snapshot));
}
}
60 changes: 60 additions & 0 deletions src/test/java/com/example/multischema/auction/AuctionInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.example.multischema.auction;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import java.util.Date;

@Entity
@Table(schema = "PUBLIC")
public class AuctionInfo {
private String id;
private String description;
private Date ends;
private Float maxAmount;

@Column(length = 1000)
public String getDescription() {
return description;
}

public Date getEnds() {
return ends;
}

@Id
public String getId() {
return id;
}


public Float getMaxAmount() {
return maxAmount;
}

public void setId(String id) {
this.id = id;
}

public void setDescription(String description) {
this.description = description;
}

public void setEnds(Date ends) {
this.ends = ends;
}

public void setMaxAmount(Float maxAmount) {
this.maxAmount = maxAmount;
}

public AuctionInfo(String id, String description, Date ends, Float maxAmount) {
this.id = id;
this.description = description;
this.ends = ends;
this.maxAmount = maxAmount;
}

}
86 changes: 86 additions & 0 deletions src/test/java/com/example/multischema/auction/AuctionItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.example.multischema.auction;

import jakarta.persistence.*;

import java.util.Date;
import java.util.List;

@Entity
@Table(schema = "PUBLIC")
public class AuctionItem extends Persistent {
private String description;
private String shortDescription;
private List<Bid> bids;
private Bid successfulBid;
private User seller;
private Date ends;
private int condition;

@OneToMany(mappedBy = "item", cascade = CascadeType.ALL)
public List<Bid> getBids() {
return bids;
}

@Column(length = 1000)
public String getDescription() {
return description;
}

@ManyToOne
public User getSeller() {
return seller;
}

@ManyToOne
public Bid getSuccessfulBid() {
return successfulBid;
}

public void setBids(List<Bid> bids) {
this.bids = bids;
}

public void setDescription(String string) {
description = string;
}

public void setSeller(User user) {
seller = user;
}

public void setSuccessfulBid(Bid bid) {
successfulBid = bid;
}

public Date getEnds() {
return ends;
}

public void setEnds(Date date) {
ends = date;
}

public int getCondition() {
return condition;
}

public void setCondition(int i) {
condition = i;
}

public String toString() {
return shortDescription + " (" + description + ": " + condition
+ "/10)";
}

@Column(length = 200)
public String getShortDescription() {
return shortDescription;
}

public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}


}
34 changes: 34 additions & 0 deletions src/test/java/com/example/multischema/auction/AuditedItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example.multischema.auction;

import jakarta.persistence.*;
import org.hibernate.envers.Audited;

@Audited
@Entity
@Table(schema = "PUBLIC")
public class AuditedItem {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AUDITED_ITEM_SEQ")
@SequenceGenerator(name = "AUDITED_ITEM_SEQ", sequenceName = "AUDITED_ITEM_SEQ")
private long id;
@Column(unique = true)
private String name;

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}
64 changes: 64 additions & 0 deletions src/test/java/com/example/multischema/auction/Bid.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.example.multischema.auction;

import jakarta.persistence.*;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

import java.util.Date;

@Entity
@Table(schema = "PUBLIC")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorValue("Y")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Bid extends Persistent {
private AuctionItem item;
private float amount;
private Date datetime;
private User bidder;

@ManyToOne
public AuctionItem getItem() {
return item;
}

public void setItem(AuctionItem item) {
this.item = item;
}

public float getAmount() {
return amount;
}

@Column(nullable = false, name = "datetime")
public Date getDatetime() {
return datetime;
}

public void setAmount(float f) {
amount = f;
}

public void setDatetime(Date date) {
datetime = date;
}

@ManyToOne(optional = false)
public User getBidder() {
return bidder;
}

public void setBidder(User user) {
bidder = user;
}

public String toString() {
return bidder.getUserName() + " $" + amount;
}

@Transient
public boolean isBuyNow() {
return false;
}

}
Loading

0 comments on commit 8c972cf

Please sign in to comment.