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