Skip to content

Commit

Permalink
feat: Add tid/record-key string format (#155)
Browse files Browse the repository at this point in the history
* Add tid/record-key string format

* Fix tests

* Add tests for tids

* Update docs and changelogs
  • Loading branch information
sugyan authored Apr 18, 2024
1 parent 8ec130f commit 7a1a070
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 123 deletions.
9 changes: 9 additions & 0 deletions atrium-api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- `atrium_api::types::string::Tid`
- `atrium_api::types::string::RecordKey`
- moved from `atrium_api::types::RecordKey`

### Removed
- `atrium_api::types::RecordKey`
- moved to `atrium_api::types::string::RecordKey`

## [0.20.1](https://github.com/sugyan/atrium/compare/atrium-api-v0.20.0...atrium-api-v0.20.1) - 2024-04-17

### Added
Expand Down
108 changes: 2 additions & 106 deletions atrium-api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
//! <https://atproto.com/specs/data-model>
use ipld_core::ipld::Ipld;
use regex::Regex;
use std::{cell::OnceCell, fmt, ops::Deref, str::FromStr};
use std::fmt;

mod cid_link;
pub use cid_link::CidLink;
Expand All @@ -12,6 +11,7 @@ mod integer;
pub use integer::*;

pub mod string;
use string::RecordKey;

/// Trait for a collection of records that can be stored in a repository.
///
Expand Down Expand Up @@ -53,72 +53,6 @@ pub trait Collection: fmt::Debug {
}
}

/// A record key (`rkey`) used to name and reference an individual record within the same
/// collection of an atproto repository.
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
pub struct RecordKey(String);

impl RecordKey {
/// Returns the record key as a string slice.
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}

impl FromStr for RecordKey {
type Err = &'static str;

#[allow(
clippy::borrow_interior_mutable_const,
clippy::declare_interior_mutable_const
)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
const RE_RKEY: OnceCell<Regex> = OnceCell::new();

if [".", ".."].contains(&s) {
Err("Disallowed rkey")
} else if !RE_RKEY
.get_or_init(|| Regex::new(r"^[a-zA-Z0-9._~-]{1,512}$").unwrap())
.is_match(s)
{
Err("Invalid rkey")
} else {
Ok(Self(s.into()))
}
}
}

impl<'de> serde::Deserialize<'de> for RecordKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
let value = serde::Deserialize::deserialize(deserializer)?;
Self::from_str(value).map_err(D::Error::custom)
}
}

impl From<RecordKey> for String {
fn from(value: RecordKey) -> Self {
value.0
}
}

impl AsRef<str> for RecordKey {
fn as_ref(&self) -> &str {
self.as_str()
}
}

impl Deref for RecordKey {
type Target = str;

fn deref(&self) -> &Self::Target {
self.as_str()
}
}

/// Definitions for Blob types.
/// Usually a map with `$type` is used, but deprecated legacy formats are also supported for parsing.
/// <https://atproto.com/specs/data-model#blob-type>
Expand Down Expand Up @@ -180,44 +114,6 @@ mod tests {
const CID_LINK_JSON: &str =
r#"{"$link":"bafkreibme22gw2h7y2h7tg2fhqotaqjucnbc24deqo72b6mkl2egezxhvy"}"#;

#[test]
fn valid_rkey() {
// From https://atproto.com/specs/record-key#examples
for valid in &["3jui7kd54zh2y", "self", "example.com", "~1.2-3_", "dHJ1ZQ"] {
assert!(
from_str::<RecordKey>(&format!("\"{}\"", valid)).is_ok(),
"valid rkey `{}` parsed as invalid",
valid,
);
}
}

#[test]
fn invalid_rkey() {
// From https://atproto.com/specs/record-key#examples
for invalid in &[
"literal:self",
"alpha/beta",
".",
"..",
"#extra",
"@handle",
"any space",
"any+space",
"number[3]",
"number(3)",
"\"quote\"",
"pre:fix",
"dHJ1ZQ==",
] {
assert!(
from_str::<RecordKey>(&format!("\"{}\"", invalid)).is_err(),
"invalid rkey `{}` parsed as valid",
invalid,
);
}
}

#[test]
fn test_cid_link_serde_json() {
let deserialized =
Expand Down
Loading

0 comments on commit 7a1a070

Please sign in to comment.