All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.objectbox.ModelBuilder Maven / Gradle / Ivy

There is a newer version: 4.0.3
Show newest version
/*
 * Copyright 2017-2024 ObjectBox Ltd. All rights reserved.
 *
 * 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.
 */

package io.objectbox;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nullable;

import io.objectbox.annotation.HnswIndex;
import io.objectbox.annotation.apihint.Internal;
import io.objectbox.flatbuffers.FlatBufferBuilder;
import io.objectbox.model.HnswDistanceType;
import io.objectbox.model.HnswFlags;
import io.objectbox.model.HnswParams;
import io.objectbox.model.IdUid;
import io.objectbox.model.Model;
import io.objectbox.model.ModelEntity;
import io.objectbox.model.ModelProperty;
import io.objectbox.model.ModelRelation;

// Remember: IdUid is a struct, not a table, and thus must be inlined
@SuppressWarnings("WeakerAccess,UnusedReturnValue, unused")
@Internal
public class ModelBuilder {
    private static final int MODEL_VERSION = 2;

    final FlatBufferBuilder fbb = new FlatBufferBuilder();
    final List entityOffsets = new ArrayList<>();

    long version = 1;

    Integer lastEntityId;
    Long lastEntityUid;

    Integer lastIndexId;
    Long lastIndexUid;

    Integer lastRelationId;
    Long lastRelationUid;

    public class PropertyBuilder {
        private final int type;
        private final int virtualTargetOffset;
        private final int propertyNameOffset;
        private final int targetEntityOffset;

        private int secondaryNameOffset;
        boolean finished;
        private int flags;
        private int id;
        private long uid;
        private int indexId;
        private long indexUid;
        private int indexMaxValueLength;
        private int hnswParamsOffset;

        PropertyBuilder(String name, @Nullable String targetEntityName, @Nullable String virtualTarget, int type) {
            this.type = type;
            propertyNameOffset = fbb.createString(name);
            targetEntityOffset = targetEntityName != null ? fbb.createString(targetEntityName) : 0;
            virtualTargetOffset = virtualTarget != null ? fbb.createString(virtualTarget) : 0;
        }

        public PropertyBuilder id(int id, long uid) {
            checkNotFinished();
            this.id = id;
            this.uid = uid;
            return this;
        }

        public PropertyBuilder indexId(int indexId, long indexUid) {
            checkNotFinished();
            this.indexId = indexId;
            this.indexUid = indexUid;
            return this;
        }

        public PropertyBuilder indexMaxValueLength(int indexMaxValueLength) {
            checkNotFinished();
            this.indexMaxValueLength = indexMaxValueLength;
            return this;
        }

        /**
         * Set parameters for {@link HnswIndex}.
         *
         * @param dimensions see {@link HnswIndex#dimensions()}.
         * @param neighborsPerNode see {@link HnswIndex#neighborsPerNode()}.
         * @param indexingSearchCount see {@link HnswIndex#indexingSearchCount()}.
         * @param flags see {@link HnswIndex#flags()}, mapped to {@link HnswFlags}.
         * @param distanceType see {@link HnswIndex#distanceType()}, mapped to {@link HnswDistanceType}.
         * @param reparationBacklinkProbability see {@link HnswIndex#reparationBacklinkProbability()}.
         * @param vectorCacheHintSizeKb see {@link HnswIndex#vectorCacheHintSizeKB()}.
         * @return this builder.
         */
        public PropertyBuilder hnswParams(long dimensions,
                                          @Nullable Long neighborsPerNode,
                                          @Nullable Long indexingSearchCount,
                                          @Nullable Integer flags,
                                          @Nullable Short distanceType,
                                          @Nullable Float reparationBacklinkProbability,
                                          @Nullable Long vectorCacheHintSizeKb) {
            checkNotFinished();
            HnswParams.startHnswParams(fbb);
            HnswParams.addDimensions(fbb, dimensions);
            if (neighborsPerNode != null) {
                HnswParams.addNeighborsPerNode(fbb, neighborsPerNode);
            }
            if (indexingSearchCount != null) {
                HnswParams.addIndexingSearchCount(fbb, indexingSearchCount);
            }
            if (flags != null) {
                HnswParams.addFlags(fbb, flags);
            }
            if (distanceType != null) {
                HnswParams.addDistanceType(fbb, distanceType);
            }
            if (reparationBacklinkProbability != null) {
                HnswParams.addReparationBacklinkProbability(fbb, reparationBacklinkProbability);
            }
            if (vectorCacheHintSizeKb != null) {
                HnswParams.addVectorCacheHintSizeKb(fbb, vectorCacheHintSizeKb);
            }
            hnswParamsOffset = HnswParams.endHnswParams(fbb);
            return this;
        }

