java.lang.Object
com.darkcollective.relix.embed.Tuple
All Implemented Interfaces:
Row

public final class Tuple extends Object implements Row
One row of a result, read as Java types.

A row the engine produces is a tuple of Values, and Value carries three methods: whether it is null, what type it is, and how to display it. That is the right surface for a sealed core type — it is a model of a relational value, not a conversion library — and it is thin for someone reading a result.

So the conversions live here, on the row view the embedding API hands back. The same argument that puts this API on the frontend side of the engine boundary puts them here: the engine keeps the model, the facade adapts it.

Pattern matching is still the authoritative route

Value is a sealed hierarchy, so a switch over it is exhaustive and the compiler will tell you about a case you forgot:

String describe(Value value) {
    return switch (value) {
        case NumberValue n -> "number " + n.value();
        case StringValue s -> "string " + s.value();
        default            -> value.asDisplayString();
    };
}

The accessors below are a convenience for the common case, not a second authority. Where a column's type genuinely varies — an ANY column over schema-on-read data — the switch is the tool, because it makes the variation visible.

What an accessor does with a value it did not expect

A NULL comes back as Java null, in every accessor, which is why none of them returns a primitive. A relational NULL is an absent value and Java spells that the same way.

A value of the wrong type raises. An accessor names a type, and quietly coercing one type to another would make it a second, weaker definition of what the column holds — the failure would then surface as a wrong answer rather than as a wrong call. The one deliberate accommodation is string(String) over a value that is not a string, which is refused for exactly that reason: display formatting is Value.asDisplayString(), and asking for it by that name says so.

Since:
1.0
  • Method Details

    • schema

      public Schema schema()
      Description copied from interface: Row
      Returns the schema that describes this row's columns.
      Specified by:
      schema in interface Row
      Returns:
      the row's schema; never null
    • get

      public Value get(String columnName)
      Description copied from interface: Row
      Returns the value in the named column (case-insensitive).
      Specified by:
      get in interface Row
      Parameters:
      columnName - the column name to look up
      Returns:
      the value; never null (absent values use NullValue.INSTANCE)
    • get

      public Value get(int index)
      Description copied from interface: Row
      Returns the value at the given zero-based column index.
      Specified by:
      get in interface Row
      Parameters:
      index - zero-based column index
      Returns:
      the value; never null
    • width

      public int width()
      Description copied from interface: Row
      Returns the number of columns in this row.
      Specified by:
      width in interface Row
      Returns:
      column count; always ≥ 1
    • columnNames

      public List<String> columnNames()
      Description copied from interface: Row
      Returns this row's column names in order.

      For a closed-schema row these are the schema's column names. For an open (schema-on-read) row — see DocumentRow — the schema declares no columns, so implementations override this to report the document's actual top-level field names. This is what lets consumers (e.g. the result formatter) enumerate the columns of a heterogeneous, schema-less row.

      Specified by:
      columnNames in interface Row
      Returns:
      the ordered, possibly empty list of column names; never null
    • isNull

      public boolean isNull(String column)
      Whether column holds NULL.

      Every accessor already answers null for one, so this is for the case where the distinction is the question rather than an aside.

      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      whether the value is NULL
      Throws:
      IllegalArgumentException - if there is no such column
      Since:
      1.0
    • string

      public String string(String column)
      Returns the value in column as a String, or null when it is NULL.
      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the value in column as a String, or null when it is NULL
      Throws:
      RelixException - if the value is not a string — Value.asDisplayString is how a value of any type is rendered for display
      Since:
      1.0
    • decimal

      public BigDecimal decimal(String column)
      Returns the value in column as a BigDecimal, or null when it is NULL.

      The exact form: a Relix number is a decimal, and this is the accessor that loses nothing.

      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the value in column as a BigDecimal, or null when it is NULL
      Throws:
      RelixException - if the value is not a number
      Since:
      1.0
    • longValue

      public Long longValue(String column)
      Returns the value in column as a Long, or null when it is NULL.

      Named for the type rather than spelled long because long is a keyword — and boxed, because a NULL has to come back as something.

      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the value in column as a Long, or null when it is NULL
      Throws:
      RelixException - if the value is not a number, or has a fractional part — silently truncating one would be the wrong answer rather than an approximate one
      Since:
      1.0
    • doubleValue

      public Double doubleValue(String column)
      Returns the value in column as a Double, or null when it is NULL.

      Lossy by construction, as any decimal-to-binary conversion is. Reach for decimal(String) where the exact value matters — money, most obviously.

      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the value in column as a Double, or null when it is NULL
      Throws:
      RelixException - if the value is not a number
      Since:
      1.0
    • booleanValue

      public Boolean booleanValue(String column)
      Returns the value in column as a Boolean, or null when it is NULL.
      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the value in column as a Boolean, or null when it is NULL
      Throws:
      RelixException - if the value is not a boolean
      Since:
      1.0
    • instant

      public Instant instant(String column)
      Returns the TIMESTAMP in column, or null when it is NULL.
      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the TIMESTAMP in column, or null when it is NULL
      Throws:
      RelixException - if the value is not a timestamp
      Since:
      1.0
    • date

      public LocalDate date(String column)
      Returns the DATE in column, or null when it is NULL.
      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the DATE in column, or null when it is NULL
      Throws:
      RelixException - if the value is not a date
      Since:
      1.0
    • time

      public LocalTime time(String column)
      Returns the TIME in column, or null when it is NULL.
      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the TIME in column, or null when it is NULL
      Throws:
      RelixException - if the value is not a time
      Since:
      1.0
    • duration

      public Duration duration(String column)
      Returns the DURATION in column, or null when it is NULL.
      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the DURATION in column, or null when it is NULL
      Throws:
      RelixException - if the value is not a duration
      Since:
      1.0
    • array

      public List<Value> array(String column)
      Returns the elements of the array in column, or null when it is NULL.

      What a COLLECT aggregate or an unexploded nested column holds. The elements stay Values: an array's elements need not share a type, so there is nothing to convert them to.

      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the elements of the array in column, or null when it is NULL
      Throws:
      RelixException - if the value is not an array
      Since:
      1.0
    • struct

      public Map<String,Value> struct(String column)
      Returns the fields of the struct in column, or null when it is NULL.

      The fields stay Values, for the reason array(String)'s elements do. A field of a nested struct is reachable by dotted name from the query itself, which is usually the better place to descend.

      Parameters:
      column - the column name (case-insensitive); must exist
      Returns:
      the fields of the struct in column, or null when it is NULL
      Throws:
      RelixException - if the value is not a struct
      Since:
      1.0
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • equals

      public boolean equals(Object o)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object