pub trait TableLogic:
Send
+ Sync
+ 'static {
type Row: Serialize + DeserializeOwned + Send + Sync;
// Required methods
fn name(&self) -> &'static str;
fn file(&self) -> &'static str;
fn title(&self) -> &'static str;
fn schema(&self, ctx: &Context) -> Result<Schema, ApiError>;
fn validate(
&self,
rows: &[Self::Row],
ctx: &Context,
) -> Result<Vec<ValidationError>, ApiError>;
// Provided methods
fn parse(&self, text: &str) -> Result<Vec<Self::Row>, ParseError> { ... }
fn serialize(&self, rows: &[Self::Row]) -> Result<String, Error> { ... }
fn derive(
&self,
_rows: &[Self::Row],
_ctx: &Context,
) -> Result<Vec<Value>, ApiError> { ... }
fn siblings(&self, _ctx: &Context) -> Result<Value, ApiError> { ... }
}Expand description
One table’s per-repository logic.
parse and serialize default to plain JSONL, so a table whose row type
serializes the way it is stored implements neither. derive and siblings
default to nothing, so a table with no derived values and no cross-table
data implements neither.
Required Associated Types§
Required Methods§
Sourcefn name(&self) -> &'static str
fn name(&self) -> &'static str
The route segment and ?table= value, such as books. The names
app, health, shutdown, and stop are reserved: the first three
are control endpoints and the fourth is the stop subcommand, which
clap takes before the positional table name.
Sourcefn file(&self) -> &'static str
fn file(&self) -> &'static str
The file under Data/, such as Books.jsonl.
It is a bare file name: no directory separators, nothing absolute, and
not . or ... Building a crate::Server over a table that names
anything else panics. It must exist before the editor can open the
table; the editor edits a table, it does not create one.
Sourcefn schema(&self, ctx: &Context) -> Result<Schema, ApiError>
fn schema(&self, ctx: &Context) -> Result<Schema, ApiError>
Rebuilt on every read, so sibling-derived options and widths are current.
Sourcefn validate(
&self,
rows: &[Self::Row],
ctx: &Context,
) -> Result<Vec<ValidationError>, ApiError>
fn validate( &self, rows: &[Self::Row], ctx: &Context, ) -> Result<Vec<ValidationError>, ApiError>
Problems with the rows, each reported against the row’s one-based position in the set. A write is not refused because of them: the editor persists what it is given and shows the errors beside the cells.
Provided Methods§
fn parse(&self, text: &str) -> Result<Vec<Self::Row>, ParseError>
Sourcefn serialize(&self, rows: &[Self::Row]) -> Result<String, Error>
fn serialize(&self, rows: &[Self::Row]) -> Result<String, Error>
Examples found in repository?
943 fn lend(fields: &Fields, args: &ViewArgs, ctx: &Context) -> Result<String, ApiError> {
944 let title = args.get_or("title", "");
945 let borrower = fields.text("borrower");
946 let days = fields.integer("days")?;
947 let from = fields.date("from")?;
948 let condition = fields.text("condition").to_lowercase();
949
950 if borrower.is_empty() {
951 return Err(ApiError::bad_request("a loan needs a borrower"));
952 }
953 if days < 1 {
954 return Err(ApiError::bad_request("a loan is at least one day long"));
955 }
956 let start = days_from_civil(from).ok_or_else(|| {
957 ApiError::bad_request(format!("{from} is not a date in the calendar"))
958 })?;
959 let due = civil_from_days(start + days);
960
961 let mut books: Vec<Book> = ctx.rows(BOOKS_FILE)?;
962 let book = books
963 .iter_mut()
964 .find(|b| b.title == title)
965 .ok_or_else(|| ApiError::bad_request(format!("no book is called \"{title}\"")))?;
966 if book.lent.unwrap_or(false) {
967 return Err(ApiError::bad_request(format!("\"{title}\" is already out")));
968 }
969 book.lent = Some(true);
970 book.due = due.clone();
971 book.notes = format!("Lent to {borrower} on {from}, {condition}.");
972
973 let problems = Books.validate(&books, ctx)?;
974 if let Some(first) = problems.first() {
975 return Err(ApiError::bad_request(format!(
976 "the loan would leave row {} in a state the table refuses: {}",
977 first.line, first.message
978 )));
979 }
980
981 let text = Books
982 .serialize(&books)
983 .map_err(|e| ApiError::server(format!("could not serialize {BOOKS_FILE}: {e}")))?;
984 ctx.write(BOOKS_FILE, &text)?;
985
986 Ok(format!("\"{title}\" is out to {borrower} until {due}."))
987 }Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".