Skip to content

Commit

Permalink
Merge pull request #7 from ergon/feature/partial-index
Browse files Browse the repository at this point in the history
add support for partial index
  • Loading branch information
jmatj authored May 21, 2024
2 parents 3b3abe5 + b279773 commit b1f9060
Show file tree
Hide file tree
Showing 11 changed files with 70 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ private boolean ignoreFieldSizeChange(DataType dataType) {
private void processIndexes(Index sourceIndex, Index targetIndex, MigrationStrategy strategy) {
if (sourceIndex.isUnique() != targetIndex.isUnique()
|| sourceIndex.isPrimary() != targetIndex.isPrimary()
|| !Arrays.equals(createSchemaItemNameArray(sourceIndex.getFields()), createSchemaItemNameArray(targetIndex.getFields()))) {
|| !Arrays.equals(createSchemaItemNameArray(sourceIndex.getFields()), createSchemaItemNameArray(targetIndex.getFields()))
|| !Objects.equals(sourceIndex.getWhere(), targetIndex.getWhere())) {
strategy.indexUpdated(sourceIndex, targetIndex);
}
}
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/ch/ergon/adam/core/db/schema/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class Index extends TableItem {
private boolean isPrimary;
private boolean isUnique;
private List<Field> fields;
private String where;
private final Set<ForeignKey> referencingForeignKeys = new LinkedHashSet<>();

public Index(String name) {
Expand Down Expand Up @@ -41,6 +42,14 @@ public void setUnique(boolean unique) {
isUnique = unique;
}

public String getWhere() {
return where;
}

public void setWhere(String where) {
this.where = where;
}

public void addReferencingForeignKey(ForeignKey foreignKey) {
referencingForeignKeys.add(foreignKey);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ fields:
- name: "col4"
dataType: "VARCHAR"
length: 10
- name: "col5"
dataType: "VARCHAR"
nullable: true
foreignKeys: []
indexes:
- name: "test_table_col1_key"
Expand All @@ -29,4 +32,8 @@ indexes:
- "id"
primary: true
unique: true
- name: "test_table_partial_key"
fields:
- "col5"
where: "col5 is null"
ruleConstraints: []
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public abstract class IndexTests extends AbstractDbTestBase {

private static final String CREATE_TABLE_SQL =
"create table test_table (" +
"id integer null unique " +
"id integer null unique, " +
"col1 varchar" +
")";

private static final String CREATE_PARTIAL_INDEX_SQL =
"create unique index partial_idx on test_table(id) where col1 = 'test'";

public IndexTests(TestDbUrlProvider testDbUrlProvider) {
super(testDbUrlProvider);
}
Expand All @@ -39,6 +44,8 @@ public void testRecreateIndexAfterTableChange() throws Exception {

// Setup db
getSourceDbConnection().createStatement().execute(CREATE_TABLE_SQL);
getSourceDbConnection().createStatement().execute(CREATE_PARTIAL_INDEX_SQL);

sourceToTarget();
DummySink dummySink = targetToDummy();
Schema schema = dummySink.getTargetSchema();
Expand All @@ -51,6 +58,9 @@ public void testRecreateIndexAfterTableChange() throws Exception {

// Verify
assertFalse(schema.getTable("test_table").getField("id").isNullable());
assertThat(schema.getTable("test_table").getIndexes().size(), is(1));
assertThat(schema.getTable("test_table").getIndexes().size(), is(2));
if (!this.getClass().getSimpleName().contains("Sqlite")) { // https://github.com/jOOQ/jOOQ/issues/16683
assertThat(schema.getTable("test_table").getIndex("partial_idx").getWhere(), is("(((col1)::text = 'test'::text))"));
}
}
}
11 changes: 9 additions & 2 deletions jooq/src/main/java/ch/ergon/adam/jooq/JooqSink.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package ch.ergon.adam.jooq;

import ch.ergon.adam.core.db.interfaces.SchemaSink;
import ch.ergon.adam.core.db.schema.*;
import ch.ergon.adam.core.db.schema.Constraint;
import ch.ergon.adam.core.db.schema.Field;
import ch.ergon.adam.core.db.schema.ForeignKey;
import ch.ergon.adam.core.db.schema.Index;
import ch.ergon.adam.core.db.schema.Schema;
import ch.ergon.adam.core.db.schema.Sequence;
import ch.ergon.adam.core.db.schema.Table;
import ch.ergon.adam.core.db.schema.*;
import com.google.common.base.Strings;
import org.jooq.DataType;
import org.jooq.*;
import org.jooq.impl.DSL;
Expand All @@ -26,6 +27,7 @@
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Stream.concat;
import static org.jooq.impl.DSL.noCondition;
import static org.jooq.impl.SQLDataType.TIMESTAMPWITHTIMEZONE;

public class JooqSink implements SchemaSink {
Expand Down Expand Up @@ -115,7 +117,12 @@ public void createIndex(Index index) {
} else {
createIndex = context.createIndex(index.getName());
}
createIndex.on(getTableName(index.getTable()), fieldNames).execute();
CreateIndexIncludeStep indexStep = createIndex.on(getTableName(index.getTable()), fieldNames);
if (Strings.isNullOrEmpty(index.getWhere())) {
indexStep.execute();
} else {
indexStep.where(DSL.condition(index.getWhere())).execute();
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions jooq/src/main/java/ch/ergon/adam/jooq/JooqSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ private Index mapIndexFromJooq(Table table, org.jooq.Index jooqIndex) {
Index index = new Index(jooqIndex.getName());
index.setFields(jooqIndex.getFields().stream().map(jooqField -> table.getField(jooqField.getName())).collect(toList()));
index.setUnique(jooqIndex.getUnique());
if (jooqIndex.getWhere() != null) {
index.setWhere(jooqIndex.getWhere().toString());
}
UniqueKey<?> primaryKey = jooqIndex.getTable().getPrimaryKey();
if (primaryKey != null) {
String[] primaryKeyFieldNames = primaryKey.getFields().stream().map(TableField::getName).toArray(String[]::new);
Expand Down
13 changes: 12 additions & 1 deletion sqlite/src/main/java/ch/ergon/adam/sqlite/SqliteSink.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

import ch.ergon.adam.jooq.JooqSink;
import ch.ergon.adam.core.db.schema.Index;
import com.google.common.base.Strings;
import org.jooq.Condition;
import org.jooq.CreateIndexIncludeStep;
import org.jooq.CreateIndexStep;
import org.jooq.Name;
import org.jooq.impl.DSL;

import java.sql.Connection;
import java.util.Collection;

import static java.util.stream.Collectors.toList;
import static org.jooq.SQLDialect.SQLITE;
import static org.jooq.impl.DSL.trueCondition;

public class SqliteSink extends JooqSink {

Expand All @@ -35,7 +40,13 @@ public void createIndex(Index index) {
} else {
createIndex = context.createIndex();
}
createIndex.on(getTableName(index.getTable()), fieldNames).execute();

CreateIndexIncludeStep indexStep = createIndex.on(getTableName(index.getTable()), fieldNames);
if (Strings.isNullOrEmpty(index.getWhere())) {
indexStep.execute();
} else {
indexStep.where(DSL.condition(index.getWhere())).execute();
}
} else {
super.createIndex(index);
}
Expand Down
1 change: 1 addition & 0 deletions yml/src/main/java/ch/ergon/adam/yml/YmlSink.java
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ private YmlIndex mapToYml(Index index) {
YmlIndex ymlIndex = new YmlIndex(index.getName());
ymlIndex.setPrimary(index.isPrimary());
ymlIndex.setUnique(index.isUnique());
ymlIndex.setWhere(index.getWhere());
ymlIndex.setFields(createSchemaItemNameArray(index.getFields()));
return ymlIndex;
}
Expand Down
1 change: 1 addition & 0 deletions yml/src/main/java/ch/ergon/adam/yml/YmlSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ private Index mapFromYml(YmlIndex ymlIndex, Table table, int position) {
Index index = new Index(indexName);
index.setPrimary(ymlIndex.isPrimary());
index.setUnique(ymlIndex.isPrimary() ? true : ymlIndex.isUnique());
index.setWhere(ymlIndex.getWhere());
index.setFields(stream(ymlIndex.getFields())
.map(name -> requireNonNull(table.getField(name), format("field %s.%s not found for index %s", table.getName(), name, ymlIndex.getName())))
.collect(toList()));
Expand Down
9 changes: 9 additions & 0 deletions yml/src/main/java/ch/ergon/adam/yml/schema/YmlIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class YmlIndex extends YmlSchemaItem {

private boolean isPrimary;
private boolean isUnique;
private String where;
private String[] fields = new String[0];

public YmlIndex(@JsonProperty("name")String name) {
Expand All @@ -32,6 +33,14 @@ public boolean isUnique() {
return isUnique;
}

public String getWhere() {
return where;
}

public void setWhere(String where) {
this.where = where;
}

public void setUnique(boolean unique) {
isUnique = unique;
}
Expand Down
5 changes: 5 additions & 0 deletions yml/table-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@
]
}
},
"where": {
"$id": "#/properties/indexes/items/properties/where",
"type": "string",
"description": "Partial index condition."
},
"primary": {
"$id": "#/properties/indexes/items/properties/primary",
"type": "boolean",
Expand Down

0 comments on commit b1f9060

Please sign in to comment.