All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fluxtion.compiler.builder.dataflow.FlowBuilder Maven / Gradle / Ivy

/*
 * Copyright (c) 2025 gregory higgins.
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Server Side Public License, version 1,
 * as published by MongoDB, Inc.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Server Side Public License for more details.
 *
 * You should have received a copy of the Server Side Public License
 * along with this program.  If not, see
 * .
 */

package com.fluxtion.compiler.builder.dataflow;

import com.fluxtion.runtime.EventProcessorBuilderService;
import com.fluxtion.runtime.dataflow.FlowFunction;
import com.fluxtion.runtime.dataflow.FlowSupplier;
import com.fluxtion.runtime.dataflow.TriggeredFlowFunction;
import com.fluxtion.runtime.dataflow.aggregate.AggregateFlowFunction;
import com.fluxtion.runtime.dataflow.aggregate.function.AggregateFlowFunctionWrapper;
import com.fluxtion.runtime.dataflow.aggregate.function.FixSizedSlidingWindow;
import com.fluxtion.runtime.dataflow.aggregate.function.TimedSlidingWindow;
import com.fluxtion.runtime.dataflow.aggregate.function.TumblingWindow;
import com.fluxtion.runtime.dataflow.function.BinaryMapFlowFunction.BinaryMapToRefFlowFunction;
import com.fluxtion.runtime.dataflow.function.*;
import com.fluxtion.runtime.dataflow.function.MapFlowFunction.MapRef2RefFlowFunction;
import com.fluxtion.runtime.dataflow.groupby.*;
import com.fluxtion.runtime.dataflow.helpers.Aggregates;
import com.fluxtion.runtime.dataflow.helpers.Collectors;
import com.fluxtion.runtime.dataflow.helpers.DefaultValue;
import com.fluxtion.runtime.dataflow.helpers.DefaultValue.DefaultValueFromSupplier;
import com.fluxtion.runtime.dataflow.helpers.Mappers;
import com.fluxtion.runtime.partition.LambdaReflection.SerializableBiFunction;
import com.fluxtion.runtime.partition.LambdaReflection.SerializableFunction;
import com.fluxtion.runtime.partition.LambdaReflection.SerializableSupplier;

import java.util.*;

public class FlowBuilder extends AbstractFlowBuilder> implements FlowDataSupplier> {


    FlowBuilder(TriggeredFlowFunction eventStream) {
        super(eventStream);
        EventProcessorBuilderService.service().add(eventStream);
    }

    @Override
    protected FlowBuilder connect(TriggeredFlowFunction stream) {
        return new FlowBuilder<>(stream);
    }


    @Override
    protected  FlowBuilder connectMap(TriggeredFlowFunction stream) {
        return new FlowBuilder<>(stream);
    }


    @Override
    protected FlowBuilder identity() {
        return this;
    }

    public FlowSupplier flowSupplier() {
        return eventStream;
    }

    public FlowBuilder defaultValue(T defaultValue) {
        return map(new DefaultValue<>(defaultValue)::getOrDefault);
    }

    public FlowBuilder defaultValue(SerializableSupplier defaultValue) {
        return map(new DefaultValueFromSupplier<>(defaultValue)::getOrDefault);
    }

    public  FlowBuilder lookup(SerializableFunction lookupKeyFunction,
                                           SerializableFunction lookupFunction,
                                           SerializableBiFunction enrichFunction) {
        return new FlowBuilder<>(new LookupFlowFunction<>(eventStream, lookupKeyFunction, lookupFunction, enrichFunction));
    }

    //PROCESSING - START
    public  FlowBuilder map(SerializableFunction mapFunction) {
        return super.mapBase(mapFunction);
    }

    public FlowBuilder> mapToSet() {
        return map(Collectors.toSet());
    }

    public  FlowBuilder> mapToSet(SerializableFunction mapFunction) {
        return map(mapFunction).map(Collectors.toSet());
    }

    public FlowBuilder> mapToList() {
        return map(Collectors.toList());
    }

    public FlowBuilder> mapToCollection() {
        return map(Collectors.toCollection());
    }

    public  FlowBuilder> mapToList(SerializableFunction mapFunction) {
        return map(mapFunction).map(Collectors.toList());
    }

    public FlowBuilder> mapToList(int maxElements) {
        return map(Collectors.toList(maxElements));
    }

    public  FlowBuilder> mapToList(SerializableFunction mapFunction, int maxElements) {
        return map(mapFunction).map(Collectors.toList(maxElements));
    }

    public  FlowBuilder mapBiFunction(SerializableBiFunction int2IntFunction,
                                               FlowBuilder stream2Builder) {
        return new FlowBuilder<>(
                new BinaryMapToRefFlowFunction<>(
                        eventStream, stream2Builder.eventStream, int2IntFunction)
        );
    }

