1use smallvec::SmallVec;
43use smol_str::SmolStr;
44use std::borrow::Cow;
45use std::fmt;
46
47#[derive(Clone, PartialEq, Eq, Hash, Default)]
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()
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
155#[derive(Clone, PartialEq, Eq, Hash)]
177pub struct CowIdentifier<'a>(Cow<'a, str>);
178
179impl<'a> CowIdentifier<'a> {
180 #[inline]
182 pub const fn borrowed(s: &'a str) -> Self {
183 Self(Cow::Borrowed(s))
184 }
185
186 #[inline]
188 pub fn owned(s: String) -> Self {
189 Self(Cow::Owned(s))
190 }
191
192 #[inline]
194 pub fn new(s: impl Into<Cow<'a, str>>) -> Self {
195 Self(s.into())
196 }
197
198 #[inline]
200 pub fn as_str(&self) -> &str {
201 &self.0
202 }
203
204 #[inline]
206 pub fn is_borrowed(&self) -> bool {
207 matches!(self.0, Cow::Borrowed(_))
208 }
209
210 #[inline]
212 pub fn into_owned(self) -> String {
213 self.0.into_owned()
214 }
215}
216
217impl<'a> fmt::Debug for CowIdentifier<'a> {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 write!(
220 f,
221 "CowIdentifier({:?}, borrowed={})",
222 self.0.as_ref(),
223 self.is_borrowed()
224 )
225 }
226}
227
228impl<'a> fmt::Display for CowIdentifier<'a> {
229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 write!(f, "{}", self.0)
231 }
232}
233
234impl<'a> From<&'a str> for CowIdentifier<'a> {
235 #[inline]
236 fn from(s: &'a str) -> Self {
237 Self::borrowed(s)
238 }
239}
240
241impl From<String> for CowIdentifier<'static> {
242 #[inline]
243 fn from(s: String) -> Self {
244 Self::owned(s)
245 }
246}
247
248impl<'a> AsRef<str> for CowIdentifier<'a> {
249 #[inline]
250 fn as_ref(&self) -> &str {
251 self.as_str()
252 }
253}
254
255impl<'a> Default for CowIdentifier<'a> {
256 fn default() -> Self {
257 Self::borrowed("")
258 }
259}
260
261pub type ColumnList = SmallVec<[Identifier; 8]>;
270
271pub type ColumnNameList = SmallVec<[String; 8]>;
273
274pub type CowColumnList<'a> = SmallVec<[Cow<'a, str>; 8]>;
276
277pub type OrderByList = SmallVec<[(Identifier, crate::types::SortOrder); 4]>;
279
280pub type PartitionByList = SmallVec<[Identifier; 4]>;
282
283pub type ExprList = SmallVec<[String; 8]>;
285
286pub type ValueList<T> = SmallVec<[T; 16]>;
288
289#[derive(Debug, Clone)]
314pub struct ReusableBuilder {
315 buffer: String,
316 initial_capacity: usize,
318}
319
320impl ReusableBuilder {
321 #[inline]
323 pub fn new() -> Self {
324 Self {
325 buffer: String::new(),
326 initial_capacity: 0,
327 }
328 }
329
330 #[inline]
332 pub fn with_capacity(capacity: usize) -> Self {
333 Self {
334 buffer: String::with_capacity(capacity),
335 initial_capacity: capacity,
336 }
337 }
338
339 #[inline]
341 pub fn push(&mut self, s: &str) -> &mut Self {
342 self.buffer.push_str(s);
343 self
344 }
345
346 #[inline]
348 pub fn push_char(&mut self, c: char) -> &mut Self {
349 self.buffer.push(c);
350 self
351 }
352
353 #[inline]
355 pub fn push_fmt(&mut self, args: fmt::Arguments<'_>) -> &mut Self {
356 use std::fmt::Write;
357 let _ = self.buffer.write_fmt(args);
358 self
359 }
360
361 #[inline]
363 pub fn space(&mut self) -> &mut Self {
364 self.buffer.push(' ');
365 self
366 }
367
368 #[inline]
370 pub fn comma(&mut self) -> &mut Self {
371 self.buffer.push_str(", ");
372 self
373 }
374
375 #[inline]
377 pub fn as_str(&self) -> &str {
378 &self.buffer
379 }
380
381 #[inline]
383 pub fn len(&self) -> usize {
384 self.buffer.len()
385 }
386
387 #[inline]
389 pub fn is_empty(&self) -> bool {
390 self.buffer.is_empty()
391 }
392
393 #[inline]
395 pub fn build(&self) -> String {
396 self.buffer.clone()
397 }
398
399 #[inline]
401 pub fn take(&mut self) -> String {
402 std::mem::take(&mut self.buffer)
403 }
404
405 #[inline]
407 pub fn reset(&mut self) {
408 self.buffer.clear();
409 }
410
411 #[inline]
413 pub fn reset_shrink(&mut self) {
414 self.buffer.clear();
415 if self.buffer.capacity() > self.initial_capacity * 2 {
416 self.buffer.shrink_to(self.initial_capacity);
417 }
418 }
419
420 #[inline]
422 pub fn reserve(&mut self, additional: usize) {
423 self.buffer.reserve(additional);
424 }
425
426 #[inline]
428 pub fn capacity(&self) -> usize {
429 self.buffer.capacity()
430 }
431}
432
433impl Default for ReusableBuilder {
434 fn default() -> Self {
435 Self::new()
436 }
437}
438
439impl fmt::Display for ReusableBuilder {
440 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441 write!(f, "{}", self.buffer)
442 }
443}
444
445impl From<ReusableBuilder> for String {
446 fn from(builder: ReusableBuilder) -> String {
447 builder.buffer
448 }
449}
450
451pub struct BuilderPool {
474 builders: parking_lot::Mutex<Vec<ReusableBuilder>>,
475 capacity: usize,
476}
477
478impl BuilderPool {
479 pub fn new(pool_size: usize, builder_capacity: usize) -> Self {
481 let builders: Vec<_> = (0..pool_size)
482 .map(|_| ReusableBuilder::with_capacity(builder_capacity))
483 .collect();
484 Self {
485 builders: parking_lot::Mutex::new(builders),
486 capacity: builder_capacity,
487 }
488 }
489
490 #[inline]
492 pub fn get(&self) -> ReusableBuilder {
493 self.builders
494 .lock()
495 .pop()
496 .unwrap_or_else(|| ReusableBuilder::with_capacity(self.capacity))
497 }
498
499 #[inline]
501 pub fn put(&self, mut builder: ReusableBuilder) {
502 builder.reset_shrink();
503 self.builders.lock().push(builder);
504 }
505
506 pub fn len(&self) -> usize {
508 self.builders.lock().len()
509 }
510
511 pub fn is_empty(&self) -> bool {
513 self.builders.lock().is_empty()
514 }
515}
516
517#[derive(Debug, Clone, Default)]
526pub struct OptimizedWindowSpec {
527 pub partition_by: PartitionByList,
529 pub order_by: SmallVec<[(Identifier, crate::types::SortOrder); 4]>,
531 pub frame: Option<WindowFrame>,
533 pub window_ref: Option<Identifier>,
535}
536
537#[derive(Debug, Clone)]
539pub struct WindowFrame {
540 pub frame_type: FrameType,
542 pub start: FrameBound,
544 pub end: Option<FrameBound>,
546}
547
548#[derive(Debug, Clone, Copy, PartialEq, Eq)]
550pub enum FrameType {
551 Rows,
552 Range,
553 Groups,
554}
555
556#[derive(Debug, Clone, PartialEq, Eq)]
558pub enum FrameBound {
559 UnboundedPreceding,
560 Preceding(u32),
561 CurrentRow,
562 Following(u32),
563 UnboundedFollowing,
564}
565
566impl OptimizedWindowSpec {
567 #[inline]
569 pub fn new() -> Self {
570 Self::default()
571 }
572
573 #[inline]
575 pub fn partition_by<I, S>(mut self, columns: I) -> Self
576 where
577 I: IntoIterator<Item = S>,
578 S: Into<Identifier>,
579 {
580 self.partition_by
581 .extend(columns.into_iter().map(Into::into));
582 self
583 }
584
585 #[inline]
587 pub fn partition_by_col(mut self, column: impl Into<Identifier>) -> Self {
588 self.partition_by.push(column.into());
589 self
590 }
591
592 #[inline]
594 pub fn order_by(
595 mut self,
596 column: impl Into<Identifier>,
597 order: crate::types::SortOrder,
598 ) -> Self {
599 self.order_by.push((column.into(), order));
600 self
601 }
602
603 #[inline]
605 pub fn rows(mut self, start: FrameBound, end: Option<FrameBound>) -> Self {
606 self.frame = Some(WindowFrame {
607 frame_type: FrameType::Rows,
608 start,
609 end,
610 });
611 self
612 }
613
614 #[inline]
616 pub fn rows_unbounded_preceding(self) -> Self {
617 self.rows(FrameBound::UnboundedPreceding, Some(FrameBound::CurrentRow))
618 }
619
620 #[inline]
622 pub fn window_ref(mut self, name: impl Into<Identifier>) -> Self {
623 self.window_ref = Some(name.into());
624 self
625 }
626
627 pub fn to_sql(&self, _db_type: crate::sql::DatabaseType) -> String {
629 let mut parts: SmallVec<[String; 4]> = SmallVec::new();
630
631 if let Some(ref name) = self.window_ref {
633 return format!("OVER {}", name);
634 }
635
636 if !self.partition_by.is_empty() {
638 let cols: Vec<_> = self.partition_by.iter().map(|c| c.as_str()).collect();
639 parts.push(format!("PARTITION BY {}", cols.join(", ")));
640 }
641
642 if !self.order_by.is_empty() {
644 let cols: Vec<_> = self
645 .order_by
646 .iter()
647 .map(|(col, order)| {
648 format!(
649 "{} {}",
650 col.as_str(),
651 match order {
652 crate::types::SortOrder::Asc => "ASC",
653 crate::types::SortOrder::Desc => "DESC",
654 }
655 )
656 })
657 .collect();
658 parts.push(format!("ORDER BY {}", cols.join(", ")));
659 }
660
661 if let Some(ref frame) = self.frame {
663 let frame_type = match frame.frame_type {
664 FrameType::Rows => "ROWS",
665 FrameType::Range => "RANGE",
666 FrameType::Groups => "GROUPS",
667 };
668
669 let start = frame_bound_to_sql(&frame.start);
670
671 if let Some(ref end) = frame.end {
672 let end_sql = frame_bound_to_sql(end);
673 parts.push(format!("{} BETWEEN {} AND {}", frame_type, start, end_sql));
674 } else {
675 parts.push(format!("{} {}", frame_type, start));
676 }
677 }
678
679 if parts.is_empty() {
680 "OVER ()".to_string()
681 } else {
682 format!("OVER ({})", parts.join(" "))
683 }
684 }
685}
686
687fn frame_bound_to_sql(bound: &FrameBound) -> &'static str {
688 match bound {
689 FrameBound::UnboundedPreceding => "UNBOUNDED PRECEDING",
690 FrameBound::Preceding(_) => "PRECEDING", FrameBound::CurrentRow => "CURRENT ROW",
692 FrameBound::Following(_) => "FOLLOWING", FrameBound::UnboundedFollowing => "UNBOUNDED FOLLOWING",
694 }
695}
696
697#[cfg(test)]
702mod tests {
703 use super::*;
704
705 #[test]
706 fn test_identifier_inline() {
707 let id = Identifier::new("user_id");
708 assert_eq!(id.as_str(), "user_id");
709 assert!(id.is_inline()); }
711
712 #[test]
713 fn test_identifier_from_static() {
714 let id = Identifier::from_static("email");
715 assert_eq!(id.as_str(), "email");
716 }
717
718 #[test]
719 fn test_cow_identifier_borrowed() {
720 let id = CowIdentifier::borrowed("user_id");
721 assert!(id.is_borrowed());
722 assert_eq!(id.as_str(), "user_id");
723 }
724
725 #[test]
726 fn test_cow_identifier_owned() {
727 let id = CowIdentifier::owned("dynamic".to_string());
728 assert!(!id.is_borrowed());
729 assert_eq!(id.as_str(), "dynamic");
730 }
731
732 #[test]
733 fn test_column_list_stack_allocation() {
734 let mut cols: ColumnList = SmallVec::new();
735 cols.push(Identifier::new("id"));
736 cols.push(Identifier::new("name"));
737 cols.push(Identifier::new("email"));
738 cols.push(Identifier::new("created_at"));
739
740 assert!(!cols.spilled());
742 assert_eq!(cols.len(), 4);
743 }
744
745 #[test]
746 fn test_column_list_heap_spillover() {
747 let mut cols: ColumnList = SmallVec::new();
748 for i in 0..10 {
749 cols.push(Identifier::new(format!("col_{}", i)));
750 }
751
752 assert!(cols.spilled());
754 assert_eq!(cols.len(), 10);
755 }
756
757 #[test]
758 fn test_reusable_builder() {
759 let mut builder = ReusableBuilder::with_capacity(64);
760
761 builder.push("SELECT * FROM users");
762 assert_eq!(builder.as_str(), "SELECT * FROM users");
763
764 builder.reset();
765 assert!(builder.is_empty());
766 assert!(builder.capacity() >= 64); builder.push("SELECT * FROM posts");
769 assert_eq!(builder.as_str(), "SELECT * FROM posts");
770 }
771
772 #[test]
773 fn test_reusable_builder_take() {
774 let mut builder = ReusableBuilder::new();
775 builder.push("test");
776
777 let taken = builder.take();
778 assert_eq!(taken, "test");
779 assert!(builder.is_empty());
780 }
781
782 #[test]
783 fn test_builder_pool() {
784 let pool = BuilderPool::new(4, 128);
785
786 let b1 = pool.get();
788 let b2 = pool.get();
789 let _b3 = pool.get();
790 let _b4 = pool.get();
791
792 assert!(pool.is_empty());
794
795 pool.put(b1);
797 pool.put(b2);
798
799 assert_eq!(pool.len(), 2);
800 }
801
802 #[test]
803 fn test_optimized_window_spec() {
804 use crate::types::SortOrder;
805
806 let spec = OptimizedWindowSpec::new()
807 .partition_by(["dept", "team"])
808 .order_by("salary", SortOrder::Desc)
809 .rows_unbounded_preceding();
810
811 let sql = spec.to_sql(crate::sql::DatabaseType::PostgreSQL);
812 assert!(sql.contains("PARTITION BY"));
813 assert!(sql.contains("ORDER BY"));
814 assert!(sql.contains("ROWS"));
815 }
816}