1use std::sync::Arc;
19
20use arrow_array::ArrayRef;
21use arrow_schema::DataType;
22
23use super::TransformFunction;
24use crate::Error;
25use crate::spec::{Datum, PrimitiveLiteral};
26
27#[derive(Debug)]
28pub struct Truncate {
29 width: u32,
30}
31
32impl Truncate {
33 pub fn new(width: u32) -> Self {
34 Self { width }
35 }
36
37 #[inline]
38 fn truncate_str(s: &str, width: usize) -> &str {
39 match s.char_indices().nth(width) {
40 None => s,
41 Some((idx, _)) => &s[..idx],
42 }
43 }
44
45 #[inline]
46 fn truncate_binary(s: &[u8], width: usize) -> &[u8] {
47 if s.len() > width { &s[0..width] } else { s }
48 }
49
50 #[inline]
51 fn truncate_i32(v: i32, width: i32) -> i32 {
52 v - v.rem_euclid(width)
53 }
54
55 #[inline]
56 fn truncate_i64(v: i64, width: i64) -> i64 {
57 v - (((v % width) + width) % width)
58 }
59
60 #[inline]
61 fn truncate_decimal_i128(v: i128, width: i128) -> i128 {
62 v - (((v % width) + width) % width)
63 }
64}
65
66impl TransformFunction for Truncate {
67 fn transform(&self, input: ArrayRef) -> crate::Result<ArrayRef> {
68 match input.data_type() {
69 DataType::Int32 => {
70 let width: i32 = self.width.try_into().map_err(|_| {
71 Error::new(
72 crate::ErrorKind::DataInvalid,
73 "width is failed to convert to i32 when truncate Int32Array",
74 )
75 })?;
76 let res: arrow_array::Int32Array = input
77 .as_any()
78 .downcast_ref::<arrow_array::Int32Array>()
79 .unwrap()
80 .unary(|v| Self::truncate_i32(v, width));
81 Ok(Arc::new(res))
82 }
83 DataType::Int64 => {
84 let width = self.width as i64;
85 let res: arrow_array::Int64Array = input
86 .as_any()
87 .downcast_ref::<arrow_array::Int64Array>()
88 .unwrap()
89 .unary(|v| Self::truncate_i64(v, width));
90 Ok(Arc::new(res))
91 }
92 DataType::Decimal128(precision, scale) => {
93 let width = self.width as i128;
94 let res: arrow_array::Decimal128Array = input
95 .as_any()
96 .downcast_ref::<arrow_array::Decimal128Array>()
97 .unwrap()
98 .unary(|v| Self::truncate_decimal_i128(v, width))
99 .with_precision_and_scale(*precision, *scale)
100 .map_err(|err| Error::new(crate::ErrorKind::Unexpected, format!("{err}")))?;
101 Ok(Arc::new(res))
102 }
103 DataType::Utf8 => {
104 let len = self.width as usize;
105 let res: arrow_array::StringArray = arrow_array::StringArray::from_iter(
106 input
107 .as_any()
108 .downcast_ref::<arrow_array::StringArray>()
109 .unwrap()
110 .iter()
111 .map(|v| v.map(|v| Self::truncate_str(v, len))),
112 );
113 Ok(Arc::new(res))
114 }
115 DataType::LargeUtf8 => {
116 let len = self.width as usize;
117 let res: arrow_array::LargeStringArray = arrow_array::LargeStringArray::from_iter(
118 input
119 .as_any()
120 .downcast_ref::<arrow_array::LargeStringArray>()
121 .unwrap()
122 .iter()
123 .map(|v| v.map(|v| Self::truncate_str(v, len))),
124 );
125 Ok(Arc::new(res))
126 }
127 DataType::Binary => {
128 let len = self.width as usize;
129 let res: arrow_array::BinaryArray = arrow_array::BinaryArray::from_iter(
130 input
131 .as_any()
132 .downcast_ref::<arrow_array::BinaryArray>()
133 .unwrap()
134 .iter()
135 .map(|v| v.map(|v| Self::truncate_binary(v, len))),
136 );
137 Ok(Arc::new(res))
138 }
139 _ => Err(crate::Error::new(
140 crate::ErrorKind::FeatureUnsupported,
141 format!(
142 "Unsupported data type for truncate transform: {:?}",
143 input.data_type()
144 ),
145 )),
146 }
147 }
148
149 fn transform_literal(&self, input: &Datum) -> crate::Result<Option<Datum>> {
150 match input.literal() {
151 PrimitiveLiteral::Int(v) => Ok(Some({
152 let width: i32 = self.width.try_into().map_err(|_| {
153 Error::new(
154 crate::ErrorKind::DataInvalid,
155 "width is failed to convert to i32 when truncate Int32Array",
156 )
157 })?;
158 Datum::int(Self::truncate_i32(*v, width))
159 })),
160 PrimitiveLiteral::Long(v) => Ok(Some({
161 let width = self.width as i64;
162 Datum::long(Self::truncate_i64(*v, width))
163 })),
164 PrimitiveLiteral::Int128(v) => Ok(Some({
165 let width = self.width as i128;
166 Datum::decimal(Self::truncate_decimal_i128(*v, width))?
167 })),
168 PrimitiveLiteral::String(v) => Ok(Some({
169 let len = self.width as usize;
170 Datum::string(Self::truncate_str(v, len).to_string())
171 })),
172 _ => Err(crate::Error::new(
173 crate::ErrorKind::FeatureUnsupported,
174 format!(
175 "Unsupported data type for truncate transform: {:?}",
176 input.data_type()
177 ),
178 )),
179 }
180 }
181}
182
183#[cfg(test)]
184mod test {
185 use std::sync::Arc;
186
187 use arrow_array::builder::PrimitiveBuilder;
188 use arrow_array::types::Decimal128Type;
189 use arrow_array::{Decimal128Array, Int32Array, Int64Array};
190
191 use crate::Result;
192 use crate::expr::PredicateOperator;
193 use crate::spec::PrimitiveType::{
194 Binary, Date, Decimal, Fixed, Int, Long, String as StringType, Time, Timestamp,
195 TimestampNs, Timestamptz, TimestamptzNs, Uuid,
196 };
197 use crate::spec::Type::{Primitive, Struct};
198 use crate::spec::{Datum, NestedField, PrimitiveType, StructType, Transform, Type};
199 use crate::transform::TransformFunction;
200 use crate::transform::test::{TestProjectionFixture, TestTransformFixture};
201
202 #[test]
203 fn test_truncate_transform() {
204 let trans = Transform::Truncate(4);
205
206 let fixture = TestTransformFixture {
207 display: "truncate[4]".to_string(),
208 json: r#""truncate[4]""#.to_string(),
209 dedup_name: "truncate[4]".to_string(),
210 preserves_order: true,
211 satisfies_order_of: vec![
212 (Transform::Truncate(4), true),
213 (Transform::Truncate(2), false),
214 (Transform::Bucket(4), false),
215 (Transform::Void, false),
216 (Transform::Day, false),
217 ],
218 trans_types: vec![
219 (Primitive(Binary), Some(Primitive(Binary))),
220 (Primitive(Date), None),
221 (
222 Primitive(Decimal {
223 precision: 8,
224 scale: 5,
225 }),
226 Some(Primitive(Decimal {
227 precision: 8,
228 scale: 5,
229 })),
230 ),
231 (Primitive(Fixed(8)), None),
232 (Primitive(Int), Some(Primitive(Int))),
233 (Primitive(Long), Some(Primitive(Long))),
234 (Primitive(StringType), Some(Primitive(StringType))),
235 (Primitive(Uuid), None),
236 (Primitive(Time), None),
237 (Primitive(Timestamp), None),
238 (Primitive(Timestamptz), None),
239 (Primitive(TimestampNs), None),
240 (Primitive(TimestamptzNs), None),
241 (
242 Struct(StructType::new(vec![
243 NestedField::optional(1, "a", Primitive(Timestamp)).into(),
244 ])),
245 None,
246 ),
247 ],
248 };
249
250 fixture.assert_transform(trans);
251 }
252
253 #[test]
254 fn test_projection_truncate_string_rewrite_op() -> Result<()> {
255 let value = "abcde";
256
257 let fixture = TestProjectionFixture::new(
258 Transform::Truncate(5),
259 "name",
260 NestedField::required(1, "value", Type::Primitive(PrimitiveType::String)),
261 );
262
263 fixture.assert_projection(
264 &fixture.binary_predicate(PredicateOperator::StartsWith, Datum::string(value)),
265 Some(r#"name = "abcde""#),
266 )?;
267
268 fixture.assert_projection(
269 &fixture.binary_predicate(PredicateOperator::NotStartsWith, Datum::string(value)),
270 Some(r#"name != "abcde""#),
271 )?;
272
273 let value = "abcdefg";
274 fixture.assert_projection(
275 &fixture.binary_predicate(PredicateOperator::StartsWith, Datum::string(value)),
276 Some(r#"name STARTS WITH "abcde""#),
277 )?;
278
279 fixture.assert_projection(
280 &fixture.binary_predicate(PredicateOperator::NotStartsWith, Datum::string(value)),
281 None,
282 )?;
283
284 Ok(())
285 }
286
287 #[test]
288 fn test_projection_truncate_string() -> Result<()> {
289 let value = "abcdefg";
290
291 let fixture = TestProjectionFixture::new(
292 Transform::Truncate(5),
293 "name",
294 NestedField::required(1, "value", Type::Primitive(PrimitiveType::String)),
295 );
296
297 fixture.assert_projection(
298 &fixture.binary_predicate(PredicateOperator::LessThan, Datum::string(value)),
299 Some(r#"name <= "abcde""#),
300 )?;
301
302 fixture.assert_projection(
303 &fixture.binary_predicate(PredicateOperator::LessThanOrEq, Datum::string(value)),
304 Some(r#"name <= "abcde""#),
305 )?;
306
307 fixture.assert_projection(
308 &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::string(value)),
309 Some(r#"name >= "abcde""#),
310 )?;
311
312 fixture.assert_projection(
313 &fixture.binary_predicate(PredicateOperator::GreaterThanOrEq, Datum::string(value)),
314 Some(r#"name >= "abcde""#),
315 )?;
316
317 fixture.assert_projection(
318 &fixture.binary_predicate(PredicateOperator::Eq, Datum::string(value)),
319 Some(r#"name = "abcde""#),
320 )?;
321
322 fixture.assert_projection(
323 &fixture.set_predicate(PredicateOperator::In, vec![
324 Datum::string(value),
325 Datum::string(format!("{value}abc")),
326 ]),
327 Some(r#"name IN ("abcde")"#),
328 )?;
329
330 fixture.assert_projection(
331 &fixture.set_predicate(PredicateOperator::NotIn, vec![
332 Datum::string(value),
333 Datum::string(format!("{value}abc")),
334 ]),
335 None,
336 )?;
337
338 Ok(())
339 }
340
341 #[test]
342 fn test_projection_truncate_upper_bound_decimal() -> Result<()> {
343 let prev = "98.99";
344 let curr = "99.99";
345 let next = "100.99";
346
347 let fixture = TestProjectionFixture::new(
348 Transform::Truncate(10),
349 "name",
350 NestedField::required(
351 1,
352 "value",
353 Type::Primitive(PrimitiveType::Decimal {
354 precision: 9,
355 scale: 2,
356 }),
357 ),
358 );
359
360 fixture.assert_projection(
361 &fixture.binary_predicate(PredicateOperator::LessThan, Datum::decimal_from_str(curr)?),
362 Some("name <= 9990"),
363 )?;
364
365 fixture.assert_projection(
366 &fixture.binary_predicate(
367 PredicateOperator::LessThanOrEq,
368 Datum::decimal_from_str(curr)?,
369 ),
370 Some("name <= 9990"),
371 )?;
372
373 fixture.assert_projection(
374 &fixture.binary_predicate(
375 PredicateOperator::GreaterThanOrEq,
376 Datum::decimal_from_str(curr)?,
377 ),
378 Some("name >= 9990"),
379 )?;
380
381 fixture.assert_projection(
382 &fixture.binary_predicate(PredicateOperator::Eq, Datum::decimal_from_str(curr)?),
383 Some("name = 9990"),
384 )?;
385
386 fixture.assert_projection(
387 &fixture.binary_predicate(PredicateOperator::NotEq, Datum::decimal_from_str(curr)?),
388 None,
389 )?;
390
391 fixture.assert_projection(
392 &fixture.set_predicate(PredicateOperator::In, vec![
393 Datum::decimal_from_str(prev)?,
394 Datum::decimal_from_str(curr)?,
395 Datum::decimal_from_str(next)?,
396 ]),
397 Some("name IN (9890, 9990, 10090)"),
398 )?;
399
400 fixture.assert_projection(
401 &fixture.set_predicate(PredicateOperator::NotIn, vec![
402 Datum::decimal_from_str(curr)?,
403 Datum::decimal_from_str(next)?,
404 ]),
405 None,
406 )?;
407
408 Ok(())
409 }
410
411 #[test]
412 fn test_projection_truncate_lower_bound_decimal() -> Result<()> {
413 let prev = "99.00";
414 let curr = "100.00";
415 let next = "101.00";
416
417 let fixture = TestProjectionFixture::new(
418 Transform::Truncate(10),
419 "name",
420 NestedField::required(
421 1,
422 "value",
423 Type::Primitive(PrimitiveType::Decimal {
424 precision: 9,
425 scale: 2,
426 }),
427 ),
428 );
429
430 fixture.assert_projection(
431 &fixture.binary_predicate(PredicateOperator::LessThan, Datum::decimal_from_str(curr)?),
432 Some("name <= 9990"),
433 )?;
434
435 fixture.assert_projection(
436 &fixture.binary_predicate(
437 PredicateOperator::LessThanOrEq,
438 Datum::decimal_from_str(curr)?,
439 ),
440 Some("name <= 10000"),
441 )?;
442
443 fixture.assert_projection(
444 &fixture.binary_predicate(
445 PredicateOperator::GreaterThanOrEq,
446 Datum::decimal_from_str(curr)?,
447 ),
448 Some("name >= 10000"),
449 )?;
450
451 fixture.assert_projection(
452 &fixture.binary_predicate(PredicateOperator::Eq, Datum::decimal_from_str(curr)?),
453 Some("name = 10000"),
454 )?;
455
456 fixture.assert_projection(
457 &fixture.binary_predicate(PredicateOperator::NotEq, Datum::decimal_from_str(curr)?),
458 None,
459 )?;
460
461 fixture.assert_projection(
462 &fixture.set_predicate(PredicateOperator::In, vec![
463 Datum::decimal_from_str(prev)?,
464 Datum::decimal_from_str(curr)?,
465 Datum::decimal_from_str(next)?,
466 ]),
467 Some("name IN (10000, 10100, 9900)"),
468 )?;
469
470 fixture.assert_projection(
471 &fixture.set_predicate(PredicateOperator::NotIn, vec![
472 Datum::decimal_from_str(curr)?,
473 Datum::decimal_from_str(next)?,
474 ]),
475 None,
476 )?;
477
478 Ok(())
479 }
480
481 #[test]
482 fn test_projection_truncate_upper_bound_long() -> Result<()> {
483 let value = 99i64;
484
485 let fixture = TestProjectionFixture::new(
486 Transform::Truncate(10),
487 "name",
488 NestedField::required(1, "value", Type::Primitive(PrimitiveType::Long)),
489 );
490
491 fixture.assert_projection(
492 &fixture.binary_predicate(PredicateOperator::LessThan, Datum::long(value)),
493 Some("name <= 90"),
494 )?;
495
496 fixture.assert_projection(
497 &fixture.binary_predicate(PredicateOperator::LessThanOrEq, Datum::long(value)),
498 Some("name <= 90"),
499 )?;
500
501 fixture.assert_projection(
502 &fixture.binary_predicate(PredicateOperator::GreaterThanOrEq, Datum::long(value)),
503 Some("name >= 90"),
504 )?;
505
506 fixture.assert_projection(
507 &fixture.binary_predicate(PredicateOperator::Eq, Datum::long(value)),
508 Some("name = 90"),
509 )?;
510
511 fixture.assert_projection(
512 &fixture.binary_predicate(PredicateOperator::NotEq, Datum::long(value)),
513 None,
514 )?;
515
516 fixture.assert_projection(
517 &fixture.set_predicate(PredicateOperator::In, vec![
518 Datum::long(value - 1),
519 Datum::long(value),
520 Datum::long(value + 1),
521 ]),
522 Some("name IN (100, 90)"),
523 )?;
524
525 fixture.assert_projection(
526 &fixture.set_predicate(PredicateOperator::NotIn, vec![
527 Datum::long(value),
528 Datum::long(value + 1),
529 ]),
530 None,
531 )?;
532
533 Ok(())
534 }
535
536 #[test]
537 fn test_projection_truncate_lower_bound_long() -> Result<()> {
538 let value = 100i64;
539
540 let fixture = TestProjectionFixture::new(
541 Transform::Truncate(10),
542 "name",
543 NestedField::required(1, "value", Type::Primitive(PrimitiveType::Long)),
544 );
545
546 fixture.assert_projection(
547 &fixture.binary_predicate(PredicateOperator::LessThan, Datum::long(value)),
548 Some("name <= 90"),
549 )?;
550
551 fixture.assert_projection(
552 &fixture.binary_predicate(PredicateOperator::LessThanOrEq, Datum::long(value)),
553 Some("name <= 100"),
554 )?;
555
556 fixture.assert_projection(
557 &fixture.binary_predicate(PredicateOperator::GreaterThanOrEq, Datum::long(value)),
558 Some("name >= 100"),
559 )?;
560
561 fixture.assert_projection(
562 &fixture.binary_predicate(PredicateOperator::Eq, Datum::long(value)),
563 Some("name = 100"),
564 )?;
565
566 fixture.assert_projection(
567 &fixture.binary_predicate(PredicateOperator::NotEq, Datum::long(value)),
568 None,
569 )?;
570
571 fixture.assert_projection(
572 &fixture.set_predicate(PredicateOperator::In, vec![
573 Datum::long(value - 1),
574 Datum::long(value),
575 Datum::long(value + 1),
576 ]),
577 Some("name IN (100, 90)"),
578 )?;
579
580 fixture.assert_projection(
581 &fixture.set_predicate(PredicateOperator::NotIn, vec![
582 Datum::long(value),
583 Datum::long(value + 1),
584 ]),
585 None,
586 )?;
587
588 Ok(())
589 }
590
591 #[test]
592 fn test_projection_truncate_upper_bound_integer() -> Result<()> {
593 let value = 99;
594
595 let fixture = TestProjectionFixture::new(
596 Transform::Truncate(10),
597 "name",
598 NestedField::required(1, "value", Type::Primitive(PrimitiveType::Int)),
599 );
600
601 fixture.assert_projection(
602 &fixture.binary_predicate(PredicateOperator::LessThan, Datum::int(value)),
603 Some("name <= 90"),
604 )?;
605
606 fixture.assert_projection(
607 &fixture.binary_predicate(PredicateOperator::LessThanOrEq, Datum::int(value)),
608 Some("name <= 90"),
609 )?;
610
611 fixture.assert_projection(
612 &fixture.binary_predicate(PredicateOperator::GreaterThanOrEq, Datum::int(value)),
613 Some("name >= 90"),
614 )?;
615
616 fixture.assert_projection(
617 &fixture.binary_predicate(PredicateOperator::Eq, Datum::int(value)),
618 Some("name = 90"),
619 )?;
620
621 fixture.assert_projection(
622 &fixture.binary_predicate(PredicateOperator::NotEq, Datum::int(value)),
623 None,
624 )?;
625
626 fixture.assert_projection(
627 &fixture.set_predicate(PredicateOperator::In, vec![
628 Datum::int(value - 1),
629 Datum::int(value),
630 Datum::int(value + 1),
631 ]),
632 Some("name IN (100, 90)"),
633 )?;
634
635 fixture.assert_projection(
636 &fixture.set_predicate(PredicateOperator::NotIn, vec![
637 Datum::int(value),
638 Datum::int(value + 1),
639 ]),
640 None,
641 )?;
642
643 Ok(())
644 }
645
646 #[test]
647 fn test_projection_truncate_lower_bound_integer() -> Result<()> {
648 let value = 100;
649
650 let fixture = TestProjectionFixture::new(
651 Transform::Truncate(10),
652 "name",
653 NestedField::required(1, "value", Type::Primitive(PrimitiveType::Int)),
654 );
655
656 fixture.assert_projection(
657 &fixture.binary_predicate(PredicateOperator::LessThan, Datum::int(value)),
658 Some("name <= 90"),
659 )?;
660
661 fixture.assert_projection(
662 &fixture.binary_predicate(PredicateOperator::LessThanOrEq, Datum::int(value)),
663 Some("name <= 100"),
664 )?;
665
666 fixture.assert_projection(
667 &fixture.binary_predicate(PredicateOperator::GreaterThanOrEq, Datum::int(value)),
668 Some("name >= 100"),
669 )?;
670
671 fixture.assert_projection(
672 &fixture.binary_predicate(PredicateOperator::Eq, Datum::int(value)),
673 Some("name = 100"),
674 )?;
675
676 fixture.assert_projection(
677 &fixture.binary_predicate(PredicateOperator::NotEq, Datum::int(value)),
678 None,
679 )?;
680
681 fixture.assert_projection(
682 &fixture.set_predicate(PredicateOperator::In, vec![
683 Datum::int(value - 1),
684 Datum::int(value),
685 Datum::int(value + 1),
686 ]),
687 Some("name IN (100, 90)"),
688 )?;
689
690 fixture.assert_projection(
691 &fixture.set_predicate(PredicateOperator::NotIn, vec![
692 Datum::int(value),
693 Datum::int(value + 1),
694 ]),
695 None,
696 )?;
697
698 Ok(())
699 }
700
701 #[test]
703 fn test_truncate_simple() {
704 let input = Arc::new(Int32Array::from(vec![1, -1]));
706 let res = super::Truncate::new(10).transform(input).unwrap();
707 assert_eq!(
708 res.as_any().downcast_ref::<Int32Array>().unwrap().value(0),
709 0
710 );
711 assert_eq!(
712 res.as_any().downcast_ref::<Int32Array>().unwrap().value(1),
713 -10
714 );
715
716 let input = Arc::new(Int64Array::from(vec![1, -1]));
718 let res = super::Truncate::new(10).transform(input).unwrap();
719 assert_eq!(
720 res.as_any().downcast_ref::<Int64Array>().unwrap().value(0),
721 0
722 );
723 assert_eq!(
724 res.as_any().downcast_ref::<Int64Array>().unwrap().value(1),
725 -10
726 );
727
728 let mut builder = PrimitiveBuilder::<Decimal128Type>::new()
730 .with_precision_and_scale(20, 2)
731 .unwrap();
732 builder.append_value(1065);
733 let input = Arc::new(builder.finish());
734 let res = super::Truncate::new(50).transform(input).unwrap();
735 assert_eq!(
736 res.as_any()
737 .downcast_ref::<Decimal128Array>()
738 .unwrap()
739 .value(0),
740 1050
741 );
742
743 let input = Arc::new(arrow_array::StringArray::from(vec!["iceberg"]));
745 let res = super::Truncate::new(3).transform(input).unwrap();
746 assert_eq!(
747 res.as_any()
748 .downcast_ref::<arrow_array::StringArray>()
749 .unwrap()
750 .value(0),
751 "ice"
752 );
753
754 let input = Arc::new(arrow_array::LargeStringArray::from(vec!["iceberg"]));
756 let res = super::Truncate::new(3).transform(input).unwrap();
757 assert_eq!(
758 res.as_any()
759 .downcast_ref::<arrow_array::LargeStringArray>()
760 .unwrap()
761 .value(0),
762 "ice"
763 );
764
765 let input = Arc::new(arrow_array::BinaryArray::from_vec(vec![b"iceberg"]));
767 let res = super::Truncate::new(3).transform(input).unwrap();
768 assert_eq!(
769 res.as_any()
770 .downcast_ref::<arrow_array::BinaryArray>()
771 .unwrap()
772 .value(0),
773 b"ice"
774 );
775 }
776
777 #[test]
778 fn test_string_truncate() {
779 let test1 = "イロハニホヘト";
780 let test1_2_expected = "イロ";
781 assert_eq!(super::Truncate::truncate_str(test1, 2), test1_2_expected);
782
783 let test1_3_expected = "イロハ";
784 assert_eq!(super::Truncate::truncate_str(test1, 3), test1_3_expected);
785
786 let test2 = "щщаεはчωいにπάほхεろへσκζ";
787 let test2_7_expected = "щщаεはчω";
788 assert_eq!(super::Truncate::truncate_str(test2, 7), test2_7_expected);
789
790 let test3 = "\u{FFFF}\u{FFFF}";
791 assert_eq!(super::Truncate::truncate_str(test3, 2), test3);
792
793 let test4 = "\u{10000}\u{10000}";
794 let test4_1_expected = "\u{10000}";
795 assert_eq!(super::Truncate::truncate_str(test4, 1), test4_1_expected);
796 }
797
798 #[test]
799 fn test_literal_int() {
800 let input = Datum::int(1);
801 let res = super::Truncate::new(10)
802 .transform_literal(&input)
803 .unwrap()
804 .unwrap();
805 assert_eq!(res, Datum::int(0),);
806
807 let input = Datum::int(-1);
808 let res = super::Truncate::new(10)
809 .transform_literal(&input)
810 .unwrap()
811 .unwrap();
812 assert_eq!(res, Datum::int(-10),);
813 }
814
815 #[test]
816 fn test_literal_long() {
817 let input = Datum::long(1);
818 let res = super::Truncate::new(10)
819 .transform_literal(&input)
820 .unwrap()
821 .unwrap();
822 assert_eq!(res, Datum::long(0),);
823
824 let input = Datum::long(-1);
825 let res = super::Truncate::new(10)
826 .transform_literal(&input)
827 .unwrap()
828 .unwrap();
829 assert_eq!(res, Datum::long(-10),);
830 }
831
832 #[test]
833 fn test_decimal_literal() {
834 let input = Datum::decimal(1065).unwrap();
835 let res = super::Truncate::new(50)
836 .transform_literal(&input)
837 .unwrap()
838 .unwrap();
839 assert_eq!(res, Datum::decimal(1050).unwrap(),);
840 }
841
842 #[test]
843 fn test_string_literal() {
844 let input = Datum::string("iceberg".to_string());
845 let res = super::Truncate::new(3)
846 .transform_literal(&input)
847 .unwrap()
848 .unwrap();
849 assert_eq!(res, Datum::string("ice".to_string()),);
850 }
851}