syntax = "proto3";

package nexuscrm.runtime.v1;

import "common/v1/common.proto";
import "runtime/v1/records.proto";

option go_package = "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1;runtimev1";

// RecordQueryService executes one bounded, already-parsed neutral records
// query. External query grammar, cursors and product response envelopes remain
// caller-owned and never cross this boundary.
service RecordQueryService {
  rpc QueryRecords(QueryRecordsRequest) returns (QueryRecordsResponse);
  rpc QueryHistory(QueryHistoryRequest) returns (QueryHistoryResponse);
}

enum QueryPredicateKind {
  QUERY_PREDICATE_KIND_UNSPECIFIED = 0;
  QUERY_PREDICATE_KIND_AND = 1;
  QUERY_PREDICATE_KIND_OR = 2;
  QUERY_PREDICATE_KIND_NOT = 3;
  QUERY_PREDICATE_KIND_EXPRESSION = 4;
  QUERY_PREDICATE_KIND_COMPARISON = 5;
  QUERY_PREDICATE_KIND_FIELD_COMPARISON = 6;
  QUERY_PREDICATE_KIND_CORRELATED_MEMBERSHIP = 7;
}

enum QueryOperandKind {
  QUERY_OPERAND_KIND_UNSPECIFIED = 0;
  QUERY_OPERAND_KIND_FIELD = 1;
  QUERY_OPERAND_KIND_LITERAL = 2;
  QUERY_OPERAND_KIND_LIST = 3;
  QUERY_OPERAND_KIND_FUNCTION = 4;
  QUERY_OPERAND_KIND_TRUSTED_CONTEXT = 5;
}

enum QueryComparisonOperator {
  QUERY_COMPARISON_OPERATOR_UNSPECIFIED = 0;
  QUERY_COMPARISON_OPERATOR_EQUAL = 1;
  QUERY_COMPARISON_OPERATOR_NOT_EQUAL = 2;
  QUERY_COMPARISON_OPERATOR_GREATER_THAN = 3;
  QUERY_COMPARISON_OPERATOR_GREATER_OR_EQUAL = 4;
  QUERY_COMPARISON_OPERATOR_LESS_THAN = 5;
  QUERY_COMPARISON_OPERATOR_LESS_OR_EQUAL = 6;
  QUERY_COMPARISON_OPERATOR_IN = 7;
  QUERY_COMPARISON_OPERATOR_NOT_IN = 8;
  QUERY_COMPARISON_OPERATOR_CONTAINS = 9;
  QUERY_COMPARISON_OPERATOR_STARTS_WITH = 10;
  QUERY_COMPARISON_OPERATOR_ENDS_WITH = 11;
  QUERY_COMPARISON_OPERATOR_LIKE = 12;
  QUERY_COMPARISON_OPERATOR_NOT_LIKE = 13;
}

enum QueryFunctionName {
  QUERY_FUNCTION_NAME_UNSPECIFIED = 0;
  QUERY_FUNCTION_NAME_COUNT = 1;
  QUERY_FUNCTION_NAME_COUNT_DISTINCT = 2;
  QUERY_FUNCTION_NAME_SUM = 3;
  QUERY_FUNCTION_NAME_AVG = 4;
  QUERY_FUNCTION_NAME_MIN = 5;
  QUERY_FUNCTION_NAME_MAX = 6;
  QUERY_FUNCTION_NAME_STRING = 7;
  QUERY_FUNCTION_NAME_FORMAT = 8;
  QUERY_FUNCTION_NAME_DISPLAY_VALUE = 9;
  QUERY_FUNCTION_NAME_NORMALIZE_CURRENCY = 10;
  QUERY_FUNCTION_NAME_GROUPING = 11;
  QUERY_FUNCTION_NAME_TEMPORAL_PART = 12;
  QUERY_FUNCTION_NAME_GEO_DISTANCE = 13;
  QUERY_FUNCTION_NAME_GEO_POINT = 14;
}

