1use smallvec::SmallVec;
43use smol_str::SmolStr;
44use std::borrow::Cow;
45use std::fmt;
46
47#[derive(Clone, PartialEq, Eq, Hash)]
68pub struct Identifier(SmolStr);
69
70impl Identifier {
71 #[inline]
73 pub fn new(s: impl AsRef<str>) -> Self {
74 Self(SmolStr::new(s.as_ref()))
75 }
76
77 #[inline]
79 pub const fn from_static(s: &'static str) -> Self {
80 Self(SmolStr::new_static(s))
81 }
82
83 #[inline]
85 pub fn as_str(&self) -> &str {
86 self.0.as_str()
87 }
88
89 #[inline]
91 pub fn is_inline(&self) -> bool {
92 self.0.is_heap_allocated() == false
93 }
94
95 #[inline]
97 pub fn len(&self) -> usize {
98 self.0.len()
99 }
100
101 #[inline]
103 pub fn is_empty(&self) -> bool {
104 self.0.is_empty()
105 }
106}
107
108impl fmt::Debug for Identifier {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 write!(f, "Identifier({:?})", self.0.as_str())
111 }
112}
113
114impl fmt::Display for Identifier {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(f, "{}", self.0)
117 }
118}
119
120impl From<&str> for Identifier {
121 #[inline]
122 fn from(s: &str) -> Self {
123 Self::new(s)
124 }
125}
126
127impl From<String> for Identifier {
128 #[inline]
129 fn from(s: String) -> Self {
130 Self(SmolStr::new(&s))
131 }
132}
133
134impl From<&String> for Identifier {
135 #[inline]
136 fn from(s: &String) -> Self {
137 Self(SmolStr::new(s))
138 }
139}
140
141impl From<Cow<'_, str>> for Identifier {
142 #[inline]
143 fn from(s: Cow<'_, str>) -> Self {
144 Self(SmolStr::new(&s))
145 }
146}
147
148impl AsRef<str> for Identifier {
149 #[inline]
150 fn as_ref(&self) -> &str {
151 self.as_str()
152 }
153}
154
155impl Default for Identifier {
156 fn default() -> Self {
157 Self(SmolStr::default())
158 }
159}
160
161#[derive(Clone, PartialEq, Eq, Hash)]
183pub struct CowIdentifier<'a>(Cow<'a, str>);
184
185impl<'a> CowIdentifier<'a> {
186 #[inline]
188 pub const fn borrowed(s: &'a str) -> Self {
189 Self(Cow::Borrowed(s))
190 }
191
192 #[inline]
194 pub fn owned(s: String) -> Self {
195 Self(Cow::Owned(s))
196 }
197
198 #[inline]
200 pub fn new(s: impl Into<Cow<'a, str>>) -> Self {
201 Self(s.into())
202 }
203
204 #[inline]
206 pub fn as_str(&self) -> &str {
207 &self.0
208 }
209
210 #[inline]
212 pub fn is_borrowed(&self) -> bool {
213 matches!(self.0, Cow::Borrowed(_))
214 }
215
216 #[inline]
218 pub fn into_owned(self) -> String {
219 self.0.into_owned()
220 }
221}
222
223impl<'a> fmt::Debug for CowIdentifier<'a> {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 write!(
226 f,
227 "CowIdentifier({:?}, borrowed={})",
228 self.0.as_ref(),
229 self.is_borrowed()
230 )
231 }
232}
233
234impl<'a> fmt::Display for CowIdentifier<'a> {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 write!(f, "{}", self.0)
237 }
238}
239
240impl<'a> From<&'a str> for CowIdentifier<'a> {
241 #[inline]
242 fn from(s: &'a str) -> Self {
243 Self::borrowed(s)
244 }
245}
246
247impl From<String> for CowIdentifier<'static> {
248 #[inline]
249 fn from(s: String) -> Self {
250 Self::owned(s)
251 }
252}
253
254impl<'a> AsRef<str> for CowIdentifier<'a> {
255 #[inline]
256 fn as_ref(&self) -> &str {
257 self.as_str()
258 }
259}
260
261impl<'a> Default for CowIdentifier<'a> {
262 fn default() -> Self {
263 Self::borrowed("")
264 }
265}
266
267pub type ColumnList = SmallVec<[Identifier; 8]>;
276
277pub type ColumnNameList = SmallVec<[String; 8]>;
279
280pub type CowColumnList<'a> = SmallVec<[Cow<'a, str>; 8]>;
282
283pub type OrderByList = SmallVec<[(Identifier, crate::types::SortOrder); 4]>;
285
286pub type PartitionByList = SmallVec<[Identifier; 4]>;
288
289pub type ExprList = SmallVec<[String; 8]>;
291
292pub type ValueList<T> = SmallVec<[T; 16]>;
294
295#[derive(Debug, Clone)]
320pub struct ReusableBuilder {
321 buffer: String,
322 initial_capacity: usize,
324}
325
326impl ReusableBuilder {
327 #[inline]
329 pub fn new() -> Self {
330 Self {
331 buffer: String::new(),
332 initial_capacity: 0,
333 }
334 }
335
336 #[inline]
338 pub fn with_capacity(capacity: usize) -> Self {
339 Self {
340 buffer: String::with_capacity(capacity),
341 initial_capacity: capacity,
342 }
343 }
344
345 #[inline]
347 pub fn push(&mut self, s: &str) -> &mut Self {
348 self.buffer.push_str(s);
349 self
350 }
351
352 #[inline]
354 pub fn push_char(&mut self, c: char) -> &mut Self {
355 self.buffer.push(c);
356 self
357 }
358
359 #[inline]
361 pub fn push_fmt(&mut self, args: fmt::Arguments<'_>) -> &mut Self {
362 use std::fmt::Write;
363 let _ = self.buffer.write_fmt(args);
364 self
365 }
366
367 #[inline]
369 pub fn space(&mut self) -> &mut Self {
370 self.buffer.push(' ');
371 self
372 }
373
374 #[inline]
376 pub fn comma(&mut self) -> &mut Self {
377 self.buffer.push_str(", ");
378 self
379 }
380
381 #[inline]
383 pub fn as_str(&self) -> &str {
384 &self.buffer
385 }
386
387 #[inline]
389 pub fn len(&self) -> usize {
390 self.buffer.len()
391 }
392
393 #[inline]
395 pub fn is_empty(&self) -> bool {
396 self.buffer.is_empty()
397 }
398
399 #[inline]
401 pub fn build(&self) -> String {
402 self.buffer.clone()
403 }
404
405 #[inline]
407 pub fn take(&mut self) -> String {
408 std::mem::take(&mut self.buffer)
409 }
410
411 #[inline]
413 pub fn reset(&mut self) {
414 self.buffer.clear();
415 }
416
417 #[inline]
419 pub fn reset_shrink(&mut self) {
420 self.buffer.clear();
421 if self.buffer.capacity() > self.initial_capacity * 2 {
422 self.buffer.shrink_to(self.initial_capacity);
423 }
424 }
425
426 #[inline]
428 pub fn reserve(&mut self, additional: usize) {
429 self.buffer.reserve(additional);
430 }
431
432 #[inline]
434 pub fn capacity(&self) -> usize {
435 self.buffer.capacity()
436 }
437}
438
439impl Default for ReusableBuilder {
440 fn default() -> Self {
441 Self::new()
442 }
443}
444
445impl fmt::Display for ReusableBuilder {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 write!(f, "{}", self.buffer)
448 }
449}
450
451impl From<ReusableBuilder> for String {
452 fn from(builder: ReusableBuilder) -> String {
453 builder.buffer
454 }
455}
456
457pub struct BuilderPool {
480 builders: parking_lot::Mutex<Vec<ReusableBuilder>>,
481 capacity: usize,
482}
483
484impl BuilderPool {
485 pub fn new(pool_size: usize, builder_capacity: usize) -> Self {
487 let builders: Vec<_> = (0..pool_size)
488 .map(|_| ReusableBuilder::with_capacity(builder_capacity))
489 .collect();
490 Self {
491 builders: parking_lot::Mutex::new(builders),
492 capacity: builder_capacity,
493 }
494 }
495
496 #[inline]
498 pub fn get(&self) -> ReusableBuilder {
499 self.builders
500 .lock()
501 .pop()
502 .unwrap_or_else(|| ReusableBuilder::with_capacity(self.capacity))
503 }
504
505 #[inline]
507 pub fn put(&self, mut builder: ReusableBuilder) {
508 builder.reset_shrink();
509 self.builders.lock().push(builder);
510 }
511
512 pub fn len(&self) -> usize {
514 self.builders.lock().len()
515 }
516
517 pub fn is_empty(&self) -> bool {
519 self.builders.lock().is_empty()
520 }
521}
522
523#[derive(Debug, Clone, Default)]
532pub struct OptimizedWindowSpec {
533 pub partition_by: PartitionByList,
535 pub order_by: SmallVec<[(Identifier, crate::types::SortOrder); 4]>,
537 pub frame: Option<WindowFrame>,
539 pub window_ref: Option<Identifier>,
541}
542
543#[derive(Debug, Clone)]
545pub struct WindowFrame {
546 pub frame_type: FrameType,
548 pub start: FrameBound,
550 pub end: Option<FrameBound>,
552}
553
554#[derive(Debug, Clone, Copy, PartialEq, Eq)]
556pub enum FrameType {
557 Rows,
558 Range,
559 Groups,
560}
561
562#[derive(Debug, Clone, PartialEq, Eq)]
564pub enum FrameBound {
565 UnboundedPreceding,
566 Preceding(u32),
567 CurrentRow,
568 Following(u32),
569 UnboundedFollowing,
570}
571
572impl OptimizedWindowSpec {
573 #[inline]
575 pub fn new() -> Self {
576 Self::default()
577 }
578
579 #[inline]
581 pub fn partition_by<I, S>(mut self, columns: I) -> Self
582 where
583 I: IntoIterator<Item = S>,
584 S: Into<Identifier>,
585 {
586 self.partition_by.extend(columns.into_iter().map(Into::into));
587 self
588 }
589
590 #[inline]
592 pub fn partition_by_col(mut self, column: impl Into<Identifier>) -> Self {
593 self.partition_by.push(column.into());
594 self
595 }
596
597 #[inline]
599 pub fn order_by(
600 mut self,
601 column: impl Into<Identifier>,
602 order: crate::types::SortOrder,
603 ) -> Self {
604 self.order_by.push((column.into(), order));
605 self
606 }
607
608 #[inline]
610 pub fn rows(mut self, start: FrameBound, end: Option<FrameBound>) -> Self {
611 self.frame = Some(WindowFrame {
612 frame_type: FrameType::Rows,
613 start,
614 end,
615 });
616 self
617 }
618
619 #[inline]
621 pub fn rows_unbounded_preceding(self) -> Self {
622 self.rows(FrameBound::UnboundedPreceding, Some(FrameBound::CurrentRow))
623 }
624
625 #[inline]
627 pub fn window_ref(mut self, name: impl Into<Identifier>) -> Self {
628 self.window_ref = Some(name.into());
629 self
630 }
631
632 pub fn to_sql(&self, _db_type: crate::sql::DatabaseType) -> String {
634 let mut parts: SmallVec<[String; 4]> = SmallVec::new();
635
636 if let Some(ref name) = self.window_ref {
638 return format!("OVER {}", name);
639 }
640
641 if !self.partition_by.is_empty() {
643 let cols: Vec<_> = self.partition_by.iter().map(|c| c.as_str()).collect();
644 parts.push(format!("PARTITION BY {}", cols.join(", ")));
645 }
646
647 if !self.order_by.is_empty() {
649 let cols: Vec<_> = self
650 .order_by
651 .iter()
652 .map(|(col, order)| {
653 format!(
654 "{} {}",
655 col.as_str(),
656 match order {
657 crate::types::SortOrder::Asc => "ASC",
658 crate::types::SortOrder::Desc => "DESC",
659 }
660 )
661 })
662 .collect();
663 parts.push(format!("ORDER BY {}", cols.join(", ")));
664 }
665
666 if let Some(ref frame) = self.frame {
668 let frame_type = match frame.frame_type {
669 FrameType::Rows => "ROWS",
670 FrameType::Range => "RANGE",
671 FrameType::Groups => "GROUPS",
672 };
673
674 let start = frame_bound_to_sql(&frame.start);
675
676 if let Some(ref end) = frame.end {
677 let end_sql = frame_bound_to_sql(end);
678 parts.push(format!("{} BETWEEN {} AND {}", frame_type, start, end_sql));
679 } else {
680 parts.push(format!("{} {}", frame_type, start));
681 }
682 }
683
684 if parts.is_empty() {
685 "OVER ()".to_string()
686 } else {
687 format!("OVER ({})", parts.join(" "))
688 }
689 }
690}
691
692fn frame_bound_to_sql(bound: &FrameBound) -> &'static str {
693 match bound {
694 FrameBound::UnboundedPreceding => "UNBOUNDED PRECEDING",
695 FrameBound::Preceding(_) => "PRECEDING", FrameBound::CurrentRow => "CURRENT ROW",
697 FrameBound::Following(_) => "FOLLOWING", FrameBound::UnboundedFollowing => "UNBOUNDED FOLLOWING",
699 }
700}
701
702#[cfg(test)]
707mod tests {
708 use super::*;
709
710 #[test]
711 fn test_identifier_inline() {
712 let id = Identifier::new("user_id");
713 assert_eq!(id.as_str(), "user_id");
714 assert!(id.is_inline()); }
716
717 #[test]
718 fn test_identifier_from_static() {
719 let id = Identifier::from_static("email");
720 assert_eq!(id.as_str(), "email");
721 }
722
723 #[test]
724 fn test_cow_identifier_borrowed() {
725 let id = CowIdentifier::borrowed("user_id");
726 assert!(id.is_borrowed());
727 assert_eq!(id.as_str(), "user_id");
728 }
729
730 #[test]
731 fn test_cow_identifier_owned() {
732 let id = CowIdentifier::owned("dynamic".to_string());
733 assert!(!id.is_borrowed());
734 assert_eq!(id.as_str(), "dynamic");
735 }
736
737 #[test]
738 fn test_column_list_stack_allocation() {
739 let mut cols: ColumnList = SmallVec::new();
740 cols.push(Identifier::new("id"));
741 cols.push(Identifier::new("name"));
742 cols.push(Identifier::new("email"));
743 cols.push(Identifier::new("created_at"));
744
745 assert!(!cols.spilled());
747 assert_eq!(cols.len(), 4);
748 }
749
750 #[test]
751 fn test_column_list_heap_spillover() {
752 let mut cols: ColumnList = SmallVec::new();
753 for i in 0..10 {
754 cols.push(Identifier::new(format!("col_{}", i)));
755 }
756
757 assert!(cols.spilled());
759 assert_eq!(cols.len(), 10);
760 }
761
762 #[test]
763 fn test_reusable_builder() {
764 let mut builder = ReusableBuilder::with_capacity(64);
765
766 builder.push("SELECT * FROM users");
767 assert_eq!(builder.as_str(), "SELECT * FROM users");
768
769 builder.reset();
770 assert!(builder.is_empty());
771 assert!(builder.capacity() >= 64); builder.push("SELECT * FROM posts");
774 assert_eq!(builder.as_str(), "SELECT * FROM posts");
775 }
776
777 #[test]
778 fn test_reusable_builder_take() {
779 let mut builder = ReusableBuilder::new();
780 builder.push("test");
781
782 let taken = builder.take();
783 assert_eq!(taken, "test");
784 assert!(builder.is_empty());
785 }
786
787 #[test]
788 fn test_builder_pool() {
789 let pool = BuilderPool::new(4, 128);
790
791 let b1 = pool.get();
793 let b2 = pool.get();
794 let _b3 = pool.get();
795 let _b4 = pool.get();
796
797 assert!(pool.is_empty());
799
800 pool.put(b1);
802 pool.put(b2);
803
804 assert_eq!(pool.len(), 2);
805 }
806
807 #[test]
808 fn test_optimized_window_spec() {
809 use crate::types::SortOrder;
810
811 let spec = OptimizedWindowSpec::new()
812 .partition_by(["dept", "team"])
813 .order_by("salary", SortOrder::Desc)
814 .rows_unbounded_preceding();
815
816 let sql = spec.to_sql(crate::sql::DatabaseType::PostgreSQL);
817 assert!(sql.contains("PARTITION BY"));
818 assert!(sql.contains("ORDER BY"));
819 assert!(sql.contains("ROWS"));
820 }
821}
822
823
824