Permalink
Browse files

[core] Support nullable flag for meta-data of row column.

```java
import acolyte.RowList2;
import acolyte.RowLists;

RowList2.Impl<String,Float> l1 =
  RowLists.rowList2(String.class, Float.class).
  withNullable(1, true); // First column is nullable

import acolyte.RowList;
import acolyte.Column;

Column<String> meta1 = new Column<String>(String.class, "a", true);

RowList2.Impl<String,Float> l2 =
  RowLists.rowLists2(meta1, RowList.Column(Float.class, "b"));

import static acolyte.RowList.Column

RowList2.Impl<String,Float> l3 =
  RowLists.rowLists2(Column(String.class, "a").withNullable(true),
    Column(Float.class, "b"));
```
  • Loading branch information...
cchantep
cchantep committed Jan 11, 2014
1 parent 2aae84f commit 4edb03ec7b48e89e3219fe898f667c63cdd356a8
@@ -0,0 +1,65 @@
+package acolyte;
+
+/**
+ * Column meta data.
+ *
+ * @author Cedric Chantepie
+ */
+public final class Column<T> {
+ /**
+ * Column class
+ */
+ public final Class<T> columnClass;
+
+ /**
+ * Column name/label
+ */
+ public final String name;
+
+ /**
+ * Column is nullable? (default: false)
+ */
+ public final boolean nullable;
+
+ // --- Constructors ---
+
+ /**
+ * Bulk constructor.
+ */
+ Column(final Class<T> columnClass,
+ final String name,
+ final boolean nullable) {
+
+ if (columnClass == null) {
+ throw new IllegalArgumentException("No column class");
+ } // end of if
+
+ if (name == null || name.length() == 0) {
+ throw new IllegalArgumentException("Invalid column name: " +
+ name);
+
+ } // end of if
+
+ this.columnClass = columnClass;
+ this.name = name;
+ this.nullable = nullable;
+ } // end of <init>
+
+ /**
+ * Creates a not nullable column.
+ */
+ Column(final Class<T> columnClass, final String name) {
+ this(columnClass, name, false);
+ } // end of <init>
+
+ // ---
+
+ /**
+ * Returns similar metadata, but with specified |nullable| flag.
+ *
+ * @param nullable Whether new metadata is nullable
+ */
+ public Column withNullable(final boolean nullable) {
+ return new Column(this.columnClass, this.name, nullable);
+ } // end of withNullable
+} // end of class Column
@@ -23,7 +23,6 @@
* Type-safe list of row.
*
* @author Cedric Chantepie
- * @todo Add nullable property to Column
*/
public abstract class RowList<R extends Row> {
@@ -45,9 +44,20 @@
*
* @param columnIndex Index of column (first index is 1)
* @param label Column name/label
+ * @see Column#name
*/
public abstract RowList<R> withLabel(int columnIndex, String label);
+ /**
+ * Returns copy of row list with updated metadata,
+ * including whether specified column is |nullable|.
+ *
+ * @param columnIndex Index of column (first index is 1)
+ * @param nullable Is column nullable?
+ * @see Column#nullable
+ */
+ public abstract RowList<R> withNullable(int columnIndex, boolean nullable);
+
/**
* Returns result set from these rows.
*
@@ -91,6 +101,13 @@ public QueryResult asResult() {
*/
public abstract Map<String,Integer> getColumnLabels();
+ /**
+ * Gets column mappings, from index to nullable flag.
+ *
+ * @return Column mappings, or empty map (not null) if none
+ */
+ public abstract Map<Integer,Boolean> getColumnNullables();
+
// --- Shared ---
/**
@@ -123,6 +140,12 @@ public QueryResult asResult() {
private final Map<String,Integer> labels =
new HashMap<String,Integer>(0);
+ /**
+ * Empty flags
+ */
+ private final Map<Integer,Boolean> nullables =
+ new HashMap<Integer,Boolean>(0);
+
// --- Constructors ---
/**
@@ -142,18 +165,23 @@ private NilRowList() { }
/**
* Returns unchanged nil row list.
*/
- public RowList<Row.Nothing> append(final Row.Nothing row) {
+ public NilRowList append(final Row.Nothing row) { return this; }
+
+ /**
+ * Returns unchanged nil row list.
+ */
+ public NilRowList withLabel(final int columnIndex, final String label) {
return this;
- } // end of append
+ } // end of withLabel
/**
* Returns unchanged nil row list.
*/
- public RowList<Row.Nothing> withLabel(final int columnIndex,
- final String label) {
+ public NilRowList withNullable(final int columnIndex,
+ final boolean nullable) {
return this;
- } // end of withLabel
+ } // end of withNullable
/**
* Returns empty list of columns classes.
@@ -168,6 +196,13 @@ private NilRowList() { }
public Map<String,Integer> getColumnLabels() {
return this.labels;
} // end of getColumnLabels
+
+ /**
+ * Returns empty list of nullable flags.
+ */
+ public Map<Integer,Boolean> getColumnNullables() {
+ return this.nullables;
+ } // end of getColumnNullables
} // end of class Nil
/**
@@ -182,39 +217,6 @@ private NilRowList() { }
return new Column<T>(columnClass, name);
} // end of column
- /**
- * Column definition.
- */
- public static final class Column<T> {
- /**
- * Column class
- */
- public final Class<T> columnClass;
-
- /**
- * Column name/label
- */
- public final String name;
-
- /**
- * Bulk constructor.
- */
- private Column(final Class<T> columnClass, final String name) {
- if (columnClass == null) {
- throw new IllegalArgumentException("No column class");
- } // end of if
-
- if (name == null || name.length() == 0) {
- throw new IllegalArgumentException("Invalid column name: " +
- name);
-
- } // end of if
-
- this.columnClass = columnClass;
- this.name = name;
- } // end of <init>
- } // end of Column
-
/**
* Result set made from list of row.
*
@@ -1138,6 +1140,7 @@ public ResultSetMetaData getMetaData() throws SQLException {
public final class RowListMetaData implements ResultSetMetaData {
final List<Class<?>> columnClasses;
final Map<String,Integer> columnLabels;
+ final Map<Integer,Boolean> columnNullables;
// --- Constructors ---
@@ -1147,6 +1150,7 @@ public ResultSetMetaData getMetaData() throws SQLException {
private RowListMetaData() {
this.columnClasses = getColumnClasses();
this.columnLabels = getColumnLabels();
+ this.columnNullables = getColumnNullables();
} // end of <init>
// ---
@@ -1236,8 +1240,13 @@ public boolean isSigned(final int column) throws SQLException {
* {@inheritDoc}
*/
public int isNullable(final int column) throws SQLException {
- // TODO: See anorm.RowSpec
- return ResultSetMetaData.columnNullableUnknown;
+ final Boolean b = this.columnNullables.get(column);
+
+ return (b == null) ? ResultSetMetaData.columnNullableUnknown :
+ (Boolean.TRUE.equals(b))
+ ? ResultSetMetaData.columnNullable
+ : ResultSetMetaData.columnNoNulls;
+
} // end of isNullable
/**
@@ -39,7 +39,7 @@ public abstract class RowList#N#<#CP#,UPDATED extends RowList#N#<#CP#,?>>
copy.add(row);
- return factory().rowList(#GC#, copy, getColumnLabels());
+ return factory().rowList(#GC#, copy, getColumnLabels(), getColumnNullables());
} // end of append
/**
@@ -57,9 +57,21 @@ public abstract class RowList#N#<#CP#,UPDATED extends RowList#N#<#CP#,?>>
cols.put(label, (Integer) columnIndex);
- return factory().rowList(#GC#, getRows(), cols);
+ return factory().rowList(#GC#, getRows(), cols, getColumnNullables());
} // end of withLabel
+ /**
+ * {@inheritDoc}
+ */
+ public UPDATED withNullable(final int columnIndex, final boolean nullable) {
+ final HashMap<Integer,Boolean> nls =
+ new HashMap<Integer,Boolean>(getColumnNullables());
+
+ nls.put(columnIndex, nullable);
+
+ return factory().rowList(#GC#, getRows(), getColumnLabels(), nls);
+ } // end of withNullable
+
// --- Inner classes ---
/**
@@ -69,8 +81,11 @@ public abstract class RowList#N#<#CP#,UPDATED extends RowList#N#<#CP#,?>>
/**
* Build row list, including |rows| with given column |labels|.
+ *
+ * @param nullables Nullable flags.
*/
- public ROWLIST rowList(#CS#, final List<Row#N#<#CP#>> rows, final Map<String,Integer> labels);
+ public ROWLIST rowList(#CS#, final List<Row#N#<#CP#>> rows, final Map<String,Integer> labels, final Map<Integer,Boolean> nullables);
+
} // end of interface Factory
/**
@@ -89,6 +104,11 @@ public abstract class RowList#N#<#CP#,UPDATED extends RowList#N#<#CP#,?>>
*/
final Map<String,Integer> colNames;
+ /**
+ * Nullable flags
+ */
+ final Map<Integer,Boolean> colNullables;
+
#PS#
/**
@@ -103,7 +123,7 @@ public abstract class RowList#N#<#CP#,UPDATED extends RowList#N#<#CP#,?>>
*
* @throws IllegalArgumentException if rows is null
*/
- Impl(#CS#, final List<Row#N#<#CP#>> rows, final Map<String,Integer> colNames) {
+ Impl(#CS#, final List<Row#N#<#CP#>> rows, final Map<String,Integer> colNames, final Map<Integer,Boolean> colNullables) {
#IC#
@@ -115,8 +135,13 @@ public abstract class RowList#N#<#CP#,UPDATED extends RowList#N#<#CP#,?>>
throw new IllegalArgumentException("Invalid names");
} // end of if
+ if (colNullables == null) {
+ throw new IllegalArgumentException("Invalid nullable flags");
+ } // end of if
+
this.rows = Collections.unmodifiableList(rows);
this.colNames = Collections.unmodifiableMap(colNames);
+ this.colNullables = Collections.unmodifiableMap(colNullables);
// Column classes
final ArrayList<Class<?>> colClasses = new ArrayList<Class<?>>();
@@ -130,7 +155,7 @@ public abstract class RowList#N#<#CP#,UPDATED extends RowList#N#<#CP#,?>>
* No-arg constructor.
*/
Impl(#CS#) {
- this(#CA#, new ArrayList<Row#N#<#CP#>>(), new HashMap<String,Integer>());
+ this(#CA#, new ArrayList<Row#N#<#CP#>>(), new HashMap<String,Integer>(), new HashMap<Integer,Boolean>());
} // end of <init>
// ---
@@ -142,8 +167,8 @@ public abstract class RowList#N#<#CP#,UPDATED extends RowList#N#<#CP#,?>>
*/
RowList#N#.Factory<#CP#, Impl<#CP#>> factory() {
return new RowList#N#.Factory<#CP#,Impl<#CP#>>() {
- public Impl<#CP#> rowList(#CS#, final List<Row#N#<#CP#>> rows, final Map<String,Integer> colNames) {
- return new Impl(#PSC#, rows, colNames);
+ public Impl<#CP#> rowList(#CS#, final List<Row#N#<#CP#>> rows, final Map<String,Integer> colNames, final Map<Integer,Boolean> colNullables) {
+ return new Impl(#PSC#, rows, colNames, colNullables);
}
};
} // end of factory
@@ -162,5 +187,10 @@ public abstract class RowList#N#<#CP#,UPDATED extends RowList#N#<#CP#,?>>
* {@inheritDoc}
*/
public List<Class<?>> getColumnClasses() { return this.colClasses; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<Integer,Boolean> getColumnNullables() { return this.colNullables; }
} // end of class Impl
} // end of class RowList#N#
Oops, something went wrong.

0 comments on commit 4edb03e

Please sign in to comment.