enum QueryTemporalPart {
  QUERY_TEMPORAL_PART_UNSPECIFIED = 0;
  QUERY_TEMPORAL_PART_MONTH = 1;
  QUERY_TEMPORAL_PART_YEAR = 2;
  QUERY_TEMPORAL_PART_QUARTER = 3;
  QUERY_TEMPORAL_PART_DAY_OF_MONTH = 4;
  QUERY_TEMPORAL_PART_DAY_OF_WEEK = 5;
  QUERY_TEMPORAL_PART_DAY_OF_YEAR = 6;
  QUERY_TEMPORAL_PART_DATE = 7;
  QUERY_TEMPORAL_PART_HOUR = 8;
  QUERY_TEMPORAL_PART_WEEK_OF_MONTH = 9;
  QUERY_TEMPORAL_PART_WEEK_OF_YEAR = 10;
}

enum QueryTemporalBasis {
  QUERY_TEMPORAL_BASIS_UNSPECIFIED = 0;
  QUERY_TEMPORAL_BASIS_CIVIL = 1;
  QUERY_TEMPORAL_BASIS_BUSINESS = 2;
}

enum QueryDistanceUnit {
  QUERY_DISTANCE_UNIT_UNSPECIFIED = 0;
  QUERY_DISTANCE_UNIT_KILOMETERS = 1;
  QUERY_DISTANCE_UNIT_MILES = 2;
}

message QueryScalar {
  oneof value {
    NullValue null_value = 1;
    string string_value = 2;
    bool boolean_value = 3;
    sint64 integer_value = 4;
    uint64 unsigned_value = 5;
    double double_value = 6;
    DecimalValue decimal_value = 7;
    DateValue date_value = 8;
    DateTimeValue datetime_value = 9;
  }
}

message QueryOperands {
  repeated QueryOperand values = 1;
}

message QueryOperand {
  QueryOperandKind kind = 1;
  oneof value {
    string field = 2;
    QueryScalar literal = 3;
    QueryOperands list = 4;
    QueryFunction function = 5;
    QueryTrustedContextValue trusted_context = 6;
  }
}

message QueryFunction {
  QueryFunctionName name = 1;
  repeated QueryOperand arguments = 2;
  QueryTemporalPart temporal_part = 3;
  QueryDistanceUnit distance_unit = 4;
  QueryTemporalBasis temporal_basis = 5;
}

message QueryPredicates {
  repeated QueryPredicate values = 1;
}

message QueryComparison {
  QueryOperand left = 1;
  QueryComparisonOperator operator = 2;
  QueryOperand right = 3;
}

message QueryFieldComparison {
  string field = 1;
  QueryComparisonOperator operator = 2;
  QueryScalar value = 3;
}

message QueryCorrelatedMembership {
  string id = 1;
  string outer_field = 2;
  bool negate = 3;
  string inner_object_id = 4;
  string inner_select_field = 5;
  QueryPredicate inner_filter = 6;
  uint32 inner_limit = 7;
  bool inner_include_deleted = 8;
}

message QueryPredicate {
  QueryPredicateKind kind = 1;
  oneof value {
    QueryPredicates children = 2;
    QueryOperand expression = 3;
    QueryComparison comparison = 4;
    QueryFieldComparison field_comparison = 5;
    QueryCorrelatedMembership correlated_membership = 6;
  }
}

enum QuerySortDirection {
  QUERY_SORT_DIRECTION_UNSPECIFIED = 0;
  QUERY_SORT_DIRECTION_ASCENDING = 1;
  QUERY_SORT_DIRECTION_DESCENDING = 2;
}

message QuerySort {
  string field = 1;
  QuerySortDirection direction = 2;
}

enum QuerySelectionKind {
  QUERY_SELECTION_KIND_UNSPECIFIED = 0;
  QUERY_SELECTION_KIND_FIELD = 1;
  QUERY_SELECTION_KIND_AGGREGATE = 2;
}

enum QueryAggregateFunction {
  QUERY_AGGREGATE_FUNCTION_UNSPECIFIED = 0;
  QUERY_AGGREGATE_FUNCTION_COUNT = 1;
  QUERY_AGGREGATE_FUNCTION_SUM = 2;
  QUERY_AGGREGATE_FUNCTION_AVG = 3;
  QUERY_AGGREGATE_FUNCTION_MIN = 4;
  QUERY_AGGREGATE_FUNCTION_MAX = 5;
}