    public FlowBuilder merge(FlowBuilder streamToMerge) {
        return new FlowBuilder<>(new MergeFlowFunction<>(eventStream, streamToMerge.eventStream));
    }

    @SuppressWarnings("unchecked")
    public FlowBuilder merge(FlowBuilder streamToMerge, FlowBuilder... streamsToMerge) {
        List> mergeList = new ArrayList<>();
        mergeList.add(eventStream);
        mergeList.add(streamToMerge.eventStream);
        for (FlowBuilder flowBuilder : streamsToMerge) {
            mergeList.add(flowBuilder.eventStream);
        }
        return new FlowBuilder<>(new MergeFlowFunction<>(mergeList));
    }

    public  FlowBuilder flatMap(SerializableFunction> iterableFunction) {
        return new FlowBuilder<>(new FlatMapFlowFunction<>(eventStream, iterableFunction));
    }

    public  FlowBuilder flatMap(SerializableFunction> iterableFunction, String flatMapCompleteSignal) {
        FlatMapFlowFunction> flatMapIteratorFlowFunction = new FlatMapFlowFunction<>(eventStream, iterableFunction);
        flatMapIteratorFlowFunction.setFlatMapCompleteSignal(flatMapCompleteSignal);
        return new FlowBuilder<>(flatMapIteratorFlowFunction);
    }

    public  FlowBuilder flatMapFromIterator(SerializableFunction> iterableFunction) {
        return new FlowBuilder<>(new FlatMapIteratorFlowFunction<>(eventStream, iterableFunction));
    }

    public  FlowBuilder flatMapFromIterator(SerializableFunction> iterableFunction, String flatMapCompleteSignal) {
        FlatMapIteratorFlowFunction> flatMapIteratorFlowFunction = new FlatMapIteratorFlowFunction<>(eventStream, iterableFunction);
        flatMapIteratorFlowFunction.setFlatMapCompleteSignal(flatMapCompleteSignal);
        return new FlowBuilder<>(flatMapIteratorFlowFunction);
    }

    public  FlowBuilder flatMapFromArray(SerializableFunction iterableFunction) {
        return new FlowBuilder<>(new FlatMapArrayFlowFunction<>(eventStream, iterableFunction));
    }

    public  FlowBuilder flatMapFromArray(SerializableFunction iterableFunction, String flatMapCompleteSignal) {
        FlatMapArrayFlowFunction> flatMapIteratorFlowFunction = new FlatMapArrayFlowFunction<>(eventStream, iterableFunction);
        flatMapIteratorFlowFunction.setFlatMapCompleteSignal(flatMapCompleteSignal);
        return new FlowBuilder<>(flatMapIteratorFlowFunction);
    }

    public > FlowBuilder
    aggregate(SerializableSupplier aggregateFunction) {
        return new FlowBuilder<>(new AggregateFlowFunctionWrapper<>(eventStream, aggregateFunction));
    }

    public > FlowBuilder
    tumblingAggregate(SerializableSupplier aggregateFunction, int bucketSizeMillis) {
        return new FlowBuilder<>(
                new TumblingWindow<>(eventStream, aggregateFunction, bucketSizeMillis));
    }

    public > FlowBuilder
    slidingAggregate(SerializableSupplier aggregateFunction, int bucketSizeMillis, int bucketsPerWindow) {
        return new FlowBuilder<>(
                new TimedSlidingWindow<>(eventStream, aggregateFunction, bucketSizeMillis, bucketsPerWindow));
    }

    public > FlowBuilder
    slidingAggregateByCount(SerializableSupplier aggregateFunction, int elementsInWindow) {
        return new FlowBuilder<>(
                new FixSizedSlidingWindow<>(eventStream, aggregateFunction, elementsInWindow));
    }

    /**
     * Aggregates a flow using a key function to group by and an aggregating function to process new values for a keyed
     * bucket.
     *
     * @param keyFunction               The key function that groups and buckets incoming values
     * @param valueFunction             The value that is extracted from the incoming stream and applied to the aggregating function
     * @param aggregateFunctionSupplier A factory that supplies aggregating functions, each function has its own function instance
     * @param                        Value type extracted from the incoming data flow
     * @param                       The type of the key used to group values
     * @param                        The return type of the aggregating function
     * @param                        The aggregating function type
     * @return A GroupByFlowBuilder for the aggregated flow
     */
    public > GroupByFlowBuilder
    groupBy(SerializableFunction keyFunction,
            SerializableFunction valueFunction,
            SerializableSupplier aggregateFunctionSupplier) {
        MapFlowFunction, TriggeredFlowFunction> x = new MapRef2RefFlowFunction<>(eventStream,
                new GroupByFlowFunctionWrapper<>(keyFunction, valueFunction, aggregateFunctionSupplier)::aggregate)
                .defaultValue(GroupBy.emptyCollection());
        return new GroupByFlowBuilder<>(x);
    }

