Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.graphar.io;

/** The simple comparison operations supported by an IO filter hint. */
public enum ComparisonOperator {
EQUAL,
NOT_EQUAL,
LESS_THAN,
LESS_THAN_OR_EQUAL,
GREATER_THAN,
GREATER_THAN_OR_EQUAL,
IS_NULL,
IS_NOT_NULL
}
109 changes: 109 additions & 0 deletions maven-projects/io-api/src/main/java/org/apache/graphar/io/Filter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.graphar.io;

import java.util.Objects;

/**
* A single inspectable table-filter hint; request filters are combined with logical AND. A physical
* reader must validate a comparison literal against the column's {@link ColumnType}: BOOLEAN uses
* Boolean; integer and floating kinds use their matching boxed Java types; STRING uses String; DATE
* uses LocalDate; and TIMESTAMP_MILLIS uses millisecond-precise Instant. Other types cannot be
* compared by this contract.
*
* <p>Comparison operands must have the same declared type; a type mismatch is invalid rather than a
* coercion. Null values never match a comparison, including NOT_EQUAL; use IS_NULL or IS_NOT_NULL
* for null tests. Ordered STRING comparisons use {@link String#compareTo(String)}, and DATE and
* TIMESTAMP_MILLIS use their natural ordering. Readers must reject an invalid comparison before
* returning a result, whether the filter is pushed down or evaluated as fallback.
*/
public final class Filter {
private final String column;
private final ComparisonOperator operator;
private final Literal value;

private Filter(String column, ComparisonOperator operator, Literal value) {
if (column == null || column.isBlank()) {
throw new IllegalArgumentException("A filter column cannot be blank.");
}
this.column = column;
this.operator = Objects.requireNonNull(operator, "Filter operator cannot be null.");
if ((operator == ComparisonOperator.IS_NULL || operator == ComparisonOperator.IS_NOT_NULL)
&& value != null) {
throw new IllegalArgumentException(operator + " does not accept a comparison value.");
}
if (operator != ComparisonOperator.IS_NULL
&& operator != ComparisonOperator.IS_NOT_NULL
&& value == null) {
throw new IllegalArgumentException(operator + " requires a non-null comparison value.");
}
this.value = value;
}

/** Creates a filter with an immutable scalar comparison value. */
public static Filter comparison(String column, ComparisonOperator operator, Literal value) {
if (operator == ComparisonOperator.IS_NULL || operator == ComparisonOperator.IS_NOT_NULL) {
throw new IllegalArgumentException("Use isNull or isNotNull for null checks.");
}
return new Filter(column, operator, value);
}

/** Creates a null check for {@code column}. */
public static Filter isNull(String column) {
return new Filter(column, ComparisonOperator.IS_NULL, null);
}

/** Creates a non-null check for {@code column}. */
public static Filter isNotNull(String column) {
return new Filter(column, ComparisonOperator.IS_NOT_NULL, null);
}

public String column() {
return column;
}

public ComparisonOperator operator() {
return operator;
}

/** Returns the scalar comparison value, or {@code null} for null checks. */
public Literal value() {
return value;
}

@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Filter)) {
return false;
}
Filter that = (Filter) other;
return column.equals(that.column)
&& operator == that.operator
&& Objects.equals(value, that.value);
}

@Override
public int hashCode() {
return Objects.hash(column, operator, value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.graphar.io;

import java.time.Instant;
import java.time.LocalDate;
import java.util.Objects;

/** An immutable scalar used by a {@link Filter} comparison. */
public final class Literal {
private final Object value;

private Literal(Object value) {
this.value = value;
}

/**
* Wraps a supported immutable scalar: {@link Boolean}, numeric boxed primitives, {@link
* String}, {@link LocalDate}, or millisecond-precise {@link Instant}.
*/
public static Literal of(Object value) {
Objects.requireNonNull(value, "A literal value cannot be null.");
if (!(value instanceof Boolean)
&& !(value instanceof Byte)
&& !(value instanceof Short)
&& !(value instanceof Integer)
&& !(value instanceof Long)
&& !(value instanceof Float)
&& !(value instanceof Double)
&& !(value instanceof String)
&& !(value instanceof LocalDate)
&& !(value instanceof Instant)) {
throw new IllegalArgumentException(
"A literal must be a Boolean, numeric boxed primitive, String, LocalDate, or Instant.");
}
if (value instanceof Float && !Float.isFinite((Float) value)) {
throw new IllegalArgumentException("A floating point literal must be finite.");
}
if (value instanceof Double && !Double.isFinite((Double) value)) {
throw new IllegalArgumentException("A floating point literal must be finite.");
}
if (value instanceof Instant && ((Instant) value).getNano() % 1_000_000 != 0) {
throw new IllegalArgumentException(
"An Instant literal must have millisecond precision.");
}
return new Literal(value);
}

/** Returns this literal's immutable scalar value. */
public Object value() {
return value;
}

@Override
public boolean equals(Object other) {
return other instanceof Literal && value.equals(((Literal) other).value);
}

@Override
public int hashCode() {
return value.hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.graphar.io;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/** An ordered set of requested output columns. */
public final class Projection {
private static final Projection ALL_COLUMNS = new Projection(true, List.of());

private final boolean allColumns;
private final List<String> columns;

private Projection(boolean allColumns, List<String> columns) {
this.allColumns = allColumns;
this.columns = columns;
}

/** Requests every available column. */
public static Projection all() {
return ALL_COLUMNS;
}

/** Requests the supplied columns in order. */
public static Projection of(List<String> columns) {
if (columns == null || columns.isEmpty()) {
throw new IllegalArgumentException("A projection must contain at least one column.");
}
List<String> copy = new ArrayList<>(columns.size());
Set<String> names = new HashSet<>();
for (String column : columns) {
if (column == null || column.isBlank()) {
throw new IllegalArgumentException("Projection column names cannot be blank.");
}
if (!names.add(column)) {
throw new IllegalArgumentException(
"Projection contains duplicate column: " + column);
}
copy.add(column);
}
return new Projection(false, List.copyOf(copy));
}

/** Returns whether this projection requests every available column. */
public boolean isAllColumns() {
return allColumns;
}

/** Returns the requested columns, or an empty list when all columns are requested. */
public List<String> columns() {
return columns;
}

@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Projection)) {
return false;
}
Projection that = (Projection) other;
return allColumns == that.allColumns && columns.equals(that.columns);
}

@Override
public int hashCode() {
return Objects.hash(allColumns, columns);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.graphar.io;

/** A physical optimization that an IO reader may apply to a request. */
public enum ReadCapability {
PROJECTION,
ROW_RANGE,
FILTER,
LIMIT
}
Loading
Loading