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

com.google.gerrit.index.Schema Maven / Gradle / Ivy

There is a newer version: 3.11.0-rc3
Show newest version
// 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.index;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.exceptions.StorageException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/** Specific version of a secondary index schema. */
public class Schema {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  public static class Builder {
    private final List> fields = new ArrayList<>();
    private boolean useLegacyNumericFields;

    public Builder add(Schema schema) {
      this.fields.addAll(schema.getFields().values());
      return this;
    }

    @SafeVarargs
    public final Builder add(FieldDef... fields) {
      this.fields.addAll(Arrays.asList(fields));
      return this;
    }

    @SafeVarargs
    public final Builder remove(FieldDef... fields) {
      this.fields.removeAll(Arrays.asList(fields));
      return this;
    }

    public Builder legacyNumericFields(boolean useLegacyNumericFields) {
      this.useLegacyNumericFields = useLegacyNumericFields;
      return this;
    }

    public Schema build() {
      return new Schema<>(useLegacyNumericFields, ImmutableList.copyOf(fields));
    }
  }

  public static class Values {
    private final FieldDef field;
    private final Iterable values;

    private Values(FieldDef field, Iterable values) {
      this.field = field;
      this.values = values;
    }

    public FieldDef getField() {
      return field;
    }

    public Iterable getValues() {
      return values;
    }
  }

  private static  FieldDef checkSame(FieldDef f1, FieldDef f2) {
    checkState(f1 == f2, "Mismatched %s fields: %s != %s", f1.getName(), f1, f2);
    return f1;
  }

  private final ImmutableMap> fields;
  private final ImmutableMap> storedFields;
  private final boolean useLegacyNumericFields;

  private int version;

  public Schema(boolean useLegacyNumericFields, Iterable> fields) {
    this(0, useLegacyNumericFields, fields);
  }

  public Schema(int version, boolean useLegacyNumericFields, Iterable> fields) {
    this.version = version;
    ImmutableMap.Builder> b = ImmutableMap.builder();
    ImmutableMap.Builder> sb = ImmutableMap.builder();
    for (FieldDef f : fields) {
      b.put(f.getName(), f);
      if (f.isStored()) {
        sb.put(f.getName(), f);
      }
    }
    this.fields = b.build();
    this.storedFields = sb.build();
    this.useLegacyNumericFields = useLegacyNumericFields;
  }

  public final int getVersion() {
    return version;
  }

  public final boolean useLegacyNumericFields() {
    return useLegacyNumericFields;
  }

  /**
   * Get all fields in this schema.
   *
   * 

This is primarily useful for iteration. Most callers should prefer one of the helper methods * {@link #getField(FieldDef, FieldDef...)} or {@link #hasField(FieldDef)} to looking up fields by * name * * @return all fields in this schema indexed by name. */ public final ImmutableMap> getFields() { return fields; } /** Returns all fields in this schema where {@link FieldDef#isStored()} is true. */ public final ImmutableMap> getStoredFields() { return storedFields; } /** * Look up fields in this schema. * * @param first the preferred field to look up. * @param rest additional fields to look up. * @return the first field in the schema matching {@code first} or {@code rest}, in order, or * absent if no field matches. */ @SafeVarargs public final Optional> getField(FieldDef first, FieldDef... rest) { FieldDef field = fields.get(first.getName()); if (field != null) { return Optional.of(checkSame(field, first)); } for (FieldDef f : rest) { field = fields.get(f.getName()); if (field != null) { return Optional.of(checkSame(field, f)); } } return Optional.empty(); } /** * Check whether a field is present in this schema. * * @param field field to look up. * @return whether the field is present. */ public final boolean hasField(FieldDef field) { FieldDef f = fields.get(field.getName()); if (f == null) { return false; } checkSame(f, field); return true; } private Values fieldValues(T obj, FieldDef f, ImmutableSet skipFields) { if (skipFields.contains(f.getName())) { return null; } Object v; try { v = f.get(obj); } catch (StorageException e) { // StorageException is thrown when the object is not found. On this case, // it is pointless to make further attempts for each field, so propagate // the exception to return an empty list. logger.atSevere().withCause(e).log("error getting field %s of %s", f.getName(), obj); throw e; } catch (RuntimeException e) { logger.atSevere().withCause(e).log("error getting field %s of %s", f.getName(), obj); return null; } if (v == null) { return null; } else if (f.isRepeatable()) { return new Values<>(f, (Iterable) v); } else { return new Values<>(f, Collections.singleton(v)); } } /** * Build all fields in the schema from an input object. * *

Null values are omitted, as are fields which cause errors, which are logged. * * @param obj input object. * @param skipFields set of field names to skip when indexing the document * @return all non-null field values from the object. */ public final Iterable> buildFields(T obj, ImmutableSet skipFields) { try { return fields.values().stream() .map(f -> fieldValues(obj, f, skipFields)) .filter(Objects::nonNull) .collect(toImmutableList()); } catch (StorageException e) { return ImmutableList.of(); } } @Override public String toString() { return MoreObjects.toStringHelper(this).addValue(fields.keySet()).toString(); } public void setVersion(int version) { this.version = version; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy