use of com.apple.foundationdb.record.metadata.RecordTypeBuilder in project fdb-record-layer by FoundationDB.
the class FDBRecordStoreQueryTest method enumFields.
/**
* Verify that enum field indexes are used.
*/
@DualPlannerTest
void enumFields() throws Exception {
RecordMetaDataHook hook = metaData -> {
final RecordTypeBuilder type = metaData.getRecordType("MyShapeRecord");
metaData.addIndex(type, new Index("size", field("size")));
metaData.addIndex(type, new Index("color", field("color")));
metaData.addIndex(type, new Index("shape", field("shape")));
};
setupEnumShapes(hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MyShapeRecord").setFilter(Query.field("color").equalsValue(TestRecordsEnumProto.MyShapeRecord.Color.RED)).build();
// Index(color [[10],[10]])
RecordQueryPlan plan = planner.plan(query);
assertMatchesExactly(plan, indexPlan().where(indexName("color")));
assertFalse(plan.hasRecordScan(), "should not use record scan");
assertEquals(1393755963, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-14917443, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-2083866282, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
try (FDBRecordContext context = openContext()) {
openEnumRecordStore(context, hook);
int i = 0;
try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
while (cursor.hasNext()) {
FDBQueriedRecord<Message> rec = cursor.next();
TestRecordsEnumProto.MyShapeRecord.Builder shapeRec = TestRecordsEnumProto.MyShapeRecord.newBuilder();
shapeRec.mergeFrom(rec.getRecord());
assertEquals(TestRecordsEnumProto.MyShapeRecord.Color.RED, shapeRec.getColor());
i++;
}
}
assertEquals(9, i);
assertDiscardedNone(context);
}
}
use of com.apple.foundationdb.record.metadata.RecordTypeBuilder in project fdb-record-layer by FoundationDB.
the class RecordMetaDataBuilder method updateUnionFieldsAndRecordTypes.
private void updateUnionFieldsAndRecordTypes(@Nonnull Descriptors.Descriptor union, boolean processExtensionOptions) {
final Map<String, RecordTypeBuilder> oldRecordTypes = ImmutableMap.copyOf(recordTypes);
recordTypes.clear();
unionFields.clear();
for (Descriptors.FieldDescriptor unionField : union.getFields()) {
Descriptors.Descriptor newDescriptor = unionField.getMessageType();
Descriptors.Descriptor oldDescriptor = findOldDescriptor(unionField, union);
if (unionFields.containsKey(newDescriptor)) {
if (!recordTypes.containsKey(newDescriptor.getName())) {
// Union field was seen before but the record type is unknown? This must not happen.
throw new MetaDataException("Unknown record type for union field " + unionField.getName());
}
// For existing record types, the preferred field is the last one, except if there is one whose name matches.
remapUnionField(newDescriptor, unionField);
} else if (oldDescriptor == null) {
// New field and record type.
RecordTypeBuilder recordType = processRecordType(unionField, processExtensionOptions);
if (recordType.getSinceVersion() != null && recordType.getSinceVersion() != version) {
throw new MetaDataException(String.format("Record type version (%d) does not match meta-data version (%d)", recordType.getSinceVersion(), version));
} else {
recordType.setSinceVersion(version);
}
unionFields.put(newDescriptor, unionField);
} else {
updateRecordType(oldRecordTypes, oldDescriptor, newDescriptor);
unionFields.put(newDescriptor, unionField);
}
}
}
use of com.apple.foundationdb.record.metadata.RecordTypeBuilder in project fdb-record-layer by FoundationDB.
the class RecordMetaDataBuilder method build.
/**
* Build and validate meta-data with specific index registry.
* @param validate {@code true} to validate the new meta-data
* @return new meta-data
*/
@Nonnull
public RecordMetaData build(boolean validate) {
Map<String, RecordType> builtRecordTypes = Maps.newHashMapWithExpectedSize(recordTypes.size());
Map<String, SyntheticRecordType<?>> builtSyntheticRecordTypes = Maps.newHashMapWithExpectedSize(syntheticRecordTypes.size());
RecordMetaData metaData = new RecordMetaData(recordsDescriptor, getUnionDescriptor(), unionFields, builtRecordTypes, builtSyntheticRecordTypes, indexes, universalIndexes, formerIndexes, splitLongRecords, storeRecordVersions, version, subspaceKeyCounter, usesSubspaceKeyCounter, recordCountKey, localFileDescriptor != null);
for (RecordTypeBuilder recordTypeBuilder : recordTypes.values()) {
KeyExpression primaryKey = recordTypeBuilder.getPrimaryKey();
if (primaryKey != null) {
builtRecordTypes.put(recordTypeBuilder.getName(), recordTypeBuilder.build(metaData));
for (Index index : recordTypeBuilder.getIndexes()) {
index.setPrimaryKeyComponentPositions(buildPrimaryKeyComponentPositions(index.getRootExpression(), primaryKey));
}
} else {
throw new MetaDataException("Record type " + recordTypeBuilder.getName() + " must have a primary key");
}
}
if (!syntheticRecordTypes.isEmpty()) {
DescriptorProtos.FileDescriptorProto.Builder fileBuilder = DescriptorProtos.FileDescriptorProto.newBuilder();
fileBuilder.setName("_synthetic");
fileBuilder.addDependency(unionDescriptor.getFile().getName());
syntheticRecordTypes.values().forEach(recordTypeBuilder -> recordTypeBuilder.buildDescriptor(fileBuilder));
final Descriptors.FileDescriptor fileDescriptor;
try {
final Descriptors.FileDescriptor[] dependencies = new Descriptors.FileDescriptor[] { unionDescriptor.getFile() };
fileDescriptor = Descriptors.FileDescriptor.buildFrom(fileBuilder.build(), dependencies);
} catch (Descriptors.DescriptorValidationException ex) {
throw new MetaDataException("Could not build synthesized file descriptor", ex);
}
for (SyntheticRecordTypeBuilder<?> recordTypeBuilder : syntheticRecordTypes.values()) {
builtSyntheticRecordTypes.put(recordTypeBuilder.getName(), recordTypeBuilder.build(metaData, fileDescriptor));
}
}
if (validate) {
final MetaDataValidator validator = new MetaDataValidator(metaData, indexMaintainerRegistry);
validator.validate();
}
return metaData;
}
use of com.apple.foundationdb.record.metadata.RecordTypeBuilder in project fdb-record-layer by FoundationDB.
the class FDBMetaDataStore method addMultiTypeIndexAsync.
/**
* Add a new index to the record meta-data that contains multiple record types asynchronously.
* If the list is null or empty, the resulting index will include all record types.
* If the list has one element it will just be a normal single record type index.
* @param recordTypes a list of record types that the index will include
* @param index the index to be added
* @return a future that completes when the index is added
*/
@Nonnull
public CompletableFuture<Void> addMultiTypeIndexAsync(@Nullable List<String> recordTypes, @Nonnull Index index) {
return loadCurrentProto().thenCompose(metaDataProto -> {
RecordMetaDataBuilder recordMetaDataBuilder = createMetaDataBuilder(metaDataProto);
List<RecordTypeBuilder> recordTypeBuilders = new ArrayList<>();
if (recordTypes != null) {
for (String type : recordTypes) {
recordTypeBuilders.add(recordMetaDataBuilder.getRecordType(type));
}
}
recordMetaDataBuilder.addMultiTypeIndex(recordTypeBuilders, index);
return saveAndSetCurrent(recordMetaDataBuilder.getRecordMetaData().toProto());
});
}
Aggregations