syntax = "proto3";
package event_store.client.streams;
option java_package = "com.eventstore.dbclient.proto.streams";

import "shared.proto";
import "status.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";

service Streams {
	rpc Read (ReadReq) returns (stream ReadResp);
	rpc Append (stream AppendReq) returns (AppendResp);
	rpc Delete (DeleteReq) returns (DeleteResp);
	rpc Tombstone (TombstoneReq) returns (TombstoneResp);
	rpc BatchAppend (stream BatchAppendReq) returns (stream BatchAppendResp);
}

message ReadReq {
	Options options = 1;

	message Options {
		oneof stream_option {
			StreamOptions stream = 1;
			AllOptions all = 2;
		}
		ReadDirection read_direction = 3;
		bool resolve_links = 4;
		oneof count_option {
			uint64 count = 5;
			SubscriptionOptions subscription = 6;
		}
		oneof filter_option {
			FilterOptions filter = 7;
			event_store.client.Empty no_filter = 8;
		}
		UUIDOption uuid_option = 9;
		ControlOption control_option = 10;

		enum ReadDirection {
			Forwards = 0;
			Backwards = 1;
		}
		message StreamOptions {
			event_store.client.StreamIdentifier stream_identifier = 1;
			oneof revision_option {
				uint64 revision = 2;
				event_store.client.Empty start = 3;
				event_store.client.Empty end = 4;
			}
		}
		message AllOptions {
			oneof all_option {
				Position position = 1;
				event_store.client.Empty start = 2;
				event_store.client.Empty end = 3;
			}
		}
		message SubscriptionOptions {
		}
		message Position {
			uint64 commit_position = 1;
			uint64 prepare_position = 2;
		}
		message FilterOptions {
			oneof filter {
				Expression stream_identifier = 1;
				Expression event_type = 2;
			}
			oneof window {
				uint32 max = 3;
				event_store.client.Empty count = 4;
			}
			uint32 checkpointIntervalMultiplier = 5;

			message Expression {
				string regex = 1;
				repeated string prefix = 2;
			}
		}
		message UUIDOption {
			oneof content {
				event_store.client.Empty structured = 1;
				event_store.client.Empty string = 2;
			}
		}
		message ControlOption {
			uint32 compatibility = 1;
		}
	}
}

message ReadResp {
	oneof content {
		ReadEvent event = 1;
		SubscriptionConfirmation confirmation = 2;
		Checkpoint checkpoint = 3;
		StreamNotFound stream_not_found = 4;
		uint64 first_stream_position = 5;
		uint64 last_stream_position = 6;
		AllStreamPosition last_all_stream_position = 7;
		CaughtUp caught_up = 8;
		FellBehind fell_behind = 9;
	}

	// The $all or stream subscription has caught up and become live.
	message CaughtUp {
		// Current time in the server when the subscription caught up
		google.protobuf.Timestamp timestamp = 1;

		// Checkpoint for resuming a stream subscription.
		// For stream subscriptions it is populated unless the stream is empty.
		// For $all subscriptions it is not populated.
		optional int64 stream_revision = 2;

		// Checkpoint for resuming a $all subscription.
		// For stream subscriptions it is not populated.
		// For $all subscriptions it is populated unless the database is empty.
		optional Position position = 3;
	}

	// The $all or stream subscription has fallen back into catchup mode and is no longer live.
	message FellBehind {
		// Current time in the server when the subscription fell behind
		google.protobuf.Timestamp timestamp = 1;

		// Checkpoint for resuming a stream subscription.
		// For stream subscriptions it is populated unless the stream is empty.
		// For $all subscriptions it is not populated.
		optional int64 stream_revision = 2;

		// Checkpoint for resuming a $all subscription.
		// For stream subscriptions it is not populated.
		// For $all subscriptions it is populated unless the database is empty.
		optional Position position = 3;
	}

	message ReadEvent {
		RecordedEvent event = 1;
		RecordedEvent link = 2;
		oneof position {
			uint64 commit_position = 3;
			event_store.client.Empty no_position = 4;
		}

		message RecordedEvent {
			event_store.client.UUID id = 1;
			event_store.client.StreamIdentifier stream_identifier = 2;
			uint64 stream_revision = 3;
			uint64 prepare_position = 4;
			uint64 commit_position = 5;
			map<string, string> metadata = 6;
			bytes custom_metadata = 7;
			bytes data = 8;
		}
	}
	message SubscriptionConfirmation {
		string subscription_id = 1;
	}
	message Checkpoint {
		uint64 commit_position = 1;
		uint64 prepare_position = 2;

		// Current time in the server when the checkpoint was reached
		google.protobuf.Timestamp timestamp = 3;
	}

	message Position {
		uint64 commit_position = 1;
		uint64 prepare_position = 2;
	}

	message StreamNotFound {
		event_store.client.StreamIdentifier stream_identifier = 1;
	}
}

