1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
6#[serde(rename_all = "lowercase")]
7pub enum CollectionMode {
8 Jsonb,
9 Typed,
10}
11
12impl CollectionMode {
13 pub fn as_str(&self) -> &'static str {
14 match self {
15 Self::Jsonb => "jsonb",
16 Self::Typed => "typed",
17 }
18 }
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct Site {
23 pub display_name: String,
24 pub metadata: Value,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct Collection {
29 pub collection_name: String,
30 pub mode: CollectionMode,
31 pub table_name: Option<String>,
32 pub strict_contract: Option<ContractSchema>,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct RegisterSiteRequest {
37 pub display_name: String,
38 #[serde(default = "default_object")]
39 pub metadata: Value,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct RegisterCollectionRequest {
44 pub collection_name: String,
45 pub mode: CollectionMode,
46 pub table_name: Option<String>,
47 pub strict_contract: Option<ContractSchema>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct RegisterCustomSchemaRequest {
52 pub definition: CustomSchemaDefinition,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct UpsertEntryRequest {
57 pub collection_name: String,
58 pub entry_key: String,
59 pub payload: Value,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct QueryEntriesRequest {
64 pub collection_name: String,
65 #[serde(default)]
66 pub entry_keys: Vec<String>,
67 pub contains: Option<Value>,
68 #[serde(default = "default_limit")]
69 pub limit: i64,
70 #[serde(default)]
71 pub offset: i64,
72 #[serde(default)]
73 pub visitor_id: Option<String>,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct EntryRecord {
78 pub entry_key: String,
79 pub payload: Value,
80 pub updated_at: DateTime<Utc>,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct ExportSiteRequest;
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct ImportSiteRequest {
88 pub export: SiteExport,
89 #[serde(default)]
90 pub overwrite_contracts: bool,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct ImportResult {
95 pub collections_imported: usize,
96 pub entries_imported: usize,
97 pub contracts_imported: usize,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct VerifyContractRequest {
102 pub collection_name: String,
103 pub samples: Vec<Value>,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct SiteExport {
108 pub site: Site,
109 pub collections: Vec<Collection>,
110 pub custom_schema: Option<CustomSchemaDefinition>,
111 pub contracts: Vec<CollectionContractRecord>,
112 pub entries: Vec<CollectionEntriesExport>,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct CollectionEntriesExport {
117 pub collection_name: String,
118 pub entries: Vec<EntryRecord>,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct CollectionContractRecord {
123 pub collection_name: String,
124 pub version: i32,
125 pub contract: ContractSchema,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct CustomSchemaApplyReport {
130 pub applied: bool,
131 pub version: i32,
132 pub additive_changes: Vec<String>,
133 pub breaking_changes: Vec<String>,
134 pub generated_sql: Vec<String>,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct ContractVerificationReport {
139 pub passes: bool,
140 pub additive_changes: Vec<String>,
141 pub breaking_changes: Vec<String>,
142 pub stored_contract: Option<ContractSchema>,
143 pub incoming_contract: ContractSchema,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct DefaultPageTemplate {
148 pub key: String,
149 pub title: String,
150 pub route: String,
151 pub section: String,
152}
153
154impl DefaultPageTemplate {
155 pub fn new(key: &str, title: &str, route: &str, section: &str) -> Self {
156 Self {
157 key: key.to_string(),
158 title: title.to_string(),
159 route: route.to_string(),
160 section: section.to_string(),
161 }
162 }
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct SiteBootstrapReport {
167 pub collections_seeded: usize,
168 pub entries_seeded: usize,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct ContractSchema {
173 pub fields: Vec<ContractField>,
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct ContractField {
178 pub path: String,
179 pub required: bool,
180 pub types: Vec<ValueType>,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
184#[serde(rename_all = "lowercase")]
185pub enum ValueType {
186 String,
187 Number,
188 Boolean,
189 Object,
190 Array,
191 Null,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct CustomSchemaDefinition {
196 #[serde(default)]
197 pub types: Vec<CustomTypeDefinition>,
198 #[serde(default)]
199 pub tables: Vec<CustomTableDefinition>,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
203#[serde(tag = "kind", rename_all = "snake_case")]
204pub enum CustomTypeDefinition {
205 Enum {
206 name: String,
207 values: Vec<String>,
208 },
209 Composite {
210 name: String,
211 fields: Vec<CustomColumnDefinition>,
212 },
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct CustomTableDefinition {
217 pub name: String,
218 #[serde(default)]
219 pub columns: Vec<CustomColumnDefinition>,
220 #[serde(default)]
221 pub primary_key: Vec<String>,
222 #[serde(default)]
223 pub unique_constraints: Vec<UniqueConstraintDefinition>,
224 #[serde(default)]
225 pub foreign_keys: Vec<ForeignKeyDefinition>,
226 #[serde(default)]
227 pub indexes: Vec<IndexDefinition>,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct CustomColumnDefinition {
232 pub name: String,
233 pub data_type: String,
234 #[serde(default)]
235 pub nullable: bool,
236 pub default_sql: Option<String>,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize)]
240pub struct UniqueConstraintDefinition {
241 pub name: Option<String>,
242 pub columns: Vec<String>,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct ForeignKeyDefinition {
247 pub name: Option<String>,
248 pub columns: Vec<String>,
249 pub ref_table: String,
250 pub ref_columns: Vec<String>,
251 pub on_delete: Option<String>,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct IndexDefinition {
256 pub name: Option<String>,
257 pub columns: Vec<String>,
258 #[serde(default)]
259 pub unique: bool,
260}
261
262#[cfg(feature = "storage")]
263#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct Asset {
265 pub id: uuid::Uuid,
266 pub filename: String,
267 pub original_key: String,
268 pub content_type: String,
269 pub size_bytes: i64,
270 pub width: Option<i32>,
271 pub height: Option<i32>,
272 pub variants: Value,
273 pub alt_text: Option<String>,
274 pub metadata: Value,
275 pub created_at: DateTime<Utc>,
276 pub updated_at: DateTime<Utc>,
277}
278
279#[cfg(feature = "storage")]
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct AssetVariant {
282 pub suffix: String,
283 pub key: String,
284 pub url: String,
285 pub content_type: String,
286 pub width: u32,
287 pub height: u32,
288}
289
290#[cfg(feature = "storage")]
291#[derive(Debug, Clone, Serialize, Deserialize)]
292pub struct QueryAssetsParams {
293 #[serde(default = "default_assets_limit")]
294 pub limit: i64,
295 #[serde(default)]
296 pub offset: i64,
297}
298
299#[cfg(feature = "storage")]
300fn default_assets_limit() -> i64 {
301 50
302}
303
304#[cfg(feature = "storage")]
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct UpdateAssetRequest {
307 pub alt_text: Option<String>,
308 pub metadata: Option<Value>,
309}
310
311fn default_object() -> Value {
312 Value::Object(Default::default())
313}
314
315fn default_limit() -> i64 {
316 100
317}