org.neo4j.internal.schema.IndexDescriptor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-schema Show documentation
Show all versions of neo4j-schema Show documentation
Schema descriptors and interfaces in Neo4j.
The newest version!
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.internal.schema;
import static java.util.Objects.requireNonNull;
import static org.neo4j.internal.schema.SchemaUserDescription.TOKEN_ID_NAME_LOOKUP;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.OptionalLong;
import java.util.stream.Stream;
import org.neo4j.common.TokenNameLookup;
import org.neo4j.string.Mask;
public final class IndexDescriptor implements IndexRef, SchemaRule {
/**
* A special index descriptor used to represent the absence of an index.
* This descriptor cannot be modified by any of the {@code with*} methods.
*/
public static final IndexDescriptor NO_INDEX = new IndexDescriptor();
// Needs to be possible to create IndexDescriptors with this special id during migration
public static final long FORMER_LABEL_SCAN_STORE_ID = -2;
private final long id;
private final String name;
private final SchemaDescriptor schema;
private final boolean isUnique;
private final IndexProviderDescriptor indexProvider;
private final Long owningConstraintId;
private final IndexCapability capability;
private final IndexType indexType;
private final IndexConfig indexConfig;
IndexDescriptor(long id, IndexPrototype prototype) {
this(
id,
SchemaNameUtil.sanitiseName(prototype.getName()),
prototype.schema(),
prototype.isUnique(),
prototype.getIndexProvider(),
null,
IndexCapability.NO_CAPABILITY,
prototype.getIndexType(),
prototype.getIndexConfig());
}
private IndexDescriptor(
long id,
String name,
SchemaDescriptor schema,
boolean isUnique,
IndexProviderDescriptor indexProvider,
Long owningConstraintId,
IndexCapability capability,
IndexType indexType,
IndexConfig indexConfig) {
if (id < 0 && id != FORMER_LABEL_SCAN_STORE_ID) {
throw new IllegalArgumentException(
"The id of an index must not be negative, but it was attempted to assign " + id + ".");
}
name = SchemaNameUtil.sanitiseName(name);
requireNonNull(schema, "The schema of an index cannot be null.");
requireNonNull(indexProvider, "The index provider cannot be null.");
// The 'owningConstraintId' is allowed to be null, which is the case when an index descriptor is initially
// created.
requireNonNull(capability, "The index capability cannot be null.");
requireNonNull(indexConfig, "The index configuration cannot be null.");
this.id = id;
this.name = name;
this.schema = schema;
this.isUnique = isUnique;
this.indexProvider = indexProvider;
this.owningConstraintId = owningConstraintId;
this.capability = capability;
this.indexType = indexType;
this.indexConfig = indexConfig;
}
/**
* This constructor is used exclusively for the {@link #NO_INDEX} field!
*/
private IndexDescriptor() {
this.id = -1;
this.name = ReservedSchemaRuleNames.NO_INDEX.getReservedName();
this.schema = SchemaDescriptors.noSchema();
this.isUnique = false;
this.indexProvider = AllIndexProviderDescriptors.UNDECIDED;
this.owningConstraintId = null;
this.capability = IndexCapability.NO_CAPABILITY;
this.indexType = IndexType.RANGE;
this.indexConfig = IndexConfig.empty();
}
@Override
public SchemaDescriptor schema() {
return schema;
}
@Override
public boolean isUnique() {
return isUnique;
}
@Override
public long getId() {
return id;
}
/**
* @return The name of this index.
*/
@Override
public String getName() {
return name;
}
@Override
public IndexDescriptor withName(String name) {
if (name == null) {
return this;
}
name = SchemaNameUtil.sanitiseName(name);
return new IndexDescriptor(
id, name, schema, isUnique, indexProvider, owningConstraintId, capability, indexType, indexConfig);
}
/**
* @return the {@link IndexConfig}
*/
@Override
public IndexConfig getIndexConfig() {
return indexConfig;
}
/**
* Produce a new index descriptor that is the same as this index descriptor in every way, except it has the given index config.
* @param indexConfig The index config of the new index descriptor.
* @return A new index descriptor with the given index config.
*/
@Override
public IndexDescriptor withIndexConfig(IndexConfig indexConfig) {
return new IndexDescriptor(
id, name, schema, isUnique, indexProvider, owningConstraintId, capability, indexType, indexConfig);
}
/**
* @return The id of the constraint that owns this index, if such a constraint exists. Otherwise {@code empty}.
*/
public OptionalLong getOwningConstraintId() {
return owningConstraintId == null ? OptionalLong.empty() : OptionalLong.of(owningConstraintId);
}
@Override
public String userDescription(TokenNameLookup tokenNameLookup) {
return userDescription(tokenNameLookup, Mask.NO);
}
private String userDescription(TokenNameLookup tokenNameLookup, Mask mask) {
return SchemaUserDescription.forIndex(
tokenNameLookup, id, name, indexType.name(), schema(), getIndexProvider(), owningConstraintId, mask);
}
@Override
public IndexType getIndexType() {
return indexType;
}
@Override
public IndexProviderDescriptor getIndexProvider() {
return indexProvider;
}
/**
* Return the capabilities of this index.
*/
public IndexCapability getCapability() {
return capability;
}
@Override
public IndexDescriptor withIndexProvider(IndexProviderDescriptor indexProvider) {
return new IndexDescriptor(
id, name, schema, isUnique, indexProvider, owningConstraintId, capability, indexType, indexConfig);
}
@Override
public IndexDescriptor withSchemaDescriptor(SchemaDescriptor schema) {
return new IndexDescriptor(
id, name, schema, isUnique, indexProvider, owningConstraintId, capability, indexType, indexConfig);
}
/**
* Produce a new index descriptor that is the same as this index descriptor in every way, except it has the given owning constraint id.
*
* @param owningConstraintId The id of the constraint that owns the index represented by this index descriptor.
* @return A new index descriptor with the given owning constraint id.
*/
public IndexDescriptor withOwningConstraintId(long owningConstraintId) {
if (!isUnique()) {
throw new IllegalStateException("Cannot assign an owning constraint id (in this case " + owningConstraintId
+ ") to a non-unique index: " + this + ".");
}
if (owningConstraintId < 0) {
throw new IllegalArgumentException(
"The owning constraint id of an index must not be negative, but it was attempted to assign "
+ owningConstraintId + ".");
}
return new IndexDescriptor(
id, name, schema, isUnique, indexProvider, owningConstraintId, capability, indexType, indexConfig);
}
/**
* Produce a new index descriptor that is the same as this index descriptor in every way, except it has the given index capabilities.
*
* @param capability The capabilities of the new index descriptor.
* @return A new index descriptor with the given capabilities.
*/
public IndexDescriptor withIndexCapability(IndexCapability capability) {
return new IndexDescriptor(
id, name, schema, isUnique, indexProvider, owningConstraintId, capability, indexType, indexConfig);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
IndexDescriptor that = (IndexDescriptor) o;
if (id != that.id) {
return false;
}
if (isUnique != that.isUnique) {
return false;
}
if (indexType != that.indexType) {
return false;
}
if (!name.equals(that.name)) {
return false;
}
if (!schema.equals(that.schema)) {
return false;
}
return indexProvider.equals(that.indexProvider);
}
@Override
public int hashCode() {
return Long.hashCode(id);
}
@Override
public String toString() {
return toString(Mask.NO);
}
@Override
public String toString(Mask mask) {
// TOKEN_ID_NAME_LOOKUP makes sure we don't include schema token names, regardless of masking
return userDescription(TOKEN_ID_NAME_LOOKUP, mask);
}
/**
* Sorts indexes by type, returning first GENERAL indexes, followed by UNIQUE. Implementation is not suitable in hot path.
*
* @param indexes Indexes to sort
* @return sorted indexes
*/
public static Iterator sortByType(Iterator indexes) {
List nonUnique = new ArrayList<>();
List unique = new ArrayList<>();
indexes.forEachRemaining(index -> (index.isUnique() ? unique : nonUnique).add(index));
return Stream.concat(nonUnique.stream(), unique.stream()).iterator();
}
}