1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//! Sidecar view designs (step 71.1, item M93).
//!
//! A view is a named `SELECT` stored in the sidecar (ADR-1 design
//! authority); execution follows the sink/source rule — SQLite applies it
//! natively, while Jet/ACE/CSV run it through the shadow SQL engine.
use serde::{Deserialize, Serialize};
/// A named SELECT stored as a sidecar design object.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ViewDef {
/// View name (unique against tables and other views, case-insensitive).
pub name: String,
/// The SELECT statement (SQLite dialect, executed by the shadow engine
/// on Jet/ACE/CSV and applied natively on SQLite).
pub sql: String,
}
impl ViewDef {
/// Creates a view definition.
pub fn new(name: impl Into<String>, sql: impl Into<String>) -> Self {
Self {
name: name.into(),
sql: sql.into(),
}
}
/// Whether the statement is a `SELECT`/`WITH` query — the shape gate the
/// create/update commands enforce.
pub fn is_select(&self) -> bool {
self.sql.split_whitespace().next().is_some_and(|word| {
word.eq_ignore_ascii_case("select") || word.eq_ignore_ascii_case("with")
})
}
}
/// Sidecar view commands (step 71.1, item M93) — one variant per action,
/// carried as `Command::View`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "action")]
#[non_exhaustive]
pub enum ViewCommand {
/// Creates a named SELECT view (unique against tables and views).
Create {
/// View name.
name: String,
/// The SELECT statement.
sql: String,
},
/// Replaces a view's SELECT statement.
SetSql {
/// Target view name (case-insensitive).
name: String,
/// The new SELECT statement.
sql: String,
},
/// Deletes a view and closes its tabs.
Delete {
/// Target view name (case-insensitive).
name: String,
},
}