diff --git a/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/DefaultValueStrategyBuilder.java b/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/DefaultValueStrategyBuilder.java new file mode 100644 index 0000000..f3bb021 --- /dev/null +++ b/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/DefaultValueStrategyBuilder.java @@ -0,0 +1,148 @@ +package com.btc.redg.runtime.defaultvalues; + +import java.util.function.BiFunction; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +import com.btc.redg.models.ColumnModel; +import com.btc.redg.runtime.defaultvalues.pluggable.DefaultDefaultValueProvider; +import com.btc.redg.runtime.defaultvalues.pluggable.PluggableDefaultValueProvider; +import com.btc.redg.runtime.defaultvalues.pluggable.PluggableDefaultValueStrategy; + +public class DefaultValueStrategyBuilder { + + private PluggableDefaultValueStrategy pluggableDefaultValueStrategy = new PluggableDefaultValueStrategy(); + private DefaultValueStrategy fallbackStrategy = new DefaultDefaultValueProvider(); + + public Condition when(final Predicate predicate) { + return new PredicateCondition(predicate); + } + + public Condition whenTableNameMatches(final String regex) { + return new TableNameRegexCondition(regex); + } + + public Condition whenColumnNameMatches(final String regex) { + return new ColumnNameRegexCondition(regex); + } + + public void setFallbackStrategy(DefaultValueStrategy fallbackStrategy) { + this.fallbackStrategy = fallbackStrategy; + } + + private void addProvider(Predicate conditionPredicate, BiFunction valueProducer) { + pluggableDefaultValueStrategy.addProvider(new PluggableDefaultValueProvider() { + @Override + public boolean willProvide(ColumnModel columnModel) { + return conditionPredicate.test(columnModel); + } + + @Override + public T getDefaultValue(ColumnModel columnModel, Class type) { + return (T) valueProducer.apply(columnModel, type); + } + }); + } + + public DefaultValueStrategy build() { + pluggableDefaultValueStrategy.addProvider(new PluggableDefaultValueProvider() { + @Override + public boolean willProvide(ColumnModel columnModel) { + return true; + } + + @Override + public T getDefaultValue(ColumnModel columnModel, Class type) { + return fallbackStrategy.getDefaultValue(columnModel, type); + } + }); + return pluggableDefaultValueStrategy; + } + + public abstract class Condition { + + public abstract boolean evaluate(ColumnModel columnModel); + + public void thenUse(Object staticValue) { + addProvider(this::evaluate, (columnModel, aClass) -> staticValue); + } + + public void thenCompute(BiFunction computationFunction) { + addProvider(this::evaluate, computationFunction); + } + + public void thenUseProvider(PluggableDefaultValueProvider provider) { + addProvider(columnModel -> evaluate(columnModel) && provider.willProvide(columnModel), provider::getDefaultValue); + } + + public Condition and(final Predicate predicate) { + return new AndCondition(this, new PredicateCondition(predicate)); + } + + public Condition andTableNameMatches(final String regex) { + return new AndCondition(this, new TableNameRegexCondition(regex)); + } + + public Condition andColumnNameMatches(final String regex) { + return new AndCondition(this, new ColumnNameRegexCondition(regex)); + } + } + + class AndCondition extends Condition { + + private final Condition condition1; + private final Condition condition2; + + public AndCondition(Condition condition1, Condition condition2) { + this.condition1 = condition1; + this.condition2 = condition2; + } + + @Override + public boolean evaluate(ColumnModel columnModel) { + return condition1.evaluate(columnModel) && condition2.evaluate(columnModel); + } + } + + class PredicateCondition extends Condition { + + private final Predicate predicate; + + PredicateCondition(Predicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean evaluate(ColumnModel columnModel) { + return predicate.test(columnModel); + } + } + + class TableNameRegexCondition extends Condition { + + private final Pattern pattern; + + TableNameRegexCondition(String regex) { + pattern = Pattern.compile(regex); + } + + @Override + public boolean evaluate(ColumnModel columnModel) { + return pattern.matcher(columnModel.getDbTableName()).matches(); + } + } + + class ColumnNameRegexCondition extends Condition { + + private final Pattern pattern; + + ColumnNameRegexCondition(String regex) { + pattern = Pattern.compile(regex); + } + + @Override + public boolean evaluate(ColumnModel columnModel) { + return pattern.matcher(columnModel.getDbName()).matches(); + } + } +} diff --git a/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/pluggable/NumberProvider.java b/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/pluggable/NumberProvider.java index 90098d1..a6d1bf3 100644 --- a/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/pluggable/NumberProvider.java +++ b/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/pluggable/NumberProvider.java @@ -44,7 +44,21 @@ public boolean willProvide(final ColumnModel columnModel) { return Number.class.isAssignableFrom(columnModel.getJavaTypeAsClass()); } - public static T convertNumber(BigDecimal number, final Class type) { + public static T convertNumber(BigDecimal number, Class type) { + if (type == double.class) { + type = (Class) Double.class; + } else if (type == float.class) { + type = (Class) Float.class; + } else if (type == long.class) { + type = (Class) Long.class; + } else if (type == int.class) { + type = (Class) Integer.class; + } else if (type == byte.class) { + type = (Class) Byte.class; + } else if (type == short.class) { + type = (Class) Short.class; + } + if (BigDecimal.class.equals(type)) { return type.cast(number); } else if (Double.class.equals(type)) { diff --git a/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/pluggable/PluggableDefaultValueStrategy.java b/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/pluggable/PluggableDefaultValueStrategy.java index dfe654f..3e5d425 100644 --- a/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/pluggable/PluggableDefaultValueStrategy.java +++ b/redg-runtime/src/main/java/com/btc/redg/runtime/defaultvalues/pluggable/PluggableDefaultValueStrategy.java @@ -62,49 +62,4 @@ public void addProvider(final PluggableDefaultValueProvider provider) { this.providers.add(provider); } - public void removeProvider(final PluggableDefaultValueProvider provider) { - this.providers.remove(provider); - } - - public void clearProviders() { - this.providers.clear(); - } - - public static class Builder { - - private PluggableDefaultValueStrategy strategy = new PluggableDefaultValueStrategy(); - - PluggableDefaultValueProvider lastProvider; - - public Builder use(final PluggableDefaultValueProvider provider) { - if (lastProvider != null) { - strategy.addProvider(lastProvider); - } - lastProvider = provider; - return this; - } - - public Builder when(final Predicate condition) { - this.lastProvider = new CustomConditionalProvider(condition, this.lastProvider); - return this; - } - - public Builder useDefault() { - if (lastProvider != null) { - strategy.addProvider(lastProvider); - } - lastProvider = new DefaultDefaultValueProvider(); - return this; - } - - public PluggableDefaultValueStrategy build() { - if (lastProvider != null) { - strategy.addProvider(lastProvider); - lastProvider = null; - } - return strategy; - } - } - - } diff --git a/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/DefaultValueStrategyBuilderTest.java b/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/DefaultValueStrategyBuilderTest.java new file mode 100644 index 0000000..7eb74c6 --- /dev/null +++ b/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/DefaultValueStrategyBuilderTest.java @@ -0,0 +1,132 @@ +package com.btc.redg.runtime.defaultvalues; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import com.btc.redg.models.ColumnModel; +import com.btc.redg.runtime.defaultvalues.pluggable.IncrementingNumberProvider; + +import static org.junit.Assert.*; + +public class DefaultValueStrategyBuilderTest { + @Test + public void testWhen() throws Exception { + DefaultValueStrategyBuilder builder = new DefaultValueStrategyBuilder(); + + builder.when(columnModel -> false).thenUse(111); + builder.when(columnModel -> true).thenUse(222); + builder.when(columnModel -> false).thenUse(333); + + DefaultValueStrategy strategy = builder.build(); + + Assert.assertEquals(222, strategy.getDefaultValue(Mockito.mock(ColumnModel.class), int.class).intValue()); + } + + @Test + public void testWhenColumnNameMatches() throws Exception { + DefaultValueStrategyBuilder builder = new DefaultValueStrategyBuilder(); + + builder.whenColumnNameMatches(".*X").thenUse(999); + + DefaultValueStrategy strategy = builder.build(); + + ColumnModel columnMock = Mockito.mock(ColumnModel.class); + Mockito.when(columnMock.getDbName()).thenReturn("ASDFX"); + Assert.assertEquals(999, strategy.getDefaultValue(columnMock, int.class).intValue()); + Mockito.when(columnMock.getDbName()).thenReturn("ASDFA"); + Assert.assertNull("should return null since the default default value is null", strategy.getDefaultValue(columnMock, int.class)); + } + + @Test + public void testWhenTableNameMatches() throws Exception { + DefaultValueStrategyBuilder builder = new DefaultValueStrategyBuilder(); + + builder.whenTableNameMatches(".*X").thenUse(999); + + DefaultValueStrategy strategy = builder.build(); + + ColumnModel columnMock = Mockito.mock(ColumnModel.class); + Mockito.when(columnMock.getDbTableName()).thenReturn("ASDFX"); + Assert.assertEquals(999, strategy.getDefaultValue(columnMock, int.class).intValue()); + Mockito.when(columnMock.getDbTableName()).thenReturn("ASDFA"); + Assert.assertNull(strategy.getDefaultValue(columnMock, int.class)); + } + + @Test + public void testThenCompute() throws Exception { + DefaultValueStrategyBuilder builder = new DefaultValueStrategyBuilder(); + + builder.when(columnModel -> true).thenCompute((columnModel, aClass) -> 123); + + DefaultValueStrategy strategy = builder.build(); + + Assert.assertEquals(123, strategy.getDefaultValue(Mockito.mock(ColumnModel.class), int.class).intValue()); + } + + @Test + public void testThenUseProvider() throws Exception { + DefaultValueStrategyBuilder builder = new DefaultValueStrategyBuilder(); + + builder.when(columnModel -> true).thenUseProvider(new IncrementingNumberProvider()); + + DefaultValueStrategy strategy = builder.build(); + + ColumnModel columnModelMock = Mockito.mock(ColumnModel.class); + Mockito.when(columnModelMock.getJavaTypeAsClass()).thenAnswer(invocationOnMock -> Integer.class); + Assert.assertEquals(1, strategy.getDefaultValue(columnModelMock, int.class).intValue()); + Assert.assertEquals(2, strategy.getDefaultValue(columnModelMock, int.class).intValue()); + Assert.assertEquals(3, strategy.getDefaultValue(columnModelMock, int.class).intValue()); + } + + @Test + public void testSetFallbackStrategy() throws Exception { + DefaultValueStrategyBuilder builder = new DefaultValueStrategyBuilder(); + + builder.when(columnModel -> false).thenUse("asdf"); + builder.setFallbackStrategy(new DefaultValueStrategy() { + @Override + public T getDefaultValue(ColumnModel columnModel, Class type) { + return (T) "fallback value"; + } + }); + + DefaultValueStrategy strategy = builder.build(); + + Assert.assertEquals("fallback value", strategy.getDefaultValue(Mockito.mock(ColumnModel.class), String.class)); + } + + @Test + public void testAndConditions() throws Exception { + DefaultValueStrategyBuilder builder = new DefaultValueStrategyBuilder(); + + builder.whenColumnNameMatches("a.*") + .andColumnNameMatches(".*z") + .andTableNameMatches("t.*") + .and(ColumnModel::isPrimitiveType) + .thenUse("matches!"); + + DefaultValueStrategy strategy = builder.build(); + + + ColumnModel columnModel = prepareMock("able", "a__z", true); + Assert.assertEquals(null, strategy.getDefaultValue(columnModel, String.class)); + columnModel = prepareMock("table", "__z", true); + Assert.assertEquals(null, strategy.getDefaultValue(columnModel, String.class)); + columnModel = prepareMock("table", "a__", true); + Assert.assertEquals(null, strategy.getDefaultValue(columnModel, String.class)); + columnModel = prepareMock("table", "a__z", false); + Assert.assertEquals(null, strategy.getDefaultValue(columnModel, String.class)); + columnModel = prepareMock("table", "a__z", true); + Assert.assertEquals("matches!", strategy.getDefaultValue(columnModel, String.class)); + } + + public ColumnModel prepareMock(String tableName, String columnName, boolean isPrimitiveType) { + ColumnModel columnModel = Mockito.mock(ColumnModel.class); + Mockito.when(columnModel.getDbTableName()).thenReturn(tableName); + Mockito.when(columnModel.getDbName()).thenReturn(columnName); + Mockito.when(columnModel.isPrimitiveType()).thenReturn(isPrimitiveType); + return columnModel; + } + +} \ No newline at end of file diff --git a/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/PluggableDefaultValueStrategyTest.java b/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/PluggableDefaultValueStrategyTest.java index a6dbf01..fdb9e71 100644 --- a/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/PluggableDefaultValueStrategyTest.java +++ b/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/PluggableDefaultValueStrategyTest.java @@ -54,56 +54,6 @@ public void testStrategy_NoProvider() { assertNull(strategy.getDefaultValue(TestUtils.getCM("", "", "", Integer.class, true), Integer.class)); } - @Test - public void test_Builder() { - PluggableDefaultValueStrategy strategy = new PluggableDefaultValueStrategy.Builder() - .use(new StaticNumberProvider(42)).when(columnName(eq("THE_ANSWER"))) - .use(new StaticNumberProvider(1337)).when(tableName(eq("LEET"))) - .use(new StaticNumberProvider(21)) - .build(); - assertEquals(42, (int) strategy.getDefaultValue(TestUtils.getCM("", "", "THE_ANSWER", Integer.class, true), Integer.class)); - - assertEquals(1337, (int) strategy.getDefaultValue(TestUtils.getCM("", "LEET", "", Integer.class, true), Integer.class)); - - assertEquals(42, (int) strategy.getDefaultValue(TestUtils.getCM("", "LEET", "THE_ANSWER", Integer.class, true), Integer.class)); - - assertEquals(21, (int) strategy.getDefaultValue(TestUtils.getCM("", "", "TEST", Integer.class, true), Integer.class)); - } - - @Test - public void test_Builder2() { - PluggableDefaultValueStrategy strategy = new PluggableDefaultValueStrategy.Builder() - .use(new ConstantStringProvider("not_test")).when(fullTableName(neq("PUBLIC.TEST"))) - .use(new ConstantStringProvider("contains_a_vowel")).when(columnName(matchesRegex(".+[aeiouAEIOU].+"))) - .useDefault() - .build(); - - assertEquals("not_test", strategy.getDefaultValue(TestUtils.getCM("PUBLIC.STUFF", "", "", String.class, true), String.class)); - assertEquals("-", strategy.getDefaultValue(TestUtils.getCM("PUBLIC.TEST", "", "", String.class, true), String.class)); - - assertEquals("contains_a_vowel", strategy.getDefaultValue(TestUtils.getCM("PUBLIC.TEST", "", "TEST", String.class, true), String.class)); - assertEquals("-", strategy.getDefaultValue(TestUtils.getCM("PUBLIC.TEST", "", "QWRTZ", String.class, true), String.class)); - } - - @Test - public void test_Builder3() { - PluggableDefaultValueStrategy strategy = new PluggableDefaultValueStrategy.Builder() - .use(new ConstantStringProvider("and_test")).when(allOf(tableName(eq("A")), columnName(eq("B")))) - .use(new ConstantStringProvider("or_test")).when(anyOf(tableName(contains("C")), columnName(contains("D")))) - .useDefault() - .build(); - - assertEquals("and_test", strategy.getDefaultValue(TestUtils.getCM("", "A", "B", String.class, true), String.class)); - assertNotEquals("and_test", strategy.getDefaultValue(TestUtils.getCM("", "A", "C", String.class, true), String.class)); - assertNotEquals("and_test", strategy.getDefaultValue(TestUtils.getCM("", "B", "B", String.class, true), String.class)); - assertNotEquals("and_test", strategy.getDefaultValue(TestUtils.getCM("", "B", "C", String.class, true), String.class)); - - assertEquals("or_test", strategy.getDefaultValue(TestUtils.getCM("", "C", "D", String.class, true), String.class)); - assertEquals("or_test", strategy.getDefaultValue(TestUtils.getCM("", "B", "D", String.class, true), String.class)); - assertEquals("or_test", strategy.getDefaultValue(TestUtils.getCM("", "C", "A", String.class, true), String.class)); - assertNotEquals("or_test", strategy.getDefaultValue(TestUtils.getCM("", "A", "B", String.class, true), String.class)); - } - @Test public void testProvider_StaticDateProvider() { final Date date = new Date(1234567891011L); diff --git a/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/pluggable/StaticNumberProviderTest.java b/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/pluggable/StaticNumberProviderTest.java new file mode 100644 index 0000000..441c8e0 --- /dev/null +++ b/redg-runtime/src/test/java/com/btc/redg/runtime/defaultvalues/pluggable/StaticNumberProviderTest.java @@ -0,0 +1,38 @@ +package com.btc.redg.runtime.defaultvalues.pluggable; + +import java.math.BigDecimal; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import com.btc.redg.models.ColumnModel; + +import static org.junit.Assert.*; + +public class StaticNumberProviderTest { + @Test + public void getDefaultValue() throws Exception { + StaticNumberProvider staticNumberProvider = new StaticNumberProvider(12L); + + Assert.assertEquals(12d, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), double.class), 0d); + Assert.assertEquals(12f, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), float.class), 0f); + Assert.assertEquals(12L, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), long.class).longValue()); + Assert.assertEquals(12, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), int.class).intValue()); + Assert.assertEquals((byte) 12, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), byte.class).byteValue()); + Assert.assertEquals((short) 12, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), short.class).shortValue()); + Assert.assertEquals(new BigDecimal(12), staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), BigDecimal.class)); + Assert.assertEquals(12d, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), Double.class), 0d); + Assert.assertEquals(12f, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), Float.class), 0f); + Assert.assertEquals(12L, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), Long.class).longValue()); + Assert.assertEquals(12, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), Integer.class).intValue()); + Assert.assertEquals((byte) 12, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), Byte.class).byteValue()); + Assert.assertEquals((short) 12, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), Short.class).shortValue()); + Assert.assertEquals(12, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), AtomicInteger.class).get()); + Assert.assertEquals(12L, staticNumberProvider.getDefaultValue(Mockito.mock(ColumnModel.class), AtomicLong.class).get()); + + } + +} \ No newline at end of file