        public PropertyBuilder flags(int flags) {
            checkNotFinished();
            this.flags = flags;
            return this;
        }

        public PropertyBuilder secondaryName(String secondaryName) {
            checkNotFinished();
            secondaryNameOffset = fbb.createString(secondaryName);
            return this;
        }

        private void checkNotFinished() {
            if (finished) {
                throw new IllegalStateException("Already finished");
            }
        }

        public int finish() {
            checkNotFinished();
            finished = true;
            ModelProperty.startModelProperty(fbb);
            ModelProperty.addName(fbb, propertyNameOffset);
            if (targetEntityOffset != 0) {
                ModelProperty.addTargetEntity(fbb, targetEntityOffset);
            }
            if (virtualTargetOffset != 0) {
                ModelProperty.addVirtualTarget(fbb, virtualTargetOffset);
            }
            if (secondaryNameOffset != 0) {
                ModelProperty.addNameSecondary(fbb, secondaryNameOffset);
            }
            if (id != 0) {
                int idOffset = IdUid.createIdUid(fbb, id, uid);
                ModelProperty.addId(fbb, idOffset);
            }
            if (indexId != 0) {
                int indexIdOffset = IdUid.createIdUid(fbb, indexId, indexUid);
                ModelProperty.addIndexId(fbb, indexIdOffset);
            }
            if (indexMaxValueLength > 0) {
                ModelProperty.addMaxIndexValueLength(fbb, indexMaxValueLength);
            }
            if (hnswParamsOffset != 0) {
                ModelProperty.addHnswParams(fbb, hnswParamsOffset);
            }
            ModelProperty.addType(fbb, type);
            if (flags != 0) {
                ModelProperty.addFlags(fbb, flags);
            }
            return ModelProperty.endModelProperty(fbb);
        }
    }

    public class EntityBuilder {
        final String name;
        final List propertyOffsets = new ArrayList<>();
        final List relationOffsets = new ArrayList<>();

        Integer id;
        Long uid;
        Integer flags;
        Integer lastPropertyId;
        Long lastPropertyUid;
        PropertyBuilder propertyBuilder;
        boolean finished;

        EntityBuilder(String name) {
            this.name = name;
        }

        public EntityBuilder id(int id, long uid) {
            checkNotFinished();
            this.id = id;
            this.uid = uid;
            return this;
        }

        public EntityBuilder lastPropertyId(int lastPropertyId, long lastPropertyUid) {
            checkNotFinished();
            this.lastPropertyId = lastPropertyId;
            this.lastPropertyUid = lastPropertyUid;
            return this;
        }

        public EntityBuilder flags(int flags) {
            this.flags = flags;
            return this;
        }

        private void checkNotFinished() {
            if (finished) {
                throw new IllegalStateException("Already finished");
            }
        }

        public PropertyBuilder property(String name, int type) {
            return property(name, null, type);
        }

        public PropertyBuilder property(String name, @Nullable String targetEntityName, int type) {
            return property(name, targetEntityName, null, type);
        }

        public PropertyBuilder property(String name, @Nullable String targetEntityName, @Nullable String virtualTarget,
                                        int type) {
            checkNotFinished();
            checkFinishProperty();
            propertyBuilder = new PropertyBuilder(name, targetEntityName, virtualTarget, type);
            return propertyBuilder;
        }

        void checkFinishProperty() {
            if (propertyBuilder != null) {
                propertyOffsets.add(propertyBuilder.finish());
                propertyBuilder = null;
            }
        }

