1417 lines
47 KiB
Rust
1417 lines
47 KiB
Rust
use crate::search::SearchGrpc;
|
|
use anyhow::{Context, Result, anyhow};
|
|
use crate::transport::{
|
|
DEFAULT_GRPC_ENDPOINT, authenticated_request as request_with_auth_token, connect_channel,
|
|
retryable_write_status,
|
|
};
|
|
pub use crate::transport::PostOperation;
|
|
use common::proto::komp_ac::analytics::analytics_service_client::AnalyticsServiceClient;
|
|
use common::proto::komp_ac::ecb::ecb_service_client::EcbServiceClient;
|
|
use common::proto::komp_ac::search2::search2_client::Search2Client;
|
|
use common::proto::komp_ac::accounting::{
|
|
Account, EnsureAccountRequest, GetJournalRequest, Journal, SearchJournalsRequest,
|
|
SearchJournalsResponse, accounting_client::AccountingClient,
|
|
};
|
|
use common::proto::komp_ac::common::Empty;
|
|
use common::proto::komp_ac::document_data::{
|
|
GetDocumentRequest, GetDocumentResponse, GetDocumentVersionRequest, GetDocumentVersionResponse,
|
|
GetDocumentsRequest, GetDocumentsResponse, GetTypstTemplateVersionRequest,
|
|
GetTypstTemplateVersionResponse, ListEnabledTypstTemplatesRequest,
|
|
ListTypstTemplatesRequest, ListTypstTemplatesResponse, RegisterTypstTemplateRequest,
|
|
RegisterTypstTemplateResponse, SaveDocumentRequest, SaveDocumentResponse,
|
|
UpdateDocumentRequest, UpdateDocumentResponse,
|
|
document_data_service_client::DocumentDataServiceClient,
|
|
};
|
|
use common::proto::komp_ac::exchange_rates::{
|
|
AddProfileCurrencySourceRequest, GetProfileExchangeRateSettingsRequest,
|
|
ProfileExchangeRateSettings, ProfileForeignCurrency,
|
|
exchange_rate_service_client::ExchangeRateServiceClient,
|
|
};
|
|
use common::proto::komp_ac::search::{
|
|
ColumnConstraint, MatchMode, SearchOrder, SearchRequest, SearchResponse,
|
|
};
|
|
use common::proto::komp_ac::table_definition::{
|
|
ApplyInvoiceTemplateTableRequest, CreateCustomExchangeRatesTableRequest,
|
|
CreateCustomExchangeRatesTableResponse, CreateInvoiceTemplateTableResponse,
|
|
GetProfileDetailsRequest, GetProfileDetailsResponse, GetTableCatalogRequest,
|
|
GetTableCatalogResponse, ListColumnTypesResponse, PostTableDefinitionRequest,
|
|
ProfileTreeResponse, PutTableDefinitionRequest, PutTableDefinitionResponse,
|
|
SetColumnFormVisibilityRequest, SetColumnFormVisibilityResponse,
|
|
SetColumnPresentationRequest, SetColumnPresentationResponse,
|
|
TableDefinitionResponse, table_definition_client::TableDefinitionClient,
|
|
};
|
|
use common::proto::komp_ac::table_script::{
|
|
GetTableScriptsRequest, GetTableScriptsResponse, HydrateScriptDependenciesRequest,
|
|
HydrateScriptDependenciesResponse, PostTableScriptRequest, TableScriptResponse,
|
|
table_script_client::TableScriptClient,
|
|
};
|
|
use common::proto::komp_ac::table_structure::table_structure_service_client::TableStructureServiceClient;
|
|
use common::proto::komp_ac::table_structure::{
|
|
GetTableImportDescriptorRequest, GetTableImportDescriptorResponse, GetTableStructureRequest,
|
|
GetTableStructureResponse, TableStructureResponse,
|
|
};
|
|
use common::proto::komp_ac::table_validation::{
|
|
ApplyValidationSetRequest, ApplyValidationSetResponse, DeleteValidationRuleRequest,
|
|
DeleteValidationRuleResponse, DeleteValidationSetRequest, DeleteValidationSetResponse,
|
|
FieldValidation, GetTableValidationRequest, ListValidationRulesRequest,
|
|
ListValidationRulesResponse, ListValidationSetsRequest, ListValidationSetsResponse,
|
|
ReplaceTableValidationRequest, ReplaceTableValidationResponse, TableValidationResponse,
|
|
UpdateFieldValidationRequest, UpdateFieldValidationResponse, UpsertValidationRuleRequest,
|
|
UpsertValidationRuleResponse, UpsertValidationSetRequest, UpsertValidationSetResponse,
|
|
table_validation_service_client::TableValidationServiceClient,
|
|
};
|
|
use common::proto::komp_ac::tables_data::{
|
|
AbortTableDataImportRequest, AbortTableDataImportResponse, ArchiveTableDataRequest,
|
|
ArchiveTableDataResponse, BeginTableDataImportRequest, BeginTableDataImportResponse,
|
|
CommitTableDataImportRequest, CommitTableDataImportResponse, DeleteTableDataRequest,
|
|
DeleteTableDataResponse, GetAdjacentTableDataRequest, GetAdjacentTableDataResponse,
|
|
GetLastTableDataRequest, GetLastTableDataResponse, GetTableDataByPositionRequest,
|
|
GetTableDataCountRequest, GetTableDataRequest, GetTableDataResponse, PostTableDataRequest,
|
|
PostTableDataResponse, PutTableDataRequest, PutTableDataResponse, RowIdDirection,
|
|
RowNavigationMode,
|
|
StageTableDataImportRequest, StageTableDataImportResponse, TableUpdateImpactRequest,
|
|
TableUpdateImpactResponse, tables_data_client::TablesDataClient,
|
|
};
|
|
use prost_types::Value;
|
|
use std::collections::HashMap;
|
|
use tonic::Request;
|
|
use tonic::transport::Channel;
|
|
|
|
#[derive(Clone)]
|
|
pub struct GrpcClient {
|
|
pub channel: Channel,
|
|
table_structure_client: TableStructureServiceClient<Channel>,
|
|
table_definition_client: TableDefinitionClient<Channel>,
|
|
table_script_client: TableScriptClient<Channel>,
|
|
tables_data_client: TablesDataClient<Channel>,
|
|
document_data_client: DocumentDataServiceClient<Channel>,
|
|
search_client: SearchGrpc,
|
|
table_validation_client: TableValidationServiceClient<Channel>,
|
|
accounting_client: AccountingClient<Channel>,
|
|
exchange_rate_client: ExchangeRateServiceClient<Channel>,
|
|
ecb_client: EcbServiceClient<Channel>,
|
|
analytics_client: AnalyticsServiceClient<Channel>,
|
|
search2_client: Search2Client<Channel>,
|
|
pub auth_token: Option<String>,
|
|
}
|
|
|
|
impl GrpcClient {
|
|
pub async fn new() -> Result<Self> {
|
|
let endpoint = std::env::var("GRPC_ENDPOINT")
|
|
.unwrap_or_else(|_| DEFAULT_GRPC_ENDPOINT.to_string());
|
|
Self::connect(&endpoint).await
|
|
}
|
|
|
|
pub async fn connect(endpoint: &str) -> Result<Self> {
|
|
Self::from_channel(connect_channel(endpoint).await?)
|
|
}
|
|
|
|
pub fn from_channel(channel: Channel) -> Result<Self> {
|
|
let table_structure_client = TableStructureServiceClient::new(channel.clone());
|
|
let table_definition_client = TableDefinitionClient::new(channel.clone());
|
|
let table_script_client = TableScriptClient::new(channel.clone());
|
|
let tables_data_client = TablesDataClient::new(channel.clone());
|
|
let document_data_client = DocumentDataServiceClient::new(channel.clone());
|
|
let search_client = SearchGrpc::new(channel.clone());
|
|
let table_validation_client = TableValidationServiceClient::new(channel.clone());
|
|
let accounting_client = AccountingClient::new(channel.clone());
|
|
let exchange_rate_client = ExchangeRateServiceClient::new(channel.clone());
|
|
let ecb_client = EcbServiceClient::new(channel.clone());
|
|
let analytics_client = AnalyticsServiceClient::new(channel.clone());
|
|
let search2_client = Search2Client::new(channel.clone());
|
|
|
|
Ok(Self {
|
|
channel,
|
|
table_structure_client,
|
|
table_definition_client,
|
|
table_script_client,
|
|
tables_data_client,
|
|
document_data_client,
|
|
search_client,
|
|
table_validation_client,
|
|
accounting_client,
|
|
exchange_rate_client,
|
|
ecb_client,
|
|
analytics_client,
|
|
search2_client,
|
|
auth_token: None,
|
|
})
|
|
}
|
|
|
|
// Expose the shared channel so other typed clients can reuse it.
|
|
pub fn channel(&self) -> Channel {
|
|
self.channel.clone()
|
|
}
|
|
|
|
pub fn set_auth_token(&mut self, auth_token: Option<String>) {
|
|
self.auth_token = auth_token;
|
|
}
|
|
|
|
pub async fn hydrate_script_dependencies(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
row_id: i64,
|
|
row_data: HashMap<String, String>,
|
|
) -> Result<HydrateScriptDependenciesResponse> {
|
|
let request = self.authenticated_request(HydrateScriptDependenciesRequest {
|
|
profile_name,
|
|
table_name,
|
|
row_id,
|
|
row_data,
|
|
})?;
|
|
let response = self
|
|
.table_script_client
|
|
.hydrate_script_dependencies(request)
|
|
.await
|
|
.context("gRPC HydrateScriptDependencies call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
fn authenticated_request<T>(&self, message: T) -> Result<Request<T>> {
|
|
request_with_auth_token(self.auth_token.as_deref(), message)
|
|
}
|
|
|
|
pub async fn get_journal(&mut self, profile_name: String, journal_id: i64) -> Result<Journal> {
|
|
let request = self.authenticated_request(GetJournalRequest {
|
|
profile_name,
|
|
journal_id,
|
|
include_deleted: false,
|
|
})?;
|
|
let response = self
|
|
.accounting_client
|
|
.get_journal(request)
|
|
.await
|
|
.context("gRPC GetJournal call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn ensure_account(
|
|
&mut self,
|
|
profile_name: String,
|
|
account: String,
|
|
denomination_currency: String,
|
|
) -> Result<Account> {
|
|
let request = self.authenticated_request(EnsureAccountRequest {
|
|
profile_name,
|
|
account,
|
|
denomination_currency,
|
|
})?;
|
|
let response = self
|
|
.accounting_client
|
|
.ensure_account(request)
|
|
.await
|
|
.context("gRPC EnsureAccount call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn search_journals(
|
|
&mut self,
|
|
profile_name: String,
|
|
name_query: String,
|
|
page_size: i32,
|
|
page_token: String,
|
|
) -> Result<SearchJournalsResponse> {
|
|
let request = self.authenticated_request(SearchJournalsRequest {
|
|
profile_name,
|
|
name_query,
|
|
page_size,
|
|
page_token,
|
|
})?;
|
|
let response = self
|
|
.accounting_client
|
|
.search_journals(request)
|
|
.await
|
|
.context("gRPC SearchJournals call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
// Fetch validation rules for a table. Absence of a field in response = no validation.
|
|
pub async fn get_table_validation(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
) -> Result<TableValidationResponse> {
|
|
let req = GetTableValidationRequest {
|
|
profile_name,
|
|
table_name,
|
|
};
|
|
let request = self.authenticated_request(req)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.get_table_validation(request)
|
|
.await
|
|
.context("gRPC GetTableValidation call failed")?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn update_field_validation(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
data_key: String,
|
|
validation: FieldValidation,
|
|
) -> Result<UpdateFieldValidationResponse> {
|
|
let req = UpdateFieldValidationRequest {
|
|
profile_name,
|
|
table_name,
|
|
data_key,
|
|
validation: Some(validation),
|
|
};
|
|
let request = self.authenticated_request(req)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.update_field_validation(request)
|
|
.await
|
|
.context("gRPC UpdateFieldValidation call failed")?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn upsert_validation_rule(
|
|
&mut self,
|
|
request: UpsertValidationRuleRequest,
|
|
) -> Result<UpsertValidationRuleResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.upsert_validation_rule(request)
|
|
.await
|
|
.map_err(|e| anyhow!("gRPC UpsertValidationRule call failed: {}", e))?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn upsert_validation_set(
|
|
&mut self,
|
|
request: UpsertValidationSetRequest,
|
|
) -> Result<UpsertValidationSetResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.upsert_validation_set(request)
|
|
.await
|
|
.map_err(|e| anyhow!("gRPC UpsertValidationSet call failed: {}", e))?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn delete_validation_rule(
|
|
&mut self,
|
|
request: DeleteValidationRuleRequest,
|
|
) -> Result<DeleteValidationRuleResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.delete_validation_rule(request)
|
|
.await
|
|
.context("gRPC DeleteValidationRule call failed")?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn delete_validation_set(
|
|
&mut self,
|
|
request: DeleteValidationSetRequest,
|
|
) -> Result<DeleteValidationSetResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.delete_validation_set(request)
|
|
.await
|
|
.context("gRPC DeleteValidationSet call failed")?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn list_validation_rules(
|
|
&mut self,
|
|
profile_name: String,
|
|
) -> Result<ListValidationRulesResponse> {
|
|
let req = ListValidationRulesRequest { profile_name };
|
|
let request = self.authenticated_request(req)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.list_validation_rules(request)
|
|
.await
|
|
.context("gRPC ListValidationRules call failed")?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn list_validation_sets(
|
|
&mut self,
|
|
profile_name: String,
|
|
) -> Result<ListValidationSetsResponse> {
|
|
let req = ListValidationSetsRequest { profile_name };
|
|
let request = self.authenticated_request(req)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.list_validation_sets(request)
|
|
.await
|
|
.context("gRPC ListValidationSets call failed")?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn apply_validation_set(
|
|
&mut self,
|
|
request: ApplyValidationSetRequest,
|
|
) -> Result<ApplyValidationSetResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.apply_validation_set(request)
|
|
.await
|
|
.context("gRPC ApplyValidationSet call failed")?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn replace_table_validation(
|
|
&mut self,
|
|
request: ReplaceTableValidationRequest,
|
|
) -> Result<ReplaceTableValidationResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let resp = self
|
|
.table_validation_client
|
|
.replace_table_validation(request)
|
|
.await
|
|
.context("gRPC ReplaceTableValidation call failed")?;
|
|
Ok(resp.into_inner())
|
|
}
|
|
|
|
pub async fn get_table_structures(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_names: Vec<String>,
|
|
) -> Result<GetTableStructureResponse> {
|
|
let grpc_request = GetTableStructureRequest {
|
|
profile_name,
|
|
table_names,
|
|
};
|
|
let request = self.authenticated_request(grpc_request)?;
|
|
let response = self
|
|
.table_structure_client
|
|
.get_table_structure(request)
|
|
.await
|
|
.context("gRPC GetTableStructure call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_table_structure(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
) -> Result<TableStructureResponse> {
|
|
let response = self
|
|
.get_table_structures(profile_name.clone(), vec![table_name.clone()])
|
|
.await?;
|
|
|
|
response
|
|
.table_structures
|
|
.into_iter()
|
|
.find_map(|(response_table_name, structure)| {
|
|
(response_table_name == table_name).then_some(structure)
|
|
})
|
|
.ok_or_else(|| {
|
|
anyhow!(
|
|
"GetTableStructure response for profile '{}' did not contain table '{}'",
|
|
profile_name,
|
|
table_name
|
|
)
|
|
})
|
|
}
|
|
|
|
pub async fn get_table_import_descriptor(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
) -> Result<GetTableImportDescriptorResponse> {
|
|
let request = self.authenticated_request(GetTableImportDescriptorRequest {
|
|
profile_name,
|
|
table_name,
|
|
})?;
|
|
let response = self
|
|
.table_structure_client
|
|
.get_table_import_descriptor(request)
|
|
.await
|
|
.context("gRPC GetTableImportDescriptor call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_profile_tree(&mut self) -> Result<ProfileTreeResponse> {
|
|
let request = self.authenticated_request(Empty::default())?;
|
|
let response = self
|
|
.table_definition_client
|
|
.get_profile_tree(request)
|
|
.await
|
|
.context("gRPC GetProfileTree call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_table_catalog(
|
|
&mut self,
|
|
profile_name: Option<String>,
|
|
) -> Result<GetTableCatalogResponse> {
|
|
let request = self.authenticated_request(GetTableCatalogRequest { profile_name })?;
|
|
let response = self
|
|
.table_definition_client
|
|
.get_table_catalog(request)
|
|
.await
|
|
.context("gRPC GetTableCatalog call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn list_column_types(&mut self) -> Result<ListColumnTypesResponse> {
|
|
let request = self.authenticated_request(Empty::default())?;
|
|
let response = self
|
|
.table_definition_client
|
|
.list_column_types(request)
|
|
.await
|
|
.context("gRPC ListColumnTypes call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_profile_details(
|
|
&mut self,
|
|
profile_name: String,
|
|
) -> Result<GetProfileDetailsResponse> {
|
|
let request = self.authenticated_request(GetProfileDetailsRequest { profile_name })?;
|
|
let response = self
|
|
.table_definition_client
|
|
.get_profile_details(request)
|
|
.await
|
|
.context("gRPC GetProfileDetails call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_profile_exchange_rate_settings(
|
|
&mut self,
|
|
profile_name: String,
|
|
) -> Result<ProfileExchangeRateSettings> {
|
|
let request =
|
|
self.authenticated_request(GetProfileExchangeRateSettingsRequest { profile_name })?;
|
|
Ok(self
|
|
.exchange_rate_client
|
|
.get_profile_exchange_rate_settings(request)
|
|
.await
|
|
.context("gRPC GetProfileExchangeRateSettings call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn add_profile_currency_source(
|
|
&mut self,
|
|
profile_name: String,
|
|
currency: String,
|
|
source_id: String,
|
|
make_default: bool,
|
|
) -> Result<ProfileForeignCurrency> {
|
|
let request = self.authenticated_request(AddProfileCurrencySourceRequest {
|
|
profile_name,
|
|
currency,
|
|
source_id,
|
|
make_default,
|
|
})?;
|
|
Ok(self
|
|
.exchange_rate_client
|
|
.add_profile_currency_source(request)
|
|
.await
|
|
.context("gRPC AddProfileCurrencySource call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn post_table_definition(
|
|
&mut self,
|
|
request: PostTableDefinitionRequest,
|
|
) -> Result<TableDefinitionResponse> {
|
|
let tonic_request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.table_definition_client
|
|
.post_table_definition(tonic_request)
|
|
.await
|
|
.context("gRPC PostTableDefinition call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn put_table_definition(
|
|
&mut self,
|
|
request: PutTableDefinitionRequest,
|
|
) -> Result<PutTableDefinitionResponse> {
|
|
let tonic_request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.table_definition_client
|
|
.put_table_definition(tonic_request)
|
|
.await
|
|
.context("gRPC PutTableDefinition call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn create_custom_exchange_rates_table(
|
|
&mut self,
|
|
profile_name: String,
|
|
) -> Result<CreateCustomExchangeRatesTableResponse> {
|
|
let request =
|
|
self.authenticated_request(CreateCustomExchangeRatesTableRequest { profile_name })?;
|
|
let response = self
|
|
.table_definition_client
|
|
.create_custom_exchange_rates_table(request)
|
|
.await
|
|
.context("gRPC CreateCustomExchangeRatesTable call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn set_column_presentation(
|
|
&mut self,
|
|
request: SetColumnPresentationRequest,
|
|
) -> Result<SetColumnPresentationResponse> {
|
|
let tonic_request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.table_definition_client
|
|
.set_column_presentation(tonic_request)
|
|
.await
|
|
.context("gRPC SetColumnPresentation call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn set_column_form_visibility(
|
|
&mut self,
|
|
request: SetColumnFormVisibilityRequest,
|
|
) -> Result<SetColumnFormVisibilityResponse> {
|
|
let tonic_request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.table_definition_client
|
|
.set_column_form_visibility(tonic_request)
|
|
.await
|
|
.context("gRPC SetColumnFormVisibility call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn post_table_script(
|
|
&mut self,
|
|
request: PostTableScriptRequest,
|
|
) -> Result<TableScriptResponse> {
|
|
let tonic_request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.table_script_client
|
|
.post_table_script(tonic_request)
|
|
.await
|
|
.context("gRPC PostTableScript call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_table_scripts(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
) -> Result<GetTableScriptsResponse> {
|
|
let request = self.authenticated_request(GetTableScriptsRequest {
|
|
profile_name,
|
|
table_name,
|
|
})?;
|
|
let response = self
|
|
.table_script_client
|
|
.get_table_scripts(request)
|
|
.await
|
|
.context("gRPC GetTableScripts call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
// Existing TablesData methods
|
|
pub async fn get_table_data_count(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
) -> Result<u64> {
|
|
let grpc_request = GetTableDataCountRequest {
|
|
profile_name,
|
|
table_name,
|
|
};
|
|
let request = self.authenticated_request(grpc_request)?;
|
|
let response = self
|
|
.tables_data_client
|
|
.get_table_data_count(request)
|
|
.await
|
|
.context("gRPC GetTableDataCount call failed")?;
|
|
let count = response.into_inner().count;
|
|
u64::try_from(count)
|
|
.with_context(|| format!("gRPC GetTableDataCount returned negative count {count}"))
|
|
}
|
|
|
|
pub async fn get_last_table_data(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
navigation_mode: RowNavigationMode,
|
|
) -> Result<GetLastTableDataResponse> {
|
|
let request = self.authenticated_request(GetLastTableDataRequest {
|
|
profile_name,
|
|
table_name,
|
|
navigation_mode: navigation_mode as i32,
|
|
})?;
|
|
let response = self
|
|
.tables_data_client
|
|
.get_last_table_data(request)
|
|
.await
|
|
.context("gRPC GetLastTableData call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_adjacent_table_data(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
anchor_id: i64,
|
|
direction: RowIdDirection,
|
|
navigation_mode: RowNavigationMode,
|
|
anchor_position: u64,
|
|
) -> Result<GetAdjacentTableDataResponse> {
|
|
let request = self.authenticated_request(GetAdjacentTableDataRequest {
|
|
profile_name,
|
|
table_name,
|
|
anchor_id,
|
|
direction: direction as i32,
|
|
navigation_mode: navigation_mode as i32,
|
|
anchor_position,
|
|
})?;
|
|
let response = self
|
|
.tables_data_client
|
|
.get_adjacent_table_data(request)
|
|
.await
|
|
.context("gRPC GetAdjacentTableData call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_table_data_by_position(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
position: i32,
|
|
) -> Result<GetTableDataResponse> {
|
|
let grpc_request = GetTableDataByPositionRequest {
|
|
profile_name,
|
|
table_name,
|
|
position,
|
|
record_id: 0,
|
|
navigation_mode: RowNavigationMode::Position as i32,
|
|
};
|
|
let request = self.authenticated_request(grpc_request)?;
|
|
let response = self
|
|
.tables_data_client
|
|
.get_table_data_by_position(request)
|
|
.await
|
|
.context("gRPC GetTableDataByPosition call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_table_data_with_navigation(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
record_id: i64,
|
|
navigation_mode: RowNavigationMode,
|
|
) -> Result<GetTableDataResponse> {
|
|
let request = self.authenticated_request(GetTableDataByPositionRequest {
|
|
profile_name,
|
|
table_name,
|
|
position: 0,
|
|
record_id,
|
|
navigation_mode: navigation_mode as i32,
|
|
})?;
|
|
let response = self
|
|
.tables_data_client
|
|
.get_table_data_by_position(request)
|
|
.await
|
|
.context("gRPC navigated GetTableData call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_table_data(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
id: i64,
|
|
) -> Result<GetTableDataResponse> {
|
|
let grpc_request = GetTableDataRequest {
|
|
profile_name,
|
|
table_name,
|
|
id,
|
|
};
|
|
let request = self.authenticated_request(grpc_request)?;
|
|
let response = self
|
|
.tables_data_client
|
|
.get_table_data(request)
|
|
.await
|
|
.context("gRPC GetTableData call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_table_data_version(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
id: i64,
|
|
version: i64,
|
|
) -> Result<GetTableDataResponse> {
|
|
let request = self.authenticated_request(
|
|
common::proto::komp_ac::tables_data::GetTableDataVersionRequest {
|
|
profile_name,
|
|
table_name,
|
|
id,
|
|
version,
|
|
},
|
|
)?;
|
|
Ok(self
|
|
.tables_data_client
|
|
.get_table_data_version(request)
|
|
.await
|
|
.context("gRPC GetTableDataVersion call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn delete_table_data(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
record_id: i64,
|
|
expected_revision: i64,
|
|
) -> Result<DeleteTableDataResponse> {
|
|
let grpc_request = DeleteTableDataRequest {
|
|
profile_name,
|
|
table_name,
|
|
record_id,
|
|
expected_revision,
|
|
};
|
|
let request = self.authenticated_request(grpc_request)?;
|
|
let response = self
|
|
.tables_data_client
|
|
.delete_table_data(request)
|
|
.await
|
|
.context("gRPC DeleteTableData call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn post_table_data(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
data: HashMap<String, Value>,
|
|
operation: PostOperation,
|
|
) -> Result<PostTableDataResponse> {
|
|
let grpc_request = PostTableDataRequest {
|
|
profile_name,
|
|
table_name,
|
|
data,
|
|
};
|
|
let mut request = self.authenticated_request(grpc_request)?;
|
|
operation.add_metadata(&mut request)?;
|
|
let response = self
|
|
.tables_data_client
|
|
.post_table_data(request)
|
|
.await
|
|
.context("gRPC PostTableData call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn begin_table_data_import(
|
|
&mut self,
|
|
profile_name: String,
|
|
) -> Result<BeginTableDataImportResponse> {
|
|
let request = self.authenticated_request(BeginTableDataImportRequest { profile_name })?;
|
|
Ok(self
|
|
.tables_data_client
|
|
.begin_table_data_import(request)
|
|
.await
|
|
.context("gRPC BeginTableDataImport call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn stage_table_data_import(
|
|
&mut self,
|
|
request: StageTableDataImportRequest,
|
|
) -> Result<StageTableDataImportResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.tables_data_client
|
|
.stage_table_data_import(request)
|
|
.await
|
|
.context("gRPC StageTableDataImport call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn commit_table_data_import(
|
|
&mut self,
|
|
import_id: String,
|
|
) -> Result<CommitTableDataImportResponse> {
|
|
for attempt in 0..2 {
|
|
let request = self.authenticated_request(CommitTableDataImportRequest {
|
|
import_id: import_id.clone(),
|
|
})?;
|
|
match self
|
|
.tables_data_client
|
|
.commit_table_data_import(request)
|
|
.await
|
|
{
|
|
Ok(response) => return Ok(response.into_inner()),
|
|
Err(status) if attempt == 0 && retryable_write_status(status.code()) => {}
|
|
Err(status) => {
|
|
return Err(status).context("gRPC CommitTableDataImport call failed");
|
|
}
|
|
}
|
|
}
|
|
unreachable!("the commit retry loop returns on its second attempt")
|
|
}
|
|
|
|
pub async fn abort_table_data_import(
|
|
&mut self,
|
|
import_id: String,
|
|
) -> Result<AbortTableDataImportResponse> {
|
|
let request = self.authenticated_request(AbortTableDataImportRequest { import_id })?;
|
|
Ok(self
|
|
.tables_data_client
|
|
.abort_table_data_import(request)
|
|
.await
|
|
.context("gRPC AbortTableDataImport call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn put_table_data(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
id: i64,
|
|
data: HashMap<String, Value>,
|
|
expected_revision: i64,
|
|
) -> Result<PutTableDataResponse> {
|
|
let grpc_request = PutTableDataRequest {
|
|
profile_name,
|
|
table_name,
|
|
id,
|
|
data,
|
|
expected_revision,
|
|
};
|
|
let request = self.authenticated_request(grpc_request)?;
|
|
let response = self
|
|
.tables_data_client
|
|
.put_table_data(request)
|
|
.await
|
|
.context("gRPC PutTableData call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn put_table_data_confirmed(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
id: i64,
|
|
data: HashMap<String, Value>,
|
|
expected_revision: i64,
|
|
expected_affected_profiles: Vec<String>,
|
|
) -> Result<PutTableDataResponse> {
|
|
let request = self.authenticated_request(
|
|
common::proto::komp_ac::tables_data::PutTableDataConfirmedRequest {
|
|
update: Some(PutTableDataRequest {
|
|
profile_name,
|
|
table_name,
|
|
id,
|
|
data,
|
|
expected_revision,
|
|
}),
|
|
expected_affected_profiles,
|
|
},
|
|
)?;
|
|
Ok(self
|
|
.tables_data_client
|
|
.put_table_data_confirmed(request)
|
|
.await
|
|
.context("gRPC confirmed PutTableData call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn get_table_update_impact(
|
|
&mut self,
|
|
request: TableUpdateImpactRequest,
|
|
) -> Result<TableUpdateImpactResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.tables_data_client
|
|
.get_table_update_impact(request)
|
|
.await
|
|
.context("gRPC table update impact call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn archive_table_data(
|
|
&mut self,
|
|
request: ArchiveTableDataRequest,
|
|
) -> Result<ArchiveTableDataResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.tables_data_client
|
|
.archive_table_data(request)
|
|
.await
|
|
.context("gRPC row archive call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn save_document(
|
|
&mut self,
|
|
request: SaveDocumentRequest,
|
|
) -> Result<SaveDocumentResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.document_data_client
|
|
.save_document(request)
|
|
.await
|
|
.context("gRPC SaveDocument call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn list_enabled_typst_templates(
|
|
&mut self,
|
|
profile_name: String,
|
|
) -> Result<ListTypstTemplatesResponse> {
|
|
let request = self.authenticated_request(ListEnabledTypstTemplatesRequest {
|
|
profile_name,
|
|
})?;
|
|
let response = self
|
|
.document_data_client
|
|
.list_enabled_typst_templates(request)
|
|
.await
|
|
.context("gRPC ListEnabledTypstTemplates call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn list_typst_templates(
|
|
&mut self,
|
|
search: String,
|
|
limit: u32,
|
|
) -> Result<ListTypstTemplatesResponse> {
|
|
let request = self.authenticated_request(ListTypstTemplatesRequest { search, limit })?;
|
|
let response = self
|
|
.document_data_client
|
|
.list_typst_templates(request)
|
|
.await
|
|
.context("gRPC ListTypstTemplates call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn register_typst_template(
|
|
&mut self,
|
|
request: RegisterTypstTemplateRequest,
|
|
) -> Result<RegisterTypstTemplateResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.document_data_client
|
|
.register_typst_template(request)
|
|
.await
|
|
.context("gRPC RegisterTypstTemplate call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn update_document(
|
|
&mut self,
|
|
request: UpdateDocumentRequest,
|
|
) -> Result<UpdateDocumentResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.document_data_client
|
|
.update_document(request)
|
|
.await
|
|
.context("gRPC UpdateDocument call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_documents(
|
|
&mut self,
|
|
request: GetDocumentsRequest,
|
|
) -> Result<GetDocumentsResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.document_data_client
|
|
.get_documents(request)
|
|
.await
|
|
.context("gRPC GetDocuments call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_document(
|
|
&mut self,
|
|
request: GetDocumentRequest,
|
|
) -> Result<GetDocumentResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.document_data_client
|
|
.get_document(request)
|
|
.await
|
|
.context("gRPC GetDocument call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_document_version(
|
|
&mut self,
|
|
request: GetDocumentVersionRequest,
|
|
) -> Result<GetDocumentVersionResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.document_data_client
|
|
.get_document_version(request)
|
|
.await
|
|
.context("gRPC GetDocumentVersion call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn get_typst_template_version(
|
|
&mut self,
|
|
request: GetTypstTemplateVersionRequest,
|
|
) -> Result<GetTypstTemplateVersionResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
let response = self
|
|
.document_data_client
|
|
.get_typst_template_version(request)
|
|
.await
|
|
.context("gRPC GetTypstTemplateVersion call failed")?;
|
|
Ok(response.into_inner())
|
|
}
|
|
|
|
pub async fn search(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: Option<String>,
|
|
free_query: String,
|
|
must: Vec<ColumnConstraint>,
|
|
limit: Option<u32>,
|
|
offset: Option<u32>,
|
|
order: Option<SearchOrder>,
|
|
) -> Result<SearchResponse> {
|
|
let request = self.authenticated_request(SearchRequest {
|
|
profile_name,
|
|
table_name,
|
|
free_query,
|
|
must,
|
|
limit,
|
|
offset,
|
|
order,
|
|
version_scope: 0,
|
|
})?;
|
|
self.search_client.search(request).await
|
|
}
|
|
|
|
pub async fn count_table_rows(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
column: String,
|
|
value: String,
|
|
) -> Result<u64> {
|
|
self.count_search_rows(
|
|
profile_name,
|
|
table_name,
|
|
String::new(),
|
|
vec![ColumnConstraint {
|
|
column,
|
|
query: value,
|
|
mode: MatchMode::Exact as i32,
|
|
}],
|
|
)
|
|
.await
|
|
}
|
|
|
|
pub async fn count_search_rows(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
free_query: String,
|
|
constraints: Vec<ColumnConstraint>,
|
|
) -> Result<u64> {
|
|
let request = self.authenticated_request(SearchRequest {
|
|
profile_name,
|
|
table_name: Some(table_name),
|
|
free_query,
|
|
must: constraints,
|
|
limit: None,
|
|
offset: None,
|
|
order: None,
|
|
version_scope: 0,
|
|
})?;
|
|
let response = self
|
|
.search_client
|
|
.count(request)
|
|
.await
|
|
.context("gRPC child relationship count search failed")?;
|
|
Ok(response.count)
|
|
}
|
|
|
|
pub async fn get_table_data_for_navigation(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: String,
|
|
record_id: i64,
|
|
navigation_mode: RowNavigationMode,
|
|
) -> Result<GetTableDataResponse> {
|
|
self.get_table_data_with_navigation(
|
|
profile_name,
|
|
table_name,
|
|
record_id,
|
|
navigation_mode,
|
|
)
|
|
.await
|
|
}
|
|
|
|
pub async fn add_table_columns(
|
|
&mut self,
|
|
request: common::proto::komp_ac::table_definition::AddTableColumnsRequest,
|
|
) -> Result<TableDefinitionResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.table_definition_client
|
|
.add_table_columns(request)
|
|
.await
|
|
.context("gRPC AddTableColumns call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn delete_table(
|
|
&mut self,
|
|
request: common::proto::komp_ac::table_definition::DeleteTableRequest,
|
|
) -> Result<common::proto::komp_ac::table_definition::DeleteTableResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.table_definition_client
|
|
.delete_table(request)
|
|
.await
|
|
.context("gRPC DeleteTable call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn copy_profile(
|
|
&mut self,
|
|
request: common::proto::komp_ac::table_definition::CopyProfileRequest,
|
|
) -> Result<common::proto::komp_ac::table_definition::CopyProfileResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.table_definition_client
|
|
.copy_profile(request)
|
|
.await
|
|
.context("gRPC CopyProfile call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn get_column_alias_rename_history(
|
|
&mut self,
|
|
request: common::proto::komp_ac::table_definition::GetColumnAliasRenameHistoryRequest,
|
|
) -> Result<common::proto::komp_ac::table_definition::GetColumnAliasRenameHistoryResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.table_definition_client
|
|
.get_column_alias_rename_history(request)
|
|
.await
|
|
.context("gRPC GetColumnAliasRenameHistory call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn create_invoice_template_table(
|
|
&mut self,
|
|
request: common::proto::komp_ac::table_definition::CreateInvoiceTemplateTableRequest,
|
|
) -> Result<CreateInvoiceTemplateTableResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.table_definition_client
|
|
.create_invoice_template_table(request)
|
|
.await
|
|
.context("gRPC CreateInvoiceTemplateTable call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn apply_invoice_template_table(
|
|
&mut self,
|
|
request: ApplyInvoiceTemplateTableRequest,
|
|
) -> Result<CreateInvoiceTemplateTableResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.table_definition_client
|
|
.apply_invoice_template_table(request)
|
|
.await
|
|
.context("gRPC ApplyInvoiceTemplateTable call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn list_rate_sources(
|
|
&mut self,
|
|
) -> Result<common::proto::komp_ac::exchange_rates::ListRateSourcesResponse> {
|
|
let request = self.authenticated_request(Empty::default())?;
|
|
Ok(self
|
|
.exchange_rate_client
|
|
.list_rate_sources(request)
|
|
.await
|
|
.context("gRPC ListRateSources call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn preview_direct_conversion(
|
|
&mut self,
|
|
request: common::proto::komp_ac::exchange_rates::PreviewDirectConversionRequest,
|
|
) -> Result<common::proto::komp_ac::exchange_rates::PreviewDirectConversionResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.exchange_rate_client
|
|
.preview_direct_conversion(request)
|
|
.await
|
|
.context("gRPC PreviewDirectConversion call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn list_conversion_evidence(
|
|
&mut self,
|
|
request: common::proto::komp_ac::exchange_rates::ListConversionEvidenceRequest,
|
|
) -> Result<common::proto::komp_ac::exchange_rates::ListConversionEvidenceResponse> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.exchange_rate_client
|
|
.list_conversion_evidence(request)
|
|
.await
|
|
.context("gRPC ListConversionEvidence call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn get_ecb_pipeline_status(
|
|
&mut self,
|
|
batch_limit: i32,
|
|
) -> Result<common::proto::komp_ac::ecb::GetEcbPipelineStatusResponse> {
|
|
let request = self.authenticated_request(
|
|
common::proto::komp_ac::ecb::GetEcbPipelineStatusRequest { batch_limit },
|
|
)?;
|
|
Ok(self
|
|
.ecb_client
|
|
.get_ecb_pipeline_status(request)
|
|
.await
|
|
.context("gRPC GetEcbPipelineStatus call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn get_analytics_catalog(
|
|
&mut self,
|
|
profile_name: String,
|
|
) -> Result<common::proto::komp_ac::analytics::GetAnalyticsCatalogResponse> {
|
|
let request = self.authenticated_request(
|
|
common::proto::komp_ac::analytics::GetAnalyticsCatalogRequest { profile_name },
|
|
)?;
|
|
Ok(self
|
|
.analytics_client
|
|
.get_analytics_catalog(request)
|
|
.await
|
|
.context("gRPC GetAnalyticsCatalog call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn execute_analytics_query(
|
|
&mut self,
|
|
profile_name: String,
|
|
sql: String,
|
|
max_rows: u32,
|
|
) -> Result<tonic::codec::Streaming<common::proto::komp_ac::analytics::AnalyticsResultBatch>> {
|
|
let request = self.authenticated_request(
|
|
common::proto::komp_ac::analytics::ExecuteAnalyticsQueryRequest {
|
|
profile_name,
|
|
sql,
|
|
max_rows,
|
|
},
|
|
)?;
|
|
Ok(self
|
|
.analytics_client
|
|
.execute_analytics_query(request)
|
|
.await
|
|
.context("gRPC ExecuteAnalyticsQuery call failed")?
|
|
.into_inner())
|
|
}
|
|
|
|
pub async fn search_versions(
|
|
&mut self,
|
|
profile_name: String,
|
|
table_name: Option<String>,
|
|
free_query: String,
|
|
limit: Option<u32>,
|
|
offset: Option<u32>,
|
|
version_scope: common::proto::komp_ac::search::SearchVersionScope,
|
|
) -> Result<SearchResponse> {
|
|
let request = self.authenticated_request(SearchRequest {
|
|
profile_name,
|
|
table_name,
|
|
free_query,
|
|
must: Vec::new(),
|
|
limit,
|
|
offset,
|
|
order: None,
|
|
version_scope: version_scope as i32,
|
|
})?;
|
|
self.search_client.search(request).await
|
|
}
|
|
|
|
pub async fn search_table(
|
|
&mut self,
|
|
request: common::proto::komp_ac::search2::Search2Request,
|
|
) -> Result<common::proto::komp_ac::search2::Search2Response> {
|
|
let request = self.authenticated_request(request)?;
|
|
Ok(self
|
|
.search2_client
|
|
.search_table(request)
|
|
.await
|
|
.context("gRPC SearchTable call failed")?
|
|
.into_inner())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::{PostOperation, request_with_auth_token};
|
|
use tonic::Request;
|
|
use uuid::Uuid;
|
|
|
|
#[test]
|
|
fn post_operation_adds_required_grpc_metadata() {
|
|
let operation = PostOperation {
|
|
idempotency_key: Uuid::parse_str("1c32db5c-b7af-4427-bf6e-8f48f75d26bd").unwrap(),
|
|
created_at: "2026-07-30T12:00:00Z".parse().unwrap(),
|
|
};
|
|
let mut request = Request::new(());
|
|
|
|
operation.add_metadata(&mut request).unwrap();
|
|
|
|
assert_eq!(
|
|
request
|
|
.metadata()
|
|
.get("idempotency-key")
|
|
.unwrap()
|
|
.to_str()
|
|
.unwrap(),
|
|
"1c32db5c-b7af-4427-bf6e-8f48f75d26bd"
|
|
);
|
|
assert_eq!(
|
|
request
|
|
.metadata()
|
|
.get("operation-created-at")
|
|
.unwrap()
|
|
.to_str()
|
|
.unwrap(),
|
|
"2026-07-30T12:00:00Z"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn authenticated_request_adds_bearer_token() {
|
|
let request = request_with_auth_token(Some("access-token"), ()).unwrap();
|
|
|
|
assert_eq!(
|
|
request
|
|
.metadata()
|
|
.get("authorization")
|
|
.unwrap()
|
|
.to_str()
|
|
.unwrap(),
|
|
"Bearer access-token"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn authenticated_request_requires_token() {
|
|
let error = request_with_auth_token(None, ()).unwrap_err();
|
|
|
|
assert_eq!(
|
|
error.to_string(),
|
|
"Authentication is required for this request"
|
|
);
|
|
}
|
|
}
|