Skip to main content

reallyme_foundationdb_kit/keys/
metadata.rs

1// SPDX-FileCopyrightText: 2026 ReallyMe LLC
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Tenant metadata keys owned by foundationdb-kit.
5
6use bytes::{Bytes, BytesMut};
7
8use super::codec::KeyEncoder;
9use super::error::KeyLabelError;
10use super::{namespace::KeyNamespace, prefix::KeyPrefix};
11
12/// Stable metadata namespace within each tenant.
13pub const TENANT_METADATA_NAMESPACE: &str = "__meta";
14const TENANT_METADATA_VERSION_PREFIX: &str = "v1";
15const SCHEMA_VERSION_KEY: &str = "schema_version";
16const CREATED_AT_KEY: &str = "created_at";
17
18/// Tenant-scoped metadata key for schema-version.
19pub struct TenantMetadataSchemaVersionKey {
20    namespace: KeyNamespace,
21    prefix: KeyPrefix,
22}
23
24/// Tenant-scoped metadata key for metadata creation timestamp.
25pub struct TenantMetadataCreatedAtKey {
26    namespace: KeyNamespace,
27    prefix: KeyPrefix,
28}
29
30/// Shared key prefix under `__meta`.
31pub struct TenantMetadataVersionPrefix;
32
33impl TenantMetadataVersionPrefix {
34    /// Returns a validated `__meta` namespace/prefix pair.
35    pub fn components() -> Result<(KeyNamespace, KeyPrefix), KeyLabelError> {
36        Ok((
37            KeyNamespace::from_static(TENANT_METADATA_NAMESPACE)?,
38            KeyPrefix::from_static(TENANT_METADATA_VERSION_PREFIX)?,
39        ))
40    }
41}
42
43impl TenantMetadataSchemaVersionKey {
44    /// Builds the `__meta/schema_version` key encoder for a version prefix.
45    pub fn new() -> Result<Self, KeyLabelError> {
46        let (namespace, prefix) = TenantMetadataVersionPrefix::components()?;
47        Ok(Self { namespace, prefix })
48    }
49}
50
51impl TenantMetadataCreatedAtKey {
52    /// Builds the `__meta/created_at` key encoder for a version prefix.
53    pub fn new() -> Result<Self, KeyLabelError> {
54        let (namespace, prefix) = TenantMetadataVersionPrefix::components()?;
55        Ok(Self { namespace, prefix })
56    }
57}
58
59fn encode_key(namespace: &str, prefix: &str, key: &str) -> Bytes {
60    let mut bytes = BytesMut::with_capacity(
61        namespace
62            .len()
63            .checked_add(prefix.len())
64            .and_then(|value| value.checked_add(key.len()))
65            .and_then(|value| value.checked_add(2))
66            .unwrap_or(namespace.len()),
67    );
68
69    bytes.extend_from_slice(namespace.as_bytes());
70    bytes.extend_from_slice(b"/");
71    bytes.extend_from_slice(prefix.as_bytes());
72    bytes.extend_from_slice(b"/");
73    bytes.extend_from_slice(key.as_bytes());
74
75    bytes.freeze()
76}
77
78impl KeyEncoder for TenantMetadataSchemaVersionKey {
79    fn encode_key(&self) -> Bytes {
80        encode_key(
81            self.namespace.as_str(),
82            self.prefix.as_str(),
83            SCHEMA_VERSION_KEY,
84        )
85    }
86}
87
88impl KeyEncoder for TenantMetadataCreatedAtKey {
89    fn encode_key(&self) -> Bytes {
90        encode_key(
91            self.namespace.as_str(),
92            self.prefix.as_str(),
93            CREATED_AT_KEY,
94        )
95    }
96}