# # Risk Querying

Sometimes in calculations we need to perform some complex operations i.e. making decisions by looking into all child risks e.g. return the sum of `bodilyInjury`

premium across all child risks or how many child risks are there for a given risk.

## # `bc.risk`

The rater provides `bc.risk`

utility which can be used to query information from risk currently being rated or from all of its child risks.

### # `bc.risk.number`

Returns the risk number. This can be used to identify whether its a first risk, second risk and so on.

```
bc.risk.number
```

### # `bc.risk.term_premium`

Returns the term premium from current risk.

```
bc.risk.term_premium
```

### # `bc.risk.pro_rata_premium`

Returns the pro rata premium from current risk.

```
bc.risk.pro_rata_premium
```

### # `bc.risk.get({lookup}, {default: optional})`

Query information from the current risk, an optional `default`

value can be provided which is returned when the query is not resolved, by default it will return `None`

.

```
bc.risk.get('fields.someField')
```

This will return the value of `someField`

or `None`

if the query is not resolved.

## # `bc.risk.{descendants-risks}`

This is the most powerful feature of risk querying which gives you access to perform aggregated operations on descendants risks.

### # `bc.risk.descendants({depth})`

Returns specific descendants risks of provided `depth`

. `depth`

is a number which tell system to grab risks from that particular level only.

If we have following Risk Type hierarchy:

```
- Policy
- Vehicle
- Driver
- Violation
```

2

3

4

Querying at Policy level:

```
bc.risk.descendants(1) # Returns risks at first level so only `Vehicle` risks will be returned
bc.risk.descendants(2) # Returns risks at second level so only `Driver` risks will be returned
bc.risk.descendants(3) # Returns risks at third level so only `Violation` risks will be returned
```

2

3

### # `bc.risk.descendants_up_to({depth})`

Returns descendants risks up to provided `depth`

. `depth`

is a number which tell system to grab risks up to that particular level only.

If we have following Risk Type hierarchy:

```
- Policy
- Vehicle
- Driver
- Violation
```

2

3

4

Querying at Policy level:

```
bc.risk.descendants_up_to(1) # Returns risks up to first level so only `Vehicle` risks will be returned
bc.risk.descendants_up_to(2) # Returns risks up to second level so `Vehicle` and `Driver` risks will be returned
bc.risk.descendants_up_to(3) # Returns risks up to third level so `Vehicle`, `Driver` and `Violation` risks will be returned
```

2

3

### # `bc.risk.all_descendants`

Returns all descendants risks.

If we have following Risk Type hierarchy:

```
- Policy
- Vehicle
- Driver
- Violation
```

2

3

4

Querying at Policy level:

```
bc.risk.all_descendants
```

Above will return all descendants risks so `Vehicle`

, `Driver`

and `Violation`

risks will be returned.

### # `bc.risk.children`

Convenience method to get specific descendants risks of first level. This is similar to `bc.risk.descendants(1)`

.

### # `bc.risk.grandchildren`

Convenience method to get specific descendants risks of second level. This is similar to `bc.risk.descendants(2)`

.

### # `bc.risk.great_grandchildren`

Convenience method to get specific descendants risks of third level. This is similar to `bc.risk.descendants(3)`

.

## # Aggregated Operations

As described earlier aggregated operations can be performed on descendants risks. All the examples hereon can be used with:

`bc.risk.descendants({depth})`

`bc.risk.descendants_up_to({depth})`

`bc.risk.all_descendants`

`bc.risk.children`

`bc.risk.grandchildren`

`bc.risk.great_grandchildren`

Not just limited to `bc.risk.children`

. For simplicity we'll only use `bc.risk.children`

for aggregation in examples hereon.

### # Lookups

The aggregated operations are based on a `lookup`

expression that is used to define which field to aggregate on.

#### # Supported lookups

Here we're using `sum`

as the example aggregation operation, but it can be any supported aggregation operation defined in the following sub-sections.

**bc.items**`bc.risk.children.sum(bc.items.bodilyInjury.premium.term.value)`

1**bc.fields**`bc.risk.children.sum(bc.fields.some_field)`

1**bc.premium**`bc.risk.children.sum(bc.premium.term.value)`

