Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 230 additions & 0 deletions core/src/main/java/io/substrait/expression/MaskExpression.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
package io.substrait.expression;

import java.util.List;
import java.util.Optional;
import org.immutables.value.Value;

/**
* A mask expression that selectively removes fields from complex types (struct, list, map).
*
* <p>This corresponds to the {@code Expression.MaskExpression} message in the Substrait protobuf
* specification. It is used in {@code ReadRel} to describe column projection — the subset of a
* relation's schema that should actually be read.
*
* @see <a href="https://substrait.io/expressions/field_references/">Substrait Field References</a>
*/
@Value.Enclosing
public interface MaskExpression {

// ---------------------------------------------------------------------------
// Top-level MaskExpression value
// ---------------------------------------------------------------------------

/** The concrete mask expression value holding the top-level struct selection and options. */
@Value.Immutable
interface MaskExpr {
/** The top-level struct selection describing which fields to include. */
StructSelect getSelect();

/**
* When {@code true}, a struct that has only a single selected field will <em>not</em> be
* unwrapped into its child type.
*/
@Value.Default
default boolean getMaintainSingularStruct() {
return false;
}

static ImmutableMaskExpression.MaskExpr.Builder builder() {
return ImmutableMaskExpression.MaskExpr.builder();
}
}

// ---------------------------------------------------------------------------
// Select – a union of StructSelect | ListSelect | MapSelect
// ---------------------------------------------------------------------------

/** A selection on a complex type – exactly one of struct, list, or map must be set. */
@Value.Immutable
interface Select {
Optional<StructSelect> getStruct();

Optional<ListSelect> getList();

Optional<MapSelect> getMap();

static ImmutableMaskExpression.Select.Builder builder() {
return ImmutableMaskExpression.Select.builder();
}

static Select ofStruct(StructSelect structSelect) {
return builder().struct(structSelect).build();
}

static Select ofList(ListSelect listSelect) {
return builder().list(listSelect).build();
}

static Select ofMap(MapSelect mapSelect) {
return builder().map(mapSelect).build();
}
}

// ---------------------------------------------------------------------------
// Struct selection
// ---------------------------------------------------------------------------

/** Selects a subset of fields from a struct type. */
@Value.Immutable
interface StructSelect {
List<StructItem> getStructItems();

static ImmutableMaskExpression.StructSelect.Builder builder() {
return ImmutableMaskExpression.StructSelect.builder();
}
}

/** Selects a single field from a struct, with an optional nested child selection. */
@Value.Immutable
interface StructItem {
/** Zero-based field index within the struct. */
int getField();

/** Optional child selection for nested complex types. */
Optional<Select> getChild();

static ImmutableMaskExpression.StructItem.Builder builder() {
return ImmutableMaskExpression.StructItem.builder();
}

static StructItem of(int field) {
return builder().field(field).build();
}

static StructItem of(int field, Select child) {
return builder().field(field).child(child).build();
}
}

// ---------------------------------------------------------------------------
// List selection
// ---------------------------------------------------------------------------

/** Selects elements from a list type by index or slice. */
@Value.Immutable
interface ListSelect {
List<ListSelectItem> getSelection();

/** Optional child selection applied to each selected element. */
Optional<Select> getChild();

static ImmutableMaskExpression.ListSelect.Builder builder() {
return ImmutableMaskExpression.ListSelect.builder();
}
}

/** A single selection within a list – either an element or a slice. */
@Value.Immutable
interface ListSelectItem {
Optional<ListElement> getItem();

Optional<ListSlice> getSlice();

static ImmutableMaskExpression.ListSelectItem.Builder builder() {
return ImmutableMaskExpression.ListSelectItem.builder();
}

static ListSelectItem ofItem(ListElement element) {
return builder().item(element).build();
}

static ListSelectItem ofSlice(ListSlice slice) {
return builder().slice(slice).build();
}
}

/** Selects a single element from a list by zero-based index. */
@Value.Immutable
interface ListElement {
int getField();

static ImmutableMaskExpression.ListElement.Builder builder() {
return ImmutableMaskExpression.ListElement.builder();
}

static ListElement of(int field) {
return builder().field(field).build();
}
}

/** Selects a contiguous range of elements from a list. */
@Value.Immutable
interface ListSlice {
int getStart();

int getEnd();

static ImmutableMaskExpression.ListSlice.Builder builder() {
return ImmutableMaskExpression.ListSlice.builder();
}

static ListSlice of(int start, int end) {
return builder().start(start).end(end).build();
}
}

// ---------------------------------------------------------------------------
// Map selection
// ---------------------------------------------------------------------------

/** Selects entries from a map type by exact key or key expression. */
@Value.Immutable
interface MapSelect {
Optional<MapKey> getKey();

Optional<MapKeyExpression> getExpression();

/** Optional child selection applied to each selected map value. */
Optional<Select> getChild();

static ImmutableMaskExpression.MapSelect.Builder builder() {
return ImmutableMaskExpression.MapSelect.builder();
}

static MapSelect ofKey(MapKey key) {
return builder().key(key).build();
}

static MapSelect ofExpression(MapKeyExpression expression) {
return builder().expression(expression).build();
}
}

/** Selects a map entry by an exact key match. */
@Value.Immutable
interface MapKey {
String getMapKey();

static ImmutableMaskExpression.MapKey.Builder builder() {
return ImmutableMaskExpression.MapKey.builder();
}

static MapKey of(String mapKey) {
return builder().mapKey(mapKey).build();
}
}

/** Selects map entries by a wildcard key expression. */
@Value.Immutable
interface MapKeyExpression {
String getMapKeyExpression();

static ImmutableMaskExpression.MapKeyExpression.Builder builder() {
return ImmutableMaskExpression.MapKeyExpression.builder();
}

static MapKeyExpression of(String mapKeyExpression) {
return builder().mapKeyExpression(mapKeyExpression).build();
}
}
}
Loading