Skip to content

Commit

Permalink
Add better naming and CFML interop with CFML Arrays and Structs
Browse files Browse the repository at this point in the history
  • Loading branch information
elpete committed Feb 28, 2024
1 parent dd72b2c commit 315c292
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 6 deletions.
47 changes: 45 additions & 2 deletions models/Stream.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,14 @@ component accessors="true" {
return variables.jStream.toArray();
}

/**
* Returns an array containing the elements of this stream.
* Right now, an alias of toArray(), with the hope that we can convert the `toArray` to a CFML array in the future.
*/
function toNativeArray(){
return variables.jStream.toArray();
}


/**
* Returns the count of elements in this stream.
Expand Down Expand Up @@ -787,6 +795,17 @@ component accessors="true" {
return variables.jStream.collect( variables.Collectors.toList() );
}

/**
* A mutable reduction operation that accumulates input elements into a mutable result container, optionally transforming the accumulated result into a final representation after all input elements have been processed.
* By default we will collect to a CFML array.
*
* This is a terminal operation.
*
*/
function collectAsArray(){
return arraySlice( variables.jStream.collect( variables.Collectors.toList() ), 1 );
}

/**
* Returns a Collector implementing a "group by" operation on input elements, grouping elements according to a
* classification function, and returning the results in a struct according to the classifier function
Expand Down Expand Up @@ -919,7 +938,7 @@ component accessors="true" {
}

/**
* Collect the items to a struct. Please be sure to map the appropriate key and value identifiers
* Collect the items to a HashMap. Please be sure to map the appropriate key and value identifiers
*
* NOTE: the struct type will only work if the collection we are collecting is a struct or an object
* This is a terminal operation.
Expand All @@ -928,7 +947,7 @@ component accessors="true" {
* @valueID If using struct, then we need to know what will be the value key in the collection struct
* @overwrite If using struct, then do you overwrite elements if the same key id is found. Defaults is true.
*/
function collectAsStruct(
function collectAsMap(
required keyID,
required valueID,
boolean overwrite = true
Expand Down Expand Up @@ -981,6 +1000,30 @@ component accessors="true" {
);
}

/**
* Collect the items to a CFML struct. Please be sure to map the appropriate key and value identifiers
*
* NOTE: the struct type will only work if the collection we are collecting is a struct or an object
* This is a terminal operation.
*
* @keyID If using struct, then we need to know what will be the key value in the collection struct
* @valueID If using struct, then we need to know what will be the value key in the collection struct
* @overwrite If using struct, then do you overwrite elements if the same key id is found. Defaults is true.
*/
function collectAsStruct(
required keyID,
required valueID,
boolean overwrite = true
){
var newStruct = {};
structAppend(
newStruct,
collectAsMap( argumentCollection = arguments ),
true
);
return newStruct;
}

/**
* Returns a Collector which partitions the input elements according to a Predicate, and organizes them into a Map<boolean, List < T>>.
*
Expand Down
9 changes: 6 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ Terminal operations are a way to finalize the execution of the stream. Please n
- `iterator()` - Return a java iterator of the stream
- `spliterator()` - Return a java spliterator of the stream
- `close()` - Close the stream
- `toArray()` - Convert the stream back into an array
- `toArray()` - Convert the stream back into a native Java array
- `toNativeArray()` - Convert the stream back into a native Java array. Currently and alias of `toArray` with the hope that in the future `toArray` will return a CFML array.
- `count()` - Count the elements in the stream
- `findAny()` - Find any element in the stream
- `findFirst()` - Find the first element in the stream
Expand All @@ -249,14 +250,16 @@ Terminal operations are a way to finalize the execution of the stream. Please n

Collectors are the way to get out of the streams world and obtain a concrete collection of values, like a list, struct, etc. Here are our collector methods available to you:

- `collect()` - Return an array of the final elements.
- `collect()` - Return an ArrayList of the final elements.
- `collectAsArray()` - Return a CFML Array of the final elements.
- `collectGroupingBy( classifier )` - Build a final collection according to the classifier lambda/closure that will classify the keys in the group. This is usually a structure of elements.
- `collectAverage( mapper, primitive=long )` - Collect an average according to the mapper function/closure.
- `collectSum( mapper, primitive=long )` - Collect a sum according to the mapper function/closure.
- `collectSummary( mapper, primitive=long )` - Collect a statistics struct according to the mapper function/closure .
- `collectAsList( delimiter=",", prefix, suffix )` - Collect results into a string list with a delimiter and attached prefix and/or suffix.
- `collectAsSet()` - Collect the items to a set which doesn't include duplicate elements.
- `collectAsStruct( keyID, valueID, overwrite=true )` - Collect the elements into a struct by leveraging the key identifier and the value identifier from the stream of elements to pass into the collection.
- `collectAsMap( keyID, valueID, overwrite=true )` - Collect the elements into a HashMap by leveraging the key identifier and the value identifier from the stream of elements to pass into the collection.
- `collectAsStruct( keyID, valueID, overwrite=true )` - Collect the elements into a CFML struct by leveraging the key identifier and the value identifier from the stream of elements to pass into the collection.
- `collectPartitioningBy( predicate )` - partitions the input elements according to a Predicate closure/lambda, and organizes them into a Struct of <Boolean, array >.


Expand Down
26 changes: 25 additions & 1 deletion test-harness/tests/specs/MainTests.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,23 @@
} );

given( "The default array collector", function(){
then( "it will produce an array collection", function(){
then( "it will produce an array", function(){
var results = new cbStreams.models.Stream( [ "aa", "aa", "bb", "c", "d", "c" ] ).collect();
expect( results ).toBeInstanceOf( "java.util.ArrayList" );
expect( results.size() ).toBe( 6 );
} );
} );

given( "The CFML array collector", function(){
then( "it will produce a CFML array", function(){
var results = new cbStreams.models.Stream( [ "aa", "aa", "bb", "c", "d", "c" ] ).collectAsArray();
expect( results ).notToBeInstanceOf( "java.util.ArrayList" );
expect( results.len() ).toBe( 6 );
} );
} );

given( "The set collector", function(){
then( "it will produce an set collection", function(){
var setOfNames = new cbStreams.models.Stream( [ "aa", "aa", "bb", "c", "d", "c" ] ).collectAsSet();
expect( setOfNames.size() ).toBe( 4 );
} );
Expand Down Expand Up @@ -460,9 +476,17 @@
} );


given( "The map collector and a key and id mapper", function(){
then( "it will produce a struct of the collection of those mappers", function(){
var results = new cbStreams.models.Stream( people ).collectAsMap( "id", "name" );
expect( results ).toBeInstanceOf( "java.util.HashMap" );
} );
} );

given( "The struct collector and a key and id mapper", function(){
then( "it will produce a struct of the collection of those mappers", function(){
var results = new cbStreams.models.Stream( people ).collectAsStruct( "id", "name" );
expect( results ).notToBeInstanceOf( "java.util.HashMap" );
expect( results ).toBeStruct();
} );
} );
Expand Down

0 comments on commit 315c292

Please sign in to comment.