diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBRecordStoreNullQueryTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBRecordStoreNullQueryTest.java index 1cc50d088a..99c9698890 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBRecordStoreNullQueryTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBRecordStoreNullQueryTest.java @@ -26,6 +26,7 @@ import com.apple.foundationdb.record.TestRecordsNulls2Proto; import com.apple.foundationdb.record.TestRecordsNulls3Proto; import com.apple.foundationdb.record.TestRecordsNulls3ExplicitProto; +import com.apple.foundationdb.record.TestRecordsNullsEditionsProto; import com.apple.foundationdb.record.TestRecordsTupleFieldsProto; import com.apple.foundationdb.record.TupleFieldsProto; import com.apple.foundationdb.record.metadata.Key; @@ -113,6 +114,10 @@ protected static RecordMetaData proto3ExplicitMetaData() { return RecordMetaData.newBuilder().setRecords(TestRecordsNulls3ExplicitProto.getDescriptor()).getRecordMetaData(); } + protected static RecordMetaData protoEditionsMetaData() { + return RecordMetaData.newBuilder().setRecords(TestRecordsNullsEditionsProto.getDescriptor()).getRecordMetaData(); + } + @FunctionalInterface interface RecordBuilder { M build(@Nonnull String name, @Nullable Integer intValue, @Nullable String stringValue); @@ -192,6 +197,18 @@ protected static TestRecordsNulls3ExplicitProto.MyNullRecord buildRecord3Explici return builder.build(); } + protected static TestRecordsNullsEditionsProto.MyNullRecord buildRecordEditions(@Nonnull String name, @Nullable Integer intValue, @Nullable String stringValue) { + TestRecordsNullsEditionsProto.MyNullRecord.Builder builder = TestRecordsNullsEditionsProto.MyNullRecord.newBuilder(); + builder.setName(name); + if (intValue != null) { + builder.setIntValue(intValue); + } + if (stringValue != null) { + builder.setStringValue(stringValue); + } + return builder.build(); + } + protected void saveTestRecords(@Nonnull RecordBuilder builder) { recordStore.saveRecord(builder.build("empty", null, null)); recordStore.saveRecord(builder.build("default", 0, "")); @@ -429,6 +446,53 @@ public void testProto3Explicit() { } } + // Explicit presence is now the default. + @Test + public void testProtoEditions() { + try (FDBRecordContext context = openContext()) { + createOrOpenRecordStore(context, protoEditionsMetaData()); + saveTestRecords(FDBRecordStoreNullQueryTest::buildRecordEditions); + + assertThat(executeQuery(RecordQuery.newBuilder() + .setRecordType("MyNullRecord") + .setFilter(Query.field("int_value").equalsValue(2)) + .build()), + is(Collections.singletonList("two"))); + assertThat(executeQuery(RecordQuery.newBuilder() + .setRecordType("MyNullRecord") + .setFilter(Query.field("string_value").equalsValue("B")) + .build()), + is(Collections.singletonList("two"))); + + assertThat(executeQuery(RecordQuery.newBuilder() + .setRecordType("MyNullRecord") + .setFilter(Query.field("int_value").isNull()) + .build()), + is(Collections.singletonList("empty"))); + assertThat(executeQuery(RecordQuery.newBuilder() + .setRecordType("MyNullRecord") + .setFilter(Query.field("int_value").equalsValue(0)) + .build()), + is(Collections.singletonList("default"))); + assertThat(executeQuery(RecordQuery.newBuilder() + .setRecordType("MyNullRecord") + .setFilter(Query.field("string_value").isNull()) + .build()), + is(Collections.singletonList("empty"))); + assertThat(executeQuery(RecordQuery.newBuilder() + .setRecordType("MyNullRecord") + .setFilter(Query.field("string_value").equalsValue("")) + .build()), + is(Collections.singletonList("default"))); + + assertThat(executeQuery(RecordQuery.newBuilder() + .setRecordType("MyNullRecord") + .setSort(Key.Expressions.field("int_value")) + .build()), + is(Arrays.asList("empty", "minus", "default", "one", "two"))); + } + } + @Test public void testCompareSerialization() throws Exception { final TestRecordsNulls2Proto.MyNullRecord emptyProto2 = buildRecord2("record", null, null); diff --git a/fdb-record-layer-core/src/test/proto/test_records_nulls_editions.proto b/fdb-record-layer-core/src/test/proto/test_records_nulls_editions.proto new file mode 100644 index 0000000000..c099a4fe84 --- /dev/null +++ b/fdb-record-layer-core/src/test/proto/test_records_nulls_editions.proto @@ -0,0 +1,37 @@ +/* + * test_records_nulls_editions.proto + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2026 Apple Inc. and the FoundationDB project authors + * + * Licensed 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. + */ +edition = "2023"; + +package com.apple.foundationdb.record.testnullseditions; + +option java_package = "com.apple.foundationdb.record"; +option java_outer_classname = "TestRecordsNullsEditionsProto"; + +import "record_metadata_options.proto"; + +message MyNullRecord { + string name = 1 [(field).primary_key = true]; + string string_value = 2 [(field).index = {}]; + int32 int_value = 3 [(field).index = {}]; +} + +message RecordTypeUnion { + MyNullRecord _MyNullRecord = 1; +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c262cc9d7..6787472d71 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,7 +35,7 @@ fdb = "7.1.26" geophile = "2.3.0" generatedAnnotation = "1.3.2" grpc = "1.64.1" -grpc-commonProtos = "2.37.0" +grpc-commonProtos = "2.64.1" gson = "2.13.2" guava = "33.4.8-jre" h2 = "1.3.148" @@ -48,7 +48,7 @@ jts = "1.16.1" log4j = "2.25.3" prometheus = "0.16.0" prometheus-grpc = "0.6.0" -protobuf = "3.25.8" +protobuf = "4.33.4" sqlline = "1.12.0" slf4j = "1.7.36"