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