Skip to content

Commit

Permalink
BREAKING CHANGE: Add DocumentPath::into_collection and change collect…
Browse files Browse the repository at this point in the history
…ion to no longer consume self
  • Loading branch information
bouzuya committed Jan 20, 2024
1 parent 6121c03 commit e031e3e
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 48 deletions.
2 changes: 1 addition & 1 deletion src/document_name.rs
Expand Up @@ -334,7 +334,7 @@ impl DocumentName {
{
Ok(CollectionName::new(
self.root_document_name,
self.document_path.collection(collection_path)?,
self.document_path.into_collection(collection_path)?,
))
}

Expand Down
137 changes: 90 additions & 47 deletions src/document_path.rs
Expand Up @@ -58,66 +58,35 @@ impl DocumentPath {
///
/// ```rust
/// # fn main() -> anyhow::Result<()> {
/// use firestore_path::{CollectionPath,DocumentPath};
/// use firestore_path::{CollectionId,CollectionPath,DocumentPath};
/// use std::str::FromStr;
///
/// let document_path = DocumentPath::from_str("chatrooms/chatroom1")?;
/// assert_eq!(
/// document_path.collection("messages")?,
/// CollectionPath::from_str("chatrooms/chatroom1/messages")?
/// );
///
/// let document_path = DocumentPath::from_str("chatrooms/chatroom1")?;
/// assert_eq!(
/// document_path.collection("messages/message1/col")?,
/// CollectionPath::from_str("chatrooms/chatroom1/messages/message1/col")?
/// );
/// assert_eq!(
/// document_path.collection(CollectionId::from_str("messages")?)?,
/// CollectionPath::from_str("chatrooms/chatroom1/messages")?
/// );
/// assert_eq!(
/// document_path.collection(CollectionPath::from_str("messages/message1/col")?)?,
/// CollectionPath::from_str("chatrooms/chatroom1/messages/message1/col")?
/// );
/// # Ok(())
/// # }
/// ```
pub fn collection<E, T>(self, collection_path: T) -> Result<CollectionPath, Error>
pub fn collection<E, T>(&self, collection_path: T) -> Result<CollectionPath, Error>
where
E: std::fmt::Display,
T: TryInto<CollectionPath, Error = E>,
{
let mut collection_path: CollectionPath = collection_path
.try_into()
.map_err(|e| Error::from(ErrorKind::CollectionPathConversion(e.to_string())))?;

enum I {
C(CollectionId),
D(DocumentId),
}
let mut path_components = vec![];
loop {
let (parent, collection_id) = collection_path.into_tuple();
path_components.push(I::C(collection_id));
if let Some(document_path) = parent {
let (next_collection_path, document_id) = document_path.into_tuple();
path_components.push(I::D(document_id));
collection_path = next_collection_path;
} else {
break;
}
}

enum P {
C(CollectionPath),
D(DocumentPath),
}
let mut result = P::D(self);
for path_component in path_components.into_iter().rev() {
result = match (result, path_component) {
(P::C(_), I::C(_)) | (P::D(_), I::D(_)) => unreachable!(),
(P::C(c), I::D(d)) => P::D(DocumentPath::new(c, d)),
(P::D(d), I::C(c)) => P::C(CollectionPath::new(Some(d), c)),
};
}
let collection_path = match result {
P::C(c) => c,
P::D(_) => unreachable!(),
};
Ok(collection_path)
self.clone().into_collection(collection_path)
}

/// Creates a new `DocumentPath` from this `DocumentPath` and `document_path`.
Expand Down Expand Up @@ -199,6 +168,80 @@ impl DocumentPath {
&self.document_id
}

/// Creates a new `CollectionPath` by consuming the `DocumentPath` with the provided `collection_path`.
///
/// # Examples
///
/// ```rust
/// # fn main() -> anyhow::Result<()> {
/// use firestore_path::{CollectionId,CollectionPath,DocumentPath};
/// use std::str::FromStr;
///
/// let document_path = DocumentPath::from_str("chatrooms/chatroom1")?;
/// assert_eq!(
/// document_path.clone().into_collection("messages")?,
/// CollectionPath::from_str("chatrooms/chatroom1/messages")?
/// );
/// assert_eq!(
/// document_path.clone().into_collection("messages/message1/col")?,
/// CollectionPath::from_str("chatrooms/chatroom1/messages/message1/col")?
/// );
/// assert_eq!(
/// document_path.clone().into_collection(CollectionId::from_str("messages")?)?,
/// CollectionPath::from_str("chatrooms/chatroom1/messages")?
/// );
/// assert_eq!(
/// document_path.into_collection(CollectionPath::from_str("messages/message1/col")?)?,
/// CollectionPath::from_str("chatrooms/chatroom1/messages/message1/col")?
/// );
/// # Ok(())
/// # }
/// ```
pub fn into_collection<E, T>(self, collection_path: T) -> Result<CollectionPath, Error>
where
E: std::fmt::Display,
T: TryInto<CollectionPath, Error = E>,
{
let mut collection_path: CollectionPath = collection_path
.try_into()
.map_err(|e| Error::from(ErrorKind::CollectionPathConversion(e.to_string())))?;

enum I {
C(CollectionId),
D(DocumentId),
}
let mut path_components = vec![];
loop {
let (parent, collection_id) = collection_path.into_tuple();
path_components.push(I::C(collection_id));
if let Some(document_path) = parent {
let (next_collection_path, document_id) = document_path.into_tuple();
path_components.push(I::D(document_id));
collection_path = next_collection_path;
} else {
break;
}
}

enum P {
C(CollectionPath),
D(DocumentPath),
}
let mut result = P::D(self);
for path_component in path_components.into_iter().rev() {
result = match (result, path_component) {
(P::C(_), I::C(_)) | (P::D(_), I::D(_)) => unreachable!(),
(P::C(c), I::D(d)) => P::D(DocumentPath::new(c, d)),
(P::D(d), I::C(c)) => P::C(CollectionPath::new(Some(d), c)),
};
}
let collection_path = match result {
P::C(c) => c,
P::D(_) => unreachable!(),
};
Ok(collection_path)
}

/// Creates a new `DocumentPath` by consuming the `DocumentPath` and the provided `document_path`.
///
/// # Examples
Expand Down Expand Up @@ -371,22 +414,22 @@ mod tests {
#[test]
fn test_collection() -> anyhow::Result<()> {
let document_path = DocumentPath::from_str("chatrooms/chatroom1")?;
let collection_path = document_path.collection("messages")?;
let collection_path = document_path.into_collection("messages")?;
assert_eq!(
collection_path,
CollectionPath::from_str("chatrooms/chatroom1/messages")?
);

let document_path = DocumentPath::from_str("chatrooms/chatroom1/messages/message1")?;
let collection_path = document_path.collection("col")?;
let collection_path = document_path.into_collection("col")?;
assert_eq!(
collection_path,
CollectionPath::from_str("chatrooms/chatroom1/messages/message1/col")?
);

let document_path = DocumentPath::from_str("chatrooms/chatroom1")?;
let collection_id = CollectionId::from_str("messages")?;
let collection_path = document_path.collection(collection_id)?;
let collection_path = document_path.into_collection(collection_id)?;
assert_eq!(
collection_path,
CollectionPath::from_str("chatrooms/chatroom1/messages")?
Expand All @@ -397,15 +440,15 @@ mod tests {
#[test]
fn test_collection_with_colleciton_path() -> anyhow::Result<()> {
let document_path = DocumentPath::from_str("chatrooms/chatroom1")?;
let collection_path = document_path.collection("messages/message1/col")?;
let collection_path = document_path.into_collection("messages/message1/col")?;
assert_eq!(
collection_path,
CollectionPath::from_str("chatrooms/chatroom1/messages/message1/col")?
);

let document_path = DocumentPath::from_str("chatrooms/chatroom1")?;
let collection_path = CollectionPath::from_str("messages/message1/col")?;
let collection_path = document_path.collection(collection_path)?;
let collection_path = document_path.into_collection(collection_path)?;
assert_eq!(
collection_path,
CollectionPath::from_str("chatrooms/chatroom1/messages/message1/col")?
Expand Down
68 changes: 68 additions & 0 deletions tests/v0_7_0.rs
Expand Up @@ -342,6 +342,39 @@ fn test_document_name_into_doc() -> anyhow::Result<()> {
Ok(())
}

#[test]
fn test_document_path_collection() -> anyhow::Result<()> {
// BREAKING CHANGE: DocumentPath::collection doesn't consume self.
let document_name = DocumentName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1",
)?;
assert_eq!(
document_name.collection("messages")?,
CollectionName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1/messages"
)?
);
assert_eq!(
document_name.collection("messages/message1/col")?,
CollectionName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1/messages/message1/col"
)?
);
assert_eq!(
document_name.collection(CollectionId::from_str("messages")?)?,
CollectionName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1/messages"
)?
);
assert_eq!(
document_name.collection(CollectionPath::from_str("messages/message1/col")?)?,
CollectionName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1/messages/message1/col"
)?
);
Ok(())
}

#[test]
fn test_document_path_doc() -> anyhow::Result<()> {
// BREAKING CHANGE: DocumentPath::doc doesn't consume self.
Expand All @@ -365,6 +398,41 @@ fn test_document_path_doc() -> anyhow::Result<()> {
Ok(())
}

#[test]
fn test_document_path_into_collection() -> anyhow::Result<()> {
// Added: DocumentPath::into_collection
let document_name = DocumentName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1",
)?;
assert_eq!(
document_name.clone().into_collection("messages")?,
CollectionName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1/messages"
)?
);
assert_eq!(
document_name.clone().into_collection("messages/message1/col")?,
CollectionName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1/messages/message1/col"
)?
);
assert_eq!(
document_name
.clone()
.into_collection(CollectionId::from_str("messages")?)?,
CollectionName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1/messages"
)?
);
assert_eq!(
document_name.into_collection(CollectionPath::from_str("messages/message1/col")?)?,
CollectionName::from_str(
"projects/my-project/databases/my-database/documents/chatrooms/chatroom1/messages/message1/col"
)?
);
Ok(())
}

#[test]
fn test_document_path_into_doc() -> anyhow::Result<()> {
// Added: DocumentPath::into_doc
Expand Down

0 comments on commit e031e3e

Please sign in to comment.