tpchgen/
generators.rs

1//! Generators for each TPC-H Tables
2use crate::dates;
3use crate::decimal::TPCHDecimal;
4use crate::distribution::Distribution;
5use crate::distribution::Distributions;
6use crate::random::RandomPhoneNumber;
7use crate::random::RowRandomInt;
8use crate::random::{PhoneNumberInstance, RandomBoundedLong, StringSequenceInstance};
9use crate::random::{RandomAlphaNumeric, RandomAlphaNumericInstance};
10use crate::text::TextPool;
11use core::fmt;
12use std::fmt::Display;
13
14use crate::dates::{GenerateUtils, TPCHDate};
15use crate::random::{RandomBoundedInt, RandomString, RandomStringSequence, RandomText};
16
17/// Generator for Nation table data
18#[derive(Debug, Clone)]
19pub struct NationGenerator<'a> {
20    distributions: &'a Distributions,
21    text_pool: &'a TextPool,
22}
23
24impl Default for NationGenerator<'_> {
25    fn default() -> Self {
26        // arguments are ignored
27        Self::new(1.0, 1, 1)
28    }
29}
30
31impl<'a> NationGenerator<'a> {
32    /// Creates a new NationGenerator with default distributions and text pool
33    ///
34    /// Nations does not depend on the scale factor or the part number. The signature of
35    /// this method is provided to be consistent with the other generators, but the
36    /// parameters are ignored. You can use [`NationGenerator::default`] to create a
37    /// default generator.
38    ///
39    /// The generator's lifetime is `&'static` because it references global
40    /// [`Distribution]`s and thus can be shared safely between threads.
41    pub fn new(_scale_factor: f64, _part: i32, _part_count: i32) -> NationGenerator<'static> {
42        // Note: use explicit lifetime to ensure this remains `&'static`
43        Self::new_with_distributions_and_text_pool(
44            Distributions::static_default(),
45            TextPool::get_or_init_default(),
46        )
47    }
48
49    /// Creates a NationGenerator with the specified distributions and text pool
50    pub fn new_with_distributions_and_text_pool<'b>(
51        distributions: &'b Distributions,
52        text_pool: &'b TextPool,
53    ) -> NationGenerator<'b> {
54        NationGenerator {
55            distributions,
56            text_pool,
57        }
58    }
59
60    /// Returns an iterator over the nation rows
61    pub fn iter(&self) -> NationGeneratorIterator<'a> {
62        NationGeneratorIterator::new(self.distributions.nations(), self.text_pool)
63    }
64}
65
66impl<'a> IntoIterator for NationGenerator<'a> {
67    type Item = Nation<'a>;
68    type IntoIter = NationGeneratorIterator<'a>;
69
70    fn into_iter(self) -> Self::IntoIter {
71        self.iter()
72    }
73}
74
75/// The NATION table
76///
77/// The Display trait is implemented to format the line item data as a string
78/// in the default TPC-H 'tbl' format.
79///
80/// ```text
81/// 0|ALGERIA|0| haggle. carefully final deposits detect slyly agai|
82/// 1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon|
83/// ```
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub struct Nation<'a> {
86    /// Primary key (0-24)
87    pub n_nationkey: i64,
88    /// Nation name
89    pub n_name: &'a str,
90    /// Foreign key to REGION
91    pub n_regionkey: i64,
92    /// Variable length comment
93    pub n_comment: &'a str,
94}
95
96impl fmt::Display for Nation<'_> {
97    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98        write!(
99            f,
100            "{}|{}|{}|{}|",
101            self.n_nationkey, self.n_name, self.n_regionkey, self.n_comment
102        )
103    }
104}
105
106impl<'a> Nation<'a> {
107    /// Create a new `nation` record with the specified values.
108    pub fn new(n_nationkey: i64, n_name: &'a str, n_regionkey: i64, n_comment: &'a str) -> Self {
109        Nation {
110            n_nationkey,
111            n_name,
112            n_regionkey,
113            n_comment,
114        }
115    }
116}
117
118/// Iterator that generates Nation rows
119#[derive(Debug)]
120pub struct NationGeneratorIterator<'a> {
121    nations: &'a Distribution,
122    comment_random: RandomText<'a>,
123    index: usize,
124}
125
126impl<'a> NationGeneratorIterator<'a> {
127    const COMMENT_AVERAGE_LENGTH: i32 = 72;
128
129    fn new(nations: &'a Distribution, text_pool: &'a TextPool) -> Self {
130        NationGeneratorIterator {
131            nations,
132            comment_random: RandomText::new(
133                606179079,
134                text_pool,
135                Self::COMMENT_AVERAGE_LENGTH as f64,
136            ),
137            index: 0,
138        }
139    }
140}
141
142impl<'a> Iterator for NationGeneratorIterator<'a> {
143    type Item = Nation<'a>;
144
145    fn next(&mut self) -> Option<Self::Item> {
146        if self.index >= self.nations.size() {
147            return None;
148        }
149
150        let nation = Nation {
151            // n_nationkey
152            n_nationkey: self.index as i64,
153            // n_name
154            n_name: self.nations.get_value(self.index),
155            // n_regionkey
156            n_regionkey: self.nations.get_weight(self.index) as i64,
157            // n_comment
158            n_comment: self.comment_random.next_value(),
159        };
160
161        self.comment_random.row_finished();
162        self.index += 1;
163
164        Some(nation)
165    }
166}
167
168/// The REGION table
169///
170/// The Display trait is implemented to format the line item data as a string
171/// in the default TPC-H 'tbl' format.
172///
173/// ```text
174/// 0|AFRICA|lar deposits. blithely final packages cajole. regular waters are final requests. regular accounts are according to |
175/// 1|AMERICA|hs use ironic, even requests. s|
176/// ```
177#[derive(Debug, Clone, PartialEq, Eq)]
178pub struct Region<'a> {
179    /// Primary key (0-4)
180    pub r_regionkey: i64,
181    /// Region name (AFRICA, AMERICA, ASIA, EUROPE, MIDDLE EAST)
182    pub r_name: &'a str,
183    /// Variable length comment
184    pub r_comment: &'a str,
185}
186
187impl fmt::Display for Region<'_> {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        write!(
190            f,
191            "{}|{}|{}|",
192            self.r_regionkey, self.r_name, self.r_comment
193        )
194    }
195}
196
197impl<'a> Region<'a> {
198    /// Creates a new `region` record with the specified values.
199    pub fn new(r_regionkey: i64, r_name: &'a str, r_comment: &'a str) -> Self {
200        Region {
201            r_regionkey,
202            r_name,
203            r_comment,
204        }
205    }
206}
207
208/// Generator for Region table data
209#[derive(Debug, Clone)]
210pub struct RegionGenerator<'a> {
211    distributions: &'a Distributions,
212    text_pool: &'a TextPool,
213}
214
215impl Default for RegionGenerator<'_> {
216    fn default() -> Self {
217        // arguments are ignored
218        Self::new(1.0, 1, 1)
219    }
220}
221
222impl<'a> RegionGenerator<'a> {
223    /// Creates a new RegionGenerator with default distributions and text pool
224    ///
225    /// Regions does not depend on the scale factor or the part number. The signature of
226    /// this method is provided to be consistent with the other generators, but the
227    /// parameters are ignored. You can use [`RegionGenerator::default`] to create a
228    /// default generator.
229    ///
230    /// Note the generator's lifetime is `&'static`. See [`NationGenerator`] for
231    /// more details.
232    pub fn new(_scale_factor: f64, _part: i32, _part_count: i32) -> RegionGenerator<'static> {
233        // Note: use explicit lifetime to ensure this remains `&'static`
234        Self::new_with_distributions_and_text_pool(
235            Distributions::static_default(),
236            TextPool::get_or_init_default(),
237        )
238    }
239
240    /// Creates a RegionGenerator with the specified distributions and text pool
241    pub fn new_with_distributions_and_text_pool<'b>(
242        distributions: &'b Distributions,
243        text_pool: &'b TextPool,
244    ) -> RegionGenerator<'b> {
245        RegionGenerator {
246            distributions,
247            text_pool,
248        }
249    }
250
251    /// Returns an iterator over the region rows
252    pub fn iter(&self) -> RegionGeneratorIterator<'a> {
253        RegionGeneratorIterator::new(self.distributions.regions(), self.text_pool)
254    }
255}
256
257impl<'a> IntoIterator for &'a RegionGenerator<'a> {
258    type Item = Region<'a>;
259    type IntoIter = RegionGeneratorIterator<'a>;
260
261    fn into_iter(self) -> Self::IntoIter {
262        self.iter()
263    }
264}
265
266/// Iterator that generates Region rows
267#[derive(Debug)]
268pub struct RegionGeneratorIterator<'a> {
269    regions: &'a Distribution,
270    comment_random: RandomText<'a>,
271    index: usize,
272}
273
274impl<'a> RegionGeneratorIterator<'a> {
275    const COMMENT_AVERAGE_LENGTH: i32 = 72;
276
277    fn new(regions: &'a Distribution, text_pool: &'a TextPool) -> Self {
278        RegionGeneratorIterator {
279            regions,
280            comment_random: RandomText::new(
281                1500869201,
282                text_pool,
283                Self::COMMENT_AVERAGE_LENGTH as f64,
284            ),
285            index: 0,
286        }
287    }
288}
289
290impl<'a> Iterator for RegionGeneratorIterator<'a> {
291    type Item = Region<'a>;
292
293    fn next(&mut self) -> Option<Self::Item> {
294        if self.index >= self.regions.size() {
295            return None;
296        }
297
298        let region = Region {
299            r_regionkey: self.index as i64,
300            r_name: self.regions.get_value(self.index),
301            r_comment: self.comment_random.next_value(),
302        };
303
304        self.comment_random.row_finished();
305        self.index += 1;
306
307        Some(region)
308    }
309}
310
311/// A Part Manufacturer, formatted as `"Manufacturer#<n>"`
312#[derive(Debug, Clone, Copy, PartialEq)]
313pub struct PartManufacturerName(i32);
314
315impl PartManufacturerName {
316    pub fn new(value: i32) -> Self {
317        PartManufacturerName(value)
318    }
319}
320
321impl fmt::Display for PartManufacturerName {
322    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
323        write!(f, "Manufacturer#{}", self.0)
324    }
325}
326
327/// A Part brand name, formatted as `"Brand#<n>"`
328#[derive(Debug, Clone, Copy, PartialEq)]
329pub struct PartBrandName(i32);
330
331impl PartBrandName {
332    pub fn new(value: i32) -> Self {
333        PartBrandName(value)
334    }
335}
336
337impl fmt::Display for PartBrandName {
338    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
339        write!(f, "Brand#{}", self.0)
340    }
341}
342
343/// The PART table
344///
345/// The Display trait is implemented to format the line item data as a string
346/// in the default TPC-H 'tbl' format.
347///
348/// ```text
349/// 1|goldenrod lavender spring chocolate lace|Manufacturer#1|Brand#13|PROMO BURNISHED COPPER|7|JUMBO PKG|901.00|ly. slyly ironi|
350/// 2|blush thistle blue yellow saddle|Manufacturer#1|Brand#13|LARGE BRUSHED BRASS|1|LG CASE|902.00|lar accounts amo|
351/// ```
352#[derive(Debug, Clone, PartialEq)]
353pub struct Part<'a> {
354    /// Primary key
355    pub p_partkey: i64,
356    /// Part name
357    pub p_name: StringSequenceInstance<'a>,
358    /// Part manufacturer.
359    pub p_mfgr: PartManufacturerName,
360    /// Part brand.
361    pub p_brand: PartBrandName,
362    /// Part type
363    pub p_type: &'a str,
364    /// Part size
365    pub p_size: i32,
366    /// Part container
367    pub p_container: &'a str,
368    /// Part retail price
369    pub p_retailprice: TPCHDecimal,
370    /// Variable length comment
371    pub p_comment: &'a str,
372}
373
374impl fmt::Display for Part<'_> {
375    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
376        write!(
377            f,
378            "{}|{}|{}|{}|{}|{}|{}|{}|{}|",
379            self.p_partkey,
380            self.p_name,
381            self.p_mfgr,
382            self.p_brand,
383            self.p_type,
384            self.p_size,
385            self.p_container,
386            self.p_retailprice,
387            self.p_comment
388        )
389    }
390}
391
392/// Generator for Part table data
393#[derive(Debug, Clone)]
394pub struct PartGenerator<'a> {
395    scale_factor: f64,
396    part: i32,
397    part_count: i32,
398    distributions: &'a Distributions,
399    text_pool: &'a TextPool,
400}
401
402impl<'a> PartGenerator<'a> {
403    /// Base scale for part generation
404    const SCALE_BASE: i32 = 200_000;
405
406    // Constants for part generation
407    const NAME_WORDS: i32 = 5;
408    const MANUFACTURER_MIN: i32 = 1;
409    const MANUFACTURER_MAX: i32 = 5;
410    const BRAND_MIN: i32 = 1;
411    const BRAND_MAX: i32 = 5;
412    const SIZE_MIN: i32 = 1;
413    const SIZE_MAX: i32 = 50;
414    const COMMENT_AVERAGE_LENGTH: i32 = 14;
415
416    /// Creates a new PartGenerator with the given scale factor
417    ///
418    /// Note the generator's lifetime is `&'static`. See [`NationGenerator`] for
419    /// more details.
420    pub fn new(scale_factor: f64, part: i32, part_count: i32) -> PartGenerator<'static> {
421        // Note: use explicit lifetime to ensure this remains `&'static`
422        Self::new_with_distributions_and_text_pool(
423            scale_factor,
424            part,
425            part_count,
426            Distributions::static_default(),
427            TextPool::get_or_init_default(),
428        )
429    }
430
431    /// Creates a PartGenerator with specified distributions and text pool
432    pub fn new_with_distributions_and_text_pool<'b>(
433        scale_factor: f64,
434        part: i32,
435        part_count: i32,
436        distributions: &'b Distributions,
437        text_pool: &'b TextPool,
438    ) -> PartGenerator<'b> {
439        PartGenerator {
440            scale_factor,
441            part,
442            part_count,
443            distributions,
444            text_pool,
445        }
446    }
447
448    /// Return the row count for the given scale factor and generator part count
449    pub fn calculate_row_count(scale_factor: f64, part: i32, part_count: i32) -> i64 {
450        GenerateUtils::calculate_row_count(Self::SCALE_BASE, scale_factor, part, part_count)
451    }
452
453    /// Returns an iterator over the part rows
454    pub fn iter(&self) -> PartGeneratorIterator<'a> {
455        PartGeneratorIterator::new(
456            self.distributions,
457            self.text_pool,
458            GenerateUtils::calculate_start_index(
459                Self::SCALE_BASE,
460                self.scale_factor,
461                self.part,
462                self.part_count,
463            ),
464            Self::calculate_row_count(self.scale_factor, self.part, self.part_count),
465        )
466    }
467}
468
469impl<'a> IntoIterator for &'a PartGenerator<'a> {
470    type Item = Part<'a>;
471    type IntoIter = PartGeneratorIterator<'a>;
472
473    fn into_iter(self) -> Self::IntoIter {
474        self.iter()
475    }
476}
477
478/// Iterator that generates Part rows
479#[derive(Debug)]
480pub struct PartGeneratorIterator<'a> {
481    name_random: RandomStringSequence<'a>,
482    manufacturer_random: RandomBoundedInt,
483    brand_random: RandomBoundedInt,
484    type_random: RandomString<'a>,
485    size_random: RandomBoundedInt,
486    container_random: RandomString<'a>,
487    comment_random: RandomText<'a>,
488
489    start_index: i64,
490    row_count: i64,
491    index: i64,
492}
493
494impl<'a> PartGeneratorIterator<'a> {
495    fn new(
496        distributions: &'a Distributions,
497        text_pool: &'a TextPool,
498        start_index: i64,
499        row_count: i64,
500    ) -> Self {
501        let mut name_random = RandomStringSequence::new(
502            709314158,
503            PartGenerator::NAME_WORDS,
504            distributions.part_colors(),
505        );
506        let mut manufacturer_random = RandomBoundedInt::new(
507            1,
508            PartGenerator::MANUFACTURER_MIN,
509            PartGenerator::MANUFACTURER_MAX,
510        );
511        let mut brand_random =
512            RandomBoundedInt::new(46831694, PartGenerator::BRAND_MIN, PartGenerator::BRAND_MAX);
513        let mut type_random = RandomString::new(1841581359, distributions.part_types());
514        let mut size_random =
515            RandomBoundedInt::new(1193163244, PartGenerator::SIZE_MIN, PartGenerator::SIZE_MAX);
516        let mut container_random = RandomString::new(727633698, distributions.part_containers());
517        let mut comment_random = RandomText::new(
518            804159733,
519            text_pool,
520            PartGenerator::COMMENT_AVERAGE_LENGTH as f64,
521        );
522
523        // Advance all generators to the starting position
524        name_random.advance_rows(start_index);
525        manufacturer_random.advance_rows(start_index);
526        brand_random.advance_rows(start_index);
527        type_random.advance_rows(start_index);
528        size_random.advance_rows(start_index);
529        container_random.advance_rows(start_index);
530        comment_random.advance_rows(start_index);
531
532        PartGeneratorIterator {
533            name_random,
534            manufacturer_random,
535            brand_random,
536            type_random,
537            size_random,
538            container_random,
539            comment_random,
540            start_index,
541            row_count,
542            index: 0,
543        }
544    }
545
546    /// Creates a part with the given key
547    fn make_part(&mut self, part_key: i64) -> Part<'a> {
548        let name = self.name_random.next_value();
549
550        let manufacturer = self.manufacturer_random.next_value();
551        let brand = manufacturer * 10 + self.brand_random.next_value();
552
553        Part {
554            p_partkey: part_key,
555            p_name: name,
556            p_mfgr: PartManufacturerName::new(manufacturer),
557            p_brand: PartBrandName::new(brand),
558            p_type: self.type_random.next_value(),
559            p_size: self.size_random.next_value(),
560            p_container: self.container_random.next_value(),
561            p_retailprice: TPCHDecimal(Self::calculate_part_price(part_key)),
562            p_comment: self.comment_random.next_value(),
563        }
564    }
565
566    /// Calculates the price for a part
567    pub fn calculate_part_price(part_key: i64) -> i64 {
568        let mut price = 90000;
569
570        // limit contribution to $200
571        price += (part_key / 10) % 20001;
572        price += (part_key % 1000) * 100;
573
574        price
575    }
576}
577
578impl<'a> Iterator for PartGeneratorIterator<'a> {
579    type Item = Part<'a>;
580
581    fn next(&mut self) -> Option<Self::Item> {
582        if self.index >= self.row_count {
583            return None;
584        }
585
586        let part = self.make_part(self.start_index + self.index + 1);
587
588        self.name_random.row_finished();
589        self.manufacturer_random.row_finished();
590        self.brand_random.row_finished();
591        self.type_random.row_finished();
592        self.size_random.row_finished();
593        self.container_random.row_finished();
594        self.comment_random.row_finished();
595
596        self.index += 1;
597
598        Some(part)
599    }
600}
601
602/// A supplier name, formatted as `"Supplier#<n>"`
603#[derive(Debug, Clone, Copy, PartialEq)]
604pub struct SupplierName(i64);
605
606impl SupplierName {
607    /// Creates a new SupplierName with the given value
608    pub fn new(value: i64) -> Self {
609        SupplierName(value)
610    }
611}
612
613impl fmt::Display for SupplierName {
614    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
615        write!(f, "Supplier#{:09}", self.0)
616    }
617}
618
619/// Records for the SUPPLIER table.
620///
621/// The Display trait is implemented to format the line item data as a string
622/// in the default TPC-H 'tbl' format.
623///
624/// ```text
625/// 1|Supplier#000000001| N kD4on9OM Ipw3,gf0JBoQDd7tgrzrddZ|17|27-918-335-1736|5755.94|each slyly above the careful|
626/// 2|Supplier#000000002|89eJ5ksX3ImxJQBvxObC,|5|15-679-861-2259|4032.68| slyly bold instructions. idle dependen|
627/// ```
628#[derive(Debug, Clone, PartialEq)]
629pub struct Supplier {
630    /// Primary key
631    pub s_suppkey: i64,
632    /// Supplier name.
633    pub s_name: SupplierName,
634    /// Supplier address
635    pub s_address: RandomAlphaNumericInstance,
636    /// Foreign key to NATION
637    pub s_nationkey: i64,
638    /// Supplier phone number
639    pub s_phone: PhoneNumberInstance,
640    /// Supplier account balance
641    pub s_acctbal: TPCHDecimal,
642    /// Variable length comment
643    pub s_comment: String,
644}
645
646impl fmt::Display for Supplier {
647    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
648        write!(
649            f,
650            "{}|{}|{}|{}|{}|{}|{}|",
651            self.s_suppkey,
652            self.s_name,
653            self.s_address,
654            self.s_nationkey,
655            self.s_phone,
656            self.s_acctbal,
657            self.s_comment
658        )
659    }
660}
661
662/// Generator for Supplier table data
663#[derive(Debug, Clone)]
664pub struct SupplierGenerator<'a> {
665    scale_factor: f64,
666    part: i32,
667    part_count: i32,
668    distributions: &'a Distributions,
669    text_pool: &'a TextPool,
670}
671
672impl<'a> SupplierGenerator<'a> {
673    /// Base scale for supplier generation
674    const SCALE_BASE: i32 = 10_000;
675
676    // Constants for supplier generation
677    const ACCOUNT_BALANCE_MIN: i32 = -99999;
678    const ACCOUNT_BALANCE_MAX: i32 = 999999;
679    const ADDRESS_AVERAGE_LENGTH: i32 = 25;
680    const COMMENT_AVERAGE_LENGTH: i32 = 63;
681
682    // Better Business Bureau comment constants
683    pub const BBB_BASE_TEXT: &'static str = "Customer ";
684    pub const BBB_COMPLAINT_TEXT: &'static str = "Complaints";
685    pub const BBB_RECOMMEND_TEXT: &'static str = "Recommends";
686    pub const BBB_COMMENT_LENGTH: usize =
687        Self::BBB_BASE_TEXT.len() + Self::BBB_COMPLAINT_TEXT.len();
688    pub const BBB_COMMENTS_PER_SCALE_BASE: i32 = 10;
689    pub const BBB_COMPLAINT_PERCENT: i32 = 50;
690
691    /// Creates a new SupplierGenerator with the given scale factor
692    ///
693    /// Note the generator's lifetime is `&'static`. See [`NationGenerator`] for
694    /// more details.
695    pub fn new(scale_factor: f64, part: i32, part_count: i32) -> SupplierGenerator<'static> {
696        // Note: use explicit lifetime to ensure this remains `&'static`
697        Self::new_with_distributions_and_text_pool(
698            scale_factor,
699            part,
700            part_count,
701            Distributions::static_default(),
702            TextPool::get_or_init_default(),
703        )
704    }
705
706    /// Creates a SupplierGenerator with specified distributions and text pool
707    pub fn new_with_distributions_and_text_pool<'b>(
708        scale_factor: f64,
709        part: i32,
710        part_count: i32,
711        distributions: &'b Distributions,
712        text_pool: &'b TextPool,
713    ) -> SupplierGenerator<'b> {
714        SupplierGenerator {
715            scale_factor,
716            part,
717            part_count,
718            distributions,
719            text_pool,
720        }
721    }
722
723    /// Return the row count for the given scale factor and generator part count
724    pub fn calculate_row_count(scale_factor: f64, part: i32, part_count: i32) -> i64 {
725        GenerateUtils::calculate_row_count(Self::SCALE_BASE, scale_factor, part, part_count)
726    }
727
728    /// Returns an iterator over the supplier rows
729    pub fn iter(&self) -> SupplierGeneratorIterator<'a> {
730        SupplierGeneratorIterator::new(
731            self.distributions,
732            self.text_pool,
733            GenerateUtils::calculate_start_index(
734                Self::SCALE_BASE,
735                self.scale_factor,
736                self.part,
737                self.part_count,
738            ),
739            Self::calculate_row_count(self.scale_factor, self.part, self.part_count),
740        )
741    }
742}
743
744impl<'a> IntoIterator for &'a SupplierGenerator<'a> {
745    type Item = Supplier;
746    type IntoIter = SupplierGeneratorIterator<'a>;
747
748    fn into_iter(self) -> Self::IntoIter {
749        self.iter()
750    }
751}
752
753/// Iterator that generates Supplier rows
754#[derive(Debug)]
755pub struct SupplierGeneratorIterator<'a> {
756    address_random: RandomAlphaNumeric,
757    nation_key_random: RandomBoundedInt,
758    phone_random: RandomPhoneNumber,
759    account_balance_random: RandomBoundedInt,
760    comment_random: RandomText<'a>,
761    bbb_comment_random: RandomBoundedInt,
762    bbb_junk_random: RowRandomInt,
763    bbb_offset_random: RowRandomInt,
764    bbb_type_random: RandomBoundedInt,
765
766    start_index: i64,
767    row_count: i64,
768    index: i64,
769}
770
771impl<'a> SupplierGeneratorIterator<'a> {
772    fn new(
773        distributions: &Distributions,
774        text_pool: &'a TextPool,
775        start_index: i64,
776        row_count: i64,
777    ) -> Self {
778        let mut address_random =
779            RandomAlphaNumeric::new(706178559, SupplierGenerator::ADDRESS_AVERAGE_LENGTH);
780        let mut nation_key_random =
781            RandomBoundedInt::new(110356601, 0, (distributions.nations().size() - 1) as i32);
782        let mut phone_random = RandomPhoneNumber::new(884434366);
783        let mut account_balance_random = RandomBoundedInt::new(
784            962338209,
785            SupplierGenerator::ACCOUNT_BALANCE_MIN,
786            SupplierGenerator::ACCOUNT_BALANCE_MAX,
787        );
788        let mut comment_random = RandomText::new(
789            1341315363,
790            text_pool,
791            SupplierGenerator::COMMENT_AVERAGE_LENGTH as f64,
792        );
793        let mut bbb_comment_random =
794            RandomBoundedInt::new(202794285, 1, SupplierGenerator::SCALE_BASE);
795        let mut bbb_junk_random = RowRandomInt::new(263032577, 1);
796        let mut bbb_offset_random = RowRandomInt::new(715851524, 1);
797        let mut bbb_type_random = RandomBoundedInt::new(753643799, 0, 100);
798
799        // Advance all generators to the starting position
800        address_random.advance_rows(start_index);
801        nation_key_random.advance_rows(start_index);
802        phone_random.advance_rows(start_index);
803        account_balance_random.advance_rows(start_index);
804        comment_random.advance_rows(start_index);
805        bbb_comment_random.advance_rows(start_index);
806        bbb_junk_random.advance_rows(start_index);
807        bbb_offset_random.advance_rows(start_index);
808        bbb_type_random.advance_rows(start_index);
809
810        SupplierGeneratorIterator {
811            address_random,
812            nation_key_random,
813            phone_random,
814            account_balance_random,
815            comment_random,
816            bbb_comment_random,
817            bbb_junk_random,
818            bbb_offset_random,
819            bbb_type_random,
820            start_index,
821            row_count,
822            index: 0,
823        }
824    }
825
826    /// Creates a supplier with the given key
827    fn make_supplier(&mut self, supplier_key: i64) -> Supplier {
828        let mut comment = self.comment_random.next_value().to_string();
829
830        // Add supplier complaints or commendation to the comment
831        let bbb_comment_random_value = self.bbb_comment_random.next_value();
832        if bbb_comment_random_value <= SupplierGenerator::BBB_COMMENTS_PER_SCALE_BASE {
833            let _buffer = comment.clone();
834
835            // select random place for BBB comment
836            let noise = self.bbb_junk_random.next_int(
837                0,
838                (comment.len() - SupplierGenerator::BBB_COMMENT_LENGTH) as i32,
839            ) as usize;
840            let offset = self.bbb_offset_random.next_int(
841                0,
842                (comment.len() - (SupplierGenerator::BBB_COMMENT_LENGTH + noise)) as i32,
843            ) as usize;
844
845            // select complaint or recommendation
846            let type_text =
847                if self.bbb_type_random.next_value() < SupplierGenerator::BBB_COMPLAINT_PERCENT {
848                    SupplierGenerator::BBB_COMPLAINT_TEXT
849                } else {
850                    SupplierGenerator::BBB_RECOMMEND_TEXT
851                };
852
853            // Create a mutable string that we can modify in chunks
854            let mut modified_comment = String::with_capacity(comment.len());
855            modified_comment.push_str(&comment[..offset]);
856            modified_comment.push_str(SupplierGenerator::BBB_BASE_TEXT);
857            modified_comment.push_str(
858                &comment[offset + SupplierGenerator::BBB_BASE_TEXT.len()
859                    ..offset + SupplierGenerator::BBB_BASE_TEXT.len() + noise],
860            );
861            modified_comment.push_str(type_text);
862            modified_comment.push_str(
863                &comment
864                    [offset + SupplierGenerator::BBB_BASE_TEXT.len() + noise + type_text.len()..],
865            );
866
867            comment = modified_comment;
868        }
869
870        let nation_key = self.nation_key_random.next_value() as i64;
871
872        Supplier {
873            s_suppkey: supplier_key,
874            s_name: SupplierName::new(supplier_key),
875            s_address: self.address_random.next_value(),
876            s_nationkey: nation_key,
877            s_phone: self.phone_random.next_value(nation_key),
878            s_acctbal: TPCHDecimal(self.account_balance_random.next_value() as i64),
879            s_comment: comment,
880        }
881    }
882}
883
884impl Iterator for SupplierGeneratorIterator<'_> {
885    type Item = Supplier;
886
887    fn next(&mut self) -> Option<Self::Item> {
888        if self.index >= self.row_count {
889            return None;
890        }
891
892        let supplier = self.make_supplier(self.start_index + self.index + 1);
893
894        self.address_random.row_finished();
895        self.nation_key_random.row_finished();
896        self.phone_random.row_finished();
897        self.account_balance_random.row_finished();
898        self.comment_random.row_finished();
899        self.bbb_comment_random.row_finished();
900        self.bbb_junk_random.row_finished();
901        self.bbb_offset_random.row_finished();
902        self.bbb_type_random.row_finished();
903
904        self.index += 1;
905
906        Some(supplier)
907    }
908}
909
910/// A Customer Name, formatted as `"Customer#<n>"`
911#[derive(Debug, Clone, Copy, PartialEq)]
912pub struct CustomerName(i64);
913
914impl CustomerName {
915    /// Creates a new CustomerName with the given value
916    pub fn new(value: i64) -> Self {
917        CustomerName(value)
918    }
919}
920
921impl fmt::Display for CustomerName {
922    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
923        write!(f, "Customer#{:09}", self.0)
924    }
925}
926
927/// The CUSTOMER table
928///
929/// The Display trait is implemented to format the line item data as a string
930/// in the default TPC-H 'tbl' format.
931///
932/// ```text
933/// 1|Customer#000000001|IVhzIApeRb ot,c,E|15|25-989-741-2988|711.56|BUILDING|to the even, regular platelets. regular, ironic epitaphs nag e|
934/// 2|Customer#000000002|XSTf4,NCwDVaWNe6tEgvwfmRchLXak|13|23-768-687-3665|121.65|AUTOMOBILE|l accounts. blithely ironic theodolites integrate boldly: caref|
935/// ```
936#[derive(Debug, Clone, PartialEq)]
937pub struct Customer<'a> {
938    /// Primary key
939    pub c_custkey: i64,
940    /// Customer name
941    pub c_name: CustomerName,
942    /// Customer address
943    pub c_address: RandomAlphaNumericInstance,
944    /// Foreign key to NATION
945    pub c_nationkey: i64,
946    /// Customer phone number
947    pub c_phone: PhoneNumberInstance,
948    /// Customer account balance
949    pub c_acctbal: TPCHDecimal,
950    /// Customer market segment
951    pub c_mktsegment: &'a str,
952    /// Variable length comment
953    pub c_comment: &'a str,
954}
955
956impl fmt::Display for Customer<'_> {
957    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
958        write!(
959            f,
960            "{}|{}|{}|{}|{}|{}|{}|{}|",
961            self.c_custkey,
962            self.c_name,
963            self.c_address,
964            self.c_nationkey,
965            self.c_phone,
966            self.c_acctbal,
967            self.c_mktsegment,
968            self.c_comment
969        )
970    }
971}
972
973/// Generator for Customer table data
974#[derive(Debug, Clone)]
975pub struct CustomerGenerator<'a> {
976    scale_factor: f64,
977    part: i32,
978    part_count: i32,
979    distributions: &'a Distributions,
980    text_pool: &'a TextPool,
981}
982
983impl<'a> CustomerGenerator<'a> {
984    /// Base scale for customer generation
985    const SCALE_BASE: i32 = 150_000;
986
987    // Constants for customer generation
988    const ACCOUNT_BALANCE_MIN: i32 = -99999;
989    const ACCOUNT_BALANCE_MAX: i32 = 999999;
990    const ADDRESS_AVERAGE_LENGTH: i32 = 25;
991    const COMMENT_AVERAGE_LENGTH: i32 = 73;
992
993    /// Creates a new CustomerGenerator with the given scale factor
994    ///
995    /// Note the generator's lifetime is `&'static`. See [`NationGenerator`] for
996    /// more details.
997    pub fn new(scale_factor: f64, part: i32, part_count: i32) -> CustomerGenerator<'static> {
998        // Note: use explicit lifetime to ensure this remains `&'static`
999        Self::new_with_distributions_and_text_pool(
1000            scale_factor,
1001            part,
1002            part_count,
1003            Distributions::static_default(),
1004            TextPool::get_or_init_default(),
1005        )
1006    }
1007
1008    /// Creates a CustomerGenerator with specified distributions and text pool
1009    pub fn new_with_distributions_and_text_pool<'b>(
1010        scale_factor: f64,
1011        part: i32,
1012        part_count: i32,
1013        distributions: &'b Distributions,
1014        text_pool: &'b TextPool,
1015    ) -> CustomerGenerator<'b> {
1016        CustomerGenerator {
1017            scale_factor,
1018            part,
1019            part_count,
1020            distributions,
1021            text_pool,
1022        }
1023    }
1024
1025    /// Return the row count for the given scale factor and generator part count
1026    pub fn calculate_row_count(scale_factor: f64, part: i32, part_count: i32) -> i64 {
1027        GenerateUtils::calculate_row_count(Self::SCALE_BASE, scale_factor, part, part_count)
1028    }
1029
1030    /// Returns an iterator over the customer rows
1031    pub fn iter(&self) -> CustomerGeneratorIterator<'a> {
1032        CustomerGeneratorIterator::new(
1033            self.distributions,
1034            self.text_pool,
1035            GenerateUtils::calculate_start_index(
1036                Self::SCALE_BASE,
1037                self.scale_factor,
1038                self.part,
1039                self.part_count,
1040            ),
1041            Self::calculate_row_count(self.scale_factor, self.part, self.part_count),
1042        )
1043    }
1044}
1045
1046impl<'a> IntoIterator for &'a CustomerGenerator<'a> {
1047    type Item = Customer<'a>;
1048    type IntoIter = CustomerGeneratorIterator<'a>;
1049
1050    fn into_iter(self) -> Self::IntoIter {
1051        self.iter()
1052    }
1053}
1054
1055/// Iterator that generates Customer rows
1056#[derive(Debug)]
1057pub struct CustomerGeneratorIterator<'a> {
1058    address_random: RandomAlphaNumeric,
1059    nation_key_random: RandomBoundedInt,
1060    phone_random: RandomPhoneNumber,
1061    account_balance_random: RandomBoundedInt,
1062    market_segment_random: RandomString<'a>,
1063    comment_random: RandomText<'a>,
1064
1065    start_index: i64,
1066    row_count: i64,
1067    index: i64,
1068}
1069
1070impl<'a> CustomerGeneratorIterator<'a> {
1071    fn new(
1072        distributions: &'a Distributions,
1073        text_pool: &'a TextPool,
1074        start_index: i64,
1075        row_count: i64,
1076    ) -> Self {
1077        let mut address_random =
1078            RandomAlphaNumeric::new(881155353, CustomerGenerator::ADDRESS_AVERAGE_LENGTH);
1079        let mut nation_key_random =
1080            RandomBoundedInt::new(1489529863, 0, (distributions.nations().size() - 1) as i32);
1081        let mut phone_random = RandomPhoneNumber::new(1521138112);
1082        let mut account_balance_random = RandomBoundedInt::new(
1083            298370230,
1084            CustomerGenerator::ACCOUNT_BALANCE_MIN,
1085            CustomerGenerator::ACCOUNT_BALANCE_MAX,
1086        );
1087        let mut market_segment_random =
1088            RandomString::new(1140279430, distributions.market_segments());
1089        let mut comment_random = RandomText::new(
1090            1335826707,
1091            text_pool,
1092            CustomerGenerator::COMMENT_AVERAGE_LENGTH as f64,
1093        );
1094
1095        // Advance all generators to the starting position
1096        address_random.advance_rows(start_index);
1097        nation_key_random.advance_rows(start_index);
1098        phone_random.advance_rows(start_index);
1099        account_balance_random.advance_rows(start_index);
1100        market_segment_random.advance_rows(start_index);
1101        comment_random.advance_rows(start_index);
1102
1103        CustomerGeneratorIterator {
1104            address_random,
1105            nation_key_random,
1106            phone_random,
1107            account_balance_random,
1108            market_segment_random,
1109            comment_random,
1110            start_index,
1111            row_count,
1112            index: 0,
1113        }
1114    }
1115
1116    /// Creates a customer with the given key
1117    fn make_customer(&mut self, customer_key: i64) -> Customer<'a> {
1118        let nation_key = self.nation_key_random.next_value() as i64;
1119
1120        Customer {
1121            c_custkey: customer_key,
1122            c_name: CustomerName::new(customer_key),
1123            c_address: self.address_random.next_value(),
1124            c_nationkey: nation_key,
1125            c_phone: self.phone_random.next_value(nation_key),
1126            c_acctbal: TPCHDecimal(self.account_balance_random.next_value() as i64),
1127            c_mktsegment: self.market_segment_random.next_value(),
1128            c_comment: self.comment_random.next_value(),
1129        }
1130    }
1131}
1132
1133impl<'a> Iterator for CustomerGeneratorIterator<'a> {
1134    type Item = Customer<'a>;
1135
1136    fn next(&mut self) -> Option<Self::Item> {
1137        if self.index >= self.row_count {
1138            return None;
1139        }
1140
1141        let customer = self.make_customer(self.start_index + self.index + 1);
1142
1143        self.address_random.row_finished();
1144        self.nation_key_random.row_finished();
1145        self.phone_random.row_finished();
1146        self.account_balance_random.row_finished();
1147        self.market_segment_random.row_finished();
1148        self.comment_random.row_finished();
1149
1150        self.index += 1;
1151
1152        Some(customer)
1153    }
1154}
1155
1156/// The PARTSUPP (part supplier) table
1157///
1158/// The Display trait is implemented to format the line item data as a string
1159/// in the default TPC-H 'tbl' format.
1160///
1161/// ```text
1162/// 1|2|3325|771.64|, even theodolites. regular, final theodolites eat after the carefully pending foxes. ...
1163/// 1|4|8076|993.49|ven ideas. quickly even packages print. pending multipliers must have to are fluff|
1164/// ```
1165#[derive(Debug, Clone, PartialEq)]
1166pub struct PartSupp<'a> {
1167    /// Primary key, foreign key to PART
1168    pub ps_partkey: i64,
1169    /// Primary key, foreign key to SUPPLIER
1170    pub ps_suppkey: i64,
1171    /// Available quantity
1172    pub ps_availqty: i32,
1173    /// Supplier cost
1174    pub ps_supplycost: TPCHDecimal,
1175    /// Variable length comment
1176    pub ps_comment: &'a str,
1177}
1178
1179impl fmt::Display for PartSupp<'_> {
1180    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1181        write!(
1182            f,
1183            "{}|{}|{}|{}|{}|",
1184            self.ps_partkey, self.ps_suppkey, self.ps_availqty, self.ps_supplycost, self.ps_comment
1185        )
1186    }
1187}
1188
1189/// Generator for PartSupp table data
1190#[derive(Debug, Clone)]
1191pub struct PartSuppGenerator<'a> {
1192    scale_factor: f64,
1193    part: i32,
1194    part_count: i32,
1195    text_pool: &'a TextPool,
1196}
1197
1198impl<'a> PartSuppGenerator<'a> {
1199    /// Base scale for part-supplier generation
1200    const SUPPLIERS_PER_PART: i32 = 4;
1201
1202    // Constants for part-supplier generation
1203    const AVAILABLE_QUANTITY_MIN: i32 = 1;
1204    const AVAILABLE_QUANTITY_MAX: i32 = 9999;
1205    const SUPPLY_COST_MIN: i32 = 100;
1206    const SUPPLY_COST_MAX: i32 = 100000;
1207    const COMMENT_AVERAGE_LENGTH: i32 = 124;
1208
1209    /// Creates a new PartSuppGenerator with the given scale factor
1210    ///
1211    /// Note the generator's lifetime is `&'static`. See [`NationGenerator`] for
1212    /// more details.
1213    pub fn new(scale_factor: f64, part: i32, part_count: i32) -> PartSuppGenerator<'static> {
1214        // Note: use explicit lifetime to ensure this remains `&'static`
1215        Self::new_with_text_pool(
1216            scale_factor,
1217            part,
1218            part_count,
1219            TextPool::get_or_init_default(),
1220        )
1221    }
1222
1223    /// Creates a PartSuppGenerator with specified text pool
1224    pub fn new_with_text_pool(
1225        scale_factor: f64,
1226        part: i32,
1227        part_count: i32,
1228        text_pool: &TextPool,
1229    ) -> PartSuppGenerator<'_> {
1230        PartSuppGenerator {
1231            scale_factor,
1232            part,
1233            part_count,
1234            text_pool,
1235        }
1236    }
1237
1238    /// Return the row count for the given scale factor and generator part count
1239    pub fn calculate_row_count(scale_factor: f64, part: i32, part_count: i32) -> i64 {
1240        // Use the part generator's scale base for start/row calculation
1241        GenerateUtils::calculate_row_count(
1242            PartGenerator::SCALE_BASE,
1243            scale_factor,
1244            part,
1245            part_count,
1246        )
1247    }
1248
1249    /// Returns an iterator over the part supplier rows
1250    pub fn iter(&self) -> PartSuppGeneratorIterator<'a> {
1251        let scale_base = PartGenerator::SCALE_BASE;
1252
1253        PartSuppGeneratorIterator::new(
1254            self.text_pool,
1255            self.scale_factor,
1256            GenerateUtils::calculate_start_index(
1257                scale_base,
1258                self.scale_factor,
1259                self.part,
1260                self.part_count,
1261            ),
1262            Self::calculate_row_count(self.scale_factor, self.part, self.part_count),
1263        )
1264    }
1265}
1266
1267impl<'a> IntoIterator for &'a PartSuppGenerator<'a> {
1268    type Item = PartSupp<'a>;
1269    type IntoIter = PartSuppGeneratorIterator<'a>;
1270
1271    fn into_iter(self) -> Self::IntoIter {
1272        self.iter()
1273    }
1274}
1275
1276/// Iterator that generates PartSupp rows
1277#[derive(Debug)]
1278pub struct PartSuppGeneratorIterator<'a> {
1279    scale_factor: f64,
1280    start_index: i64,
1281    row_count: i64,
1282
1283    available_quantity_random: RandomBoundedInt,
1284    supply_cost_random: RandomBoundedInt,
1285    comment_random: RandomText<'a>,
1286
1287    index: i64,
1288    part_supplier_number: i32,
1289}
1290
1291impl<'a> PartSuppGeneratorIterator<'a> {
1292    fn new(text_pool: &'a TextPool, scale_factor: f64, start_index: i64, row_count: i64) -> Self {
1293        let mut available_quantity_random = RandomBoundedInt::new_with_seeds_per_row(
1294            1671059989,
1295            PartSuppGenerator::AVAILABLE_QUANTITY_MIN,
1296            PartSuppGenerator::AVAILABLE_QUANTITY_MAX,
1297            PartSuppGenerator::SUPPLIERS_PER_PART,
1298        );
1299        let mut supply_cost_random = RandomBoundedInt::new_with_seeds_per_row(
1300            1051288424,
1301            PartSuppGenerator::SUPPLY_COST_MIN,
1302            PartSuppGenerator::SUPPLY_COST_MAX,
1303            PartSuppGenerator::SUPPLIERS_PER_PART,
1304        );
1305        let mut comment_random = RandomText::new_with_expected_row_count(
1306            1961692154,
1307            text_pool,
1308            PartSuppGenerator::COMMENT_AVERAGE_LENGTH as f64,
1309            PartSuppGenerator::SUPPLIERS_PER_PART,
1310        );
1311
1312        // Advance all generators to the starting position
1313        available_quantity_random.advance_rows(start_index);
1314        supply_cost_random.advance_rows(start_index);
1315        comment_random.advance_rows(start_index);
1316
1317        PartSuppGeneratorIterator {
1318            scale_factor,
1319            start_index,
1320            row_count,
1321            available_quantity_random,
1322            supply_cost_random,
1323            comment_random,
1324            index: 0,
1325            part_supplier_number: 0,
1326        }
1327    }
1328
1329    /// Creates a part-supplier entry with the given part key
1330    fn make_part_supplier(&mut self, part_key: i64) -> PartSupp<'a> {
1331        let supplier_key = Self::select_part_supplier(
1332            part_key,
1333            self.part_supplier_number as i64,
1334            self.scale_factor,
1335        );
1336
1337        let ps_availqty = self.available_quantity_random.next_value();
1338        let ps_supplycost = TPCHDecimal(self.supply_cost_random.next_value() as i64);
1339        let ps_comment = self.comment_random.next_value();
1340
1341        PartSupp {
1342            ps_partkey: part_key,
1343            ps_suppkey: supplier_key,
1344            ps_availqty,
1345            ps_supplycost,
1346            ps_comment,
1347        }
1348    }
1349
1350    /// Selects a supplier for a given part and supplier number
1351    pub fn select_part_supplier(part_key: i64, supplier_number: i64, scale_factor: f64) -> i64 {
1352        // Use supplier generator's scale base
1353        let supplier_count = (SupplierGenerator::SCALE_BASE as f64 * scale_factor) as i64;
1354
1355        ((part_key
1356            + (supplier_number
1357                * ((supplier_count / PartSuppGenerator::SUPPLIERS_PER_PART as i64)
1358                    + ((part_key - 1) / supplier_count))))
1359            % supplier_count)
1360            + 1
1361    }
1362}
1363
1364impl<'a> Iterator for PartSuppGeneratorIterator<'a> {
1365    type Item = PartSupp<'a>;
1366
1367    fn next(&mut self) -> Option<Self::Item> {
1368        if self.index >= self.row_count {
1369            return None;
1370        }
1371
1372        let part_key = self.start_index + self.index + 1;
1373        let part_supplier = self.make_part_supplier(part_key);
1374        self.part_supplier_number += 1;
1375
1376        // advance next row only when all suppliers for the part have been produced
1377        if self.part_supplier_number >= PartSuppGenerator::SUPPLIERS_PER_PART {
1378            self.available_quantity_random.row_finished();
1379            self.supply_cost_random.row_finished();
1380            self.comment_random.row_finished();
1381
1382            self.index += 1;
1383            self.part_supplier_number = 0;
1384        }
1385
1386        Some(part_supplier)
1387    }
1388}
1389
1390/// A clerk name, formatted as `"Clerk#<n>"`
1391#[derive(Debug, Clone, Copy, PartialEq)]
1392pub struct ClerkName(i32);
1393
1394impl ClerkName {
1395    /// Creates a new ClerkName with the given value
1396    pub fn new(value: i32) -> Self {
1397        ClerkName(value)
1398    }
1399}
1400
1401impl fmt::Display for ClerkName {
1402    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1403        write!(f, "Clerk#{:09}", self.0)
1404    }
1405}
1406
1407/// Order status (F=final, O=open, P=pending)
1408#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd)]
1409pub enum OrderStatus {
1410    /// Fulfilled - all line items shipped
1411    Fulfilled,
1412    /// Open - no line items shipped
1413    Open,
1414    /// Partially fulfilled - some line items shipped
1415    Pending,
1416}
1417
1418impl OrderStatus {
1419    pub fn as_str(&self) -> &'static str {
1420        match self {
1421            OrderStatus::Fulfilled => "F",
1422            OrderStatus::Open => "O",
1423            OrderStatus::Pending => "P",
1424        }
1425    }
1426}
1427
1428impl Display for OrderStatus {
1429    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1430        write!(f, "{}", self.as_str())
1431    }
1432}
1433
1434/// The ORDERS table
1435///
1436/// The Display trait is implemented to format the line item data as a string
1437/// in the default TPC-H 'tbl' format.
1438///
1439/// ```text
1440/// 1|37|O|131251.81|1996-01-02|5-LOW|Clerk#000000951|0|nstructions sleep furiously among |
1441///  2|79|O|40183.29|1996-12-01|1-URGENT|Clerk#000000880|0| foxes. pending accounts at the pending, silent asymptot|
1442/// ```
1443#[derive(Debug, Clone, PartialEq)]
1444pub struct Order<'a> {
1445    /// Primary key
1446    pub o_orderkey: i64,
1447    /// Foreign key to CUSTOMER
1448    pub o_custkey: i64,
1449    /// Order status (F=final, O=open, P=pending)
1450    pub o_orderstatus: OrderStatus,
1451    /// Order total price
1452    pub o_totalprice: TPCHDecimal,
1453    /// Order date
1454    pub o_orderdate: TPCHDate,
1455    /// Order priority
1456    pub o_orderpriority: &'a str,
1457    /// Clerk who processed the order.
1458    pub o_clerk: ClerkName,
1459    /// Order shipping priority
1460    pub o_shippriority: i32,
1461    /// Variable length comment
1462    pub o_comment: &'a str,
1463}
1464
1465impl fmt::Display for Order<'_> {
1466    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1467        write!(
1468            f,
1469            "{}|{}|{}|{}|{}|{}|{}|{}|{}|",
1470            self.o_orderkey,
1471            self.o_custkey,
1472            self.o_orderstatus,
1473            self.o_totalprice,
1474            self.o_orderdate,
1475            self.o_orderpriority,
1476            self.o_clerk,
1477            self.o_shippriority,
1478            self.o_comment
1479        )
1480    }
1481}
1482
1483/// Generator for Order table data
1484#[derive(Debug, Clone)]
1485pub struct OrderGenerator<'a> {
1486    scale_factor: f64,
1487    part: i32,
1488    part_count: i32,
1489    distributions: &'a Distributions,
1490    text_pool: &'a TextPool,
1491}
1492
1493impl<'a> OrderGenerator<'a> {
1494    /// Base scale for order generation
1495    pub const SCALE_BASE: i32 = 1_500_000;
1496
1497    // Constants for order generation
1498    const CUSTOMER_MORTALITY: i32 = 3; // portion with no orders
1499    const ORDER_DATE_MIN: i32 = dates::MIN_GENERATE_DATE;
1500    const ORDER_DATE_MAX: i32 =
1501        Self::ORDER_DATE_MIN + (dates::TOTAL_DATE_RANGE - LineItemGenerator::ITEM_SHIP_DAYS - 1);
1502    const CLERK_SCALE_BASE: i32 = 1000;
1503
1504    const LINE_COUNT_MIN: i32 = 1;
1505    pub const LINE_COUNT_MAX: i32 = 7;
1506
1507    const COMMENT_AVERAGE_LENGTH: i32 = 49;
1508
1509    const ORDER_KEY_SPARSE_BITS: i32 = 2;
1510    const ORDER_KEY_SPARSE_KEEP: i32 = 3;
1511    /// Creates a new OrderGenerator with the given scale factor
1512    ///
1513    /// Note the generator's lifetime is `&'static`. See [`NationGenerator`] for
1514    /// more details.
1515    pub fn new(scale_factor: f64, part: i32, part_count: i32) -> OrderGenerator<'static> {
1516        // Note: use explicit lifetime to ensure this remains `&'static`
1517        Self::new_with_distributions_and_text_pool(
1518            scale_factor,
1519            part,
1520            part_count,
1521            Distributions::static_default(),
1522            TextPool::get_or_init_default(),
1523        )
1524    }
1525
1526    /// Creates a OrderGenerator with specified distributions and text pool
1527    pub fn new_with_distributions_and_text_pool<'b>(
1528        scale_factor: f64,
1529        part: i32,
1530        part_count: i32,
1531        distributions: &'b Distributions,
1532        text_pool: &'b TextPool,
1533    ) -> OrderGenerator<'b> {
1534        OrderGenerator {
1535            scale_factor,
1536            part,
1537            part_count,
1538            distributions,
1539            text_pool,
1540        }
1541    }
1542
1543    /// Return the row count for the given scale factor and generator part count
1544    pub fn calculate_row_count(scale_factor: f64, part: i32, part_count: i32) -> i64 {
1545        GenerateUtils::calculate_row_count(Self::SCALE_BASE, scale_factor, part, part_count)
1546    }
1547
1548    /// Returns an iterator over the order rows
1549    pub fn iter(&self) -> OrderGeneratorIterator<'a> {
1550        OrderGeneratorIterator::new(
1551            self.distributions,
1552            self.text_pool,
1553            self.scale_factor,
1554            GenerateUtils::calculate_start_index(
1555                Self::SCALE_BASE,
1556                self.scale_factor,
1557                self.part,
1558                self.part_count,
1559            ),
1560            Self::calculate_row_count(self.scale_factor, self.part, self.part_count),
1561        )
1562    }
1563
1564    /// Creates the order date random generator
1565    pub fn create_order_date_random() -> RandomBoundedInt {
1566        RandomBoundedInt::new(1066728069, Self::ORDER_DATE_MIN, Self::ORDER_DATE_MAX)
1567    }
1568
1569    /// Creates the line count random generator
1570    pub fn create_line_count_random() -> RandomBoundedInt {
1571        RandomBoundedInt::new(1434868289, Self::LINE_COUNT_MIN, Self::LINE_COUNT_MAX)
1572    }
1573
1574    /// Creates an order key from an index
1575    pub fn make_order_key(order_index: i64) -> i64 {
1576        let low_bits = order_index & ((1 << Self::ORDER_KEY_SPARSE_KEEP) - 1);
1577
1578        let mut ok = order_index;
1579        ok >>= Self::ORDER_KEY_SPARSE_KEEP;
1580        ok <<= Self::ORDER_KEY_SPARSE_BITS;
1581        ok <<= Self::ORDER_KEY_SPARSE_KEEP;
1582        ok += low_bits;
1583
1584        ok
1585    }
1586}
1587
1588impl<'a> IntoIterator for &'a OrderGenerator<'a> {
1589    type Item = Order<'a>;
1590    type IntoIter = OrderGeneratorIterator<'a>;
1591
1592    fn into_iter(self) -> Self::IntoIter {
1593        self.iter()
1594    }
1595}
1596
1597/// Iterator that generates Order rows
1598#[derive(Debug)]
1599pub struct OrderGeneratorIterator<'a> {
1600    order_date_random: RandomBoundedInt,
1601    line_count_random: RandomBoundedInt,
1602    customer_key_random: RandomBoundedLong,
1603    order_priority_random: RandomString<'a>,
1604    clerk_random: RandomBoundedInt,
1605    comment_random: RandomText<'a>,
1606
1607    // For line item simulation to determine order status
1608    line_quantity_random: RandomBoundedInt,
1609    line_discount_random: RandomBoundedInt,
1610    line_tax_random: RandomBoundedInt,
1611    line_part_key_random: RandomBoundedLong,
1612    line_ship_date_random: RandomBoundedInt,
1613
1614    start_index: i64,
1615    row_count: i64,
1616    max_customer_key: i64,
1617
1618    index: i64,
1619}
1620impl<'a> OrderGeneratorIterator<'a> {
1621    fn new(
1622        distributions: &'a Distributions,
1623        text_pool: &'a TextPool,
1624        scale_factor: f64,
1625        start_index: i64,
1626        row_count: i64,
1627    ) -> Self {
1628        let mut order_date_random = OrderGenerator::create_order_date_random();
1629        let mut line_count_random = OrderGenerator::create_line_count_random();
1630
1631        let max_customer_key = (CustomerGenerator::SCALE_BASE as f64 * scale_factor) as i64;
1632
1633        let mut customer_key_random =
1634            RandomBoundedLong::new(851767375, scale_factor >= 30000.0, 1, max_customer_key);
1635
1636        let mut order_priority_random =
1637            RandomString::new(591449447, distributions.order_priority());
1638
1639        let max_clerk = (scale_factor * OrderGenerator::CLERK_SCALE_BASE as f64)
1640            .max(OrderGenerator::CLERK_SCALE_BASE as f64) as i32;
1641        let mut clerk_random = RandomBoundedInt::new(1171034773, 1, max_clerk);
1642
1643        let mut comment_random = RandomText::new(
1644            276090261,
1645            text_pool,
1646            OrderGenerator::COMMENT_AVERAGE_LENGTH as f64,
1647        );
1648
1649        // For line item simulation
1650        let mut line_quantity_random = LineItemGenerator::create_quantity_random();
1651        let mut line_discount_random = LineItemGenerator::create_discount_random();
1652        let mut line_tax_random = LineItemGenerator::create_tax_random();
1653        let mut line_part_key_random = LineItemGenerator::create_part_key_random(scale_factor);
1654        let mut line_ship_date_random = LineItemGenerator::create_ship_date_random();
1655
1656        // Advance all generators to the starting position
1657        order_date_random.advance_rows(start_index);
1658        line_count_random.advance_rows(start_index);
1659        customer_key_random.advance_rows(start_index);
1660        order_priority_random.advance_rows(start_index);
1661        clerk_random.advance_rows(start_index);
1662        comment_random.advance_rows(start_index);
1663
1664        line_quantity_random.advance_rows(start_index);
1665        line_discount_random.advance_rows(start_index);
1666        line_tax_random.advance_rows(start_index);
1667        line_part_key_random.advance_rows(start_index);
1668        line_ship_date_random.advance_rows(start_index);
1669
1670        OrderGeneratorIterator {
1671            order_date_random,
1672            line_count_random,
1673            customer_key_random,
1674            order_priority_random,
1675            clerk_random,
1676            comment_random,
1677            line_quantity_random,
1678            line_discount_random,
1679            line_tax_random,
1680            line_part_key_random,
1681            line_ship_date_random,
1682            start_index,
1683            row_count,
1684            max_customer_key,
1685            index: 0,
1686        }
1687    }
1688
1689    /// Creates an order with the given index
1690    fn make_order(&mut self, index: i64) -> Order<'a> {
1691        let order_key = OrderGenerator::make_order_key(index);
1692
1693        let order_date = self.order_date_random.next_value();
1694
1695        // generate customer key, taking into account customer mortality rate
1696        let mut customer_key = self.customer_key_random.next_value();
1697        let mut delta = 1;
1698        while customer_key % OrderGenerator::CUSTOMER_MORTALITY as i64 == 0 {
1699            customer_key += delta;
1700            customer_key = customer_key.min(self.max_customer_key);
1701            delta *= -1;
1702        }
1703
1704        let mut total_price = 0;
1705        let mut shipped_count = 0;
1706
1707        let line_count = self.line_count_random.next_value();
1708        for _ in 0..line_count {
1709            let quantity = self.line_quantity_random.next_value();
1710            let discount = self.line_discount_random.next_value();
1711            let tax = self.line_tax_random.next_value();
1712
1713            let part_key = self.line_part_key_random.next_value();
1714
1715            let part_price = PartGeneratorIterator::calculate_part_price(part_key);
1716            let extended_price = part_price * quantity as i64;
1717            let discounted_price = extended_price * (100 - discount as i64);
1718            total_price += ((discounted_price / 100) * (100 + tax as i64)) / 100;
1719
1720            let ship_date = self.line_ship_date_random.next_value() + order_date;
1721            if TPCHDate::is_in_past(ship_date) {
1722                shipped_count += 1;
1723            }
1724        }
1725
1726        let order_status = if shipped_count == line_count {
1727            OrderStatus::Fulfilled
1728        } else if shipped_count > 0 {
1729            OrderStatus::Pending
1730        } else {
1731            OrderStatus::Open
1732        };
1733
1734        let clerk_id = self.clerk_random.next_value();
1735        let clerk_name = ClerkName::new(clerk_id);
1736
1737        Order {
1738            o_orderkey: order_key,
1739            o_custkey: customer_key,
1740            o_orderstatus: order_status,
1741            o_totalprice: TPCHDecimal(total_price),
1742            o_orderdate: TPCHDate::new(order_date),
1743            o_orderpriority: self.order_priority_random.next_value(),
1744            o_clerk: clerk_name,
1745            o_shippriority: 0, // Fixed value per TPC-H spec
1746            o_comment: self.comment_random.next_value(),
1747        }
1748    }
1749}
1750
1751impl<'a> Iterator for OrderGeneratorIterator<'a> {
1752    type Item = Order<'a>;
1753
1754    fn next(&mut self) -> Option<Self::Item> {
1755        if self.index >= self.row_count {
1756            return None;
1757        }
1758
1759        let order = self.make_order(self.start_index + self.index + 1);
1760
1761        self.order_date_random.row_finished();
1762        self.line_count_random.row_finished();
1763        self.customer_key_random.row_finished();
1764        self.order_priority_random.row_finished();
1765        self.clerk_random.row_finished();
1766        self.comment_random.row_finished();
1767
1768        self.line_quantity_random.row_finished();
1769        self.line_discount_random.row_finished();
1770        self.line_tax_random.row_finished();
1771        self.line_part_key_random.row_finished();
1772        self.line_ship_date_random.row_finished();
1773
1774        self.index += 1;
1775
1776        Some(order)
1777    }
1778}
1779
1780/// The LINEITEM table
1781///
1782/// The Display trait is implemented to format the line item data as a string
1783/// in the default TPC-H 'tbl' format.
1784///
1785/// Example
1786/// ```text
1787/// 1|156|4|1|17|17954.55|0.04|0.02|N|O|1996-03-13|1996-02-12|1996-03-22|DELIVER IN PERSON|TRUCK|egular courts above the|
1788/// 1|68|9|2|36|34850.16|0.09|0.06|N|O|1996-04-12|1996-02-28|1996-04-20|TAKE BACK RETURN|MAIL|ly final dependencies: slyly bold |
1789/// ```
1790#[derive(Debug, Clone, PartialEq)]
1791pub struct LineItem<'a> {
1792    /// Foreign key to ORDERS
1793    pub l_orderkey: i64,
1794    /// Foreign key to PART
1795    pub l_partkey: i64,
1796    /// Foreign key to SUPPLIER
1797    pub l_suppkey: i64,
1798    /// Line item number within order
1799    pub l_linenumber: i32,
1800    /// Quantity ordered
1801    // TODO: Spec has this as decimal.
1802    pub l_quantity: i64,
1803    /// Extended price (l_quantity * p_retailprice)
1804    pub l_extendedprice: TPCHDecimal,
1805    /// Discount percentage
1806    pub l_discount: TPCHDecimal,
1807    /// Tax percentage
1808    pub l_tax: TPCHDecimal,
1809    /// Return flag (R=returned, A=accepted, null=pending)
1810    pub l_returnflag: &'a str,
1811    /// Line status (O=ordered, F=fulfilled)
1812    pub l_linestatus: &'static str,
1813    /// Date shipped
1814    pub l_shipdate: TPCHDate,
1815    /// Date committed to ship
1816    pub l_commitdate: TPCHDate,
1817    /// Date received
1818    pub l_receiptdate: TPCHDate,
1819    /// Shipping instructions
1820    pub l_shipinstruct: &'a str,
1821    /// Shipping mode
1822    pub l_shipmode: &'a str,
1823    /// Variable length comment
1824    pub l_comment: &'a str,
1825}
1826
1827impl fmt::Display for LineItem<'_> {
1828    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1829        write!(
1830            f,
1831            "{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|",
1832            self.l_orderkey,
1833            self.l_partkey,
1834            self.l_suppkey,
1835            self.l_linenumber,
1836            self.l_quantity,
1837            self.l_extendedprice,
1838            self.l_discount,
1839            self.l_tax,
1840            self.l_returnflag,
1841            self.l_linestatus,
1842            self.l_shipdate,
1843            self.l_commitdate,
1844            self.l_receiptdate,
1845            self.l_shipinstruct,
1846            self.l_shipmode,
1847            self.l_comment
1848        )
1849    }
1850}
1851
1852/// Generator for LineItem table data
1853#[derive(Debug, Clone)]
1854pub struct LineItemGenerator<'a> {
1855    scale_factor: f64,
1856    part: i32,
1857    part_count: i32,
1858    distributions: &'a Distributions,
1859    text_pool: &'a TextPool,
1860}
1861
1862impl<'a> LineItemGenerator<'a> {
1863    // Constants for line item generation
1864    const QUANTITY_MIN: i32 = 1;
1865    const QUANTITY_MAX: i32 = 50;
1866    const TAX_MIN: TPCHDecimal = TPCHDecimal(0); // 0.00
1867    const TAX_MAX: TPCHDecimal = TPCHDecimal(8); // 0.08
1868    const DISCOUNT_MIN: TPCHDecimal = TPCHDecimal(0); // 0.00
1869    const DISCOUNT_MAX: TPCHDecimal = TPCHDecimal(10); // 0.10
1870    const PART_KEY_MIN: i32 = 1;
1871
1872    const SHIP_DATE_MIN: i32 = 1;
1873    const SHIP_DATE_MAX: i32 = 121;
1874    const COMMIT_DATE_MIN: i32 = 30;
1875    const COMMIT_DATE_MAX: i32 = 90;
1876    const RECEIPT_DATE_MIN: i32 = 1;
1877    const RECEIPT_DATE_MAX: i32 = 30;
1878
1879    pub const ITEM_SHIP_DAYS: i32 = Self::SHIP_DATE_MAX + Self::RECEIPT_DATE_MAX;
1880
1881    const COMMENT_AVERAGE_LENGTH: i32 = 27;
1882
1883    /// Creates a new LineItemGenerator with the given scale factor
1884    ///
1885    /// Note the generator's lifetime is `&'static`. See [`NationGenerator`] for
1886    /// more details.
1887    pub fn new(scale_factor: f64, part: i32, part_count: i32) -> LineItemGenerator<'static> {
1888        Self::new_with_distributions_and_text_pool(
1889            scale_factor,
1890            part,
1891            part_count,
1892            Distributions::static_default(),
1893            TextPool::get_or_init_default(),
1894        )
1895    }
1896
1897    /// Creates a LineItemGenerator with specified distributions and text pool
1898    pub fn new_with_distributions_and_text_pool<'b>(
1899        scale_factor: f64,
1900        part: i32,
1901        part_count: i32,
1902        distributions: &'b Distributions,
1903        text_pool: &'b TextPool,
1904    ) -> LineItemGenerator<'b> {
1905        LineItemGenerator {
1906            scale_factor,
1907            part,
1908            part_count,
1909            distributions,
1910            text_pool,
1911        }
1912    }
1913
1914    /// Returns an iterator over the line item rows
1915    pub fn iter(&self) -> LineItemGeneratorIterator<'a> {
1916        LineItemGeneratorIterator::new(
1917            self.distributions,
1918            self.text_pool,
1919            self.scale_factor,
1920            GenerateUtils::calculate_start_index(
1921                OrderGenerator::SCALE_BASE,
1922                self.scale_factor,
1923                self.part,
1924                self.part_count,
1925            ),
1926            GenerateUtils::calculate_row_count(
1927                OrderGenerator::SCALE_BASE,
1928                self.scale_factor,
1929                self.part,
1930                self.part_count,
1931            ),
1932        )
1933    }
1934
1935    /// Creates a quantity random generator
1936    pub fn create_quantity_random() -> RandomBoundedInt {
1937        RandomBoundedInt::new_with_seeds_per_row(
1938            209208115,
1939            Self::QUANTITY_MIN,
1940            Self::QUANTITY_MAX,
1941            OrderGenerator::LINE_COUNT_MAX,
1942        )
1943    }
1944
1945    /// Creates a discount random generator
1946    pub fn create_discount_random() -> RandomBoundedInt {
1947        RandomBoundedInt::new_with_seeds_per_row(
1948            554590007,
1949            Self::DISCOUNT_MIN.0 as i32,
1950            Self::DISCOUNT_MAX.0 as i32,
1951            OrderGenerator::LINE_COUNT_MAX,
1952        )
1953    }
1954
1955    /// Creates a tax random generator
1956    pub fn create_tax_random() -> RandomBoundedInt {
1957        RandomBoundedInt::new_with_seeds_per_row(
1958            721958466,
1959            Self::TAX_MIN.0 as i32,
1960            Self::TAX_MAX.0 as i32,
1961            OrderGenerator::LINE_COUNT_MAX,
1962        )
1963    }
1964
1965    /// Creates a part key random generator
1966    pub fn create_part_key_random(scale_factor: f64) -> RandomBoundedLong {
1967        // If scale_factor >= 30000, use long `RandomBoundedLong` otherwise
1968        // use `RandomBoundedInt` to avoid overflow.
1969        RandomBoundedLong::new_with_seeds_per_row(
1970            1808217256,
1971            scale_factor >= 30000.0,
1972            Self::PART_KEY_MIN as i64,
1973            (PartGenerator::SCALE_BASE as f64 * scale_factor) as i64,
1974            OrderGenerator::LINE_COUNT_MAX,
1975        )
1976    }
1977
1978    /// Creates a ship date random generator
1979    pub fn create_ship_date_random() -> RandomBoundedInt {
1980        RandomBoundedInt::new_with_seeds_per_row(
1981            1769349045,
1982            Self::SHIP_DATE_MIN,
1983            Self::SHIP_DATE_MAX,
1984            OrderGenerator::LINE_COUNT_MAX,
1985        )
1986    }
1987}
1988
1989impl<'a> IntoIterator for &'a LineItemGenerator<'a> {
1990    type Item = LineItem<'a>;
1991    type IntoIter = LineItemGeneratorIterator<'a>;
1992
1993    fn into_iter(self) -> Self::IntoIter {
1994        self.iter()
1995    }
1996}
1997
1998/// Iterator that generates LineItem rows
1999#[derive(Debug)]
2000pub struct LineItemGeneratorIterator<'a> {
2001    order_date_random: RandomBoundedInt,
2002    line_count_random: RandomBoundedInt,
2003
2004    quantity_random: RandomBoundedInt,
2005    discount_random: RandomBoundedInt,
2006    tax_random: RandomBoundedInt,
2007
2008    line_part_key_random: RandomBoundedLong,
2009
2010    supplier_number_random: RandomBoundedInt,
2011
2012    ship_date_random: RandomBoundedInt,
2013    commit_date_random: RandomBoundedInt,
2014    receipt_date_random: RandomBoundedInt,
2015
2016    returned_flag_random: RandomString<'a>,
2017    ship_instructions_random: RandomString<'a>,
2018    ship_mode_random: RandomString<'a>,
2019
2020    comment_random: RandomText<'a>,
2021
2022    scale_factor: f64,
2023    start_index: i64,
2024    row_count: i64,
2025
2026    index: i64,
2027    order_date: i32,
2028    line_count: i32,
2029    line_number: i32,
2030}
2031
2032impl<'a> LineItemGeneratorIterator<'a> {
2033    fn new(
2034        distributions: &'a Distributions,
2035        text_pool: &'a TextPool,
2036        scale_factor: f64,
2037        start_index: i64,
2038        row_count: i64,
2039    ) -> Self {
2040        let mut order_date_random = OrderGenerator::create_order_date_random();
2041        let mut line_count_random = OrderGenerator::create_line_count_random();
2042
2043        let mut quantity_random = LineItemGenerator::create_quantity_random();
2044        let mut discount_random = LineItemGenerator::create_discount_random();
2045        let mut tax_random = LineItemGenerator::create_tax_random();
2046
2047        let mut line_part_key_random = LineItemGenerator::create_part_key_random(scale_factor);
2048
2049        let mut supplier_number_random = RandomBoundedInt::new_with_seeds_per_row(
2050            2095021727,
2051            0,
2052            3,
2053            OrderGenerator::LINE_COUNT_MAX,
2054        );
2055
2056        let mut ship_date_random = LineItemGenerator::create_ship_date_random();
2057        let mut commit_date_random = RandomBoundedInt::new_with_seeds_per_row(
2058            904914315,
2059            LineItemGenerator::COMMIT_DATE_MIN,
2060            LineItemGenerator::COMMIT_DATE_MAX,
2061            OrderGenerator::LINE_COUNT_MAX,
2062        );
2063        let mut receipt_date_random = RandomBoundedInt::new_with_seeds_per_row(
2064            373135028,
2065            LineItemGenerator::RECEIPT_DATE_MIN,
2066            LineItemGenerator::RECEIPT_DATE_MAX,
2067            OrderGenerator::LINE_COUNT_MAX,
2068        );
2069
2070        let mut returned_flag_random = RandomString::new_with_expected_row_count(
2071            717419739,
2072            distributions.return_flags(),
2073            OrderGenerator::LINE_COUNT_MAX,
2074        );
2075        let mut ship_instructions_random = RandomString::new_with_expected_row_count(
2076            1371272478,
2077            distributions.ship_instructions(),
2078            OrderGenerator::LINE_COUNT_MAX,
2079        );
2080        let mut ship_mode_random = RandomString::new_with_expected_row_count(
2081            675466456,
2082            distributions.ship_modes(),
2083            OrderGenerator::LINE_COUNT_MAX,
2084        );
2085        let mut comment_random = RandomText::new_with_expected_row_count(
2086            1095462486,
2087            text_pool,
2088            LineItemGenerator::COMMENT_AVERAGE_LENGTH as f64,
2089            OrderGenerator::LINE_COUNT_MAX,
2090        );
2091
2092        // Advance all generators to the starting position
2093        order_date_random.advance_rows(start_index);
2094        line_count_random.advance_rows(start_index);
2095
2096        quantity_random.advance_rows(start_index);
2097        discount_random.advance_rows(start_index);
2098        tax_random.advance_rows(start_index);
2099
2100        line_part_key_random.advance_rows(start_index);
2101
2102        supplier_number_random.advance_rows(start_index);
2103
2104        ship_date_random.advance_rows(start_index);
2105        commit_date_random.advance_rows(start_index);
2106        receipt_date_random.advance_rows(start_index);
2107
2108        returned_flag_random.advance_rows(start_index);
2109        ship_instructions_random.advance_rows(start_index);
2110        ship_mode_random.advance_rows(start_index);
2111
2112        comment_random.advance_rows(start_index);
2113
2114        // generate information for initial order
2115        let order_date = order_date_random.next_value();
2116        let line_count = line_count_random.next_value() - 1;
2117
2118        LineItemGeneratorIterator {
2119            order_date_random,
2120            line_count_random,
2121            quantity_random,
2122            discount_random,
2123            tax_random,
2124            line_part_key_random,
2125            supplier_number_random,
2126            ship_date_random,
2127            commit_date_random,
2128            receipt_date_random,
2129            returned_flag_random,
2130            ship_instructions_random,
2131            ship_mode_random,
2132            comment_random,
2133            scale_factor,
2134            start_index,
2135            row_count,
2136            index: 0,
2137            order_date,
2138            line_count,
2139            line_number: 0,
2140        }
2141    }
2142
2143    /// Creates a line item with the given order index
2144    fn make_line_item(&mut self, order_index: i64) -> LineItem<'a> {
2145        let order_key = OrderGenerator::make_order_key(order_index);
2146
2147        let quantity = self.quantity_random.next_value();
2148        let discount = self.discount_random.next_value();
2149        let tax = self.tax_random.next_value();
2150
2151        let part_key = self.line_part_key_random.next_value();
2152
2153        let supplier_number = self.supplier_number_random.next_value() as i64;
2154        let supplier_key = PartSuppGeneratorIterator::select_part_supplier(
2155            part_key,
2156            supplier_number,
2157            self.scale_factor,
2158        );
2159
2160        let part_price = PartGeneratorIterator::calculate_part_price(part_key);
2161        let extended_price = part_price * quantity as i64;
2162
2163        let mut ship_date = self.ship_date_random.next_value();
2164        ship_date += self.order_date;
2165        let mut commit_date = self.commit_date_random.next_value();
2166        commit_date += self.order_date;
2167        let mut receipt_date = self.receipt_date_random.next_value();
2168        receipt_date += ship_date;
2169
2170        let returned_flag = if TPCHDate::is_in_past(receipt_date) {
2171            self.returned_flag_random.next_value()
2172        } else {
2173            "N"
2174        };
2175
2176        let status = if TPCHDate::is_in_past(ship_date) {
2177            "F" // Fulfilled
2178        } else {
2179            "O" // Open
2180        };
2181
2182        let ship_instructions = self.ship_instructions_random.next_value();
2183        let ship_mode = self.ship_mode_random.next_value();
2184        let comment = self.comment_random.next_value();
2185
2186        LineItem {
2187            l_orderkey: order_key,
2188            l_partkey: part_key,
2189            l_suppkey: supplier_key,
2190            l_linenumber: (self.line_number + 1),
2191            l_quantity: quantity as i64,
2192            l_extendedprice: TPCHDecimal(extended_price),
2193            l_discount: TPCHDecimal(discount as i64),
2194            l_tax: TPCHDecimal(tax as i64),
2195            l_returnflag: returned_flag,
2196            l_linestatus: status,
2197            l_shipdate: TPCHDate::new(ship_date),
2198            l_commitdate: TPCHDate::new(commit_date),
2199            l_receiptdate: TPCHDate::new(receipt_date),
2200            l_shipinstruct: ship_instructions,
2201            l_shipmode: ship_mode,
2202            l_comment: comment,
2203        }
2204    }
2205}
2206
2207impl<'a> Iterator for LineItemGeneratorIterator<'a> {
2208    type Item = LineItem<'a>;
2209
2210    fn next(&mut self) -> Option<Self::Item> {
2211        if self.index >= self.row_count {
2212            return None;
2213        }
2214
2215        let line_item = self.make_line_item(self.start_index + self.index + 1);
2216        self.line_number += 1;
2217
2218        // advance next row only when all lines for the order have been produced
2219        if self.line_number > self.line_count {
2220            self.order_date_random.row_finished();
2221            self.line_count_random.row_finished();
2222
2223            self.quantity_random.row_finished();
2224            self.discount_random.row_finished();
2225            self.tax_random.row_finished();
2226
2227            self.line_part_key_random.row_finished();
2228            self.supplier_number_random.row_finished();
2229
2230            self.ship_date_random.row_finished();
2231            self.commit_date_random.row_finished();
2232            self.receipt_date_random.row_finished();
2233
2234            self.returned_flag_random.row_finished();
2235            self.ship_instructions_random.row_finished();
2236            self.ship_mode_random.row_finished();
2237
2238            self.comment_random.row_finished();
2239
2240            self.index += 1;
2241
2242            // generate information for next order
2243            self.line_count = self.line_count_random.next_value() - 1;
2244            self.order_date = self.order_date_random.next_value();
2245            self.line_number = 0;
2246        }
2247
2248        Some(line_item)
2249    }
2250}
2251
2252#[cfg(test)]
2253mod tests {
2254    use super::*;
2255
2256    #[test]
2257    fn test_nation_generator() {
2258        let generator = NationGenerator::default();
2259        let nations: Vec<_> = generator.iter().collect();
2260
2261        // TPC-H typically has 25 nations
2262        assert_eq!(nations.len(), 25);
2263    }
2264
2265    #[test]
2266    fn test_region_generator() {
2267        let generator = RegionGenerator::default();
2268        let regions: Vec<_> = generator.iter().collect();
2269
2270        // TPC-H typically has 5 regions
2271        assert_eq!(regions.len(), 5);
2272    }
2273
2274    #[test]
2275    fn test_part_generation() {
2276        // Create a generator with a small scale factor
2277        let generator = PartGenerator::new(0.01, 1, 1);
2278        let parts: Vec<_> = generator.iter().collect();
2279
2280        // Should have 0.01 * 200,000 = 2,000 parts
2281        assert_eq!(parts.len(), 2000);
2282    }
2283
2284    #[test]
2285    fn test_calculate_part_price() {
2286        // Test with a few part keys
2287        assert_eq!(PartGeneratorIterator::calculate_part_price(1), 90100);
2288        assert_eq!(PartGeneratorIterator::calculate_part_price(10), 91001);
2289        assert_eq!(PartGeneratorIterator::calculate_part_price(100), 100010);
2290        assert_eq!(PartGeneratorIterator::calculate_part_price(1000), 90100);
2291    }
2292
2293    #[test]
2294    fn test_supplier_generation() {
2295        // Create a generator with a small scale factor
2296        let generator = SupplierGenerator::new(0.01, 1, 1);
2297        let suppliers: Vec<_> = generator.iter().collect();
2298
2299        // Should have 0.01 * 10,000 = 100 suppliers
2300        assert_eq!(suppliers.len(), 100);
2301
2302        // Check first supplier
2303        let first = &suppliers[0];
2304        assert_eq!(first.s_suppkey, 1);
2305        assert_eq!(first.to_string(), "1|Supplier#000000001| N kD4on9OM Ipw3,gf0JBoQDd7tgrzrddZ|17|27-918-335-1736|5755.94|each slyly above the careful|")
2306    }
2307
2308    #[test]
2309    fn test_customer_generation() {
2310        // Create a generator with a small scale factor
2311        let generator = CustomerGenerator::new(0.01, 1, 1);
2312        let customers: Vec<_> = generator.iter().collect();
2313
2314        // Should have 0.01 * 150,000 = 1,500 customers
2315        assert_eq!(customers.len(), 1500);
2316
2317        // Check first customer
2318        let first = &customers[0];
2319        assert_eq!(first.c_custkey, 1);
2320        assert_eq!(first.to_string(), "1|Customer#000000001|IVhzIApeRb ot,c,E|15|25-989-741-2988|711.56|BUILDING|to the even, regular platelets. regular, ironic epitaphs nag e|");
2321
2322        // Check market segment distribution
2323        let market_segments: std::collections::HashSet<_> =
2324            customers.iter().map(|c| &c.c_mktsegment).collect();
2325
2326        // Should have multiple different market segments
2327        assert!(market_segments.len() > 1);
2328
2329        // Check nation key distribution
2330        let nation_keys: std::collections::HashSet<_> =
2331            customers.iter().map(|c| c.c_nationkey).collect();
2332
2333        // Should have multiple different nation keys
2334        assert!(nation_keys.len() > 1);
2335    }
2336
2337    #[test]
2338    fn test_part_supplier_generation() {
2339        // Create a generator with a small scale factor
2340        let generator = PartSuppGenerator::new(0.01, 1, 1);
2341        let part_suppliers: Vec<_> = generator.iter().collect();
2342
2343        // Should have 0.01 * 200,000 * 4 = 8,000 part-supplier relationships
2344        assert_eq!(part_suppliers.len(), 8000);
2345
2346        // Each part should have SUPPLIERS_PER_PART suppliers
2347        let part_keys: std::collections::HashSet<_> =
2348            part_suppliers.iter().map(|ps| ps.ps_partkey).collect();
2349
2350        assert_eq!(part_keys.len(), 2000); // 8,000 / 4 = 2,000 parts
2351
2352        // Check first part supplier
2353        let first = &part_suppliers[0];
2354        assert_eq!(first.ps_partkey, 1);
2355        assert_ne!(first.ps_suppkey, 0); // Should have a valid supplier key
2356        assert!(first.ps_availqty > 0);
2357        assert!(first.ps_supplycost > TPCHDecimal::ZERO);
2358        assert!(!first.ps_comment.is_empty());
2359
2360        // Verify supplier distribution
2361        let suppliers_for_first_part: Vec<_> = part_suppliers
2362            .iter()
2363            .filter(|ps| ps.ps_partkey == 1)
2364            .map(|ps| ps.ps_suppkey)
2365            .collect();
2366
2367        assert_eq!(
2368            suppliers_for_first_part.len(),
2369            PartSuppGenerator::SUPPLIERS_PER_PART as usize
2370        );
2371
2372        // Supplier keys should be unique for each part
2373        let unique_suppliers: std::collections::HashSet<_> =
2374            suppliers_for_first_part.iter().collect();
2375        assert_eq!(
2376            unique_suppliers.len(),
2377            PartSuppGenerator::SUPPLIERS_PER_PART as usize
2378        );
2379    }
2380
2381    #[test]
2382    fn test_select_part_supplier() {
2383        // Test the supplier selection logic for consistency
2384        let scale_factor = 1.0;
2385
2386        // Same part with different supplier numbers should yield different suppliers
2387        let supplier1 = PartSuppGeneratorIterator::select_part_supplier(1, 0, scale_factor);
2388        let supplier2 = PartSuppGeneratorIterator::select_part_supplier(1, 1, scale_factor);
2389        let supplier3 = PartSuppGeneratorIterator::select_part_supplier(1, 2, scale_factor);
2390        let supplier4 = PartSuppGeneratorIterator::select_part_supplier(1, 3, scale_factor);
2391
2392        // All suppliers should be different
2393        let suppliers = vec![supplier1, supplier2, supplier3, supplier4];
2394        let unique_suppliers: std::collections::HashSet<_> = suppliers.iter().collect();
2395        assert_eq!(
2396            unique_suppliers.len(),
2397            PartSuppGenerator::SUPPLIERS_PER_PART as usize
2398        );
2399
2400        // All supplier keys should be within valid range (1 to supplier_count)
2401        let supplier_count = (SupplierGenerator::SCALE_BASE as f64 * scale_factor) as i64;
2402        for supplier in suppliers {
2403            assert!(supplier >= 1 && supplier <= supplier_count);
2404        }
2405    }
2406
2407    #[test]
2408    fn test_order_generation() {
2409        // Create a generator with a small scale factor
2410        let generator = OrderGenerator::new(0.01, 1, 1);
2411        let orders: Vec<_> = generator.iter().collect();
2412
2413        // Should have 0.01 * 1,500,000 = 15,000 orders
2414        assert_eq!(orders.len(), 15000);
2415
2416        // Check first order
2417        let first = &orders[0];
2418        assert_eq!(first.o_orderkey, OrderGenerator::make_order_key(1));
2419        assert!(first.o_custkey > 0);
2420        assert!(first.o_totalprice > TPCHDecimal::ZERO);
2421
2422        // Check order status distribution
2423        let status_counts =
2424            orders
2425                .iter()
2426                .fold(std::collections::HashMap::new(), |mut acc, order| {
2427                    *acc.entry(&order.o_orderstatus).or_insert(0) += 1;
2428                    acc
2429                });
2430
2431        // Should have multiple order statuses
2432        assert!(status_counts.len() >= 2);
2433
2434        // Check customer key distribution - no customer with mortality factor
2435        assert!(orders
2436            .iter()
2437            .all(|o| o.o_custkey % OrderGenerator::CUSTOMER_MORTALITY as i64 != 0));
2438
2439        // Check order key sparsity
2440        for (i, order) in orders.iter().enumerate() {
2441            assert_eq!(
2442                order.o_orderkey,
2443                OrderGenerator::make_order_key(i as i64 + 1)
2444            );
2445        }
2446    }
2447
2448    #[test]
2449    fn test_make_order_key() {
2450        // Test order key generation logic
2451        assert_eq!(OrderGenerator::make_order_key(1), 1); // Low values are preserved
2452        assert_eq!(OrderGenerator::make_order_key(8), 32); // 8 becomes 1000000
2453        assert_eq!(OrderGenerator::make_order_key(9), 32 + 1); // 9 becomes 1000001
2454        assert_eq!(OrderGenerator::make_order_key(10), 32 + 2); // 10 becomes 1000010
2455    }
2456
2457    #[test]
2458    fn test_line_item_generation() {
2459        // Create a generator with a small scale factor
2460        let generator = LineItemGenerator::new(0.01, 1, 1);
2461        let line_items: Vec<_> = generator.iter().collect();
2462
2463        // Check first line item
2464        let first = &line_items[0];
2465        assert_eq!(first.l_orderkey, OrderGenerator::make_order_key(1));
2466        assert_eq!(first.l_linenumber, 1);
2467        assert!(first.l_partkey > 0);
2468        assert!(first.l_suppkey > 0);
2469
2470        assert!(first.l_quantity >= LineItemGenerator::QUANTITY_MIN as i64);
2471        assert!(first.l_quantity <= LineItemGenerator::QUANTITY_MAX as i64);
2472
2473        assert!(first.l_discount >= LineItemGenerator::DISCOUNT_MIN);
2474        assert!(first.l_discount <= LineItemGenerator::DISCOUNT_MAX);
2475
2476        assert!(first.l_tax >= LineItemGenerator::TAX_MIN);
2477        assert!(first.l_tax <= LineItemGenerator::TAX_MAX);
2478
2479        // Verify line numbers are sequential per order
2480        let mut order_lines = std::collections::HashMap::new();
2481        for line in &line_items {
2482            order_lines
2483                .entry(line.l_orderkey)
2484                .or_insert_with(Vec::new)
2485                .push(line.l_linenumber);
2486        }
2487
2488        // Check each order's line numbers
2489        for (_, lines) in order_lines {
2490            let mut sorted_lines = lines.clone();
2491            sorted_lines.sort();
2492
2493            // Line numbers should start at 1 and be sequential
2494            for (i, line_num) in sorted_lines.iter().enumerate() {
2495                assert_eq!(*line_num, (i + 1) as i32);
2496            }
2497        }
2498
2499        // Verify return flags and line status distributions
2500        let return_flags: std::collections::HashSet<_> =
2501            line_items.iter().map(|l| &l.l_returnflag).collect();
2502
2503        assert!(return_flags.len() > 1);
2504
2505        let line_statuses: std::collections::HashSet<_> =
2506            line_items.iter().map(|l| &l.l_linestatus).collect();
2507
2508        assert!(!line_statuses.is_empty());
2509    }
2510
2511    #[test]
2512    fn check_iter_static_lifetimes() {
2513        // Lifetimes of iterators should be independent of the generator that
2514        // created it. This test case won't compile if that's not the case.
2515
2516        let _iter: NationGeneratorIterator<'static> = NationGenerator::default().iter();
2517        let _iter: RegionGeneratorIterator<'static> = RegionGenerator::default().iter();
2518        let _iter: PartGeneratorIterator<'static> = PartGenerator::new(0.1, 1, 1).iter();
2519        let _iter: SupplierGeneratorIterator<'static> = SupplierGenerator::new(0.1, 1, 1).iter();
2520        let _iter: CustomerGeneratorIterator<'static> = CustomerGenerator::new(0.1, 1, 1).iter();
2521        let _iter: PartSuppGeneratorIterator<'static> = PartSuppGenerator::new(0.1, 1, 1).iter();
2522        let _iter: OrderGeneratorIterator<'static> = OrderGenerator::new(0.1, 1, 1).iter();
2523        let _iter: LineItemGeneratorIterator<'static> = LineItemGenerator::new(0.1, 1, 1).iter();
2524    }
2525}