use crate::models::{
resource_id::{ResourceId, ResourceIdentifier, ResourceName},
AccountReference, PartitionKey, PartitionKeyDefinition,
};
use std::borrow::Cow;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct DatabaseReference {
account: AccountReference,
id: ResourceIdentifier,
}
impl DatabaseReference {
pub fn from_name(account: AccountReference, name: impl Into<Cow<'static, str>>) -> Self {
Self {
account,
id: ResourceIdentifier::ByName(ResourceName::new(name)),
}
}
pub fn from_rid(account: AccountReference, rid: impl Into<Cow<'static, str>>) -> Self {
Self {
account,
id: ResourceIdentifier::ByRid(ResourceId::new(rid)),
}
}
pub fn account(&self) -> &AccountReference {
&self.account
}
pub fn into_account(self) -> AccountReference {
self.account
}
pub fn name(&self) -> Option<&str> {
self.id.name()
}
pub fn rid(&self) -> Option<&str> {
self.id.rid()
}
pub fn is_by_name(&self) -> bool {
matches!(self.id, ResourceIdentifier::ByName(_))
}
pub fn is_by_rid(&self) -> bool {
matches!(self.id, ResourceIdentifier::ByRid(_))
}
pub fn name_based_path(&self) -> Option<String> {
self.id.name().map(|n| format!("/dbs/{}", n))
}
pub fn rid_based_path(&self) -> Option<String> {
self.id.rid().map(|r| format!("/dbs/{}", r))
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct ContainerReference {
account: AccountReference,
db_name: ResourceName,
db_rid: ResourceId,
container_name: ResourceName,
container_rid: ResourceId,
partition_key_definition: PartitionKeyDefinition,
name_based_path: Arc<str>,
rid_based_path: Arc<str>,
}
impl PartialEq for ContainerReference {
fn eq(&self, other: &Self) -> bool {
self.account == other.account
&& self.container_rid == other.container_rid
&& self.container_name == other.container_name
}
}
impl Eq for ContainerReference {}
impl Hash for ContainerReference {
fn hash<H: Hasher>(&self, state: &mut H) {
self.account.hash(state);
self.container_rid.hash(state);
self.container_name.hash(state);
}
}
impl ContainerReference {
pub(crate) fn new(
account: AccountReference,
db_name: impl Into<ResourceName>,
db_rid: impl Into<ResourceId>,
container_name: impl Into<ResourceName>,
container_rid: impl Into<ResourceId>,
container_properties: &crate::models::ContainerProperties,
) -> Self {
let db_name: ResourceName = db_name.into();
let db_rid: ResourceId = db_rid.into();
let container_name: ResourceName = container_name.into();
let container_rid: ResourceId = container_rid.into();
let name_based_path: Arc<str> = format!("/dbs/{}/colls/{}", db_name, container_name).into();
let rid_based_path: Arc<str> = format!("/dbs/{}/colls/{}", db_rid, container_rid).into();
Self {
account,
db_name,
db_rid,
container_name,
container_rid,
partition_key_definition: container_properties.partition_key.clone(),
name_based_path,
rid_based_path,
}
}
pub fn account(&self) -> &AccountReference {
&self.account
}
pub fn name(&self) -> &str {
self.container_name.as_str()
}
pub fn rid(&self) -> &str {
self.container_rid.as_str()
}
pub fn database_name(&self) -> &str {
self.db_name.as_str()
}
pub fn database_rid(&self) -> &str {
self.db_rid.as_str()
}
pub fn partition_key_definition(&self) -> &crate::models::PartitionKeyDefinition {
&self.partition_key_definition
}
pub fn name_based_path(&self) -> &str {
&self.name_based_path
}
pub fn rid_based_path(&self) -> &str {
&self.rid_based_path
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct ItemReference {
container: ContainerReference,
partition_key: PartitionKey,
item_identifier: ResourceIdentifier,
resource_link: String,
}
impl ItemReference {
pub fn from_name(
container: &ContainerReference,
partition_key: PartitionKey,
item_name: impl Into<Cow<'static, str>>,
) -> Self {
let name = ResourceName::new(item_name);
let resource_link = format!("{}/docs/{}", container.name_based_path(), name);
Self {
container: container.clone(),
partition_key,
item_identifier: ResourceIdentifier::by_name(name),
resource_link,
}
}
pub fn from_rid(
container: &ContainerReference,
partition_key: PartitionKey,
item_rid: impl Into<Cow<'static, str>>,
) -> Self {
let rid = ResourceId::new(item_rid);
let resource_link = format!("{}/docs/{}", container.rid_based_path(), rid);
Self {
container: container.clone(),
partition_key,
item_identifier: ResourceIdentifier::by_rid(rid),
resource_link,
}
}
pub fn container(&self) -> &ContainerReference {
&self.container
}
pub fn account(&self) -> &AccountReference {
self.container.account()
}
pub fn partition_key(&self) -> &PartitionKey {
&self.partition_key
}
pub fn name(&self) -> Option<&str> {
self.item_identifier.name()
}
pub fn rid(&self) -> Option<&str> {
self.item_identifier.rid()
}
pub fn is_by_name(&self) -> bool {
self.item_identifier.is_by_name()
}
pub fn is_by_rid(&self) -> bool {
self.item_identifier.is_by_rid()
}
pub fn resource_link(&self) -> &str {
&self.resource_link
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct StoredProcedureReference {
container: ContainerReference,
stored_procedure_identifier: ResourceIdentifier,
resource_link: String,
}
impl StoredProcedureReference {
pub fn from_name(
container: &ContainerReference,
stored_procedure_name: impl Into<Cow<'static, str>>,
) -> Self {
let stored_procedure_name = ResourceName::new(stored_procedure_name);
let resource_link = format!(
"{}/sprocs/{}",
container.name_based_path(),
stored_procedure_name
);
Self {
container: container.clone(),
stored_procedure_identifier: ResourceIdentifier::by_name(stored_procedure_name),
resource_link,
}
}
pub fn from_rid(
container: &ContainerReference,
stored_procedure_rid: impl Into<Cow<'static, str>>,
) -> Self {
let stored_procedure_rid = ResourceId::new(stored_procedure_rid);
let resource_link = format!(
"{}/sprocs/{}",
container.rid_based_path(),
stored_procedure_rid
);
Self {
container: container.clone(),
stored_procedure_identifier: ResourceIdentifier::by_rid(stored_procedure_rid),
resource_link,
}
}
pub fn container(&self) -> &ContainerReference {
&self.container
}
pub fn account(&self) -> &AccountReference {
self.container.account()
}
pub fn name(&self) -> Option<&str> {
self.stored_procedure_identifier.name()
}
pub fn rid(&self) -> Option<&str> {
self.stored_procedure_identifier.rid()
}
pub fn is_by_name(&self) -> bool {
self.stored_procedure_identifier.is_by_name()
}
pub fn is_by_rid(&self) -> bool {
self.stored_procedure_identifier.is_by_rid()
}
pub fn resource_link(&self) -> &str {
&self.resource_link
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct TriggerReference {
container: ContainerReference,
trigger_identifier: ResourceIdentifier,
resource_link: String,
}
impl TriggerReference {
pub fn from_name(
container: &ContainerReference,
trigger_name: impl Into<Cow<'static, str>>,
) -> Self {
let trigger_name = ResourceName::new(trigger_name);
let resource_link = format!("{}/triggers/{}", container.name_based_path(), trigger_name);
Self {
container: container.clone(),
trigger_identifier: ResourceIdentifier::by_name(trigger_name),
resource_link,
}
}
pub fn from_rid(
container: &ContainerReference,
trigger_rid: impl Into<Cow<'static, str>>,
) -> Self {
let trigger_rid = ResourceId::new(trigger_rid);
let resource_link = format!("{}/triggers/{}", container.rid_based_path(), trigger_rid);
Self {
container: container.clone(),
trigger_identifier: ResourceIdentifier::by_rid(trigger_rid),
resource_link,
}
}
pub fn container(&self) -> &ContainerReference {
&self.container
}
pub fn account(&self) -> &AccountReference {
self.container.account()
}
pub fn name(&self) -> Option<&str> {
self.trigger_identifier.name()
}
pub fn rid(&self) -> Option<&str> {
self.trigger_identifier.rid()
}
pub fn is_by_name(&self) -> bool {
self.trigger_identifier.is_by_name()
}
pub fn is_by_rid(&self) -> bool {
self.trigger_identifier.is_by_rid()
}
pub fn resource_link(&self) -> &str {
&self.resource_link
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct UdfReference {
container: ContainerReference,
udf_identifier: ResourceIdentifier,
resource_link: String,
}
impl UdfReference {
pub fn from_name(
container: &ContainerReference,
udf_name: impl Into<Cow<'static, str>>,
) -> Self {
let udf_name = ResourceName::new(udf_name);
let resource_link = format!("{}/udfs/{}", container.name_based_path(), udf_name);
Self {
container: container.clone(),
udf_identifier: ResourceIdentifier::by_name(udf_name),
resource_link,
}
}
pub fn from_rid(container: &ContainerReference, udf_rid: impl Into<Cow<'static, str>>) -> Self {
let udf_rid = ResourceId::new(udf_rid);
let resource_link = format!("{}/udfs/{}", container.rid_based_path(), udf_rid);
Self {
container: container.clone(),
udf_identifier: ResourceIdentifier::by_rid(udf_rid),
resource_link,
}
}
pub fn container(&self) -> &ContainerReference {
&self.container
}
pub fn account(&self) -> &AccountReference {
self.container.account()
}
pub fn name(&self) -> Option<&str> {
self.udf_identifier.name()
}
pub fn rid(&self) -> Option<&str> {
self.udf_identifier.rid()
}
pub fn is_by_name(&self) -> bool {
self.udf_identifier.is_by_name()
}
pub fn is_by_rid(&self) -> bool {
self.udf_identifier.is_by_rid()
}
pub fn resource_link(&self) -> &str {
&self.resource_link
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PartitionKeyRangeReference {
container: ContainerReference,
range_id: ResourceName,
}
impl PartitionKeyRangeReference {
pub fn from_range_id(
container: &ContainerReference,
range_id: impl Into<Cow<'static, str>>,
) -> Self {
let range_id = ResourceName::new(range_id);
Self {
container: container.clone(),
range_id,
}
}
pub fn container(&self) -> &ContainerReference {
&self.container
}
pub fn account(&self) -> &AccountReference {
self.container.account()
}
pub fn range_id(&self) -> &str {
self.range_id.as_str()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::models::{ContainerProperties, PartitionKeyDefinition};
use url::Url;
fn make_container_reference() -> ContainerReference {
let account = AccountReference::with_master_key(
Url::parse("https://example.documents.azure.com:443/").unwrap(),
"test-key",
);
let partition_key: PartitionKeyDefinition =
serde_json::from_str(r#"{"paths":["/tenantId"]}"#).unwrap();
let container_properties = ContainerProperties {
id: "my-container".into(),
partition_key,
system_properties: Default::default(),
};
ContainerReference::new(
account,
"my-db",
"db-rid",
"my-container",
"container-rid",
&container_properties,
)
}
#[test]
fn container_partition_key_definition_is_available() {
let container = make_container_reference();
let partition_key_definition = container.partition_key_definition();
assert_eq!(partition_key_definition.paths().len(), 1);
assert_eq!(partition_key_definition.paths()[0].as_ref(), "/tenantId");
}
}