Skip to content

Commit b4eee52

Browse files
ModelBuilder: make relation buildable, extract common builder code
1 parent 04f5d38 commit b4eee52

File tree

1 file changed

+142
-62
lines changed

1 file changed

+142
-62
lines changed

objectbox-java/src/main/java/io/objectbox/ModelBuilder.java

Lines changed: 142 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2024 ObjectBox Ltd. All rights reserved.
2+
* Copyright 2017-2025 ObjectBox Ltd. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,34 +34,82 @@
3434
import io.objectbox.model.ModelProperty;
3535
import io.objectbox.model.ModelRelation;
3636

37-
// Remember: IdUid is a struct, not a table, and thus must be inlined
38-
@SuppressWarnings("WeakerAccess,UnusedReturnValue, unused")
37+
// To learn how to use the FlatBuffers API see https://flatbuffers.dev/tutorial/
38+
// Note: IdUid is a struct, not a table, and thus must be inlined
39+
40+
/**
41+
* Builds a flatbuffer representation of the database model to be passed when opening a store.
42+
* <p>
43+
* This is an internal API that should only be called by the generated MyObjectBox code.
44+
*/
3945
@Internal
4046
public class ModelBuilder {
4147
private static final int MODEL_VERSION = 2;
4248

43-
final FlatBufferBuilder fbb = new FlatBufferBuilder();
44-
final List<Integer> entityOffsets = new ArrayList<>();
49+
private final FlatBufferBuilder fbb = new FlatBufferBuilder();
50+
private final List<Integer> entityOffsets = new ArrayList<>();
51+
52+
private long version = 1;
53+
54+
private Integer lastEntityId;
55+
private Long lastEntityUid;
56+
57+
private Integer lastIndexId;
58+
private Long lastIndexUid;
59+
60+
private Integer lastRelationId;
61+
private Long lastRelationUid;
62+
63+
/**
64+
* Base class for builders.
65+
* <p>
66+
* Methods adding properties to be used by {@link #createFlatBufferTable(FlatBufferBuilder)} should call
67+
* {@link #checkNotFinished()}.
68+
* <p>
69+
* The last call should be {@link #finish()}.
70+
*/
71+
abstract static class PartBuilder {
72+
73+
private final FlatBufferBuilder fbb;
74+
private boolean finished;
75+
76+
PartBuilder(FlatBufferBuilder fbb) {
77+
this.fbb = fbb;
78+
}
4579

46-
long version = 1;
80+
FlatBufferBuilder getFbb() {
81+
return fbb;
82+
}
4783

48-
Integer lastEntityId;
49-
Long lastEntityUid;
84+
void checkNotFinished() {
85+
if (finished) {
86+
throw new IllegalStateException("Already finished");
87+
}
88+
}
89+
90+
/**
91+
* Marks this as finished and returns {@link #createFlatBufferTable(FlatBufferBuilder)}.
92+
*/
93+
public final int finish() {
94+
checkNotFinished();
95+
finished = true;
96+
return createFlatBufferTable(getFbb());
97+
}
5098

51-
Integer lastIndexId;
52-
Long lastIndexUid;
99+
/**
100+
* Creates a flatbuffer table using the given builder and returns its offset.
101+
*/
102+
public abstract int createFlatBufferTable(FlatBufferBuilder fbb);
103+
}
53104

54-
Integer lastRelationId;
55-
Long lastRelationUid;
105+
public static class PropertyBuilder extends PartBuilder {
56106

57-
public class PropertyBuilder {
58107
private final int type;
59108
private final int virtualTargetOffset;
60109
private final int propertyNameOffset;
61110
private final int targetEntityOffset;
62111

63112
private int secondaryNameOffset;
64-
boolean finished;
65113
private int flags;
66114
private int id;
67115
private long uid;
@@ -71,7 +119,9 @@ public class PropertyBuilder {
71119
private int externalPropertyType;
72120
private int hnswParamsOffset;
73121

74-
PropertyBuilder(String name, @Nullable String targetEntityName, @Nullable String virtualTarget, int type) {
122+
private PropertyBuilder(FlatBufferBuilder fbb, String name, @Nullable String targetEntityName,
123+
@Nullable String virtualTarget, int type) {
124+
super(fbb);
75125
this.type = type;
76126
propertyNameOffset = fbb.createString(name);
77127
targetEntityOffset = targetEntityName != null ? fbb.createString(targetEntityName) : 0;
@@ -129,6 +179,7 @@ public PropertyBuilder hnswParams(long dimensions,
129179
@Nullable Float reparationBacklinkProbability,
130180
@Nullable Long vectorCacheHintSizeKb) {
131181
checkNotFinished();
182+
FlatBufferBuilder fbb = getFbb();
132183
HnswParams.startHnswParams(fbb);
133184
HnswParams.addDimensions(fbb, dimensions);
134185
if (neighborsPerNode != null) {
@@ -161,19 +212,12 @@ public PropertyBuilder flags(int flags) {
161212

162213
public PropertyBuilder secondaryName(String secondaryName) {
163214
checkNotFinished();
164-
secondaryNameOffset = fbb.createString(secondaryName);
215+
secondaryNameOffset = getFbb().createString(secondaryName);
165216
return this;
166217
}
167218

168-
private void checkNotFinished() {
169-
if (finished) {
170-
throw new IllegalStateException("Already finished");
171-
}
172-
}
173-
174-
public int finish() {
175-
checkNotFinished();
176-
finished = true;
219+
@Override
220+
public int createFlatBufferTable(FlatBufferBuilder fbb) {
177221
ModelProperty.startModelProperty(fbb);
178222
ModelProperty.addName(fbb, propertyNameOffset);
179223
if (targetEntityOffset != 0) {
@@ -210,7 +254,41 @@ public int finish() {
210254
}
211255
}
212256

213-
public class EntityBuilder {
257+
public static class RelationBuilder extends PartBuilder {
258+
259+
private final String name;
260+
private final int relationId;
261+
private final long relationUid;
262+
private final int targetEntityId;
263+
private final long targetEntityUid;
264+
265+
private RelationBuilder(FlatBufferBuilder fbb, String name, int relationId, long relationUid,
266+
int targetEntityId, long targetEntityUid) {
267+
super(fbb);
268+
this.name = name;
269+
this.relationId = relationId;
270+
this.relationUid = relationUid;
271+
this.targetEntityId = targetEntityId;
272+
this.targetEntityUid = targetEntityUid;
273+
}
274+
275+
@Override
276+
public int createFlatBufferTable(FlatBufferBuilder fbb) {
277+
int nameOffset = fbb.createString(name);
278+
279+
ModelRelation.startModelRelation(fbb);
280+
ModelRelation.addName(fbb, nameOffset);
281+
int relationIdOffset = IdUid.createIdUid(fbb, relationId, relationUid);
282+
ModelRelation.addId(fbb, relationIdOffset);
283+
int targetEntityIdOffset = IdUid.createIdUid(fbb, targetEntityId, targetEntityUid);
284+
ModelRelation.addTargetEntityId(fbb, targetEntityIdOffset);
285+
return ModelRelation.endModelRelation(fbb);
286+
}
287+
}
288+
289+
public static class EntityBuilder extends PartBuilder {
290+
291+
private final ModelBuilder model;
214292
final String name;
215293
final List<Integer> propertyOffsets = new ArrayList<>();
216294
final List<Integer> relationOffsets = new ArrayList<>();
@@ -220,10 +298,13 @@ public class EntityBuilder {
220298
Integer flags;
221299
Integer lastPropertyId;
222300
Long lastPropertyUid;
223-
PropertyBuilder propertyBuilder;
301+
@Nullable PropertyBuilder propertyBuilder;
302+
@Nullable RelationBuilder relationBuilder;
224303
boolean finished;
225304

226-
EntityBuilder(String name) {
305+
EntityBuilder(ModelBuilder model, FlatBufferBuilder fbb, String name) {
306+
super(fbb);
307+
this.model = model;
227308
this.name = name;
228309
}
229310

@@ -246,12 +327,6 @@ public EntityBuilder flags(int flags) {
246327
return this;
247328
}
248329

249-
private void checkNotFinished() {
250-
if (finished) {
251-
throw new IllegalStateException("Already finished");
252-
}
253-
}
254-
255330
public PropertyBuilder property(String name, int type) {
256331
return property(name, null, type);
257332
}
@@ -263,43 +338,48 @@ public PropertyBuilder property(String name, @Nullable String targetEntityName,
263338
public PropertyBuilder property(String name, @Nullable String targetEntityName, @Nullable String virtualTarget,
264339
int type) {
265340
checkNotFinished();
266-
checkFinishProperty();
267-
propertyBuilder = new PropertyBuilder(name, targetEntityName, virtualTarget, type);
341+
finishPropertyOrRelation();
342+
propertyBuilder = new PropertyBuilder(getFbb(), name, targetEntityName, virtualTarget, type);
268343
return propertyBuilder;
269344
}
270345

271-
void checkFinishProperty() {
346+
public RelationBuilder relation(String name, int relationId, long relationUid, int targetEntityId,
347+
long targetEntityUid) {
348+
checkNotFinished();
349+
finishPropertyOrRelation();
350+
351+
RelationBuilder relationBuilder = new RelationBuilder(getFbb(), name, relationId, relationUid, targetEntityId, targetEntityUid);
352+
this.relationBuilder = relationBuilder;
353+
return relationBuilder;
354+
}
355+
356+
private void finishPropertyOrRelation() {
357+
if (propertyBuilder != null && relationBuilder != null) {
358+
throw new IllegalStateException("Must not build property and relation at the same time.");
359+
}
272360
if (propertyBuilder != null) {
273361
propertyOffsets.add(propertyBuilder.finish());
274362
propertyBuilder = null;
275363
}
364+
if (relationBuilder != null) {
365+
relationOffsets.add(relationBuilder.finish());
366+
relationBuilder = null;
367+
}
276368
}
277369

278-
public EntityBuilder relation(String name, int relationId, long relationUid, int targetEntityId,
279-
long targetEntityUid) {
370+
public ModelBuilder entityDone() {
371+
// Make sure any pending property or relation is finished first
280372
checkNotFinished();
281-
checkFinishProperty();
282-
283-
int propertyNameOffset = fbb.createString(name);
284-
285-
ModelRelation.startModelRelation(fbb);
286-
ModelRelation.addName(fbb, propertyNameOffset);
287-
int relationIdOffset = IdUid.createIdUid(fbb, relationId, relationUid);
288-
ModelRelation.addId(fbb, relationIdOffset);
289-
int targetEntityIdOffset = IdUid.createIdUid(fbb, targetEntityId, targetEntityUid);
290-
ModelRelation.addTargetEntityId(fbb, targetEntityIdOffset);
291-
relationOffsets.add(ModelRelation.endModelRelation(fbb));
292-
293-
return this;
373+
finishPropertyOrRelation();
374+
model.entityOffsets.add(finish());
375+
return model;
294376
}
295377

296-
public ModelBuilder entityDone() {
297-
checkNotFinished();
298-
checkFinishProperty();
299-
finished = true;
378+
@Override
379+
public int createFlatBufferTable(FlatBufferBuilder fbb) {
300380
int testEntityNameOffset = fbb.createString(name);
301-
int propertiesOffset = createVector(propertyOffsets);
302-
int relationsOffset = relationOffsets.isEmpty() ? 0 : createVector(relationOffsets);
381+
int propertiesOffset = model.createVector(propertyOffsets);
382+
int relationsOffset = relationOffsets.isEmpty() ? 0 : model.createVector(relationOffsets);
303383

304384
ModelEntity.startModelEntity(fbb);
305385
ModelEntity.addName(fbb, testEntityNameOffset);
@@ -316,12 +396,12 @@ public ModelBuilder entityDone() {
316396
if (flags != null) {
317397
ModelEntity.addFlags(fbb, flags);
318398
}
319-
entityOffsets.add(ModelEntity.endModelEntity(fbb));
320-
return ModelBuilder.this;
399+
return ModelEntity.endModelEntity(fbb);
321400
}
401+
322402
}
323403

324-
int createVector(List<Integer> offsets) {
404+
private int createVector(List<Integer> offsets) {
325405
int[] offsetArray = new int[offsets.size()];
326406
for (int i = 0; i < offsets.size(); i++) {
327407
offsetArray[i] = offsets.get(i);
@@ -335,7 +415,7 @@ public ModelBuilder version(long version) {
335415
}
336416

337417
public EntityBuilder entity(String name) {
338-
return new EntityBuilder(name);
418+
return new EntityBuilder(this, fbb, name);
339419
}
340420

341421
public ModelBuilder lastEntityId(int lastEntityId, long lastEntityUid) {

0 commit comments

Comments
 (0)