syntax = "proto3";

package nnext;

import "json_with_int.proto";

// ---------------------------------------------
// ------------- Point Id Requests -------------
// ---------------------------------------------

message PointId {
  oneof point_id_options {
    uint64 num = 1; // Numerical ID of the point
    string uuid = 2; // UUID
  }
}


// ---------------------------------------------
// ---------------- RPC Requests ---------------
// ---------------------------------------------

message UpsertPoints {
  string collection_name = 1; // name of the collection
  optional bool wait = 2; // Wait until the changes have been applied?
  repeated PointStruct points = 3;
}

message DeletePoints {
  string collection_name = 1; // name of the collection
  optional bool wait = 2; // Wait until the changes have been applied?
  PointsSelector points = 3; // Affected points
}

message GetPoints {
  string collection_name = 1; // name of the collection
  repeated PointId ids = 2; // List of points to retrieve
  optional bool with_vector = 3; // Return point vector with the result.
  WithPayloadSelector with_payload = 4; // Options for specifying which payload to include or not
}

message SetPayloadPoints {
  string collection_name = 1; // name of the collection
  optional bool wait = 2; // Wait until the changes have been applied?
  map<string, Value> payload = 3; // New payload values
  repeated PointId points = 4; // List of point to modify
}

message DeletePayloadPoints {
  string collection_name = 1; // name of the collection
  optional bool wait = 2; // Wait until the changes have been applied?
  repeated string keys = 3; // List of keys to delete
  repeated PointId points = 4; // Affected points
}

message ClearPayloadPoints {
  string collection_name = 1; // name of the collection
  optional bool wait = 2; // Wait until the changes have been applied?
  PointsSelector points = 3; // Affected points
}

enum FieldType {
  FieldTypeKeyword = 0;
  FieldTypeInteger = 1;
  FieldTypeFloat = 2;
  FieldTypeGeo = 3;
}

message CreateFieldIndexCollection {
  string collection_name = 1; // name of the collection
  optional bool wait = 2; // Wait until the changes have been applied?
  string field_name = 3; // Field name to index
  optional FieldType field_type = 4; // Field type.
}

message DeleteFieldIndexCollection {
  string collection_name = 1; // name of the collection
  optional bool wait = 2; // Wait until the changes have been applied?
  string field_name = 3; // Field name to delete
}

message PayloadIncludeSelector {
  repeated string fields = 1; // List of payload keys to include into result
}

message PayloadExcludeSelector {
  repeated string fields = 1; // List of payload keys to exclude from the result
}

message WithPayloadSelector {
  oneof selector_options {
    bool enable = 1; // If `true` - return all payload, if `false` - none
    PayloadIncludeSelector include = 2;
    PayloadExcludeSelector exclude = 3;
  }
}

message SearchParams {
  /*
  Params relevant to HNSW index. Size of the beam in a beam-search.
  Larger the value - more accurate the result, more time required for search.
   */
  optional uint64 hnsw_ef = 1;


}

message SearchPoints {
  string collection_name = 1; // name of the collection
  repeated float vector = 2; // vector
  Filter filter = 3; // Filter conditions - return only those points that satisfy the specified conditions
  uint64 limit = 4; // Max number of result
  optional bool with_vector = 5; // Return point vector with the result.
  WithPayloadSelector with_payload = 6; // Options for specifying which payload to include or not
  SearchParams params = 7; // Search config
  optional float score_threshold = 8; // If provided - cut off results with worse scores
  optional uint64 offset = 9; // Offset of the result
}

message ScrollPoints {
  string collection_name = 1;
  Filter filter = 2; // Filter conditions - return only those points that satisfy the specified conditions
  optional PointId offset = 3; // Start with this ID
  optional uint32 limit = 4; // Max number of result
  optional bool with_vector = 5; // Return point vector with the result.
  WithPayloadSelector with_payload = 6; // Options for specifying which payload to include or not
}

message RecommendPoints {
  string collection_name = 1; // name of the collection
  repeated PointId positive = 2; // Look for vectors closest to those
  repeated PointId negative = 3; // Try to avoid vectors like this
  Filter filter = 4; // Filter conditions - return only those points that satisfy the specified conditions
  uint64 limit = 5; // Max number of result
  optional bool with_vector = 6; // Return point vector with the result.
  WithPayloadSelector with_payload = 7; // Options for specifying which payload to include or not
  SearchParams params = 8; // Search config
  optional float score_threshold = 9; // If provided - cut off results with worse scores
  optional uint64 offset = 10; // Offset of the result
}

