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

org.neo4j.procedure.builtin.graphschema.GraphSchemaGraphyResultWrapper Maven / Gradle / Ivy

/*
 * 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.procedure.builtin.graphschema;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Entity;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.ResourceIterable;
import org.neo4j.procedure.builtin.graphschema.GraphSchema.NodeObjectType;
import org.neo4j.procedure.builtin.graphschema.GraphSchema.Ref;
import org.neo4j.procedure.builtin.graphschema.GraphSchema.RelationshipObjectType;
import org.neo4j.procedure.builtin.graphschema.GraphSchema.Token;

/**
 * A graph-y result build from a {@link GraphSchema}. The wrapper is needed to make the Neo4j embedded API happy.
 */
public final class GraphSchemaGraphyResultWrapper {

    public static GraphSchemaGraphyResultWrapper flat(GraphSchema graphSchema) {

        var nodeLabels = graphSchema.nodeLabels().values().stream().collect(Collectors.toMap(Token::id, Token::value));
        var relationshipTypes =
                graphSchema.relationshipTypes().values().stream().collect(Collectors.toMap(Token::id, Token::value));

        var result = new GraphSchemaGraphyResultWrapper();

        var nodeObjectTypeNodes = new HashMap();
        for (NodeObjectType nodeObjectType : graphSchema.nodeObjectTypes().values()) {
            var labels = nodeObjectType.labels().stream()
                    .map(v -> nodeLabels.get(v.value()))
                    .toArray(String[]::new);
            var node = new VirtualNode(
                    Map.of(
                            "$id",
                            nodeObjectType.id(),
                            "name",
                            labels.length == 0 ? "n/a" : labels[0],
                            "properties",
                            GraphSchemaModule.asJsonString(nodeObjectType.properties())),
                    labels);
            nodeObjectTypeNodes.put(new Ref(nodeObjectType.id()), node);
        }
        result.nodes.addAll(nodeObjectTypeNodes.values());

        for (RelationshipObjectType relationshipObjectType :
                graphSchema.relationshipObjectTypes().values()) {
            var relationship = new VirtualRelationship(
                    nodeObjectTypeNodes.get(relationshipObjectType.from()),
                    relationshipTypes.get(relationshipObjectType.type().value()),
                    Map.of(
                            "$id",
                            relationshipObjectType.id(),
                            "properties",
                            GraphSchemaModule.asJsonString(relationshipObjectType.properties())),
                    nodeObjectTypeNodes.get(relationshipObjectType.to()));
            result.relationships.add(relationship);
        }

        return result;
    }

    public static GraphSchemaGraphyResultWrapper full(GraphSchema graphSchema) {

        var nodeLabelNodes = graphSchema.nodeLabels().values().stream()
                .collect(Collectors.toMap(Token::id, t -> toVirtualNode(t, "NodeLabel")));
        var relationshipTypeNodes = graphSchema.relationshipTypes().values().stream()
                .collect(Collectors.toMap(Token::id, t -> toVirtualNode(t, "RelationshipType")));

        var result = new GraphSchemaGraphyResultWrapper();

        var nodeObjectTypeNodes = new HashMap();
        for (var entry : graphSchema.nodeObjectTypes().entrySet()) {
            var nodeObjectType = entry.getValue();
            var node = new VirtualNode(
                    Map.of(
                            "$id",
                            nodeObjectType.id(),
                            "properties",
                            GraphSchemaModule.asJsonString(nodeObjectType.properties())),
                    "NodeObjectType");
            nodeObjectTypeNodes.put(entry.getKey(), node);

            for (var ref : nodeObjectType.labels()) {
                var tokenNode = nodeLabelNodes.get(ref.value());
                result.relationships.add(new VirtualRelationship(node, "HAS_LABEL", tokenNode));
            }
        }

        for (RelationshipObjectType relationshipObjectType :
                graphSchema.relationshipObjectTypes().values()) {
            var node = new VirtualNode(
                    Map.of(
                            "$id",
                            relationshipObjectType.id(),
                            "properties",
                            GraphSchemaModule.asJsonString(relationshipObjectType.properties())),
                    "RelationshipObjectTypes");
            result.nodes.add(node);
            result.relationships.add(new VirtualRelationship(
                    node,
                    "HAS_TYPE",
                    relationshipTypeNodes.get(relationshipObjectType.type().value())));
            result.relationships.add(
                    new VirtualRelationship(node, "FROM", nodeObjectTypeNodes.get(relationshipObjectType.from())));
            result.relationships.add(
                    new VirtualRelationship(node, "TO", nodeObjectTypeNodes.get(relationshipObjectType.to())));
        }

        // Add remaining things
        result.nodes.addAll(nodeLabelNodes.values());
        result.nodes.addAll(relationshipTypeNodes.values());
        result.nodes.addAll(nodeObjectTypeNodes.values());

        return result;
    }

    private static Node toVirtualNode(Token token, String label) {

        return new VirtualNode(Map.of("$id", token.id(), "value", token.value()), "Token", label);
    }

    // Public field required for Neo4j internal API.
    public final List nodes = new ArrayList<>();
    public final List relationships = new ArrayList<>();

    /**
     * A virtual entity, spotting a negative ID and a random element id.
     */
    abstract static class VirtualEntity implements Entity {

        private static final Supplier ID_FACTORY = new AtomicLong(-1)::decrementAndGet;

        private final long id;

        private final String elementId;

        private final Map properties;

        VirtualEntity(Map properties) {
            this.id = ID_FACTORY.get();
            this.elementId = String.valueOf(this.id);
            this.properties = Map.copyOf(properties);
        }

        @SuppressWarnings("removal")
        @Override
        public final long getId() {
            return id;
        }

        @Override
        public final String getElementId() {
            return elementId;
        }

        @Override
        public final boolean hasProperty(String key) {
            return properties.containsKey(key);
        }

        @Override
        public final Object getProperty(String key) {
            return properties.get(key);
        }

        @Override
        public final Object getProperty(String key, Object defaultValue) {
            return properties.getOrDefault(key, defaultValue);
        }

        @Override
        public final void setProperty(String key, Object value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public final Object removeProperty(String key) {
            throw new UnsupportedOperationException();
        }

        @Override
        public final Iterable getPropertyKeys() {
            return properties.keySet();
        }

        @Override
        public final Map getProperties(String... keys) {
            Map result = new HashMap<>();
            for (String key : keys) {
                if (!hasProperty(key)) {
                    continue;
                }
                result.put(key, getProperty(key));
            }
            return result;
        }

        @Override
        public final Map getAllProperties() {
            return properties;
        }

        @Override
        public final void delete() {
            throw new UnsupportedOperationException();
        }
    }

    static final class VirtualNode extends VirtualEntity implements Node {

        private final Set




© 2015 - 2025 Weber Informatics LLC | Privacy Policy