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::sh_weaver::actor::Author;
29use crate::sh_weaver::notebook::ContentRating;
30use crate::sh_weaver::notebook::ContentWarnings;
31use crate::sh_weaver::notebook::Path;
32use crate::sh_weaver::notebook::Tags;
33use crate::sh_weaver::notebook::Title;
34#[lexicon]
37#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
38#[serde(rename_all = "camelCase", rename = "sh.weaver.notebook.entry", tag = "$type")]
39pub struct Entry<'a> {
40 #[serde(skip_serializing_if = "Option::is_none")]
41 #[serde(borrow)]
42 pub authors: Option<Vec<Author<'a>>>,
43 #[serde(borrow)]
45 pub content: CowStr<'a>,
46 #[serde(skip_serializing_if = "Option::is_none")]
47 #[serde(borrow)]
48 pub content_warnings: Option<ContentWarnings<'a>>,
49 pub created_at: Datetime,
51 #[serde(skip_serializing_if = "Option::is_none")]
53 #[serde(borrow)]
54 pub embeds: Option<EntryEmbeds<'a>>,
55 #[serde(borrow)]
56 pub path: Path<'a>,
57 #[serde(skip_serializing_if = "Option::is_none")]
58 #[serde(borrow)]
59 pub rating: Option<ContentRating<'a>>,
60 #[serde(skip_serializing_if = "Option::is_none")]
61 #[serde(borrow)]
62 pub tags: Option<Tags<'a>>,
63 #[serde(borrow)]
64 pub title: Title<'a>,
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub updated_at: Option<Datetime>,
68}
69
70#[lexicon]
73#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
74#[serde(rename_all = "camelCase")]
75pub struct EntryEmbeds<'a> {
76 #[serde(skip_serializing_if = "Option::is_none")]
77 #[serde(borrow)]
78 pub externals: Option<crate::sh_weaver::embed::external::External<'a>>,
79 #[serde(skip_serializing_if = "Option::is_none")]
80 #[serde(borrow)]
81 pub images: Option<crate::sh_weaver::embed::images::Images<'a>>,
82 #[serde(skip_serializing_if = "Option::is_none")]
83 #[serde(borrow)]
84 pub records: Option<crate::sh_weaver::embed::records::Records<'a>>,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 #[serde(borrow)]
87 pub records_with_media: Option<
88 Vec<crate::sh_weaver::embed::record_with_media::RecordWithMedia<'a>>,
89 >,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 #[serde(borrow)]
92 pub videos: Option<crate::sh_weaver::embed::video::VideoRecord<'a>>,
93}
94
95#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
98#[serde(rename_all = "camelCase")]
99pub struct EntryGetRecordOutput<'a> {
100 #[serde(skip_serializing_if = "Option::is_none")]
101 #[serde(borrow)]
102 pub cid: Option<Cid<'a>>,
103 #[serde(borrow)]
104 pub uri: AtUri<'a>,
105 #[serde(borrow)]
106 pub value: Entry<'a>,
107}
108
109impl<'a> Entry<'a> {
110 pub fn uri(
111 uri: impl Into<CowStr<'a>>,
112 ) -> Result<RecordUri<'a, EntryRecord>, UriError> {
113 RecordUri::try_from_uri(AtUri::new_cow(uri.into())?)
114 }
115}
116
117#[derive(Debug, Serialize, Deserialize)]
120pub struct EntryRecord;
121impl XrpcResp for EntryRecord {
122 const NSID: &'static str = "sh.weaver.notebook.entry";
123 const ENCODING: &'static str = "application/json";
124 type Output<'de> = EntryGetRecordOutput<'de>;
125 type Err<'de> = RecordError<'de>;
126}
127
128impl From<EntryGetRecordOutput<'_>> for Entry<'_> {
129 fn from(output: EntryGetRecordOutput<'_>) -> Self {
130 use jacquard_common::IntoStatic;
131 output.value.into_static()
132 }
133}
134
135impl Collection for Entry<'_> {
136 const NSID: &'static str = "sh.weaver.notebook.entry";
137 type Record = EntryRecord;
138}
139
140impl Collection for EntryRecord {
141 const NSID: &'static str = "sh.weaver.notebook.entry";
142 type Record = EntryRecord;
143}
144
145impl<'a> LexiconSchema for Entry<'a> {
146 fn nsid() -> &'static str {
147 "sh.weaver.notebook.entry"
148 }
149 fn def_name() -> &'static str {
150 "main"
151 }
152 fn lexicon_doc() -> LexiconDoc<'static> {
153 lexicon_doc_sh_weaver_notebook_entry()
154 }
155 fn validate(&self) -> Result<(), ConstraintError> {
156 Ok(())
157 }
158}
159
160impl<'a> LexiconSchema for EntryEmbeds<'a> {
161 fn nsid() -> &'static str {
162 "sh.weaver.notebook.entry"
163 }
164 fn def_name() -> &'static str {
165 "EntryEmbeds"
166 }
167 fn lexicon_doc() -> LexiconDoc<'static> {
168 lexicon_doc_sh_weaver_notebook_entry()
169 }
170 fn validate(&self) -> Result<(), ConstraintError> {
171 Ok(())
172 }
173}
174
175fn lexicon_doc_sh_weaver_notebook_entry() -> LexiconDoc<'static> {
176 #[allow(unused_imports)]
177 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
178 use jacquard_lexicon::lexicon::*;
179 use alloc::collections::BTreeMap;
180 LexiconDoc {
181 lexicon: Lexicon::Lexicon1,
182 id: CowStr::new_static("sh.weaver.notebook.entry"),
183 defs: {
184 let mut map = BTreeMap::new();
185 map.insert(
186 SmolStr::new_static("main"),
187 LexUserType::Record(LexRecord {
188 description: Some(CowStr::new_static("A notebook entry")),
189 key: Some(CowStr::new_static("tid")),
190 record: LexRecordRecord::Object(LexObject {
191 required: Some(
192 vec![
193 SmolStr::new_static("content"),
194 SmolStr::new_static("title"), SmolStr::new_static("path"),
195 SmolStr::new_static("createdAt")
196 ],
197 ),
198 properties: {
199 #[allow(unused_mut)]
200 let mut map = BTreeMap::new();
201 map.insert(
202 SmolStr::new_static("authors"),
203 LexObjectProperty::Array(LexArray {
204 items: LexArrayItem::Ref(LexRef {
205 r#ref: CowStr::new_static("sh.weaver.actor.defs#author"),
206 ..Default::default()
207 }),
208 ..Default::default()
209 }),
210 );
211 map.insert(
212 SmolStr::new_static("content"),
213 LexObjectProperty::String(LexString {
214 description: Some(
215 CowStr::new_static(
216 "The content of the notebook entry. This should be some flavor of Markdown.",
217 ),
218 ),
219 ..Default::default()
220 }),
221 );
222 map.insert(
223 SmolStr::new_static("contentWarnings"),
224 LexObjectProperty::Ref(LexRef {
225 r#ref: CowStr::new_static(
226 "sh.weaver.notebook.defs#contentWarnings",
227 ),
228 ..Default::default()
229 }),
230 );
231 map.insert(
232 SmolStr::new_static("createdAt"),
233 LexObjectProperty::String(LexString {
234 description: Some(
235 CowStr::new_static(
236 "Client-declared timestamp when this was originally created.",
237 ),
238 ),
239 format: Some(LexStringFormat::Datetime),
240 ..Default::default()
241 }),
242 );
243 map.insert(
244 SmolStr::new_static("embeds"),
245 LexObjectProperty::Object(LexObject {
246 description: Some(
247 CowStr::new_static(
248 "The set of images and records, if any, embedded in the notebook entry.",
249 ),
250 ),
251 properties: {
252 #[allow(unused_mut)]
253 let mut map = BTreeMap::new();
254 map.insert(
255 SmolStr::new_static("externals"),
256 LexObjectProperty::Ref(LexRef {
257 r#ref: CowStr::new_static("sh.weaver.embed.external"),
258 ..Default::default()
259 }),
260 );
261 map.insert(
262 SmolStr::new_static("images"),
263 LexObjectProperty::Ref(LexRef {
264 r#ref: CowStr::new_static("sh.weaver.embed.images"),
265 ..Default::default()
266 }),
267 );
268 map.insert(
269 SmolStr::new_static("records"),
270 LexObjectProperty::Ref(LexRef {
271 r#ref: CowStr::new_static("sh.weaver.embed.records"),
272 ..Default::default()
273 }),
274 );
275 map.insert(
276 SmolStr::new_static("recordsWithMedia"),
277 LexObjectProperty::Array(LexArray {
278 items: LexArrayItem::Ref(LexRef {
279 r#ref: CowStr::new_static(
280 "sh.weaver.embed.recordWithMedia",
281 ),
282 ..Default::default()
283 }),
284 ..Default::default()
285 }),
286 );
287 map.insert(
288 SmolStr::new_static("videos"),
289 LexObjectProperty::Ref(LexRef {
290 r#ref: CowStr::new_static("sh.weaver.embed.video"),
291 ..Default::default()
292 }),
293 );
294 map
295 },
296 ..Default::default()
297 }),
298 );
299 map.insert(
300 SmolStr::new_static("path"),
301 LexObjectProperty::Ref(LexRef {
302 r#ref: CowStr::new_static("sh.weaver.notebook.defs#path"),
303 ..Default::default()
304 }),
305 );
306 map.insert(
307 SmolStr::new_static("rating"),
308 LexObjectProperty::Ref(LexRef {
309 r#ref: CowStr::new_static(
310 "sh.weaver.notebook.defs#contentRating",
311 ),
312 ..Default::default()
313 }),
314 );
315 map.insert(
316 SmolStr::new_static("tags"),
317 LexObjectProperty::Ref(LexRef {
318 r#ref: CowStr::new_static("sh.weaver.notebook.defs#tags"),
319 ..Default::default()
320 }),
321 );
322 map.insert(
323 SmolStr::new_static("title"),
324 LexObjectProperty::Ref(LexRef {
325 r#ref: CowStr::new_static("sh.weaver.notebook.defs#title"),
326 ..Default::default()
327 }),
328 );
329 map.insert(
330 SmolStr::new_static("updatedAt"),
331 LexObjectProperty::String(LexString {
332 description: Some(
333 CowStr::new_static(
334 "Client-declared timestamp of last modification. Used for canonicality tiebreaking in multi-author scenarios.",
335 ),
336 ),
337 format: Some(LexStringFormat::Datetime),
338 ..Default::default()
339 }),
340 );
341 map
342 },
343 ..Default::default()
344 }),
345 ..Default::default()
346 }),
347 );
348 map
349 },
350 ..Default::default()
351 }
352}
353
354pub mod entry_state {
355
356 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
357 #[allow(unused)]
358 use ::core::marker::PhantomData;
359 mod sealed {
360 pub trait Sealed {}
361 }
362 pub trait State: sealed::Sealed {
364 type Title;
365 type CreatedAt;
366 type Content;
367 type Path;
368 }
369 pub struct Empty(());
371 impl sealed::Sealed for Empty {}
372 impl State for Empty {
373 type Title = Unset;
374 type CreatedAt = Unset;
375 type Content = Unset;
376 type Path = Unset;
377 }
378 pub struct SetTitle<S: State = Empty>(PhantomData<fn() -> S>);
380 impl<S: State> sealed::Sealed for SetTitle<S> {}
381 impl<S: State> State for SetTitle<S> {
382 type Title = Set<members::title>;
383 type CreatedAt = S::CreatedAt;
384 type Content = S::Content;
385 type Path = S::Path;
386 }
387 pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
389 impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
390 impl<S: State> State for SetCreatedAt<S> {
391 type Title = S::Title;
392 type CreatedAt = Set<members::created_at>;
393 type Content = S::Content;
394 type Path = S::Path;
395 }
396 pub struct SetContent<S: State = Empty>(PhantomData<fn() -> S>);
398 impl<S: State> sealed::Sealed for SetContent<S> {}
399 impl<S: State> State for SetContent<S> {
400 type Title = S::Title;
401 type CreatedAt = S::CreatedAt;
402 type Content = Set<members::content>;
403 type Path = S::Path;
404 }
405 pub struct SetPath<S: State = Empty>(PhantomData<fn() -> S>);
407 impl<S: State> sealed::Sealed for SetPath<S> {}
408 impl<S: State> State for SetPath<S> {
409 type Title = S::Title;
410 type CreatedAt = S::CreatedAt;
411 type Content = S::Content;
412 type Path = Set<members::path>;
413 }
414 #[allow(non_camel_case_types)]
416 pub mod members {
417 pub struct title(());
419 pub struct created_at(());
421 pub struct content(());
423 pub struct path(());
425 }
426}
427
428pub struct EntryBuilder<'a, S: entry_state::State> {
430 _state: PhantomData<fn() -> S>,
431 _fields: (
432 Option<Vec<Author<'a>>>,
433 Option<CowStr<'a>>,
434 Option<ContentWarnings<'a>>,
435 Option<Datetime>,
436 Option<EntryEmbeds<'a>>,
437 Option<Path<'a>>,
438 Option<ContentRating<'a>>,
439 Option<Tags<'a>>,
440 Option<Title<'a>>,
441 Option<Datetime>,
442 ),
443 _lifetime: PhantomData<&'a ()>,
444}
445
446impl<'a> Entry<'a> {
447 pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
449 EntryBuilder::new()
450 }
451}
452
453impl<'a> EntryBuilder<'a, entry_state::Empty> {
454 pub fn new() -> Self {
456 EntryBuilder {
457 _state: PhantomData,
458 _fields: (None, None, None, None, None, None, None, None, None, None),
459 _lifetime: PhantomData,
460 }
461 }
462}
463
464impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
465 pub fn authors(mut self, value: impl Into<Option<Vec<Author<'a>>>>) -> Self {
467 self._fields.0 = value.into();
468 self
469 }
470 pub fn maybe_authors(mut self, value: Option<Vec<Author<'a>>>) -> Self {
472 self._fields.0 = value;
473 self
474 }
475}
476
477impl<'a, S> EntryBuilder<'a, S>
478where
479 S: entry_state::State,
480 S::Content: entry_state::IsUnset,
481{
482 pub fn content(
484 mut self,
485 value: impl Into<CowStr<'a>>,
486 ) -> EntryBuilder<'a, entry_state::SetContent<S>> {
487 self._fields.1 = Option::Some(value.into());
488 EntryBuilder {
489 _state: PhantomData,
490 _fields: self._fields,
491 _lifetime: PhantomData,
492 }
493 }
494}
495
496impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
497 pub fn content_warnings(
499 mut self,
500 value: impl Into<Option<ContentWarnings<'a>>>,
501 ) -> Self {
502 self._fields.2 = value.into();
503 self
504 }
505 pub fn maybe_content_warnings(mut self, value: Option<ContentWarnings<'a>>) -> Self {
507 self._fields.2 = value;
508 self
509 }
510}
511
512impl<'a, S> EntryBuilder<'a, S>
513where
514 S: entry_state::State,
515 S::CreatedAt: entry_state::IsUnset,
516{
517 pub fn created_at(
519 mut self,
520 value: impl Into<Datetime>,
521 ) -> EntryBuilder<'a, entry_state::SetCreatedAt<S>> {
522 self._fields.3 = Option::Some(value.into());
523 EntryBuilder {
524 _state: PhantomData,
525 _fields: self._fields,
526 _lifetime: PhantomData,
527 }
528 }
529}
530
531impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
532 pub fn embeds(mut self, value: impl Into<Option<EntryEmbeds<'a>>>) -> Self {
534 self._fields.4 = value.into();
535 self
536 }
537 pub fn maybe_embeds(mut self, value: Option<EntryEmbeds<'a>>) -> Self {
539 self._fields.4 = value;
540 self
541 }
542}
543
544impl<'a, S> EntryBuilder<'a, S>
545where
546 S: entry_state::State,
547 S::Path: entry_state::IsUnset,
548{
549 pub fn path(
551 mut self,
552 value: impl Into<Path<'a>>,
553 ) -> EntryBuilder<'a, entry_state::SetPath<S>> {
554 self._fields.5 = Option::Some(value.into());
555 EntryBuilder {
556 _state: PhantomData,
557 _fields: self._fields,
558 _lifetime: PhantomData,
559 }
560 }
561}
562
563impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
564 pub fn rating(mut self, value: impl Into<Option<ContentRating<'a>>>) -> Self {
566 self._fields.6 = value.into();
567 self
568 }
569 pub fn maybe_rating(mut self, value: Option<ContentRating<'a>>) -> Self {
571 self._fields.6 = value;
572 self
573 }
574}
575
576impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
577 pub fn tags(mut self, value: impl Into<Option<Tags<'a>>>) -> Self {
579 self._fields.7 = value.into();
580 self
581 }
582 pub fn maybe_tags(mut self, value: Option<Tags<'a>>) -> Self {
584 self._fields.7 = value;
585 self
586 }
587}
588
589impl<'a, S> EntryBuilder<'a, S>
590where
591 S: entry_state::State,
592 S::Title: entry_state::IsUnset,
593{
594 pub fn title(
596 mut self,
597 value: impl Into<Title<'a>>,
598 ) -> EntryBuilder<'a, entry_state::SetTitle<S>> {
599 self._fields.8 = Option::Some(value.into());
600 EntryBuilder {
601 _state: PhantomData,
602 _fields: self._fields,
603 _lifetime: PhantomData,
604 }
605 }
606}
607
608impl<'a, S: entry_state::State> EntryBuilder<'a, S> {
609 pub fn updated_at(mut self, value: impl Into<Option<Datetime>>) -> Self {
611 self._fields.9 = value.into();
612 self
613 }
614 pub fn maybe_updated_at(mut self, value: Option<Datetime>) -> Self {
616 self._fields.9 = value;
617 self
618 }
619}
620
621impl<'a, S> EntryBuilder<'a, S>
622where
623 S: entry_state::State,
624 S::Title: entry_state::IsSet,
625 S::CreatedAt: entry_state::IsSet,
626 S::Content: entry_state::IsSet,
627 S::Path: entry_state::IsSet,
628{
629 pub fn build(self) -> Entry<'a> {
631 Entry {
632 authors: self._fields.0,
633 content: self._fields.1.unwrap(),
634 content_warnings: self._fields.2,
635 created_at: self._fields.3.unwrap(),
636 embeds: self._fields.4,
637 path: self._fields.5.unwrap(),
638 rating: self._fields.6,
639 tags: self._fields.7,
640 title: self._fields.8.unwrap(),
641 updated_at: self._fields.9,
642 extra_data: Default::default(),
643 }
644 }
645 pub fn build_with_data(
647 self,
648 extra_data: BTreeMap<
649 jacquard_common::deps::smol_str::SmolStr,
650 jacquard_common::types::value::Data<'a>,
651 >,
652 ) -> Entry<'a> {
653 Entry {
654 authors: self._fields.0,
655 content: self._fields.1.unwrap(),
656 content_warnings: self._fields.2,
657 created_at: self._fields.3.unwrap(),
658 embeds: self._fields.4,
659 path: self._fields.5.unwrap(),
660 rating: self._fields.6,
661 tags: self._fields.7,
662 title: self._fields.8.unwrap(),
663 updated_at: self._fields.9,
664 extra_data: Some(extra_data),
665 }
666 }
667}