    /**
     * Specialisation of groupBy where the value is the identity of the incoming data flow
     *
     * @param keyFunction               The key function that groups and buckets incoming values
     * @param aggregateFunctionSupplier A factory that supplies aggregating functions, each function has its own function instance
     * @param                       The type of the key used to group values
     * @param                        The return type of the aggregating function
     * @param                        The aggregating function type
     * @return A GroupByFlowBuilder for the aggregated flow
     * @see FlowBuilder#groupBy(SerializableFunction, SerializableFunction, SerializableSupplier)
     */
    public > GroupByFlowBuilder
    groupBy(SerializableFunction keyFunction, SerializableSupplier aggregateFunctionSupplier) {
        return groupBy(keyFunction, Mappers::identity, aggregateFunctionSupplier);
    }

    /**
     * Specialisation of groupBy where the output of the groupBy is the last value received for a bucket. The value is
     * extracted using the value function
     *
     * @param keyFunction   The key function that groups and buckets incoming values
     * @param valueFunction The value that is extracted from the incoming stream and applied to the aggregating function
     * @param            Value type extracted from the incoming data flow
     * @param           The type of the key used to group values
     * @return A GroupByFlowBuilder for the aggregated flow
     * @see FlowBuilder#groupBy(SerializableFunction, SerializableFunction, SerializableSupplier)
     */
    public  GroupByFlowBuilder groupBy(
            SerializableFunction keyFunction,
            SerializableFunction valueFunction) {
        return groupBy(keyFunction, valueFunction, Aggregates.identityFactory());
    }

    /**
     * Specialisation of groupBy where the output of the groupBy is the last value received for a bucket, where
     * the value is the identity of the incoming data flow
     *
     * @param keyFunction The key function that groups and buckets incoming values
     * @param          The type of the key used to group values
     * @return A GroupByFlowBuilder for the aggregated flow
     */
    public  GroupByFlowBuilder groupBy(SerializableFunction keyFunction) {
        return groupBy(keyFunction, Mappers::identity);
    }

    /**
     * Creates a GroupByFlowBuilder using a compound key created by a set of method reference accessors to for the value.
     * The value is the last value supplied
     *
     * @param keyFunctions multi arg key accessors
     * @return GroupByFlowBuilder keyed on properties
     */
    @SafeVarargs
    public final GroupByFlowBuilder, T> groupByFields(
            SerializableFunction... keyFunctions) {
        return groupBy(GroupByKey.build(keyFunctions));
    }

    /**
     * Aggregates a flow using a key to group by and an aggregating function to process new values for a keyed
     * bucket. The key is a compound key created by a set of method reference accessors to for the value.
     *
     * @param aggregateFunctionSupplier A factory that supplies aggregating functions, each function has its own function instance
     * @param keyFunctions              multi arg key accessors
     * @param                        The return type of the aggregating function
     * @param                        The aggregating function type
     * @return A GroupByFlowBuilder for the aggregated flow
     * @see FlowBuilder#groupBy(SerializableFunction, SerializableFunction, SerializableSupplier)
     */
    @SafeVarargs
    public final > GroupByFlowBuilder, A> groupByFieldsAggregate(
            SerializableSupplier aggregateFunctionSupplier,
            SerializableFunction... keyFunctions) {
        return groupBy(GroupByKey.build(keyFunctions), aggregateFunctionSupplier);
    }

    /**
     * Creates a GroupByFlowBuilder using a compound key created by a set of method reference accessors to for the key
     * The value is extracted from the input using the value function
     *
     * @param valueFunction the value that will be stored in the groupBy
     * @param keyFunctions  multi arg key accessors
     * @return GroupByFlowBuilder keyed on properties
     */
    @SafeVarargs
    public final  GroupByFlowBuilder, V> groupByFieldsAndGet(
            SerializableFunction valueFunction,
            SerializableFunction... keyFunctions) {
        return groupBy(GroupByKey.build(keyFunctions), valueFunction);
    }

    /**
     * Creates a GroupByFlowBuilder using a compound key created by a set of method reference accessors to for the key
     * The value is extracted from the input using the value function and is used as an input to the aggregating function
     *
     * @param valueFunction             the value that will be stored in the groupBy
     * @param aggregateFunctionSupplier A factory that supplies aggregating functions, each function has its own function instance
     * @param keyFunctions              multi arg key accessors
     * @param                        Value type extracted from the incoming data flow
     * @param                        The return type of the aggregating function
     * @param                        The aggregating function type
     * @return A GroupByFlowBuilder for the aggregated flow
     * @see FlowBuilder#groupBy(SerializableFunction, SerializableFunction, SerializableSupplier)
     */
    @SafeVarargs
    public final > GroupByFlowBuilder, A> groupByFieldsGetAndAggregate(
            SerializableFunction valueFunction,
            SerializableSupplier aggregateFunctionSupplier,
            SerializableFunction... keyFunctions) {
        return groupBy(GroupByKey.build(keyFunctions), valueFunction, aggregateFunctionSupplier);
    }

