blob: cf3fd09369bc2b2146bb2bbe706addabe902bec8 [file] [log] [blame]
// Copyright (C) 2013 The Android Open Source Project
//
// 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 com.google.gerrit.server.index;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.base.CharMatcher;
import com.google.common.base.Preconditions;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.TrackingFooters;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
/**
* Definition of a field stored in the secondary index.
*
* @param <I> input type from which documents are created and search results are
* returned.
* @param <T> type that should be extracted from the input object when converting
* to an index document.
*/
public abstract class FieldDef<I, T> {
/** Definition of a single (non-repeatable) field. */
public abstract static class Single<I, T> extends FieldDef<I, T> {
Single(String name, FieldType<T> type, boolean stored) {
super(name, type, stored);
}
@Override
public final boolean isRepeatable() {
return false;
}
}
/** Definition of a repeatable field. */
public abstract static class Repeatable<I, T>
extends FieldDef<I, Iterable<T>> {
Repeatable(String name, FieldType<T> type, boolean stored) {
super(name, type, stored);
Preconditions.checkArgument(type != FieldType.INTEGER_RANGE,
"Range queries against repeated fields are unsupported");
}
@Override
public final boolean isRepeatable() {
return true;
}
}
/** Arguments needed to fill in missing data in the input object. */
public static class FillArgs {
final TrackingFooters trackingFooters;
final boolean allowsDrafts;
@Inject
FillArgs(TrackingFooters trackingFooters,
@GerritServerConfig Config cfg) {
this.trackingFooters = trackingFooters;
this.allowsDrafts = cfg == null
? true
: cfg.getBoolean("change", "allowDrafts", true);
}
}
private final String name;
private final FieldType<?> type;
private final boolean stored;
private FieldDef(String name, FieldType<?> type, boolean stored) {
this.name = checkName(name);
this.type = type;
this.stored = stored;
}
private static String checkName(String name) {
CharMatcher m = CharMatcher.anyOf("abcdefghijklmnopqrstuvwxyz0123456789_");
checkArgument(m.matchesAllOf(name), "illegal field name: %s", name);
return name;
}
/** @return name of the field. */
public final String getName() {
return name;
}
/**
* @return type of the field; for repeatable fields, the inner type, not the
* iterable type.
*/
public final FieldType<?> getType() {
return type;
}
/** @return whether the field should be stored in the index. */
public final boolean isStored() {
return stored;
}
/**
* Get the field contents from the input object.
*
* @param input input object.
* @param args arbitrary arguments needed to fill in indexable fields of the
* input object.
* @return the field value(s) to index.
*
* @throws OrmException
*/
public abstract T get(I input, FillArgs args) throws OrmException;
/** @return whether the field is repeatable. */
public abstract boolean isRepeatable();
}