        public EntityBuilder relation(String name, int relationId, long relationUid, int targetEntityId,
                                      long targetEntityUid) {
            checkNotFinished();
            checkFinishProperty();

            int propertyNameOffset = fbb.createString(name);

            ModelRelation.startModelRelation(fbb);
            ModelRelation.addName(fbb, propertyNameOffset);
            int relationIdOffset = IdUid.createIdUid(fbb, relationId, relationUid);
            ModelRelation.addId(fbb, relationIdOffset);
            int targetEntityIdOffset = IdUid.createIdUid(fbb, targetEntityId, targetEntityUid);
            ModelRelation.addTargetEntityId(fbb, targetEntityIdOffset);
            relationOffsets.add(ModelRelation.endModelRelation(fbb));

            return this;
        }

        public ModelBuilder entityDone() {
            checkNotFinished();
            checkFinishProperty();
            finished = true;
            int testEntityNameOffset = fbb.createString(name);
            int propertiesOffset = createVector(propertyOffsets);
            int relationsOffset = relationOffsets.isEmpty() ? 0 : createVector(relationOffsets);

            ModelEntity.startModelEntity(fbb);
            ModelEntity.addName(fbb, testEntityNameOffset);
            ModelEntity.addProperties(fbb, propertiesOffset);
            if (relationsOffset != 0) ModelEntity.addRelations(fbb, relationsOffset);
            if (id != null && uid != null) {
                int idOffset = IdUid.createIdUid(fbb, id, uid);
                ModelEntity.addId(fbb, idOffset);
            }
            if (lastPropertyId != null) {
                int idOffset = IdUid.createIdUid(fbb, lastPropertyId, lastPropertyUid);
                ModelEntity.addLastPropertyId(fbb, idOffset);
            }
            if (flags != null) {
                ModelEntity.addFlags(fbb, flags);
            }
            entityOffsets.add(ModelEntity.endModelEntity(fbb));
            return ModelBuilder.this;
        }
    }

    int createVector(List offsets) {
        int[] offsetArray = new int[offsets.size()];
        for (int i = 0; i < offsets.size(); i++) {
            offsetArray[i] = offsets.get(i);
        }
        return fbb.createVectorOfTables(offsetArray);
    }

    public ModelBuilder version(long version) {
        this.version = version;
        return this;
    }

    public EntityBuilder entity(String name) {
        return new EntityBuilder(name);
    }

    public ModelBuilder lastEntityId(int lastEntityId, long lastEntityUid) {
        this.lastEntityId = lastEntityId;
        this.lastEntityUid = lastEntityUid;
        return this;
    }

    public ModelBuilder lastIndexId(int lastIndexId, long lastIndexUid) {
        this.lastIndexId = lastIndexId;
        this.lastIndexUid = lastIndexUid;
        return this;
    }

    public ModelBuilder lastRelationId(int lastRelationId, long lastRelationUid) {
        this.lastRelationId = lastRelationId;
        this.lastRelationUid = lastRelationUid;
        return this;
    }

    public byte[] build() {
        int nameOffset = fbb.createString("default");
        int entityVectorOffset = createVector(entityOffsets);
        Model.startModel(fbb);
        Model.addName(fbb, nameOffset);
        Model.addModelVersion(fbb, MODEL_VERSION);
        Model.addVersion(fbb, 1);
        Model.addEntities(fbb, entityVectorOffset);
        if (lastEntityId != null) {
            int idOffset = IdUid.createIdUid(fbb, lastEntityId, lastEntityUid);
            Model.addLastEntityId(fbb, idOffset);
        }
        if (lastIndexId != null) {
            int idOffset = IdUid.createIdUid(fbb, lastIndexId, lastIndexUid);
            Model.addLastIndexId(fbb, idOffset);
        }
        if (lastRelationId != null) {
            int idOffset = IdUid.createIdUid(fbb, lastRelationId, lastRelationUid);
            Model.addLastRelationId(fbb, idOffset);
        }
        int offset = Model.endModel(fbb);

        fbb.finish(offset);
        return fbb.sizedByteArray();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy