SyntheticRecordPlanner { @Nonnull public SyntheticRecordPlan scanForType(@Nonnull SyntheticRecordType<?> syntheticRecordType) { final SyntheticRecordFromStoredRecordPlan fromRecord = forType(syntheticRecordType); RecordQueryPlan query = queryPlanner.plan(RecordQuery.newBuilder().setRecordTypes(fromRecord.getStoredRecordTypes()).build()); return new SyntheticRecordScanPlan(query, fromRecord, true); } SyntheticRecordPlanner(@Nonnull RecordMetaData recordMetaData, @Nonnull RecordStoreState storeState);  SyntheticRecordPlanner(@Nonnull FDBRecordStore store); @Nonnull SyntheticRecordPlan scanForType(@Nonnull SyntheticRecordType<?> syntheticRecordType); @Nonnull SyntheticRecordFromStoredRecordPlan forType(@Nonnull SyntheticRecordType<?> syntheticRecordType); @Nonnull SyntheticRecordFromStoredRecordPlan forType(@Nonnull JoinedRecordType joinedRecordType); @Nullable SyntheticRecordFromStoredRecordPlan fromStoredType(@Nonnull RecordType storedRecordType, boolean onlyIfIndexed); Set<RecordType> storedRecordTypesForIndex(@Nonnull Index index, @Nullable Collection<RecordType> recordTypes); @Nonnull SyntheticRecordFromStoredRecordPlan forIndex(@Nonnull Index index); @Nonnull SyntheticRecordFromStoredRecordPlan forJoinConstituent(@Nonnull JoinedRecordType joinedRecordType,
                                                                  @Nonnull JoinedRecordType.JoinConstituent joinConstituent);  }