message CountPoints {
  string collection_name = 1; // name of the collection
  Filter filter = 2; // Filter conditions - return only those points that satisfy the specified conditions
  optional bool exact = 3; // If `true` - return exact count, if `false` - return approximate count
}

// ---------------------------------------------
// ---------------- RPC Response ---------------
// ---------------------------------------------

message PointsOperationResponse {
  UpdateResult result = 1;
  double time = 2; // Time spent to process
}

message UpdateResult {
  uint64 operation_id = 1; // Number of operation
  UpdateStatus status = 2; // Operation status
}

enum UpdateStatus {
  UnknownUpdateStatus = 0;
  Acknowledged = 1; // Update is received, but not processed yet
  Completed = 2; // Update is applied and ready for search
}

message ScoredPoint {
  PointId id = 1; // Point id
  map<string, Value> payload = 2; // Payload
  float score = 3; // Similarity score
  repeated float vector = 4; // Vector
  uint64 version = 5; // Last update operation applied to this point
}

message SearchResponse {
  repeated ScoredPoint result = 1;
  double time = 2; // Time spent to process
}

message CountResponse {
  CountResult result = 1;
  double time = 2; // Time spent to process
}

message ScrollResponse {
  optional PointId next_page_offset = 1; // Use this offset for the next query
  repeated RetrievedPoint result = 2;
  double time = 3; // Time spent to process
}

message CountResult {
  uint64 count = 1;
}

message RetrievedPoint {
  PointId id = 1;
  map<string, Value> payload = 2;
  repeated float vector = 3;
}

message GetResponse {
  repeated RetrievedPoint result = 1;
  double time = 2; // Time spent to process
}

message RecommendResponse {
  repeated ScoredPoint result = 1;
  double time = 2; // Time spent to process
}

// ---------------------------------------------
// ------------- Filter Conditions -------------
// ---------------------------------------------

message Filter {
  repeated Condition should = 1; // At least one of those conditions should match
  repeated Condition must = 2; // All conditions must match
  repeated Condition must_not = 3; // All conditions must NOT match
}

message Condition {
  oneof condition_one_of {
    FieldCondition field = 1;
    IsEmptyCondition isEmpty = 2;
    HasIdCondition hasId = 3;
    Filter filter = 4;
  }
}

message IsEmptyCondition {
  string key = 1;
}

message HasIdCondition {
  repeated PointId has_id = 1;
}

message FieldCondition {
  string key = 1;
  Match match = 2; // Check if point has field with a given value
  Range range = 3; // Check if points value lies in a given range
  GeoBoundingBox geo_bounding_box = 4; // Check if points geo location lies in a given area
  GeoRadius geo_radius = 5; // Check if geo point is within a given radius
  ValuesCount values_count = 6; // Check number of values for a specific field
}

message Match {
  oneof match_value {
    string keyword = 1; // Match string keyword
    int64 integer = 2; // Match integer
    bool boolean = 3; // Match boolean
  }
}

message Range {
  optional double lt = 1;
  optional double gt = 2;
  optional double gte = 3;
  optional double lte = 4;
}

message GeoBoundingBox {
  GeoPoint top_left = 1; // north-west corner
  GeoPoint bottom_right = 2; // south-east corner
}

message GeoRadius {
  GeoPoint center = 1; // Center of the circle
  float radius = 2; // In meters
}

message ValuesCount {
  optional uint64 lt = 1;
  optional uint64 gt = 2;
  optional uint64 gte = 3;
  optional uint64 lte = 4;
}

// ---------------------------------------------
// -------------- Points Selector --------------
// ---------------------------------------------

message PointsSelector {
  oneof points_selector_one_of {
    PointsIdsList points = 1;
    Filter filter = 2;
  }
}

message PointsIdsList {
  repeated PointId ids = 1;
}

// ---------------------------------------------
// ------------------- Point -------------------
// ---------------------------------------------


message PointStruct {
  PointId id = 1;
  repeated float vector = 2;
  map<string, Value> payload = 3;
}


message GeoPoint {
  double lon = 1;
  double lat = 2;
}
