syntax = "proto3";

package nominal.connections.v1;

import "google/api/annotations.proto";

option java_multiple_files = true;
option java_package = "io.nominal.connections.v1";

// Nanosecond precision timestamp type, represented by an epoch time in seconds and a nanosecond offset.
// The nanosecond offset is from the start of the epoch second, so must be less than 1 billion.
message Timestamp {
  int64 seconds = 1;

  int64 nanos = 2;
}

message Range {
  Timestamp start_time_inclusive = 1;
  Timestamp end_time_exclusive = 2;
}

message TagValues {
  // All the allowed values the tag can have. Tag values are opaque and will be passed back to the server in future
  // calls. The values are expected to be unique.
  repeated string values = 1;
}

enum DataType {
  DATA_TYPE_UNSPECIFIED = 0;
  DATA_TYPE_INT = 1;
  DATA_TYPE_DOUBLE = 2;
  DATA_TYPE_STRING = 3;
}

message ChannelMetadata {
  // Channels are opaque values that will be passed back to the server in future calls.
  string channel = 1;
  // Every value in the channel is expected to have the same type.
  DataType data_type = 2;
  // All the possible tags and their values associated with the channel.
  map<string, TagValues> all_tag_values = 3;
}

message ListChannelsRequest {
  // The max number of elements returned in the response, the actual number can be lower but should never exceed this.
  int32 page_size = 1;
  // The time range for which we want to see channels which exist
  Range range = 2;
  // Where to continue paging from in subsequent requests. This will be empty on the first call.
  optional string page_token = 3;
}

message ListChannelsResponse {
  repeated ChannelMetadata channels = 1;
  optional string page_token = 2;
}

message QueryChannelRequest {
  // The channel should be a value that was previously returned by a ListChannels call.
  string channel = 1;
  // The tag name/value pairs to filter on.
  map<string, string> tags = 2;
  // The time range to filter on.
  Range range = 3;
}

message IntPoints {
  repeated Timestamp timestamps = 1;
  repeated int64 values = 2;
}

message DoublePoints {
  repeated Timestamp timestamps = 1;
  repeated double values = 2;
}

message StringPoints {
  repeated Timestamp timestamps = 1;
  repeated string values = 2;
}

message QueryChannelResponse {
  oneof values {
    IntPoints ints = 1;
    DoublePoints doubles = 2;
    StringPoints strings = 3;
  }
}

/**
 * Defines the interface for how Nominal expects to interact with custom connection implementations. All sources of
 * time series data is abstracted by a channel identifier, allowing for flexibility of the underlying data source
 * implementations.
 *
 * The authorization credentials are passed as http headers as:
 *     "Authorization: Bearer <token>"
 */
service ConnectionsService {
  /**
   * Paging endpoint to list all the channels and their allowed tag values. Callers should expect that more results are
   * available as long as ListChannelsResponse continues to return a pageToken and will pass in this pageToken in the
   * next ListChannelsRequest.
   */
  rpc ListChannels(ListChannelsRequest) returns (ListChannelsResponse) {
    option (google.api.http) = {get: "/connections/v1/channels/list"};
  }

  /**
   * Endpoint to query a given channel for time series data for a given set of tags and time range. The response is a
   * stream of points.
   */
  rpc QueryChannel(QueryChannelRequest) returns (stream QueryChannelResponse) {
    option (google.api.http) = {get: "/connections/v1/channel/{channel}/query"};
  }
}