1**bc.calculations**`bc.risk.children.sum(bc.calculations.some_calculation)`

1**bc.rate_tables**`bc.risk.children.sum(bc.rate_tables.some_rate_table)`

1

### # `bc.risk.children.min({lookup})`

Returns the minimum value from all child risks for a given `lookup`

e.g.

```
bc.risk.children.min(bc.items.bodilyInjury.premium.term.value)
```

Above will return the minimum `bodilyInjury`

premium across all child risks. So if child risk 1 `bodilyInjury.premium.term.value`

resolved to 1.0 and child risk 2 `bodilyInjury.premium.term.value`

resolved to 2.0 it will return `1.0`

.

If there are no child risks or query is not resolved then `min`

will return `None`

.

### # `bc.risk.children.max({lookup})`

Returns the maximum value from all child risks for a given `lookup`

e.g.

```
bc.risk.children.max(bc.items.bodilyInjury.premium.term.value)
```

Above will return the maximum `bodilyInjury`

premium across all child risks. So if child risk 1 `bodilyInjury.premium.term.value`

resolved to 1.0 and child risk 2 `bodilyInjury.premium.term.value`

resolved to 2.0 it will return `2.0`

.

If there are no child risks or query is not resolved then `max`

will return `None`

.

### # `bc.risk.children.sum({lookup})`

Returns the sum of all resolved values from all child risks for a given `lookup`

e.g.

```
bc.risk.children.sum(bc.items.bodilyInjury.premium.term.value)
```

Above will return the sum of `bodilyInjury`

premium across all child risks. So if child risk 1 `bodilyInjury.premium.term.value`

resolved to 1.0 and child risk 2 `bodilyInjury.premium.term.value`

resolved to 2.0 it will return `3.0`

.

### # `bc.risk.children.avg({lookup})`

Returns the average of all resolved values from all child risks for a given `lookup`

e.g.

```
bc.risk.children.avg(bc.items.bodilyInjury.premium.term.value)
```

Above will return the average of `bodilyInjury`

premium across all child risks. So if child risk 1 `bodilyInjury.premium.term.value`

resolved to 100.0 and child risk 2 `bodilyInjury.premium.term.value`

resolved to 300 it will return `200.0`

.

### # `bc.risk.children.count({lookup: optional})`

Returns the count of all child risks optionally you can pass lookup which checks its existence.

```
bc.risk.children.count()
```

If a risk has two sub child risks the answer will be `2`

.

```
bc.risk.children.count(bc.items.bodilyInjury)
```

If a risk has two sub child risks but only one of them has `bodilyInjury`

then answer will be `1`

.

### # `bc.risk.children.exists({lookup})`

Returns `True`

or `False`

if provided `lookup`

successfully resolved in any child risks.

```
bc.risk.children.exists(bc.items.bodilyInjury)
```

Returns `True`

if any of child risks has `bodilyInjury`

coverage enabled otherwise will return `False`

.

### # `bc.risk.children.get({lookup}, {default: optional})`

Return the value of a given `lookup`

. This operation should only be accessed after filtering children risks to the point in
which only one risk is found. If there are multiple risks that meet the criteria this operation will fail. An optional `default`

value can be provided which is returned when the query is not resolved, by default it will return `None`

.

```
bc.risk.children.filter(type__name='drivers').get(bc.fields.goodStudent)
```

Returns the value of the `goodStudent`

field for the `drivers`

Risk Type or `None`

if the query is not resolved.

## # Children Operations

### # `bc.risk.children.order_by({lookup}, {direction: optional})`

Sorts the children risks based on a field defined by the `lookup`

.
A direction parameter can be provided. If not provided, it defaults to `asc`

, returning
the results in ascending order. `desc`

is the other valid value. In this case, the results are returned in descending order.

```
bc.risk.children.order_by(bc.items.bodilyInjury.premium.term.value)
```

Returns the children ordered by their `bodilyInjury`

coverage term premium, smallest first.

```
bc.risk.children.order_by(bc.items.bodilyInjury.premium.term.value, 'desc')
```

Returns the children ordered by their `bodilyInjury`

coverage term premium, smallest last.

