Created
October 7, 2017 07:59
-
-
Save izmajlowiczl/1e17614d802eaa9174e0c419ba530d6b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Source + Unit Tests | |
package pl.expensive.storage; | |
import java.util.ArrayList; | |
import java.util.List; | |
public class SQLiteTableBuilder { | |
private String table; | |
private List<String> commands; | |
private List<String> fields, pks, fks; | |
private SQLiteTableBuilder(String table) { | |
this.table = table; | |
commands = new ArrayList<>(); | |
} | |
public static SQLiteTableBuilder newTable(String table) { | |
checkNotEmpty(table); | |
return new SQLiteTableBuilder(table); | |
} | |
public SQLiteTableBuilder withOptionalText(String column) { | |
checkNotEmpty(column); | |
initLazyFieldsCollection(); | |
fields.add(column); | |
commands.add(column + " TEXT"); | |
return this; | |
} | |
public SQLiteTableBuilder withOptionalDecimal(String column) { | |
checkNotEmpty(column); | |
initLazyFieldsCollection(); | |
fields.add(column); | |
commands.add(column + " INTEGER"); | |
return this; | |
} | |
public SQLiteTableBuilder withMandatoryText(String column) { | |
checkNotEmpty(column); | |
initLazyFieldsCollection(); | |
fields.add(column); | |
commands.add(column + " TEXT NOT NULL"); | |
return this; | |
} | |
public SQLiteTableBuilder withMandatoryDecimal(String column) { | |
checkNotEmpty(column); | |
initLazyFieldsCollection(); | |
fields.add(column); | |
commands.add(column + " INTEGER NOT NULL"); | |
return this; | |
} | |
public SQLiteTableBuilder withPrimaryKey(String column) { | |
checkNotEmpty(column); | |
initLazyPrimaryKeysCollection(); | |
pks.add(column); | |
commands.add("PRIMARY KEY (" + column + ")"); | |
return this; | |
} | |
/** | |
* It does not check if referenced column exists. | |
* It does not check if referenced table exists, is PRIMARY KEY or UNIQUE! | |
*/ | |
public SQLiteTableBuilder withForeignKey(String column, String referenceTable, String referenceColumn) { | |
checkNotEmpty(column); | |
checkNotEmpty(referenceTable); | |
checkNotEmpty(referenceColumn); | |
initLazyForeignKeysCollection(); | |
fks.add(column); | |
commands.add("FOREIGN KEY (" + column + ") REFERENCES " + referenceTable + "(" + referenceColumn + ")"); | |
return this; | |
} | |
public String build() { | |
if (commands.isEmpty()) { | |
throw new IllegalStateException("Cannot create table without any field"); | |
} | |
// Check if all Primary Keys have backing fields | |
if (pks != null) { | |
for (String pk : pks) { | |
if (!fields.contains(pk)) { | |
throw new IllegalStateException("Cannot find field for primary key [" + pk + "]"); | |
} | |
} | |
} | |
// Check if all Foreign Keys have backing fields | |
if (fks != null) { | |
for (String pk : fks) { | |
if (!fields.contains(pk)) { | |
throw new IllegalStateException("Cannot find field for foreign key [" + pk + "]"); | |
} | |
} | |
} | |
return "CREATE TABLE " + table + " (" + join(commands) + ");"; | |
} | |
private static void checkNotEmpty(String param) { | |
if (param == null || param.isEmpty()) { | |
throw new IllegalArgumentException("Table name is mandatory."); | |
} | |
} | |
private void initLazyPrimaryKeysCollection() { | |
if (pks == null) { | |
pks = new ArrayList<>(); | |
} | |
} | |
private void initLazyForeignKeysCollection() { | |
if (fks == null) { | |
fks = new ArrayList<>(); | |
} | |
} | |
private void initLazyFieldsCollection() { | |
if (fields == null) { | |
fields = new ArrayList<>(); | |
} | |
} | |
/** | |
* | |
* Copy of Apache Commons StringUtils.join() with small modification. | |
* | |
* <p>Joins the elements of the provided array into a single String | |
* containing the provided list of elements.</p> | |
* <p> | |
* <p>No delimiter is added before or after the list. | |
* Null objects or empty strings within the array are represented by | |
* empty strings.</p> | |
* <p> | |
* <pre> | |
* StringUtils.join(null, *) = null | |
* StringUtils.join([], *) = "" | |
* StringUtils.join([null], *) = "" | |
* StringUtils.join(["a", "b", "c"], ';') = "a;b;c" | |
* StringUtils.join(["a", "b", "c"], null) = "abc" | |
* StringUtils.join([null, "", "a"], ';') = ";;a" | |
* </pre> | |
* | |
* @param array the array of values to join together, may be null | |
* @return the joined String, <code>null</code> if null array input | |
* @since 2.0 | |
*/ | |
private static String join(List<String> array) { | |
if (array == null) { | |
return null; | |
} | |
int startIndex = 0; | |
int endIndex = array.size(); | |
char separator = ','; | |
int bufSize = (endIndex - startIndex); | |
if (bufSize <= 0) { | |
return ""; | |
} | |
bufSize *= ((array.get(startIndex) == null ? 16 : array.get(startIndex).length()) + 1); | |
StringBuilder buf = new StringBuilder(bufSize); | |
for (int i = startIndex; i < endIndex; i++) { | |
if (i > startIndex) { | |
buf.append(separator); | |
} | |
if (array.get(i) != null) { | |
buf.append(array.get(i)); | |
} | |
} | |
return buf.toString(); | |
} | |
} | |
// Tests | |
package pl.expensive.storage; | |
import org.junit.Test; | |
import static org.hamcrest.CoreMatchers.equalTo; | |
import static org.hamcrest.MatcherAssert.assertThat; | |
public class SQLiteTableBuilderTest { | |
@Test | |
public void CreateOptionalText() { | |
String sql = SQLiteTableBuilder.newTable("tbl") | |
.withOptionalText("col_text") | |
.build(); | |
String expected = "CREATE TABLE tbl (col_text TEXT);"; | |
assertThat(sql, equalTo(expected)); | |
} | |
@Test | |
public void CreateOptionalDecimal() { | |
String sql = SQLiteTableBuilder.newTable("tbl") | |
.withOptionalDecimal("col_number") | |
.build(); | |
String expected = "CREATE TABLE tbl (col_number INTEGER);"; | |
assertThat(sql, equalTo(expected)); | |
} | |
@Test | |
public void CreateMandatoryText() { | |
String sql = SQLiteTableBuilder.newTable("tbl") | |
.withMandatoryText("col_text") | |
.build(); | |
String expected = "CREATE TABLE tbl (col_text TEXT NOT NULL);"; | |
assertThat(sql, equalTo(expected)); | |
} | |
@Test | |
public void mandatoryDecimal() { | |
String sql = SQLiteTableBuilder.newTable("tbl") | |
.withMandatoryDecimal("col_number") | |
.build(); | |
String expected = "CREATE TABLE tbl (col_number INTEGER NOT NULL);"; | |
assertThat(sql, equalTo(expected)); | |
} | |
@Test | |
public void CreateMultipleFields() { | |
String sql = SQLiteTableBuilder.newTable("tbl") | |
.withOptionalText("col_text") | |
.withMandatoryDecimal("col_number") | |
.build(); | |
String expected = "CREATE TABLE tbl (" + | |
"col_text TEXT," + | |
"col_number INTEGER NOT NULL);"; | |
assertThat(sql, equalTo(expected)); | |
} | |
@Test | |
public void CreatePrimaryKey() { | |
String sql = SQLiteTableBuilder.newTable("tbl") | |
.withMandatoryText("pk_col") | |
.withPrimaryKey("pk_col") | |
.build(); | |
String expected = "CREATE TABLE tbl (" + | |
"pk_col TEXT NOT NULL," + | |
"PRIMARY KEY (pk_col));"; | |
assertThat(sql, equalTo(expected)); | |
} | |
@Test | |
public void CreateMultiplePrimaryKeys() { | |
String sql = SQLiteTableBuilder.newTable("tbl") | |
.withMandatoryText("pk_col") | |
.withMandatoryText("pk_col1") | |
.withPrimaryKey("pk_col") | |
.withPrimaryKey("pk_col1") | |
.build(); | |
String expected = "CREATE TABLE tbl (" + | |
"pk_col TEXT NOT NULL," + | |
"pk_col1 TEXT NOT NULL," + | |
"PRIMARY KEY (pk_col)," + | |
"PRIMARY KEY (pk_col1)" + | |
");"; | |
assertThat(sql, equalTo(expected)); | |
} | |
@Test | |
public void CreateForeignKey() { | |
String sql = SQLiteTableBuilder.newTable("tbl") | |
.withMandatoryText("fk_col") | |
.withForeignKey("fk_col", "tbl_other", "col_other") | |
.build(); | |
String expected = "CREATE TABLE tbl (" + | |
"fk_col TEXT NOT NULL," + | |
"FOREIGN KEY (fk_col) REFERENCES tbl_other(col_other));"; | |
assertThat(sql, equalTo(expected)); | |
} | |
@Test | |
public void CreateMultipleForeignKey() { | |
String sql = SQLiteTableBuilder.newTable("tbl") | |
.withMandatoryText("fk_col") | |
.withMandatoryDecimal("fk_col1") | |
.withForeignKey("fk_col", "tbl_other", "col_other") | |
.withForeignKey("fk_col1", "tbl_other1", "col_other1") | |
.build(); | |
String expected = "CREATE TABLE tbl (" + | |
"fk_col TEXT NOT NULL," + | |
"fk_col1 INTEGER NOT NULL," + | |
"FOREIGN KEY (fk_col) REFERENCES tbl_other(col_other)," + | |
"FOREIGN KEY (fk_col1) REFERENCES tbl_other1(col_other1)" + | |
");"; | |
assertThat(sql, equalTo(expected)); | |
} | |
@Test(expected = IllegalStateException.class) | |
public void CreateTable_WithoutFields_ThrowsException() { | |
SQLiteTableBuilder.newTable("tbl").build(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void CreateTable_WithoutName_ThrowsException() { | |
SQLiteTableBuilder.newTable("") | |
.withOptionalText("col") | |
.build(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void CreateOptionalText_WithoutFieldName_ThrowsException() { | |
SQLiteTableBuilder.newTable("table") | |
.withOptionalText("") | |
.build(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void CreateOptionalDecimal_WithoutFieldName_ThrowsException() { | |
SQLiteTableBuilder.newTable("table") | |
.withOptionalDecimal("") | |
.build(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void CreateMandatoryText_WithoutFieldName_ThrowsException() { | |
SQLiteTableBuilder.newTable("table") | |
.withMandatoryText("") | |
.build(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void CreateMandatoryDecimal_WithoutFieldName_ThrowsException() { | |
SQLiteTableBuilder.newTable("table") | |
.withMandatoryDecimal("") | |
.build(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void CreatePrimaryKey_WithoutFieldName_ThrowsException() { | |
SQLiteTableBuilder.newTable("table") | |
.withOptionalText("col_text") | |
.withPrimaryKey("") | |
.build(); | |
} | |
@Test(expected = IllegalStateException.class) | |
public void CreatePrimaryKey_WithoutBakingField_ThrowsException() { | |
SQLiteTableBuilder.newTable("tbl") | |
.withOptionalDecimal("col_number") | |
.withPrimaryKey("pk_col") | |
.build(); | |
} | |
@Test(expected = IllegalStateException.class) | |
public void CreateMultiplePrimaryKeys_WithMissingBackingField_ThrowsException() { | |
SQLiteTableBuilder.newTable("tbl") | |
.withMandatoryText("pk_col") | |
.withPrimaryKey("pk_col") | |
.withPrimaryKey("pk_col1") | |
.build(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void CreateForeignKey_WithoutColumnName_ThrowsException() { | |
SQLiteTableBuilder.newTable("table") | |
.withForeignKey("", "other_tbl", "other_field") | |
.build(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void CreateForeignKey_WithoutReferenceTable_ThrowsException() { | |
SQLiteTableBuilder.newTable("table") | |
.withForeignKey("col", "", "other_field") | |
.build(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void CreateForeignKey_WithoutReferenceColumn_ThrowsException() { | |
SQLiteTableBuilder.newTable("table") | |
.withForeignKey("col", "other", "") | |
.build(); | |
} | |
@Test(expected = IllegalStateException.class) | |
public void CreateForeignKey_WithoutBakingField_ThrowsException() { | |
SQLiteTableBuilder.newTable("tbl") | |
.withOptionalDecimal("not-a-foreign-key") | |
.withForeignKey("fk_col", "tbl_other", "col_other") | |
.build(); | |
} | |
@Test(expected = IllegalStateException.class) | |
public void CreateMultipleForeignKeys_WithMissingBackingField_ThrowsException() { | |
SQLiteTableBuilder.newTable("tbl") | |
.withMandatoryText("fk_col") | |
.withForeignKey("fk_col", "tbl_other", "col_other") | |
.withForeignKey("fk_col1", "tbl_other1", "col_other1") | |
.build(); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment