npm package: @litemotion/tree
Description: Convet array of object to tree
Author: Simon CHAM
Latest version: 0.0.2

# @litemtion/tree

A simple class to convert an array of elements to a tree with aggregation attributes in the tree.

## Illustration

```mermaid
flowchart LR
  
  subgraph LIST
    a["{orderNo:'123', price:456 .. ..}"]
    b["{orderNo:'123', price:67 .. ..}"]
    c["{orderNo:'223', price:89 .. ..}"]
  end

  subgraph TREE
    root[" "]
    subgraph x["orderNo:123"]
      xx["maxPrice: 456"]
      x1["rows"]
    end
    x2["{orderNo:'123', price:456 .. ..}"]
    x3["{orderNo:'123', price:67 .. ..}"]
    subgraph y["orderNo:223"]
      yy["maxPrice: 89"]
      y1["rows"]
    end
    y2["{orderNo:'223', price:89 .. ..}"]
  end
  
  LIST --> TREE
  root --- x
  root --- y
  x --- x1
  y --- y1
  x1 --- x2
  x1 --- x3
  y1 --- y2

```

## Example

```ts
// import the library
import {Tree} from '@litemotion/tree'

// an array to be converted to a tree
const list = [
  {id:1, name:'Gether',  score:13 , class:'1B'},
  {id:2, name:'Wyan',    score:32 , class:'1A'},
  {id:3, name:'Reisman', score:23 , class:'1B'},
  {id:4, name:'Peter',   score:50 , class:'1A'},
  {id:5, name:'Simon',   score:20 , class:'2B'},
  {id:6, name:'Jay',     score:26 , class:'2D'},
]

// define the config of the tree
const config = {
  // all element with the same key will group together 
  // and the element will be added to `rows` property of the tree.
  key(el:any)=>`${el.class}`
  // define an aggregate property maxScore which is the max of 
  // score of the elements of the group, 
  // with the helper function `Tree.Max`.
  maxScore:Tree.Max("score","maxScore")
}

// initialize a tree maker with the config
let tree = new Tree(config)
// generate the output 
let t = tree.fromArray(list)
```

The output will look like:

```ts
 {
      "1B": {
        "key": "1B",
        "rows": [
          { "id": 1,"name": "Gether", "score": 13, "class": "1B" },
          { "id": 3, "name": "Reisman", "score": 23, "class": "1B" }
        ],
        "maxScore": 23
      },
      "1A": {
        "key": "1A",
        "rows": [ 
          { "id": 2, "name": "Wyan", "score": 32, "class": "1A" },
          { "id": 4, "name": "Peter", "score": 50, "class": "1A" }
        ],
        "maxScore": 50
      },
      "2B": {
        "key": "2B",
        "rows": [
          { "id": 5, "name": "Simon", "score": 20, "class": "2B" }
        ],
        "maxScore": 20
      },
      "2D": {
        "key": "2D",
        "rows": [
          { "id": 6, "name": "Jay", "score": 26, "class": "2D" }
        ],
        "maxScore": 26
      }
    }
```

## API

### Tree

Class `Tree` is initialzed with `TreeConfig` object. 

```ts
const tree = new Tree(config);
```

The instance of the `Tree` has several methods to parse an array.

- `.fromArray(rows:any[])`

- `.fromArrayToArray(rows:any[])`

The instance also has a method to parse the resulting object back to an array.

- `.toArray(object:any)`


### TreeConfig

The configuration to define how a `Tree` instance to perform its parsing. It contains the following parts:

- key generator - a *function* to define a key of a tree.
- childrenName - (optional) a *string* to define the name of property of a tree to hold its elements. Default is `rows`
- attribute functions - (optional) any number of *functions* which create attributes of a tree, based on the elements of a tree.

### Tree.Count(..)

`Tree.Count()` is a helper function to assign the attribute with the number of elements of a tree.

Example:
```ts
let config:TreeConfig = {
  count:Tree.Count(),
  ...
}
```

### Tree.Max(..)

`Tree.Max(source, target)` where `source` is the name of source property in an element and `target` is the name of the resulting  property of a tree.
This helper function is to assign the target property of a tree with the maximum of values of the source property of its elements.

Example:
```ts
let config:TreeConfig = {
  maxPrice:Tree.Max("price","maxPrice"),
  ...
}
```

### Tree.Min(..)

`Tree.Min(source, target)` where `source` is the name of source property in an element and `target` is the name of the resulting  property of a tree.
This helper function is to assign the target property of a tree with the minimum of values of the source property of its elements.

Example:
```ts
let config:TreeConfig = {
  minPrice:Tree.Min("price","minPrice"),
  ...
}
```

### Tree.Sum(..)

`Tree.Sum(source, target)` where `source` is the name of source property in an element and `target` is the name of the resulting  property of a tree.
This helper function is to assign the target property of a tree with the sum of the values of the source property of its elements.

Example:
```ts
let config:TreeConfig = {
  totalPrice:Tree.Sum("price","totalPrice"),
  ...
}
```

### Custom attribute function

You may define a custom attribute function which is of type `AttributeFunction` `(el:any, t:any) => any`. 
In the type `AttributeFunction`, `el` is the element of a tree and `t` is the tree holding the element.

In the following example, a tree will have an attribute `lastName` which value is the `name` of the last elment of the tree.
```ts
let config:TreeConfig = {
  key(el:any) => `${el.class}::${el.name}`,
  lastName : (el:any,t:any)=>`${el.name}`
}
```
This looks like a SQL
```sql
 select class as key, name as lastName 
 from sometable
 group by class, name
```

Sometimes both `el` and `t` are required. In the following example, 
a tree has an attribute `evenCount` to count how many elements with even price.
```ts
let config:TreeConfig = {
  key(el:any) => `${el.class}`,
  evenCount : (el:any,t:any)=>{
    if( !t.evenCount ) t.evenCount = 0
    if( el.price % 2 == 0) t.evenCount++
    return t.evenCount
  }
}
```