1+ // Copyright (c) Microsoft Corporation.
2+ // Licensed under the MIT License.
3+
4+ use crate :: DscError ;
5+ use crate :: configure:: context:: Context ;
6+ use crate :: functions:: { FunctionArgKind , Function , FunctionCategory , FunctionMetadata } ;
7+ use rust_i18n:: t;
8+ use serde_json:: { Map , Value } ;
9+ use tracing:: debug;
10+
11+ #[ derive( Debug , Default ) ]
12+ pub struct Intersection { }
13+
14+ impl Function for Intersection {
15+ fn get_metadata ( & self ) -> FunctionMetadata {
16+ FunctionMetadata {
17+ name : "intersection" . to_string ( ) ,
18+ description : t ! ( "functions.intersection.description" ) . to_string ( ) ,
19+ category : FunctionCategory :: Array ,
20+ min_args : 2 ,
21+ max_args : usize:: MAX ,
22+ accepted_arg_ordered_types : vec ! [
23+ vec![ FunctionArgKind :: Array , FunctionArgKind :: Object ] ,
24+ vec![ FunctionArgKind :: Array , FunctionArgKind :: Object ] ,
25+ ] ,
26+ remaining_arg_accepted_types : Some ( vec ! [ FunctionArgKind :: Array , FunctionArgKind :: Object ] ) ,
27+ return_types : vec ! [ FunctionArgKind :: Array , FunctionArgKind :: Object ] ,
28+ }
29+ }
30+
31+ fn invoke ( & self , args : & [ Value ] , _context : & Context ) -> Result < Value , DscError > {
32+ debug ! ( "{}" , t!( "functions.intersection.invoked" ) ) ;
33+
34+ if args[ 0 ] . is_array ( ) {
35+ let first_array = args[ 0 ] . as_array ( ) . unwrap ( ) ;
36+ let mut result = Vec :: new ( ) ;
37+
38+ for item in first_array {
39+ let mut found_in_all = true ;
40+
41+ for arg in & args[ 1 ..] {
42+ if let Some ( array) = arg. as_array ( ) {
43+ if !array. contains ( item) {
44+ found_in_all = false ;
45+ break ;
46+ }
47+ } else {
48+ return Err ( DscError :: Parser ( t ! ( "functions.intersection.invalidArgType" ) . to_string ( ) ) ) ;
49+ }
50+ }
51+
52+ if found_in_all && !result. contains ( item) {
53+ result. push ( item. clone ( ) ) ;
54+ }
55+ }
56+
57+ return Ok ( Value :: Array ( result) ) ;
58+ }
59+
60+ if args[ 0 ] . is_object ( ) {
61+ let first_object = args[ 0 ] . as_object ( ) . unwrap ( ) ;
62+ let mut result = Map :: new ( ) ;
63+
64+ for ( key, value) in first_object {
65+ let mut found_in_all = true ;
66+
67+ for arg in & args[ 1 ..] {
68+ if let Some ( object) = arg. as_object ( ) {
69+ if let Some ( other_value) = object. get ( key) {
70+ if other_value != value {
71+ found_in_all = false ;
72+ break ;
73+ }
74+ } else {
75+ found_in_all = false ;
76+ break ;
77+ }
78+ } else {
79+ return Err ( DscError :: Parser ( t ! ( "functions.intersection.invalidArgType" ) . to_string ( ) ) ) ;
80+ }
81+ }
82+
83+ if found_in_all {
84+ result. insert ( key. clone ( ) , value. clone ( ) ) ;
85+ }
86+ }
87+
88+ return Ok ( Value :: Object ( result) ) ;
89+ }
90+
91+ Err ( DscError :: Parser ( t ! ( "functions.intersection.invalidArgType" ) . to_string ( ) ) )
92+ }
93+ }
94+
95+ #[ cfg( test) ]
96+ mod tests {
97+ use crate :: configure:: context:: Context ;
98+ use crate :: parser:: Statement ;
99+
100+ #[ test]
101+ fn array_intersection ( ) {
102+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
103+ let result = parser. parse_and_execute ( "[intersection(createArray(1, 2, 3), createArray(2, 3, 4))]" , & Context :: new ( ) ) . unwrap ( ) ;
104+ assert_eq ! ( result, serde_json:: json!( [ 2 , 3 ] ) ) ;
105+ }
106+
107+ #[ test]
108+ fn array_intersection_three_arrays ( ) {
109+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
110+ let result = parser. parse_and_execute ( "[intersection(createArray(1, 2, 3, 4), createArray(2, 3, 4, 5), createArray(3, 4, 5, 6))]" , & Context :: new ( ) ) . unwrap ( ) ;
111+ assert_eq ! ( result, serde_json:: json!( [ 3 , 4 ] ) ) ;
112+ }
113+
114+ #[ test]
115+ fn array_intersection_no_common_elements ( ) {
116+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
117+ let result = parser. parse_and_execute ( "[intersection(createArray(1, 2), createArray(3, 4))]" , & Context :: new ( ) ) . unwrap ( ) ;
118+ assert_eq ! ( result, serde_json:: json!( [ ] ) ) ;
119+ }
120+
121+ #[ test]
122+ fn array_intersection_with_duplicates ( ) {
123+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
124+ let result = parser. parse_and_execute ( "[intersection(createArray(1, 2, 2, 3), createArray(2, 2, 3, 4))]" , & Context :: new ( ) ) . unwrap ( ) ;
125+ assert_eq ! ( result, serde_json:: json!( [ 2 , 3 ] ) ) ;
126+ }
127+
128+ #[ test]
129+ fn object_intersection ( ) {
130+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
131+ let result = parser. parse_and_execute ( "[intersection(createObject('a', 1, 'b', 2), createObject('b', 2, 'c', 3))]" , & Context :: new ( ) ) . unwrap ( ) ;
132+ assert_eq ! ( result, serde_json:: json!( { "b" : 2 } ) ) ;
133+ }
134+
135+ #[ test]
136+ fn object_intersection_different_values ( ) {
137+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
138+ let result = parser. parse_and_execute ( "[intersection(createObject('a', 1, 'b', 2), createObject('a', 2, 'b', 2))]" , & Context :: new ( ) ) . unwrap ( ) ;
139+ assert_eq ! ( result, serde_json:: json!( { "b" : 2 } ) ) ;
140+ }
141+
142+ #[ test]
143+ fn object_intersection_no_common_keys ( ) {
144+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
145+ let result = parser. parse_and_execute ( "[intersection(createObject('a', 1), createObject('b', 2))]" , & Context :: new ( ) ) . unwrap ( ) ;
146+ assert_eq ! ( result, serde_json:: json!( { } ) ) ;
147+ }
148+
149+ #[ test]
150+ fn mixed_types_error ( ) {
151+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
152+ let result = parser. parse_and_execute ( "[intersection(createArray(1, 2), createObject('a', 1))]" , & Context :: new ( ) ) ;
153+ assert ! ( result. is_err( ) ) ;
154+ }
155+ }
0 commit comments