### # `bc.risk.children.limit({count})`

Return a subset of the children risks, limited to the number defined by `count`

.

```
bc.risk.children.limit(2)
```

Returns only the first two children. If the original children set is empty, an empty set is returned. If the original children set contains 1 child, only this child is returned.

## # Filtering

Sometimes we want to filter before calling on aggregated operations, for that you can use:

`bc.risk.children.filter(*args, **kwargs)`

This filters child risks using the provided lookup parameters. Lookup parameters can be passed as,

**Keyword filtering**Keyword arguments of type

`fields__lookuptype=value`

where`lookuptype`

specifies the filtering operation e.g.``bc.risk.children.filter(number__gt=2)``

The above filter will match all child risks where the number field is greater than 2.

Each lookup is treated as a conditional clause. If multiple lookups are provided then they are combined using the logical

`and`

operator.For nested fields, double underscore can be used e.g.

``bc.risk.children.filter(fields__mileage__lt=1000)` -> will match all child risks where the mileage is less than 1000 `bc.risk.children.filter(calculations__driverFactor=2.0)` -> will match all child risks where the driverFactor calculation is 2.0 `bc.risk.children.filter(rate_tables__bodilyInjuryBaseRateTable=100)` -> will match all child risks where the bodilyInjuryBaseRateTable rate table is 100 `bc.risk.children.filter(items__bodilyInjury__premium__term__value=2.0)` -> will match all child risks where the bodilyInjury item's term premium is 2.0`

**Positional filtering**Positional arguments of the type

`.filter(Q(...))`

. These can be useful to build conditional clauses that need to be combined using logical`or`

or negated using`not`

``bc.risk.children.filter(Q(number=1) | Q(number=2))``

The above query will only filter the child risk states where number is either 1 or 2

### # Supported lookup types

**exact**exact equality (default)**neq**inequality**contains**containment**icontains**insensitive containment**in**membership**startswith**string startswith**istartswith**insensitive startswith**endswith**string endswith**iendswith**insensitive endswith**gt**greater than**gte**greater than or equal to**lt**less than**lte**less than or equal to**regex**regular expression search**filter**nested filter

### # Examples

`bc.risk.children.filter(type__name='vehicles').min(bc.items.bodilyInjury.premium.term.value)`

This will return minimum

`bodilyInjury`

premium across all child`Vehicle`

risks`bc.risk.children.filter(type__name__in=['vehicles', 'trailers']).min(bc.items.bodilyInjury.premium.term.value)`

This will return minimum

`bodilyInjury`

premium across all child`Vehicle`

or`Trailer`

risks`bc.risk.children.filter(type__name='vehicles').min(bc.calculations.driverFactor)`

This will return the minimum

`driverFactor`

calculation result across all child`Vehicle`

risks`bc.risk.children.filter(type__name='vehicles').min(bc.rate_tables.propertyDamageLimitFactorTable)`

This will return the minimum

`propertyDamageLimitFactorTable`

rate table result across all child`Vehicle`

risks`bc.risk.children.filter(type__name='vehicles').filter(fields__mileage__gte=1000).avg(bc.fields.mileage)`

This will return the average

`mileage`

across all`Vehicle`

risks whose`mileage`

is greater than or equal to 1000.`bc.risk.children.filter(type__name='vehicles').filter(~Q(fields__ratingTier__in=['ratingTier_standard', 'ratingTier_preferred']).count()`

This will return the total count of all the

`Vehicle`

risks whose`ratingTier`

is not`Standard`

or`Preferred`

.

### # Gotchas!

- Filtering should always come before aggregation operations (
`min`

,`max`

,`sum`

, or`count`

). - Filtering should not yield 0 results when using on following aggregated operations
`min`

,`max`

or`sum`

### # Shorthand methods for filtering

Following are the shorthand methods which are provided for convenience:

`bc.risk.{risk_type_name}`

This is an alternative for:

`bc.risk.children.filter(type__name='vehicles')`

1Usage:

`bc.risk.vehicles.count() bc.risk.vehicles.min(bc.items.bodilyInjury.premium.term.value)`

1

2min and max will return

`None`

if there are no risks have been added to the Quote for the referenced Risk Type.