mchades commented on code in PR #12499: URL: https://github.com/apache/gravitino/pull/12499#discussion_r3843032098
########## api/src/main/java/org/apache/gravitino/semantic/AIContextObject.java: ########## @@ -0,0 +1,376 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.gravitino.semantic; + +import com.google.common.base.Preconditions; +import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import javax.annotation.Nullable; +import org.apache.gravitino.annotation.Evolving; + +/** Structured AI context with optional standard fields and retained custom JSON properties. */ +@Evolving +public final class AIContextObject { + + @Nullable private final String instructions; + @Nullable private final String[] synonyms; + @Nullable private final String[] examples; + private final Map<String, Object> additionalProperties; + + private AIContextObject(Builder builder) { + this.instructions = builder.instructions; + this.synonyms = copyOrNull(builder.synonyms); + this.examples = copyOrNull(builder.examples); + this.additionalProperties = immutableAdditionalProperties(builder.additionalProperties); + } + + /** + * Creates a builder for structured AI context. + * + * @return A new builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns instructions for AI tools. + * + * @return The instructions, or null when not provided. + */ + @Nullable + public String instructions() { + return instructions; + } + + /** + * Returns alternative names and terms. + * + * @return A defensive copy of the synonyms, or {@code null} when not provided. + */ + @Nullable + public String[] synonyms() { + return copyOrNull(synonyms); + } + + /** + * Returns sample questions or use cases. + * + * @return A defensive copy of the examples, or {@code null} when not provided. + */ + @Nullable + public String[] examples() { + return copyOrNull(examples); + } + + /** + * Returns custom JSON-compatible properties not represented by the standard fields. + * + * <p>The returned map and every nested map or JSON array are unmodifiable. Java arrays supplied + * to the builder are represented as unmodifiable lists. Integral numbers are represented as + * {@link BigInteger}, and decimal numbers are represented as {@link BigDecimal}. + * + * @return The deeply immutable additional properties, preserving iteration order. + */ + public Map<String, Object> additionalProperties() { + return additionalProperties; + } + + /** + * Compares this structured AI context with another object. + * + * @param other The object to compare. + * @return {@code true} if the object has the same standard and additional properties. + */ + @Override + public boolean equals(@Nullable Object other) { + if (this == other) { + return true; + } + if (!(other instanceof AIContextObject)) { + return false; + } + AIContextObject that = (AIContextObject) other; + return Objects.equals(instructions, that.instructions) + && Arrays.equals(synonyms, that.synonyms) + && Arrays.equals(examples, that.examples) + && additionalProperties.equals(that.additionalProperties); + } + + /** + * Returns the hash code of this structured AI context. + * + * @return The hash code. + */ + @Override + public int hashCode() { + int result = Objects.hash(instructions, additionalProperties); + result = 31 * result + Arrays.hashCode(synonyms); + result = 31 * result + Arrays.hashCode(examples); + return result; + } + + /** + * Returns a string representation of this structured AI context. + * + * @return The string representation. + */ + @Override + public String toString() { + return "AIContextObject{" + + "instructions='" + + instructions + + '\'' + + ", synonyms=" + + Arrays.toString(synonyms) + + ", examples=" + + Arrays.toString(examples) + + ", additionalProperties=" + + additionalProperties + + '}'; + } + + /** A builder for {@link AIContextObject}. */ + public static final class Builder { + + @Nullable private String instructions; + @Nullable private String[] synonyms; + @Nullable private String[] examples; + private Map<String, Object> additionalProperties = Collections.emptyMap(); + + private Builder() {} + + /** + * Sets or clears instructions for AI tools. + * + * @param instructions The instructions, or null to leave them unset. + * @return This builder. + */ + public Builder withInstructions(@Nullable String instructions) { + this.instructions = instructions; + return this; + } + + /** + * Sets or clears alternative names and terms. + * + * @param synonyms The synonyms, or null to leave them unset. + * @return This builder. + */ + public Builder withSynonyms(@Nullable String[] synonyms) { + this.synonyms = synonyms; + return this; + } + + /** + * Sets or clears sample questions or use cases. + * + * @param examples The examples, or null to leave them unset. + * @return This builder. + */ + public Builder withExamples(@Nullable String[] examples) { + this.examples = examples; + return this; + } + + /** + * Sets additional JSON-compatible properties. + * + * <p>Values may be null, strings, booleans, JSON-compatible numbers, maps with string keys, + * lists, or Java arrays. Integral numbers are normalized to {@link BigInteger}, and decimal + * numbers are normalized to {@link BigDecimal} so their value semantics remain stable across + * JSON round trips. Property names must not duplicate {@code instructions}, {@code synonyms}, + * or {@code examples}. + * + * @param additionalProperties The additional properties. + * @return This builder. + */ + public Builder withAdditionalProperties(Map<String, Object> additionalProperties) { + this.additionalProperties = additionalProperties; + return this; + } + + /** + * Builds structured AI context. + * + * @return The immutable structured AI context. + * @throws IllegalArgumentException If a string array contains null, the additional properties + * are null, a property duplicates a standard field, or a property value is not + * JSON-compatible. + */ + public AIContextObject build() { + SemanticModelDefinition.validateNoNullElements("synonyms", synonyms); + SemanticModelDefinition.validateNoNullElements("examples", examples); + Preconditions.checkArgument( + additionalProperties != null, "additionalProperties must not be null"); + return new AIContextObject(this); + } + } + + @Nullable + private static String[] copyOrNull(@Nullable String[] values) { Review Comment: Nullable one-dimensional array copying is now centralized in the package-private generic `SemanticModelDefinition.copyOrNull` helper and reused across the API value classes. `Dataset.uniqueKeys` keeps its dedicated deep-copy implementation because its nested arrays require copying each inner array. ########## api/src/main/java/org/apache/gravitino/semantic/SemanticModelChange.java: ########## @@ -0,0 +1,326 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.gravitino.semantic; + +import com.google.common.base.Preconditions; +import java.util.Objects; +import javax.annotation.Nullable; +import org.apache.commons.lang3.StringUtils; +import org.apache.gravitino.annotation.Evolving; + +/** + * A change that can be applied to a Semantic Model through {@link + * SemanticModelCatalog#alterSemanticModel(org.apache.gravitino.NameIdentifier, Review Comment: The Javadoc link now uses `{@link SemanticModelCatalog#alterSemanticModel}`. The method is not overloaded, so the parameter signature and fully qualified type name are unnecessary. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
