diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 9f428d122e..dc8a704081 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -20,8 +20,8 @@ jobs: stale-pr-message: 'Due to the lack of activity, the current pr is marked as stale and will be closed after 180 days, any update will remove the stale label' stale-issue-label: 'inactive' stale-pr-label: 'inactive' - exempt-issue-labels: 'feature,bug,enhancement,improvement,wontfix,todo,guide,doc,help wanted' - exempt-pr-labels: 'feature,bug,enhancement,improvement,wontfix,todo,guide,doc,help wanted' + exempt-issue-labels: 'feature,bug,enhancement,improvement,todo,guide,doc,help wanted,security' + exempt-pr-labels: 'feature,bug,enhancement,improvement,todo,guide,doc,help wanted,security' exempt-all-milestones: true days-before-issue-stale: 15 diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/schema/PropertyKey.java b/hugegraph-core/src/main/java/org/apache/hugegraph/schema/PropertyKey.java index 42fe14aa34..f86bec0aec 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/schema/PropertyKey.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/schema/PropertyKey.java @@ -228,7 +228,7 @@ private boolean checkDataType(V value) { } /** - * Check type of all the values(may be some of list properties) valid + * Check type of all the values(maybe some list properties) valid * @param values the property values to be checked data type * @param the property value class * @return true if all the values are or can convert to the data type, diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeEdge.java b/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeEdge.java index 9886b42a11..a1e667cd9b 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeEdge.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeEdge.java @@ -45,12 +45,14 @@ import org.apache.hugegraph.backend.serializer.BytesBuffer; import org.apache.hugegraph.perf.PerfUtil.Watched; import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyProperty; + import com.google.common.collect.ImmutableList; public class HugeEdge extends HugeElement implements Edge, Cloneable { private Id id; - private EdgeLabel label; + private final EdgeLabel label; private String name; private HugeVertex sourceVertex; @@ -200,6 +202,11 @@ public Property property(String key, V value) { E.checkArgument(this.label.properties().contains(propertyKey.id()), "Invalid property '%s' for edge label '%s'", key, this.label()); + if (value == null) { + this.removeProperty(propertyKey.id()); + return EmptyProperty.instance(); + } + // Sort-Keys can only be set once if (this.schemaLabel().sortKeys().contains(propertyKey.id())) { E.checkArgument(!this.hasProperty(propertyKey.id()), @@ -279,7 +286,7 @@ public Iterator> properties(String... keys) { if (keys.length == 0) { for (HugeProperty prop : this.getProperties()) { - assert prop instanceof Property; + assert prop != null; props.add((Property) prop); } } else { @@ -295,7 +302,6 @@ public Iterator> properties(String... keys) { // Not found continue; } - assert prop instanceof Property; props.add((Property) prop); } } @@ -320,8 +326,7 @@ public Object sysprop(HugeKeys key) { case PROPERTIES: return this.getPropertiesMap(); default: - E.checkArgument(false, - "Invalid system property '%s' of Edge", key); + E.checkArgument(false, "Invalid system property '%s' of Edge", key); return null; } } @@ -362,6 +367,7 @@ public void vertices(HugeVertex owner, HugeVertex other) { if (ownerLabel.equals(this.label.sourceLabel())) { this.vertices(true, owner, other); } else { + // TODO: why compare the label but ignore the result? ownerLabel.equals(this.label.targetLabel()); this.vertices(false, owner, other); } @@ -515,8 +521,7 @@ public static HugeEdge constructEdge(HugeVertex ownerVertex, ownerVertex.correctVertexLabel(tgtLabel); otherVertexLabel = srcLabel; } - HugeVertex otherVertex = new HugeVertex(graph, otherVertexId, - otherVertexLabel); + HugeVertex otherVertex = new HugeVertex(graph, otherVertexId, otherVertexLabel); ownerVertex.propNotLoaded(); otherVertex.propNotLoaded(); diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeElement.java b/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeElement.java index e02408f855..652360307d 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeElement.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeElement.java @@ -31,7 +31,9 @@ import org.apache.hugegraph.backend.id.EdgeId; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.backend.id.IdGenerator; +import org.apache.hugegraph.backend.serializer.BytesBuffer; import org.apache.hugegraph.backend.tx.GraphTransaction; +import org.apache.hugegraph.perf.PerfUtil.Watched; import org.apache.hugegraph.schema.PropertyKey; import org.apache.hugegraph.schema.SchemaLabel; import org.apache.hugegraph.schema.VertexLabel; @@ -39,6 +41,9 @@ import org.apache.hugegraph.type.Idfiable; import org.apache.hugegraph.type.define.Cardinality; import org.apache.hugegraph.type.define.HugeKeys; +import org.apache.hugegraph.util.CollectionUtil; +import org.apache.hugegraph.util.E; +import org.apache.hugegraph.util.InsertionOrderUtil; import org.apache.hugegraph.util.collection.CollectionFactory; import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Property; @@ -47,12 +52,6 @@ import org.eclipse.collections.api.iterator.IntIterator; import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; -import org.apache.hugegraph.backend.serializer.BytesBuffer; -import org.apache.hugegraph.perf.PerfUtil.Watched; -import org.apache.hugegraph.util.CollectionUtil; -import org.apache.hugegraph.util.E; -import org.apache.hugegraph.util.InsertionOrderUtil; - public abstract class HugeElement implements Element, GraphType, Idfiable { private static final MutableIntObjectMap> EMPTY_MAP = @@ -61,8 +60,8 @@ public abstract class HugeElement implements Element, GraphType, Idfiable { private final HugeGraph graph; private MutableIntObjectMap> properties; - - private long expiredTime; // TODO: move into properties to keep small object + // TODO: move into properties to keep small object + private long expiredTime; private boolean removed; private boolean fresh; @@ -425,14 +424,14 @@ public static final ElementKeys classifyKeys(Object... keyValues) { Object val = keyValues[i + 1]; if (!(key instanceof String) && !(key instanceof T)) { - throw Element.Exceptions - .providedKeyValuesMustHaveALegalKeyOnEvenIndices(); + throw Element.Exceptions.providedKeyValuesMustHaveALegalKeyOnEvenIndices(); } if (val == null) { - if (key.equals(T.label)) { + if (T.label.equals(key)) { throw Element.Exceptions.labelCanNotBeNull(); } - throw Property.Exceptions.propertyDoesNotExist(); + // Ignore null value for tinkerpop test compatibility + continue; } if (key.equals(T.id)) { diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeProperty.java b/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeProperty.java index 02ed4cdffb..b23a961e6f 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeProperty.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeProperty.java @@ -49,8 +49,7 @@ public PropertyKey propertyKey() { } public Object id() { - return SplicingIdGenerator.concat(this.owner.id().asString(), - this.key()); + return SplicingIdGenerator.concat(this.owner.id().asString(), this.key()); } @Override diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeVertex.java b/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeVertex.java index ea773f342c..a61ab5a2fc 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeVertex.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeVertex.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -59,6 +60,9 @@ import org.apache.hugegraph.type.define.HugeKeys; import org.apache.hugegraph.type.define.IdStrategy; import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyProperty; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyVertexProperty; + import com.google.common.collect.ImmutableList; public class HugeVertex extends HugeElement implements Vertex, Cloneable { @@ -162,8 +166,7 @@ public void assignId(Id id, boolean force) { } break; default: - throw new AssertionError(String.format( - "Unknown id strategy '%s'", strategy)); + throw new AssertionError(String.format("Unknown id strategy '%s'", strategy)); } this.checkIdLength(); } @@ -250,7 +253,7 @@ public void addEdge(HugeEdge edge) { /** * Add one edge between this vertex and other vertex - * + *

* *** this method is not thread safe, must clone this vertex first before * multi thread access e.g. `vertex.copy().resetTx();` *** */ @@ -295,7 +298,7 @@ public HugeEdge constructEdge(String label, HugeVertex vertex, label, this.label(), vertex.label()); // Check sortKeys List keys = this.graph().mapPkName2Id(elemKeys.keys()); - E.checkArgument(keys.containsAll(edgeLabel.sortKeys()), + E.checkArgument(new HashSet<>(keys).containsAll(edgeLabel.sortKeys()), "The sort key(s) must be set for the edge " + "with label: '%s'", edgeLabel.name()); @@ -304,7 +307,7 @@ public HugeEdge constructEdge(String label, HugeVertex vertex, Collection nonNullKeys = CollectionUtils.subtract( edgeLabel.properties(), edgeLabel.nullableKeys()); - if (!keys.containsAll(nonNullKeys)) { + if (!new HashSet<>(keys).containsAll(nonNullKeys)) { @SuppressWarnings("unchecked") Collection missed = CollectionUtils.subtract(nonNullKeys, keys); E.checkArgument(false, "All non-null property keys: %s " + @@ -419,9 +422,8 @@ public void remove() { @Watched(prefix = "vertex") @Override - public VertexProperty property( - VertexProperty.Cardinality cardinality, - String key, V value, Object... objects) { + public VertexProperty property(VertexProperty.Cardinality cardinality, + String key, V value, Object... objects) { if (objects.length != 0 && objects[0].equals(T.id)) { throw VertexProperty.Exceptions.userSuppliedIdsNotSupported(); } @@ -437,7 +439,7 @@ public VertexProperty property( * .property(list, "key2", val2) * * The cardinality single may be user supplied single, it may also be - * that user doesn't supplied cardinality, when it is latter situation, + * that user doesn't supply cardinality, when it is latter situation, * we shouldn't check it. Because of this reason, we are forced to * give up the check of user supplied cardinality single. * The cardinality not single must be user supplied, so should check it @@ -460,10 +462,14 @@ public VertexProperty property( E.checkArgument(!this.hasProperty(propertyKey.id()), "Can't update primary key: '%s'", key); } + if (value == null) { + this.removeProperty(propertyKey.id()); + return EmptyVertexProperty.instance(); + } @SuppressWarnings("unchecked") - VertexProperty prop = (VertexProperty) this.addProperty( - propertyKey, value, !this.fresh()); + VertexProperty prop = (VertexProperty) this.addProperty(propertyKey, + value, !this.fresh()); return prop; } diff --git a/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/ProcessStandardTest.java b/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/ProcessStandardTest.java index cecccece52..85bef64f44 100644 --- a/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/ProcessStandardTest.java +++ b/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/ProcessStandardTest.java @@ -21,7 +21,6 @@ import org.junit.runner.RunWith; @RunWith(ProcessBasicSuite.class) -@GraphProviderClass(provider = ProcessTestGraphProvider.class, - graph = TestGraph.class) +@GraphProviderClass(provider = ProcessTestGraphProvider.class, graph = TestGraph.class) public class ProcessStandardTest { } diff --git a/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/TestGraph.java b/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/TestGraph.java index b2e44802ef..c6dcff4a87 100644 --- a/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/TestGraph.java +++ b/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/TestGraph.java @@ -45,6 +45,7 @@ import org.apache.hugegraph.testutil.Whitebox; import org.apache.hugegraph.type.define.IdStrategy; import org.apache.hugegraph.type.define.NodeRole; + import com.google.common.collect.ImmutableSet; @Graph.OptIn("org.apache.hugegraph.tinkerpop.StructureBasicSuite") @@ -55,8 +56,7 @@ public class TestGraph implements Graph { public static final String DEFAULT_VL = "vertex"; - public static final Set TRUNCATE_BACKENDS = - ImmutableSet.of("rocksdb", "mysql"); + public static final Set TRUNCATE_BACKENDS = ImmutableSet.of("rocksdb", "mysql"); private static volatile int id = 666; @@ -130,19 +130,19 @@ protected void clearSchema() { // Clear schema and graph data will be cleared at same time SchemaManager schema = this.graph.schema(); - schema.getIndexLabels().stream().forEach(elem -> { + schema.getIndexLabels().forEach(elem -> { schema.indexLabel(elem.name()).remove(); }); - schema.getEdgeLabels().stream().forEach(elem -> { + schema.getEdgeLabels().forEach(elem -> { schema.edgeLabel(elem.name()).remove(); }); - schema.getVertexLabels().stream().forEach(elem -> { + schema.getVertexLabels().forEach(elem -> { schema.vertexLabel(elem.name()).remove(); }); - schema.getPropertyKeys().stream().forEach(elem -> { + schema.getPropertyKeys().forEach(elem -> { schema.propertyKey(elem.name()).remove(); }); @@ -155,7 +155,7 @@ protected void clearSchema() { @Watched protected void clearVariables() { Variables variables = this.variables(); - variables.keys().forEach(key -> variables.remove(key)); + variables.keys().forEach(variables::remove); } protected boolean closed() { @@ -250,8 +250,7 @@ public GraphComputer compute() throws IllegalArgumentException { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public I io(final Io.Builder builder) { - Whitebox.setInternalState(HugeGraphSONModule.class, - "OPTIMIZE_SERIALIZE", false); + Whitebox.setInternalState(HugeGraphSONModule.class, "OPTIMIZE_SERIALIZE", false); return (I) builder.graph(this).onMapper(mapper -> mapper.addRegistry(HugeGraphIoRegistry.instance()) ).create(); @@ -315,8 +314,7 @@ private boolean needAddIdToLoadGraph() { case "regularLoad": return false; default: - throw new AssertionError(String.format( - "Wrong IO type %s", this.loadedGraph)); + throw new AssertionError(String.format("Wrong IO type %s", this.loadedGraph)); } } @@ -344,24 +342,19 @@ public void initPropertyKey(String key, String type) { schema.propertyKey(key).ifNotExist().create(); break; case "BooleanArray": - schema.propertyKey(key).asBoolean().valueList() - .ifNotExist().create(); + schema.propertyKey(key).asBoolean().valueList().ifNotExist().create(); break; case "IntegerArray": - schema.propertyKey(key).asInt().valueList() - .ifNotExist().create(); + schema.propertyKey(key).asInt().valueList().ifNotExist().create(); break; case "LongArray": - schema.propertyKey(key).asLong().valueList() - .ifNotExist().create(); + schema.propertyKey(key).asLong().valueList().ifNotExist().create(); break; case "FloatArray": - schema.propertyKey(key).asFloat().valueList() - .ifNotExist().create(); + schema.propertyKey(key).asFloat().valueList().ifNotExist().create(); break; case "DoubleArray": - schema.propertyKey(key).asDouble().valueList() - .ifNotExist().create(); + schema.propertyKey(key).asDouble().valueList().ifNotExist().create(); break; case "StringArray": schema.propertyKey(key).valueList().ifNotExist().create(); @@ -374,8 +367,7 @@ public void initPropertyKey(String key, String type) { case "Serializable": break; default: - throw new RuntimeException( - String.format("Wrong type %s for %s", type, key)); + throw new RuntimeException(String.format("Wrong type %s for %s", type, key)); } } @@ -411,8 +403,7 @@ public void initGratefulSchema(IdStrategy idStrategy) { .useCustomizeStringId().ifNotExist().create(); break; default: - throw new AssertionError(String.format( - "Id strategy must be customize or automatic")); + throw new AssertionError("Id strategy must be customize or automatic"); } schema.edgeLabel("followedBy") @@ -507,8 +498,7 @@ public void initModernSchema(IdStrategy idStrategy) { .useCustomizeStringId().ifNotExist().create(); break; default: - throw new AssertionError(String.format( - "Id strategy must be customize or automatic")); + throw new AssertionError("Id strategy must be customize or automatic"); } schema.edgeLabel("knows").link("person", "person") @@ -584,8 +574,7 @@ public void initClassicSchema(IdStrategy idStrategy) { .useCustomizeStringId().ifNotExist().create(); break; default: - throw new AssertionError(String.format( - "Id strategy must be customize or automatic")); + throw new AssertionError("Id strategy must be customize or automatic"); } schema.edgeLabel("knows").link("vertex", "vertex") @@ -673,8 +662,7 @@ private void initBasicPropertyKey() { schema.propertyKey("new").ifNotExist().create(); schema.propertyKey("color").ifNotExist().create(); schema.propertyKey("every").ifNotExist().create(); - schema.propertyKey("gremlin.partitionGraphStrategy.partition") - .ifNotExist().create(); + schema.propertyKey("gremlin.partitionGraphStrategy.partition").ifNotExist().create(); schema.propertyKey("blah").asDouble().ifNotExist().create(); schema.propertyKey("bloop").asInt().ifNotExist().create(); @@ -693,8 +681,7 @@ private void initBasicPropertyKey() { } @Watched - private void initBasicVertexLabelV(IdStrategy idStrategy, - String defaultVL) { + private void initBasicVertexLabelV(IdStrategy idStrategy, String defaultVL) { SchemaManager schema = this.graph.schema(); switch (idStrategy) { @@ -767,7 +754,7 @@ private void initBasicVertexLabelV(IdStrategy idStrategy, private void initBasicVertexLabelAndEdgeLabelExceptV(String defaultVL) { SchemaManager schema = this.graph.schema(); - if (!defaultVL.equals("person")) { + if (!"person".equals(defaultVL)) { schema.vertexLabel("person") .properties("name", "age") .nullableKeys("name", "age")