lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

dto.rs (6250B)


      1 use dto_bindgen_core::{
      2     BackendId, DescribeCtx, Dto, FieldDef, FieldPresence, IdentName, RootDescriptor, RustTypeId,
      3     SourceSpan, StructDef, TargetFieldNames, TargetOverride, TypeDef, TypeRef, WireFieldNames,
      4 };
      5 
      6 use crate::{
      7     checkpoint::{RadrootsEventsIndexedIndexCheckpoint, RadrootsEventsIndexedShardCheckpoint},
      8     manifest::{RadrootsEventsIndexedManifest, RadrootsEventsIndexedShardMetadata},
      9     types::RadrootsEventsIndexedIdRange,
     10 };
     11 
     12 pub fn dto_roots() -> [RootDescriptor; 5] {
     13     [
     14         RootDescriptor::new::<RadrootsEventsIndexedIdRange>(),
     15         RootDescriptor::new::<RadrootsEventsIndexedShardMetadata>(),
     16         RootDescriptor::new::<RadrootsEventsIndexedManifest>(),
     17         RootDescriptor::new::<RadrootsEventsIndexedShardCheckpoint>(),
     18         RootDescriptor::new::<RadrootsEventsIndexedIndexCheckpoint>(),
     19     ]
     20 }
     21 
     22 impl Dto for RadrootsEventsIndexedShardCheckpoint {
     23     fn describe(ctx: &mut DescribeCtx) -> TypeRef {
     24         let def = StructDef::new(
     25             "RadrootsEventsIndexedShardCheckpoint",
     26             "RadrootsEventsIndexedShardCheckpoint",
     27             span("crates/events_indexed/src/checkpoint.rs", 10),
     28         )
     29         .with_field(field(
     30             "shard_id",
     31             "shard_id",
     32             shard_id_ref(),
     33             "crates/events_indexed/src/checkpoint.rs",
     34             11,
     35         ))
     36         .with_field(field(
     37             "last_created_at",
     38             "last_created_at",
     39             u32::describe(ctx),
     40             "crates/events_indexed/src/checkpoint.rs",
     41             16,
     42         ))
     43         .with_field(optional_nullable_field(
     44             "last_event_id",
     45             "last_event_id",
     46             <Option<String> as Dto>::describe(ctx),
     47             "crates/events_indexed/src/checkpoint.rs",
     48             17,
     49         ))
     50         .with_field(optional_nullable_field(
     51             "cursor",
     52             "cursor",
     53             <Option<String> as Dto>::describe(ctx),
     54             "crates/events_indexed/src/checkpoint.rs",
     55             18,
     56         ));
     57         register(
     58             ctx,
     59             "RadrootsEventsIndexedShardCheckpoint",
     60             TypeDef::Struct(def),
     61         )
     62     }
     63 }
     64 
     65 impl Dto for RadrootsEventsIndexedIndexCheckpoint {
     66     fn describe(ctx: &mut DescribeCtx) -> TypeRef {
     67         let def = StructDef::new(
     68             "RadrootsEventsIndexedIndexCheckpoint",
     69             "RadrootsEventsIndexedIndexCheckpoint",
     70             span("crates/events_indexed/src/checkpoint.rs", 24),
     71         )
     72         .with_field(field(
     73             "generated_at",
     74             "generated_at",
     75             u32::describe(ctx),
     76             "crates/events_indexed/src/checkpoint.rs",
     77             30,
     78         ))
     79         .with_field(field(
     80             "shards",
     81             "shards",
     82             <Vec<RadrootsEventsIndexedShardCheckpoint> as Dto>::describe(ctx),
     83             "crates/events_indexed/src/checkpoint.rs",
     84             31,
     85         ));
     86         register(
     87             ctx,
     88             "RadrootsEventsIndexedIndexCheckpoint",
     89             TypeDef::Struct(def),
     90         )
     91     }
     92 }
     93 
     94 fn register(ctx: &mut DescribeCtx, rust_ident: &str, type_def: TypeDef) -> TypeRef {
     95     ctx.register_type(
     96         RustTypeId::new("radroots_events_indexed", rust_ident),
     97         type_def,
     98     )
     99 }
    100 
    101 fn shard_id_ref() -> TypeRef {
    102     TypeRef::Override(TargetOverride::new(
    103         BackendId::TypeScript,
    104         "RadrootsEventsIndexedShardId",
    105     ))
    106 }
    107 
    108 fn optional_nullable_field(
    109     rust_name: &str,
    110     wire_name: &str,
    111     ty: TypeRef,
    112     file: &str,
    113     line: u32,
    114 ) -> FieldDef {
    115     field(rust_name, wire_name, ty, file, line).with_presence(FieldPresence::optional_nullable())
    116 }
    117 
    118 fn field(rust_name: &str, wire_name: &str, ty: TypeRef, file: &str, line: u32) -> FieldDef {
    119     FieldDef::new(
    120         IdentName::new(rust_name),
    121         WireFieldNames::same(wire_name),
    122         TargetFieldNames::new(wire_name, rust_name),
    123         ty,
    124         span(file, line),
    125     )
    126 }
    127 
    128 fn span(file: &str, line: u32) -> SourceSpan {
    129     SourceSpan::new(file, line, 1)
    130 }
    131 
    132 #[cfg(test)]
    133 mod tests {
    134     use dto_bindgen_core::{FieldDef, Primitive, StructDef, TypeDef, TypeRef, build_registry};
    135 
    136     use super::dto_roots;
    137 
    138     #[test]
    139     fn indexed_descriptor_roots_build_registry() {
    140         let registry = build_registry(dto_roots());
    141 
    142         assert!(!registry.has_errors());
    143         assert_eq!(registry.roots.len(), dto_roots().len());
    144         assert!(registry.types_by_id.values().any(
    145             |def| matches!(def, TypeDef::Struct(def) if def.export_name == "RadrootsEventsIndexedManifest")
    146         ));
    147     }
    148 
    149     #[test]
    150     fn custom_epoch_second_fields_render_as_numbers() {
    151         let registry = build_registry(dto_roots());
    152         let shard_checkpoint = find_struct(&registry, "RadrootsEventsIndexedShardCheckpoint");
    153         let index_checkpoint = find_struct(&registry, "RadrootsEventsIndexedIndexCheckpoint");
    154 
    155         assert_eq!(
    156             find_field(shard_checkpoint, "last_created_at").ty,
    157             TypeRef::Primitive(Primitive::U32)
    158         );
    159         assert_eq!(
    160             find_field(index_checkpoint, "generated_at").ty,
    161             TypeRef::Primitive(Primitive::U32)
    162         );
    163     }
    164 
    165     #[test]
    166     fn optional_checkpoint_fields_are_optional_nullable() {
    167         let registry = build_registry(dto_roots());
    168         let checkpoint = find_struct(&registry, "RadrootsEventsIndexedShardCheckpoint");
    169 
    170         for field_name in ["last_event_id", "cursor"] {
    171             let field = find_field(checkpoint, field_name);
    172 
    173             assert!(field.presence.nullable);
    174             assert!(!field.presence.required_on_deserialize);
    175         }
    176     }
    177 
    178     fn find_struct<'a>(
    179         registry: &'a dto_bindgen_core::Registry,
    180         export_name: &str,
    181     ) -> &'a StructDef {
    182         registry
    183             .types_by_id
    184             .values()
    185             .find_map(|def| match def {
    186                 TypeDef::Struct(def) if def.export_name == export_name => Some(def),
    187                 _ => None,
    188             })
    189             .expect("descriptor struct")
    190     }
    191 
    192     fn find_field<'a>(def: &'a StructDef, typescript_name: &str) -> &'a FieldDef {
    193         def.fields
    194             .iter()
    195             .find(|field| field.target.typescript == typescript_name)
    196             .expect("descriptor field")
    197     }
    198 }