syntax = "proto3";

package indradb;

import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";

// A UUID.
message Uuid {
    bytes value = 1;
}

// A string that must be less than 256 characters long, and can only contain
// letters, numbers, dashes and underscores. This is used for vertex and edge
// types, as well as property names.
message Identifier {
    string value = 1;
}

// A JSON value.
message Json {
    string value = 1;
}

// An edge.
//
// Edges are how you would represent a verb or a relationship in the
// datastore. An example might be "liked" or "reviewed". Edges are typed and
// directed.
message Edge {
    // The id of the outbound vertex.
    Uuid outbound_id = 1;
    // The type of the edge.
    Identifier t = 2;
    // The id of the inbound vertex.
    Uuid inbound_id = 3;
}

// A vertex.
//
// Vertices are how you would represent nouns in the datastore. An example
// might be a user, or a movie. All vertices have a unique ID and a type.
message Vertex {
    // The id of the vertex.
    Uuid id = 1;
    // The type of the vertex.
    Identifier t = 2;
}

// A query to get a set of values from the database.
message Query {
    oneof query {
        // Gets all vertices.
        google.protobuf.Empty all_vertex = 1;
        // Gets a range of vertices.
        RangeVertexQuery range_vertex = 2;
        // Gets a specific set of vertices.
        SpecificVertexQuery specific_vertex = 3;
        // Gets vertices with or without a given property.
        VertexWithPropertyPresenceQuery vertex_with_property_presence = 4;
        // Gets vertices with a property equal to a given value.
        VertexWithPropertyValueQuery vertex_with_property_value = 5;

        // Gets all edges.
        google.protobuf.Empty all_edge = 6;
        // Gets a specific set of edges.
        SpecificEdgeQuery specific_edge = 7;
        // Gets edges with or without a given property.
        EdgeWithPropertyPresenceQuery edge_with_property_presence = 8;
        // Gets edges with a property equal to a given value.
        EdgeWithPropertyValueQuery edge_with_property_value = 9;

        // Gets the vertices associated with edges, or edges associated with
        // vertices.
        PipeQuery pipe = 10;
        // Returns the properties associated with a vertex or edge.
        PipePropertyQuery pipe_property = 11;
        // Gets vertices or edges with or without a property.
        PipeWithPropertyPresenceQuery pipe_with_property_presence = 12;
        // Gets vertices or edges with a property equal to a given value.
        PipeWithPropertyValueQuery pipe_with_property_value = 13;

        // Includes the results of a query in output.
        IncludeQuery include = 14;
        // Counts the number of items returned from a query.
        CountQuery count = 15;
    }
}

// Gets a range of vertices.
message RangeVertexQuery {
    // Limits the number of vertices to get.
    uint32 limit = 1;
    // Filters the type of vertices returned.
    Identifier t = 2;
    // Sets the lowest vertex ID to return.
    Uuid start_id = 3;
}

// Gets a specific set of vertices.
message SpecificVertexQuery {
    // The IDs of the vertices to get.
    repeated Uuid ids = 1;
}

// Gets vertices with or without a given property.
message VertexWithPropertyPresenceQuery {
    // The name of the property.
    Identifier name = 1;
}

// Gets vertices with a property equal to a given value.
message VertexWithPropertyValueQuery {
    // The name of the property.
    Identifier name = 1;
    // The value of the property.
    Json value = 2;
}

// Gets a specific set of edges.
message SpecificEdgeQuery {
    // The edges to get.
    repeated Edge edges = 1;
}

// Gets edges with or without a given property.
message EdgeWithPropertyPresenceQuery {
    // The name of the property.
    Identifier name = 1;
}

// Gets edges with a property equal to a given value.
message EdgeWithPropertyValueQuery {
    // The name of the property.
    Identifier name = 1;
    // The value of the property.
    Json value = 2;
}

// Gets the vertices associated with edges, or edges associated with
// vertices.
message PipeQuery {
    // The query to build off of.
    Query inner = 1;
    // Whether to get outbound or inbound vertices on the edges.
    EdgeDirection direction = 2;
    // Limits the number of vertices to get.
    uint32 limit = 3;
    // Filters the type of vertices returned.
    Identifier t = 4;
}

// Returns the properties associated with a vertex or edge.
message PipePropertyQuery {
    // The inner query.
    Query inner = 1;
    // The property name to get. If `None`, all properties will be fetched.
    Identifier name = 2;
}

// Gets vertices or edges with or without a property.
message PipeWithPropertyPresenceQuery {
    // The query to filter.
    Query inner = 1;
    // The name of the property.
    Identifier name = 2;
    // Whether we should look for property presence or lack thereof.
    bool exists = 3;
}

// Gets vertices or edges with a property equal to a given value.
message PipeWithPropertyValueQuery {
    // The query to filter.
    Query inner = 1;
    // The name of the property.
    Identifier name = 2;
    // The value of the property.
    Json value = 3;
    // Whether we should look for property equality or non-equality.
    bool equal = 4;
}

