bonsaidb_local/cli/
schema.rs

1use std::str::FromStr;
2
3use bonsaidb_core::connection::{AsyncStorageConnection, StorageConnection};
4use bonsaidb_core::schema::{
5    CollectionName, InvalidNameError, SchemaName, SchemaSummary, ViewName,
6};
7use clap::Parser;
8
9/// A schema query against a storage instance.
10#[derive(Parser, Debug)]
11pub struct Command {
12    /// The name of the schema to query.
13    pub name: Option<SchemaName>,
14
15    /// The item in the schema to query.
16    pub item: Option<CollectionOrView>,
17}
18
19impl Command {
20    /// Executes the command on `storage`.
21    pub fn execute<SC: StorageConnection>(self, storage: &SC) -> Result<(), crate::Error> {
22        let schemas = storage.list_available_schemas()?;
23        self.handle_schema_command(schemas)
24    }
25
26    /// Executes the command on `storage`.
27    pub async fn execute_async<SC: AsyncStorageConnection>(
28        self,
29        storage: &SC,
30    ) -> Result<(), crate::Error> {
31        let schemas = storage.list_available_schemas().await?;
32        self.handle_schema_command(schemas)
33    }
34
35    fn handle_schema_command(self, schemas: Vec<SchemaSummary>) -> Result<(), crate::Error> {
36        if let Some(name) = self.name {
37            let Some(schema) = schemas.into_iter().find(|s| s.name == name) else {
38                return Err(crate::Error::Core(
39                    bonsaidb_core::Error::SchemaNotRegistered(name),
40                ));
41            };
42
43            if let Some(item) = self.item {
44                match item {
45                    CollectionOrView::View(view) => {
46                        let Some(collection) = schema.collection(&view.collection) else {
47                            return Err(crate::Error::Core(
48                                bonsaidb_core::Error::CollectionNotFound,
49                            ));
50                        };
51                        let Some(view) = collection.view(&view) else {
52                            return Err(crate::Error::Core(bonsaidb_core::Error::ViewNotFound));
53                        };
54                        println!("Version: {}", view.version);
55                        println!("Policy: {}", view.policy);
56                    }
57                    CollectionOrView::Collection(collection) => {
58                        let Some(collection) = schema.collection(&collection) else {
59                            return Err(crate::Error::Core(
60                                bonsaidb_core::Error::CollectionNotFound,
61                            ));
62                        };
63                        let mut views = collection.views().collect::<Vec<_>>();
64                        views.sort_by(|v1, v2| v1.name.cmp(&v2.name));
65                        for view in views {
66                            println!("{}", view.name);
67                        }
68                    }
69                }
70            } else {
71                print_collection_list(&schema);
72            }
73        } else if let Some(item) = self.item {
74            eprintln!("missing `schema` for inspecting {item:?}");
75            std::process::exit(-1);
76        } else {
77            print_schema_list(schemas);
78        }
79        Ok(())
80    }
81}
82
83fn print_schema_list(mut schemas: Vec<SchemaSummary>) {
84    schemas.sort_by(|s1, s2| s1.name.cmp(&s2.name));
85
86    for schema in schemas {
87        println!("{}", schema.name);
88    }
89}
90
91fn print_collection_list(schema: &SchemaSummary) {
92    let mut collections = schema.collections().collect::<Vec<_>>();
93    collections.sort_by(|c1, c2| c1.name.cmp(&c2.name));
94
95    for collection in collections {
96        println!("{}", collection.name);
97    }
98}
99
100/// A name that is either a [`CollectionName`] or [`ViewName`].
101#[derive(Debug, Clone)]
102pub enum CollectionOrView {
103    /// A view name.
104    View(ViewName),
105    /// A collection name.
106    Collection(CollectionName),
107}
108
109impl FromStr for CollectionOrView {
110    type Err = InvalidNameError;
111
112    fn from_str(s: &str) -> Result<Self, Self::Err> {
113        if let Ok(view) = ViewName::from_str(s) {
114            Ok(Self::View(view))
115        } else {
116            CollectionName::from_str(s).map(Self::Collection)
117        }
118    }
119}