message AppendReq {
	oneof content {
		Options options = 1;
		ProposedMessage proposed_message = 2;
	}

	message Options {
		event_store.client.StreamIdentifier stream_identifier = 1;
		oneof expected_stream_revision {
			uint64 revision = 2;
			event_store.client.Empty no_stream = 3;
			event_store.client.Empty any = 4;
			event_store.client.Empty stream_exists = 5;
		}
	}
	message ProposedMessage {
		event_store.client.UUID id = 1;
		map<string, string> metadata = 2;
		bytes custom_metadata = 3;
		bytes data = 4;
	}
}

message AppendResp {
	oneof result {
		Success success = 1;
		WrongExpectedVersion wrong_expected_version = 2;
	}

	message Position {
		uint64 commit_position = 1;
		uint64 prepare_position = 2;
	}

	message Success {
		oneof current_revision_option {
			uint64 current_revision = 1;
			event_store.client.Empty no_stream = 2;
		}
		oneof position_option {
			Position position = 3;
			event_store.client.Empty no_position = 4;
		}
	}

	message WrongExpectedVersion {
		oneof current_revision_option_20_6_0 {
			uint64 current_revision_20_6_0 = 1;
			event_store.client.Empty no_stream_20_6_0 = 2;
		}
		oneof expected_revision_option_20_6_0 {
			uint64 expected_revision_20_6_0 = 3;
			event_store.client.Empty any_20_6_0 = 4;
			event_store.client.Empty stream_exists_20_6_0 = 5;
		}
		oneof current_revision_option {
			uint64 current_revision = 6;
			event_store.client.Empty current_no_stream = 7;
		}
		oneof expected_revision_option {
			uint64 expected_revision = 8;
			event_store.client.Empty expected_any = 9;
			event_store.client.Empty expected_stream_exists = 10;
			event_store.client.Empty expected_no_stream = 11;
		}

	}
}

message BatchAppendReq {
	event_store.client.UUID correlation_id = 1;
	Options options = 2;
	repeated ProposedMessage proposed_messages = 3;
	bool is_final = 4;

	message Options {
		event_store.client.StreamIdentifier stream_identifier = 1;
		oneof expected_stream_position {
			uint64 stream_position = 2;
			google.protobuf.Empty no_stream = 3;
			google.protobuf.Empty any = 4;
			google.protobuf.Empty stream_exists = 5;
		}
		oneof deadline_option {
			google.protobuf.Timestamp deadline_21_10_0 = 6;
			google.protobuf.Duration deadline = 7;
		}
	}

	message ProposedMessage {
		event_store.client.UUID id = 1;
		map<string, string> metadata = 2;
		bytes custom_metadata = 3;
		bytes data = 4;
	}
}

message BatchAppendResp {
	event_store.client.UUID correlation_id = 1;
	oneof result {
		google.rpc.Status error = 2;
		Success success = 3;
	}

	event_store.client.StreamIdentifier stream_identifier = 4;

	oneof expected_stream_position {
		uint64 stream_position = 5;
		google.protobuf.Empty no_stream = 6;
		google.protobuf.Empty any = 7;
		google.protobuf.Empty stream_exists = 8;
	}

	message Success {
		oneof current_revision_option {
			uint64 current_revision = 1;
			google.protobuf.Empty no_stream = 2;
		}
		oneof position_option {
			event_store.client.AllStreamPosition position = 3;
			google.protobuf.Empty no_position = 4;
		}
	}
}

message DeleteReq {
	Options options = 1;

	message Options {
		event_store.client.StreamIdentifier stream_identifier = 1;
		oneof expected_stream_revision {
			uint64 revision = 2;
			event_store.client.Empty no_stream = 3;
			event_store.client.Empty any = 4;
			event_store.client.Empty stream_exists = 5;
		}
	}
}

message DeleteResp {
	oneof position_option {
		Position position = 1;
		event_store.client.Empty no_position = 2;
	}

	message Position {
		uint64 commit_position = 1;
		uint64 prepare_position = 2;
	}
}

message TombstoneReq {
	Options options = 1;

	message Options {
		event_store.client.StreamIdentifier stream_identifier = 1;
		oneof expected_stream_revision {
			uint64 revision = 2;
			event_store.client.Empty no_stream = 3;
			event_store.client.Empty any = 4;
			event_store.client.Empty stream_exists = 5;
		}
	}
}

message TombstoneResp {
	oneof position_option {
		Position position = 1;
		event_store.client.Empty no_position = 2;
	}

	message Position {
		uint64 commit_position = 1;
		uint64 prepare_position = 2;
	}
}