// Includes the results of a query in output.
//
// The outermost part of a query will always be explicitly included. This
// allows you to also output an intermediate result.
message IncludeQuery {
    // The query to export.
    Query inner = 1;
}

// Counts the number of items returned from a query.
message CountQuery {
    // The query to export.
    Query inner = 1;
}

// Value(s) returned from a query.
message QueryOutputValue {
    oneof value {
        QueryOutputVertices vertices = 1;
        QueryOutputEdges edges = 2;
        uint64 count = 3;
        QueryOutputVertexProperties vertex_properties = 4;
        QueryOutputEdgeProperties edge_properties = 5;
    }
}

message QueryOutputVertices {
    repeated Vertex vertices = 1;
}

message QueryOutputEdges {
    repeated Edge edges = 1;
}

message QueryOutputVertexProperties {
    repeated VertexProperties vertex_properties = 1;
}

message QueryOutputEdgeProperties {
    repeated EdgeProperties edge_properties = 1;
}

// Specifies what kind of items should be piped from one type of query to
// another.
//
// Edge and vertex queries can build off of one another via pipes - e.g. you
// can get the outbound edges of a set of vertices by piping from a vertex
// query to an edge query. `EdgeDirection`s are used to specify which
// end of things you want to pipe - either the outbound items or the inbound
// items.
enum EdgeDirection {
    OUTBOUND = 0;
    INBOUND = 1;
}

// A property.
message NamedProperty {
    reserved 1;
    // The id of the vertex.
    Identifier name = 3;
    // The property value.
    Json value = 2;
}

// Represents a vertex property.
message VertexProperty {
    // The id of the vertex.
    Uuid id = 1;
    // The property value.
    Json value = 2;
}

// A vertex with properties.
message VertexProperties {
    // The vertex.
    Vertex vertex = 1;
    // All of the vertex's properties.
    repeated NamedProperty props = 2;
}

// Represents an edge property.
message EdgeProperty {
    // The edge.
    Edge edge = 1;
    // The property value.
    Json value = 2;
}

// An edge with properties.
message EdgeProperties {
    // The edge.
    Edge edge = 1;
    // All of the edge's properties.
    repeated NamedProperty props = 2;
}

// An item to insert, as part of a bulk insert request.
message BulkInsertItem {
    oneof item {
        Vertex vertex = 1;
        Edge edge = 2;
        VertexPropertyBulkInsertItem vertex_property = 3;
        EdgePropertyBulkInsertItem edge_property = 4;
    }
}

// A vertex property to insert.
message VertexPropertyBulkInsertItem {
    reserved 2;
    Uuid id = 1;
    Identifier name = 4;
    Json value = 3;
}

// An edge property to insert.
message EdgePropertyBulkInsertItem {
    reserved 2;
    Edge edge = 1;
    Identifier name = 4;
    Json value = 3;
}

// A request to index a property.
message IndexPropertyRequest {
    Identifier name = 1;
}

message SetPropertiesRequest {
    Query q = 1;
    Identifier name = 2;
    Json value = 3;
}

message CreateResponse {
    bool created = 1;
}

// A request to execute a plugin.
message ExecutePluginRequest {
    string name = 1;
    Json arg = 2;
}

// A response to a plugin execution.
message ExecutePluginResponse {
    Json value = 1;
}

service IndraDB {
    // Pings the server.
    rpc Ping(google.protobuf.Empty) returns (google.protobuf.Empty);

    // Syncs persisted content. Depending on the datastore implementation,
    // this has different meanings - including potentially being a no-op.
    rpc Sync(google.protobuf.Empty) returns (google.protobuf.Empty);

    // Creates a new vertex.
    rpc CreateVertex(Vertex) returns (CreateResponse);

    // Creates a new vertex with just a type specification. As opposed to
    // `CreateVertex`, this is used when you do not want to manually specify
    // the vertex's UUID. Returns the new vertex's UUID.
    rpc CreateVertexFromType(Identifier) returns (Uuid);

    // Creates a new edge.
    rpc CreateEdge(Edge) returns (CreateResponse);

    // Gets values specified by a query.
    rpc Get(Query) returns (stream QueryOutputValue);

    // Deletes values specified by a query.
    rpc Delete(Query) returns (google.protobuf.Empty);

    // Sets properties.
    rpc SetProperties(SetPropertiesRequest) returns (google.protobuf.Empty);

    // Bulk inserts many vertices, edges, and/or properties.
    //
    // Note that datastores have discretion on how to approach safeguard vs
    // performance tradeoffs. In particular:
    // * If the datastore is disk-backed, it may or may not flush before
    //   returning.
    // * The datastore might not verify for correctness; e.g., it might not
    //   ensure that the relevant vertices exist before inserting an edge.
    rpc BulkInsert(stream BulkInsertItem) returns (google.protobuf.Empty);

    // Enables indexing on a specified property. When indexing is enabled on a
    // property, it's possible to query on its presence and values.
    rpc IndexProperty(IndexPropertyRequest) returns (google.protobuf.Empty);

    // Executes a plugin and returns back the response from the plugin.
    rpc ExecutePlugin(ExecutePluginRequest) returns (ExecutePluginResponse);
}
