1#[allow(unused_imports)]
9use alloc::collections::BTreeMap;
10
11#[allow(unused_imports)]
12use core::marker::PhantomData;
13use jacquard_common::CowStr;
14
15#[allow(unused_imports)]
16use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
17use jacquard_common::types::collection::{Collection, RecordError};
18use jacquard_common::types::string::{AtUri, Cid, Datetime};
19use jacquard_common::types::uri::{RecordUri, UriError};
20use jacquard_common::xrpc::XrpcResp;
21use jacquard_derive::{IntoStatic, lexicon};
22use jacquard_lexicon::lexicon::LexiconDoc;
23use jacquard_lexicon::schema::LexiconSchema;
24
25#[allow(unused_imports)]
26use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
27use serde::{Serialize, Deserialize};
28use crate::com_whtwnd::blog::BlobMetadata;
29use crate::com_whtwnd::blog::Ogp;
30#[lexicon]
33#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
34#[serde(rename_all = "camelCase", rename = "com.whtwnd.blog.entry", tag = "$type")]
35pub struct Entry<'a> {
36 #[serde(skip_serializing_if = "Option::is_none")]
37 #[serde(borrow)]
38 pub blobs: Option<Vec<BlobMetadata<'a>>>,
39 #[serde(borrow)]
40 pub content: CowStr<'a>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub created_at: Option<Datetime>,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub is_draft: Option<bool>,
46 #[serde(skip_serializing_if = "Option::is_none")]
47 #[serde(borrow)]
48 pub ogp: Option<Ogp<'a>>,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 #[serde(borrow)]
51 pub subtitle: Option<CowStr<'a>>,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 #[serde(borrow)]
54 pub theme: Option<CowStr<'a>>,
55 #[serde(skip_serializing_if = "Option::is_none")]
56 #[serde(borrow)]
57 pub title: Option<CowStr<'a>>,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 #[serde(default = "_default_entry_visibility")]
61 #[serde(borrow)]
62 pub visibility: Option<CowStr<'a>>,
63}
64
65#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
68#[serde(rename_all = "camelCase")]
69pub struct EntryGetRecordOutput<'a> {
70 #[serde(skip_serializing_if = "Option::is_none")]
71 #[serde(borrow)]
72 pub cid: Option<Cid<'a>>,
73 #[serde(borrow)]
74 pub uri: AtUri<'a>,
75 #[serde(borrow)]
76 pub value: Entry<'a>,
77}
78
79impl<'a> Entry<'a> {
80 pub fn uri(
81 uri: impl Into<CowStr<'a>>,
82 ) -> Result<RecordUri<'a, EntryRecord>, UriError> {
83 RecordUri::try_from_uri(AtUri::new_cow(uri.into())?)
84 }
85}
86
87#[derive(Debug, Serialize, Deserialize)]
90pub struct EntryRecord;
91impl XrpcResp for EntryRecord {
92 const NSID: &'static str = "com.whtwnd.blog.entry";
93 const ENCODING: &'static str = "application/json";
94 type Output<'de> = EntryGetRecordOutput<'de>;
95 type Err<'de> = RecordError<'de>;
96}
97
98impl From<EntryGetRecordOutput<'_>> for Entry<'_> {
99 fn from(output: EntryGetRecordOutput<'_>) -> Self {
100 use jacquard_common::IntoStatic;
101 output.value.into_static()
102 }
103}
104
105impl Collection for Entry<'_> {
106 const NSID: &'static str = "com.whtwnd.blog.entry";
107 type Record = EntryRecord;
108}
109
110impl Collection for EntryRecord {
111 const NSID: &'static str = "com.whtwnd.blog.entry";
112 type Record = EntryRecord;
113}
114
115impl<'a> LexiconSchema for Entry<'a> {
116 fn nsid() -> &'static str {
117 "com.whtwnd.blog.entry"
118 }
119 fn def_name() -> &'static str {
120 "main"
121 }
122 fn lexicon_doc() -> LexiconDoc<'static> {
123 lexicon_doc_com_whtwnd_blog_entry()
124 }
125 fn validate(&self) -> Result<(), ConstraintError> {
126 {
127 let value = &self.content;
128 #[allow(unused_comparisons)]
129 if <str>::len(value.as_ref()) > 100000usize {
130 return Err(ConstraintError::MaxLength {
131 path: ValidationPath::from_field("content"),
132 max: 100000usize,
133 actual: <str>::len(value.as_ref()),
134 });
135 }
136 }
137 if let Some(ref value) = self.subtitle {
138 #[allow(unused_comparisons)]
139 if <str>::len(value.as_ref()) > 1000usize {
140 return Err(ConstraintError::MaxLength {
141 path: ValidationPath::from_field("subtitle"),
142 max: 1000usize,
143 actual: <str>::len(value.as_ref()),
144 });
145 }
146 }
147 if let Some(ref value) = self.title {
148 #[allow(unused_comparisons)]
149 if <str>::len(value.as_ref()) > 1000usize {
150 return Err(ConstraintError::MaxLength {
151 path: ValidationPath::from_field("title"),
152 max: 1000usize,
153 actual: <str>::len(value.as_ref()),
154 });
155 }
156 }
157 Ok(())
158 }
159}
160
161fn _default_entry_visibility() -> Option<CowStr<'static>> {
162 Some(CowStr::from("public"))
163}
164
165pub mod entry_state {
166
167 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
168 #[allow(unused)]
169 use ::core::marker::PhantomData;
170 mod sealed {
171 pub trait Sealed {}
172 }
173 pub trait State: sealed::Sealed {
175 type Content;
176 }
177 pub struct Empty(());
179 impl sealed::Sealed for Empty {}
180 impl State for Empty {
181 type Content = Unset;
182 }
183 pub struct SetContent<S: State = Empty>(PhantomData<fn() -> S>);
185 impl<S: State> sealed::Sealed for SetContent<S> {}
186 impl<S: State> State for SetContent<S> {
187 type Content = Set<members::content>;
188 }
189 #[allow(non_camel_case_types)]
191 pub mod members {
192 pub struct content(());
194 }
195}
196
197pub struct EntryBuilder<'a, S: entry_state::State> {
199 _state: PhantomData<fn() -> S>,
200 _fields: (
201 Option<Vec<BlobMetadata<'a>>>,
202 Option<CowStr<'a>>,
203 Option<Datetime>,
204 Option<bool>,
205 Option<Ogp<'a>>,
206 Option<CowStr<'a>>,
207 Option<CowStr<'a>>,
208 Option<CowStr<'a>>,
209 Option<CowStr<'a>>,
210 ),
211 _lifetime: PhantomData<&'a ()>,
212}
213
214impl<'a> Entry<'a> {
215 pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
217 EntryBuilder::new()
218 }
219}
220
221impl<'a> EntryBuilder<'a, entry_state::Empty> {
222 pub fn new() -> Self {
224 EntryBuilder {
225 _state: PhantomData,
226 _fields: (None, None, None, None, None, None, None, None, None),
227 _lifetime: PhantomData,
228 }
229 }
230}
231
232impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
233 pub fn blobs(mut self, value: impl Into<Option<Vec<BlobMetadata<'a>>>>) -> Self {
235 self._fields.0 = value.into();
236 self
237 }
238 pub fn maybe_blobs(mut self, value: Option<Vec<BlobMetadata<'a>>>) -> Self {
240 self._fields.0 = value;
241 self
242 }
243}
244
245impl<'a, S> EntryBuilder<'a, S>
246where
247 S: entry_state::State,
248 S::Content: entry_state::IsUnset,
249{
250 pub fn content(
252 mut self,
253 value: impl Into<CowStr<'a>>,
254 ) -> EntryBuilder<'a, entry_state::SetContent<S>> {
255 self._fields.1 = Option::Some(value.into());
256 EntryBuilder {
257 _state: PhantomData,
258 _fields: self._fields,
259 _lifetime: PhantomData,
260 }
261 }
262}
263
264impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
265 pub fn created_at(mut self, value: impl Into<Option<Datetime>>) -> Self {
267 self._fields.2 = value.into();
268 self
269 }
270 pub fn maybe_created_at(mut self, value: Option<Datetime>) -> Self {
272 self._fields.2 = value;
273 self
274 }
275}
276
277impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
278 pub fn is_draft(mut self, value: impl Into<Option<bool>>) -> Self {
280 self._fields.3 = value.into();
281 self
282 }
283 pub fn maybe_is_draft(mut self, value: Option<bool>) -> Self {
285 self._fields.3 = value;
286 self
287 }
288}
289
290impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
291 pub fn ogp(mut self, value: impl Into<Option<Ogp<'a>>>) -> Self {
293 self._fields.4 = value.into();
294 self
295 }
296 pub fn maybe_ogp(mut self, value: Option<Ogp<'a>>) -> Self {
298 self._fields.4 = value;
299 self
300 }
301}
302
303impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
304 pub fn subtitle(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
306 self._fields.5 = value.into();
307 self
308 }
309 pub fn maybe_subtitle(mut self, value: Option<CowStr<'a>>) -> Self {
311 self._fields.5 = value;
312 self
313 }
314}
315
316impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
317 pub fn theme(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
319 self._fields.6 = value.into();
320 self
321 }
322 pub fn maybe_theme(mut self, value: Option<CowStr<'a>>) -> Self {
324 self._fields.6 = value;
325 self
326 }
327}
328
329impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
330 pub fn title(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
332 self._fields.7 = value.into();
333 self
334 }
335 pub fn maybe_title(mut self, value: Option<CowStr<'a>>) -> Self {
337 self._fields.7 = value;
338 self
339 }
340}
341
342impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
343 pub fn visibility(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
345 self._fields.8 = value.into();
346 self
347 }
348 pub fn maybe_visibility(mut self, value: Option<CowStr<'a>>) -> Self {
350 self._fields.8 = value;
351 self
352 }
353}
354
355impl<'a, S> EntryBuilder<'a, S>
356where
357 S: entry_state::State,
358 S::Content: entry_state::IsSet,
359{
360 pub fn build(self) -> Entry<'a> {
362 Entry {
363 blobs: self._fields.0,
364 content: self._fields.1.unwrap(),
365 created_at: self._fields.2,
366 is_draft: self._fields.3,
367 ogp: self._fields.4,
368 subtitle: self._fields.5,
369 theme: self._fields.6,
370 title: self._fields.7,
371 visibility: self._fields.8.or_else(|| Some(CowStr::from("public"))),
372 extra_data: Default::default(),
373 }
374 }
375 pub fn build_with_data(
377 self,
378 extra_data: BTreeMap<
379 jacquard_common::deps::smol_str::SmolStr,
380 jacquard_common::types::value::Data<'a>,
381 >,
382 ) -> Entry<'a> {
383 Entry {
384 blobs: self._fields.0,
385 content: self._fields.1.unwrap(),
386 created_at: self._fields.2,
387 is_draft: self._fields.3,
388 ogp: self._fields.4,
389 subtitle: self._fields.5,
390 theme: self._fields.6,
391 title: self._fields.7,
392 visibility: self._fields.8.or_else(|| Some(CowStr::from("public"))),
393 extra_data: Some(extra_data),
394 }
395 }
396}
397
398fn lexicon_doc_com_whtwnd_blog_entry() -> LexiconDoc<'static> {
399 #[allow(unused_imports)]
400 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
401 use jacquard_lexicon::lexicon::*;
402 use alloc::collections::BTreeMap;
403 LexiconDoc {
404 lexicon: Lexicon::Lexicon1,
405 id: CowStr::new_static("com.whtwnd.blog.entry"),
406 defs: {
407 let mut map = BTreeMap::new();
408 map.insert(
409 SmolStr::new_static("main"),
410 LexUserType::Record(LexRecord {
411 description: Some(CowStr::new_static("A declaration of a post.")),
412 key: Some(CowStr::new_static("tid")),
413 record: LexRecordRecord::Object(LexObject {
414 required: Some(vec![SmolStr::new_static("content")]),
415 properties: {
416 #[allow(unused_mut)]
417 let mut map = BTreeMap::new();
418 map.insert(
419 SmolStr::new_static("blobs"),
420 LexObjectProperty::Array(LexArray {
421 items: LexArrayItem::Ref(LexRef {
422 r#ref: CowStr::new_static(
423 "com.whtwnd.blog.defs#blobMetadata",
424 ),
425 ..Default::default()
426 }),
427 ..Default::default()
428 }),
429 );
430 map.insert(
431 SmolStr::new_static("content"),
432 LexObjectProperty::String(LexString {
433 max_length: Some(100000usize),
434 ..Default::default()
435 }),
436 );
437 map.insert(
438 SmolStr::new_static("createdAt"),
439 LexObjectProperty::String(LexString {
440 format: Some(LexStringFormat::Datetime),
441 ..Default::default()
442 }),
443 );
444 map.insert(
445 SmolStr::new_static("isDraft"),
446 LexObjectProperty::Boolean(LexBoolean {
447 ..Default::default()
448 }),
449 );
450 map.insert(
451 SmolStr::new_static("ogp"),
452 LexObjectProperty::Ref(LexRef {
453 r#ref: CowStr::new_static("com.whtwnd.blog.defs#ogp"),
454 ..Default::default()
455 }),
456 );
457 map.insert(
458 SmolStr::new_static("subtitle"),
459 LexObjectProperty::String(LexString {
460 max_length: Some(1000usize),
461 ..Default::default()
462 }),
463 );
464 map.insert(
465 SmolStr::new_static("theme"),
466 LexObjectProperty::String(LexString {
467 ..Default::default()
468 }),
469 );
470 map.insert(
471 SmolStr::new_static("title"),
472 LexObjectProperty::String(LexString {
473 max_length: Some(1000usize),
474 ..Default::default()
475 }),
476 );
477 map.insert(
478 SmolStr::new_static("visibility"),
479 LexObjectProperty::String(LexString {
480 description: Some(
481 CowStr::new_static(
482 "Tells the visibility of the article to AppView.",
483 ),
484 ),
485 ..Default::default()
486 }),
487 );
488 map
489 },
490 ..Default::default()
491 }),
492 ..Default::default()
493 }),
494 );
495 map
496 },
497 ..Default::default()
498 }
499}