Generators

Generators

Definition of the data is done via instances of type IndexedGenerator. Possible values for those can be found in the package de.awagen.kolibri.datatypes.collections.generators (GitHub Link). These can hold single collections of values or combinations of multiple collections. By using the right combination of those, all kinds of permutations of values can be composed.

So lets say you had multiple stores (lets say identified by storeIds), and they are classified into certain types, and you wanted to request certain queries pro store type. In this case you can create a generator of queries for each store-type, and per store-type a generator of storeIds. You could create a PermutatingIndexedGenerator (see below) for each query-per-type-generator and store-per-type generator, and combine all generators in a OneAfterAnotherIndexedGenerator. This now combines all stores with the right queries. The resulting generator of (storeId, query) pairs could now again be combined with any other generator to provide the needed combinations.

An IndexedGenerator has the following signature:

trait IndexedGenerator[+T] extends KolibriSerializable {
    /** partitioning of the overall data, where each partition is a generator itself, 
    specific for the distinct generator types **/    
    def partitions: IndexedGenerator[IndexedGenerator[T]]
    /** iterator over all elements generated by the generator **/
    def iterator: Iterator[T]
    /** number of elements generated by the generator **/
    def size: Int
    /** partial generator between start (inclusive) and end index (exclusive) **/
    def getPart(startIndex: Int, endIndex: Int): IndexedGenerator[T]
    /** get element specified by given index if index within valid range, otherwise None **/
    def get(index: Int): Option[T]
    /** new generator generating elements by retrieving elements of this generator and applying
    the map function on it **/ 
    def mapGen[B](f: SerializableFunction1[T, B]): IndexedGenerator[B]

}

Generator Types

ByFunctionNrLimitedIndexedGenerator

Takes the number of elements and a function mapping the index to a value. Helper-function ByFunctionNrLimitedIndexedGenerator.createFromSeq takes any Seq and provides a generator generating the elements of the Seq.

BatchBySizeIndexedGenerator

Takes a generator of Seq[T] and a batch size and generates partial generators which in turn generate at most the number of Seq[T] elements given by the batch size (the last element generated might contain less).

BatchByGeneratorIndexedGenerator

Takes Seq of IndexedGenerators and a batchByIndex, and generates generators of Seq[T], where each partial generator corresponds to a single value of the generator provided at index given by batchByIndex. The values for the remaining generators are generated by all possible combinations of the values of each generator.

MergingIndexedGenerator

Takes two generators, generates all possible combinations of values of those generators and applies a mapping function to the pair of values to yield the generated values.

NthIsNthForEachIndexedGenerator

Generator that yields for index n the Seq of values made of one value per generator, while for each generator its n-th element is chosen. Thus no permutations here.

OneAfterAnotherIndexedGenerator

Generator that just starts picking elements from the next generator when the requested element exceeds its own elements, e.g just sequentially provides the elements of the distinct generators.

PartitionByGroupIndexedGenerator

Generator that takes a sequence of generators and acts like a normal OneAfterAnotherIndexedGenerator, e.g will generate the elements of each contained generator sequentially, thus the number of overall elements is the sum of the elements of the single generators. What differs here is the partitions function, which will keep the groups. This partitioning by this generator and still keep logical groups within it, e.g where each generator passed reflects such as logical grouping.

PermutatingIndexedGenerator

Takes a number of generators of same type and generates all permutations of all the values within the distinct generators, where the values generated by the distinct generators will have the same Seq-index as its generator.

Example Use-Cases

TODO: give some basic example use cases showing the composition.

Helper Structures - Define Your Data

The structures below extends the ModifierGeneratorProvider trait, providing to basic defs

trait ModifierGeneratorProvider extends KolibriSerializable {
    def partitions: IndexedGenerator[IndexedGenerator[Modifier[RequestTemplateBuilder]]]
    def modifiers: Seq[IndexedGenerator[Modifier[RequestTemplateBuilder]]]
  }

RequestPermutation

The signature is as follows:

case class RequestPermutation(params: OrderedMultiValues,
                              headers: OrderedMultiValues,
                              bodies: Seq[String],
                              bodyContentType: ContentType = ContentTypes.`application/json`) extends ModifierGeneratorProvider

Mappings: Simplifying composition of data that belongs together

MappingModifier

The definition of MappingModifier can be found in de.awagen.kolibri.base.processing.modifiers.RequestPermutations. It simplifies the logical grouping of data by keys and providing the appropriate generators, combining the data within the group boundaries.

The signature of the MappingModifier is the following:

case class MappingModifier(keyGen: IndexedGenerator[String],
                           paramsMapper: ParamsMapper,
                           headersMapper: HeadersMapper,
                           bodyMapper: BodyMapper) extends ModifierGeneratorProvider

It simply is a combination of a key generator and distinct mappers for parameters, headers and bodies. Per generated key, each of the mappers is checked for existence of a matching generator of type Modifier[RequestTemplateBuilder]. All of those generators for the specific key are then combined in an PermutatingIndexedGenerator. Thus this leads to a Seq of generators, where each generator reflects all permutations (including all varied parameters, headers, bodies) for a single key.

The generator provided by the partitions supplier just provides each of those per-key generators in sequence. The Seq of generators provided by modifiers supplier contains a single element, that is a single OneAfterAnotherIndexedGenerator containing the per-key generators in sequence, that is it will not mix the generators for the single keys, but fully generate the values for a single key before going to the next. In this manner it generates all values for all keys.