@Test public void oneToOne() throws Exception { metaDataBuilder.addIndex("MySimpleRecord", new Index("MySimpleRecord$other_rec_no", field("other_rec_no"), IndexTypes.VALUE, IndexOptions.UNIQUE_OPTIONS)); final JoinedRecordTypeBuilder joined = metaDataBuilder.addJoinedRecordType("OneToOne"); joined.addConstituent("simple", "MySimpleRecord"); joined.addConstituent("other", "MyOtherRecord"); joined.addJoin("simple", "other_rec_no", "other", "rec_no"); try (FDBRecordContext context = openContext()) { final FDBRecordStore recordStore = recordStoreBuilder.setContext(context).create(); for (int i = 0; i < 3; i++) { TestRecordsJoinIndexProto.MySimpleRecord.Builder simple = TestRecordsJoinIndexProto.MySimpleRecord.newBuilder(); simple.setRecNo(i).setOtherRecNo(1000 + i); recordStore.saveRecord(simple.build()); TestRecordsJoinIndexProto.MyOtherRecord.Builder other = TestRecordsJoinIndexProto.MyOtherRecord.newBuilder(); other.setRecNo(1000 + i); recordStore.saveRecord(other.build()); } context.commit(); } try (FDBRecordContext context = openContext()) { final FDBRecordStore recordStore = recordStoreBuilder.setContext(context).open(); final SyntheticRecordPlanner planner = new SyntheticRecordPlanner(recordStore); SyntheticRecordPlan plan1 = planner.scanForType(recordStore.getRecordMetaData().getSyntheticRecordType("OneToOne")); Multiset<Tuple> expected1 = ImmutableMultiset.of( Tuple.from(-1, Tuple.from(0), Tuple.from(1000)), Tuple.from(-1, Tuple.from(1), Tuple.from(1001)), Tuple.from(-1, Tuple.from(2), Tuple.from(1002))); Multiset<Tuple> results1 = HashMultiset.create(plan1.execute(recordStore).map(FDBSyntheticRecord::getPrimaryKey).asList().join()); assertEquals(expected1, results1); } }
@Test public void manyToMany() throws Exception { final JoinedRecordTypeBuilder joined = metaDataBuilder.addJoinedRecordType("ManyToMany"); joined.addConstituent("simple", "MySimpleRecord"); joined.addConstituent("other", "MyOtherRecord"); joined.addConstituent("joining", "JoiningRecord"); joined.addJoin("joining", "simple_rec_no", "simple", "rec_no"); joined.addJoin("joining", "other_rec_no", "other", "rec_no"); try (FDBRecordContext context = openContext()) { final FDBRecordStore recordStore = recordStoreBuilder.setContext(context).create(); for (int i = 0; i < 3; i++) { TestRecordsJoinIndexProto.MySimpleRecord.Builder simple = TestRecordsJoinIndexProto.MySimpleRecord.newBuilder(); simple.setRecNo(i); recordStore.saveRecord(simple.build()); TestRecordsJoinIndexProto.MyOtherRecord.Builder other = TestRecordsJoinIndexProto.MyOtherRecord.newBuilder(); other.setRecNo(1000 + i); recordStore.saveRecord(other.build()); } TestRecordsJoinIndexProto.JoiningRecord.Builder joining = TestRecordsJoinIndexProto.JoiningRecord.newBuilder(); joining.setRecNo(100).setSimpleRecNo(1).setOtherRecNo(1000); recordStore.saveRecord(joining.build()); joining.setRecNo(101).setSimpleRecNo(2).setOtherRecNo(1000); recordStore.saveRecord(joining.build()); joining.setRecNo(102).setSimpleRecNo(2).setOtherRecNo(1002); recordStore.saveRecord(joining.build()); context.commit(); } try (FDBRecordContext context = openContext()) { final FDBRecordStore recordStore = recordStoreBuilder.setContext(context).open(); final SyntheticRecordPlanner planner = new SyntheticRecordPlanner(recordStore); SyntheticRecordPlan plan1 = planner.scanForType(recordStore.getRecordMetaData().getSyntheticRecordType("ManyToMany")); Multiset<Tuple> expected1 = ImmutableMultiset.of( Tuple.from(-1, Tuple.from(1), Tuple.from(1000), Tuple.from(100)), Tuple.from(-1, Tuple.from(2), Tuple.from(1000), Tuple.from(101)), Tuple.from(-1, Tuple.from(2), Tuple.from(1002), Tuple.from(102))); Multiset<Tuple> results1 = HashMultiset.create(plan1.execute(recordStore).map(FDBSyntheticRecord::getPrimaryKey).asList().join()); assertEquals(expected1, results1); } }
@Test public void clique() throws Exception { final JoinedRecordTypeBuilder clique = metaDataBuilder.addJoinedRecordType("Clique"); clique.addConstituent("type_a", "TypeA"); clique.addConstituent("type_b", "TypeB"); clique.addConstituent("type_c", "TypeC"); clique.addJoin("type_a", "type_b_rec_no", "type_b", "rec_no"); clique.addJoin("type_b", "type_c_rec_no", "type_c", "rec_no"); clique.addJoin("type_c", "type_a_rec_no", "type_a", "rec_no"); try (FDBRecordContext context = openContext()) { final FDBRecordStore recordStore = recordStoreBuilder.setContext(context).create(); for (int i = 0; i < 3; i++) { TestRecordsJoinIndexProto.TypeA.Builder typeA = TestRecordsJoinIndexProto.TypeA.newBuilder(); typeA.setRecNo(100 + i).setTypeBRecNo(200 + i); recordStore.saveRecord(typeA.build()); TestRecordsJoinIndexProto.TypeB.Builder typeB = TestRecordsJoinIndexProto.TypeB.newBuilder(); typeB.setRecNo(200 + i).setTypeCRecNo(300 + i); recordStore.saveRecord(typeB.build()); TestRecordsJoinIndexProto.TypeC.Builder typeC = TestRecordsJoinIndexProto.TypeC.newBuilder(); typeC.setRecNo(300 + i).setTypeARecNo(100 + i); recordStore.saveRecord(typeC.build()); } context.commit(); } try (FDBRecordContext context = openContext()) { final FDBRecordStore recordStore = recordStoreBuilder.setContext(context).open(); final SyntheticRecordPlanner planner = new SyntheticRecordPlanner(recordStore); SyntheticRecordPlan plan1 = planner.scanForType(recordStore.getRecordMetaData().getSyntheticRecordType("Clique")); Multiset<Tuple> expected1 = ImmutableMultiset.of( Tuple.from(-1, Tuple.from(100), Tuple.from(200), Tuple.from(300)), Tuple.from(-1, Tuple.from(101), Tuple.from(201), Tuple.from(301)), Tuple.from(-1, Tuple.from(102), Tuple.from(202), Tuple.from(302))); Multiset<Tuple> results1 = HashMultiset.create(plan1.execute(recordStore).map(FDBSyntheticRecord::getPrimaryKey).asList().join()); assertEquals(expected1, results1); TestRecordsJoinIndexProto.TypeC.Builder typeC = TestRecordsJoinIndexProto.TypeC.newBuilder(); typeC.setRecNo(301).setTypeARecNo(999); recordStore.saveRecord(typeC.build()); SyntheticRecordPlan plan2 = planner.scanForType(recordStore.getRecordMetaData().getSyntheticRecordType("Clique")); Multiset<Tuple> expected2 = ImmutableMultiset.of( Tuple.from(-1, Tuple.from(100), Tuple.from(200), Tuple.from(300)), Tuple.from(-1, Tuple.from(102), Tuple.from(202), Tuple.from(302))); Multiset<Tuple> results2 = HashMultiset.create(plan2.execute(recordStore).map(FDBSyntheticRecord::getPrimaryKey).asList().join()); assertEquals(expected2, results2); } }