message QuerySelection {
  QuerySelectionKind kind = 1;
  string field = 2;
  QueryAggregateFunction aggregate = 3;
  string alias = 4;
}

message QuerySubquery {
  string relationship_name = 1;
  repeated string selected_fields = 2;
  QueryPredicate filter = 3;
  repeated QuerySort order_by = 4;
  uint32 limit = 5;
}

message QueryRecordsRequest {
  string object_id = 1;
  repeated QuerySelection selections = 2;
  QueryPredicate filter = 3;
  reserved 4, 5;
  uint32 limit = 6;
  uint64 offset = 7;
  bool skip_total_size = 8;
  bool include_deleted = 9;
  repeated QuerySort order_by = 10;
  string group_by = 11;
  QueryPredicate having = 12;
  repeated QuerySubquery subqueries = 13;
  uint32 aggregate_fetch_limit = 14;
  optional uint64 min_catalog_revision = 15;
}

enum QueryValueKind {
  QUERY_VALUE_KIND_UNSPECIFIED = 0;
  QUERY_VALUE_KIND_STRING = 1;
  QUERY_VALUE_KIND_BOOLEAN = 2;
  QUERY_VALUE_KIND_INTEGER = 3;
  QUERY_VALUE_KIND_UNSIGNED = 4;
  QUERY_VALUE_KIND_DOUBLE = 5;
  QUERY_VALUE_KIND_DECIMAL = 6;
  QUERY_VALUE_KIND_DATE = 7;
  QUERY_VALUE_KIND_DATETIME = 8;
  QUERY_VALUE_KIND_REFERENCE = 9;
  QUERY_VALUE_KIND_OBJECT = 10;
  QUERY_VALUE_KIND_LIST = 11;
}

message QueryValues {
  repeated QueryValue values = 1;
}

message QueryValue {
  QueryValueKind declared_kind = 1;
  oneof value {
    NullValue null_value = 2;
    string string_value = 3;
    bool boolean_value = 4;
    sint64 integer_value = 5;
    uint64 unsigned_value = 6;
    double double_value = 7;
    DecimalValue decimal_value = 8;
    DateValue date_value = 9;
    DateTimeValue datetime_value = 10;
    ReferenceValue reference_value = 11;
    QueryRecord object_value = 12;
    QueryValues list_value = 13;
  }
}

message QueryField {
  string name = 1;
  QueryValue value = 2;
}

message QueryRecord {
  string object_id = 1;
  // Canonical ascending bytewise UTF-8 field order. Absent and FLS-hidden
  // fields have no entry; explicit null has the NullValue arm.
  repeated QueryField fields = 2;
}

message QueryRecordsResponse {
  uint64 total_size = 1;
  bool total_size_unknown = 2;
  bool done = 3;
  repeated QueryRecord records = 4;
  bool aggregate = 5;
  nexuscrm.common.v1.ConsistencyReceipts receipts = 6;
}

message QueryHistoryRequest {
  string parent_object_id = 1;
  repeated string selected_fields = 2;
  string parent_record_id = 3;
  QueryPredicate filter = 4;
  uint32 limit = 5;
  uint64 offset = 6;
  bool sort_descending = 7;
  bool include_deleted = 8;
  uint32 page_size = 9;
  uint64 cursor_offset = 10;
  optional uint64 min_catalog_revision = 11;
}

message QueryHistoryRow {
  string id = 1;
  string parent_id = 2;
  string field = 3;
  optional string old_value = 4;
  optional string new_value = 5;
  string data_type = 6;
  string created_date = 7;
  string created_by_id = 8;
}

message QueryHistoryResponse {
  uint64 total_size = 1;
  bool done = 2;
  repeated QueryHistoryRow rows = 3;
  nexuscrm.common.v1.ConsistencyReceipts receipts = 4;
}

// QueryTrustedContextValue is deliberately appended after the v1 message and
// enum set. Existing generated enum ordinals remain stable while the operand
// oneof can reference this additive authority selector.
enum QueryTrustedContextValue {
  QUERY_TRUSTED_CONTEXT_VALUE_UNSPECIFIED = 0;
  QUERY_TRUSTED_CONTEXT_VALUE_PRINCIPAL_ID = 1;
}