    public  GroupByFlowBuilder> groupByToList(SerializableFunction keyFunction) {
        return groupBy(keyFunction, Mappers::identity, Collectors.listFactory());
    }

    /**
     * Aggregates a set of instances into a multimap style structure. The key is a compound key made up from the accessors
     * of the input data
     *
     * @param keyFunctions The accessors that make up the compound key
     * @return The GroupByFlowBuilder that represents the multimap
     */
    @SafeVarargs
    public final GroupByFlowBuilder, List> groupByToList(SerializableFunction... keyFunctions) {
        return groupByFieldsAggregate(Collectors.listFactory(), keyFunctions);
    }


    public  GroupByFlowBuilder> groupByToList(
            SerializableFunction keyFunction, SerializableFunction valueFunction) {
        return groupBy(keyFunction, valueFunction, Collectors.listFactory());
    }

    public  GroupByFlowBuilder> groupByToSet(SerializableFunction keyFunction) {
        return groupBy(keyFunction, Mappers::identity, Collectors.setFactory());
    }

    /**
     * Aggregates a set of instances into a multiset style structure. The key is a compound key made up from the accessors
     * of the input data
     *
     * @param keyFunctions The accessors that make up the compound key
     * @return The GroupByFlowBuilder that represents the multimap
     */
    @SafeVarargs
    public final GroupByFlowBuilder, Set> groupByToSet(SerializableFunction... keyFunctions) {
        return groupByFieldsAggregate(Collectors.setFactory(), keyFunctions);
    }

    public  GroupByFlowBuilder> groupByToSet(SerializableFunction keyFunction, SerializableFunction valueFunction) {
        return groupBy(keyFunction, valueFunction, Collectors.setFactory());
    }

    public  GroupByFlowBuilder> groupByToList(
            SerializableFunction keyFunction,
            int maxElementsInList) {
        return groupBy(keyFunction, Mappers::identity, Collectors.listFactory(maxElementsInList));
    }

    public > GroupByFlowBuilder
    groupByTumbling(SerializableFunction keyFunction,
                    SerializableFunction valueFunction,
                    SerializableSupplier aggregateFunctionSupplier,
                    int bucketSizeMillis) {
        return new GroupByFlowBuilder<>(new GroupByTumblingWindow<>(
                eventStream,
                aggregateFunctionSupplier,
                keyFunction,
                valueFunction,
                bucketSizeMillis
        ));
    }

    public  GroupByFlowBuilder
    groupByTumbling(SerializableFunction keyFunction,
                    SerializableFunction valueFunction,
                    int bucketSizeMillis) {
        return groupByTumbling(keyFunction, valueFunction, Aggregates.identityFactory(), bucketSizeMillis);
    }

    public > GroupByFlowBuilder
    groupBySliding(SerializableFunction keyFunction,
                   SerializableFunction valueFunction,
                   SerializableSupplier aggregateFunctionSupplier,
                   int bucketSizeMillis,
                   int numberOfBuckets) {
        return new GroupByFlowBuilder<>(new GroupByTimedSlidingWindow<>(
                eventStream,
                aggregateFunctionSupplier,
                keyFunction,
                valueFunction,
                bucketSizeMillis,
                numberOfBuckets
        ));
    }

    public  GroupByFlowBuilder
    groupBySliding(SerializableFunction keyFunction,
                   SerializableFunction valueFunction,
                   int bucketSizeMillis,
                   int numberOfBuckets) {
        return groupBySliding(keyFunction, valueFunction, Aggregates.identityFactory(), bucketSizeMillis, numberOfBuckets);
    }

    public > GroupByFlowBuilder
    groupBySliding(SerializableFunction keyFunction,
                   SerializableSupplier aggregateFunctionSupplier,
                   int bucketSizeMillis,
                   int numberOfBuckets) {
        return new GroupByFlowBuilder<>(new GroupByTimedSlidingWindow<>(
                eventStream,
                aggregateFunctionSupplier,
                keyFunction,
                Mappers::identity,
                bucketSizeMillis,
                numberOfBuckets
        ));
    }

    public > Z mapOnNotify(I target) {
        return super.mapOnNotifyBase(target);
    }


    /*
    Done:
    ================
    add peek to primitive streams
    Use transient reference in any stream that has an instance function reference. Remove anchor
    add standard predicates for primitives
    De-dupe filter
    mapOnNotify

    optional:
    ================
    add peek functions to support log and audit helpers
    zip - really just a stateful function
     */

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy