kg-tree 0.1.6

Generic object tree with Opath query language, similar to XPath.
Documentation
# kg-tree

[![Latest Version](https://img.shields.io/crates/v/kg-tree.svg)](https://crates.io/crates/kg-tree)
[![Documentation](https://docs.rs/kg-tree/badge.svg)](https://docs.rs/kg-tree)
[![Build Status](https://travis-ci.org/Kodegenix/kg-tree.svg?branch=master)](https://travis-ci.org/Kodegenix/kg-tree)
[![codecov](https://codecov.io/gh/kodegenix/kg-tree/branch/master/graph/badge.svg)](https://codecov.io/gh/kodegenix/kg-tree)

Generic object tree with Opath query language, similar to XPath.

## Builds statuses for Rust channels

| stable            | beta              | nightly           |
|-------------------|-------------------|-------------------|
| [![Build1][3]][4] | [![Build2][2]][4] | [![Build3][1]][4] |

[1]: https://travis-matrix-badges.herokuapp.com/repos/kodegenix/kg-tree/branches/master/1
[2]: https://travis-matrix-badges.herokuapp.com/repos/kodegenix/kg-tree/branches/master/2
[3]: https://travis-matrix-badges.herokuapp.com/repos/kodegenix/kg-tree/branches/master/3
[4]: https://travis-ci.org/kodegenix/kg-tree


## Opath
Simple language for object tree lookup and transformation, similar to XPath in function.

### Data types
All data types transferable through `json`, `yaml` and `toml` formats are supported.
* *null* - empty value
* *number* - internally stored as either 64-bit integer or 64-bit float
* *boolean* - `true` or `false`
* *string* - strings are stored as UTF-8 encoded data.
* *binary* - binary data.
* *object* - object or map, can contain string-keyed properties
* *array* - array or sequence of elements
* *date* - **to be implemented!!**

### Literals
* `123`, `-2` - 64-bit integer values
* `1.13`, `.e10`, `-1E-2`, `.3` - 64-bit float values
* `'id'`, `"id"` - string values
* `true`, `false` - boolean values
* `null` - null value

### Type conversions
Same as ECMAScript, integers promoted to floats when mixed operands (do rozwiniecia)

### Mathematical operators
Typical mathematical operators and parentheses are supported.
* `2 + 3`, `@.count + 1` - numerical addition
* `2 - 3`, `@.count - 1` - numerical subtraction
* `2 * 3`, `@.count * 2` - numerical multiplication
* `2 / 3`, `@.count / 2` - numerical division
* `2 + 6 / 2` - yields value `5`, as expected
* `(2 + 6) / 2` - yields value `4`

Internally, type conversion is avoided as long as possible, i.e. adding two integer values will yield integer sum.

### String concatenation
If any of the addition operands has a string value, addition will become string concatenation
* `2 + "3"`, `"2" + 3` - both expressions yield string value `"23"`
* `"John" + " " + 'Doe'` - yields `"John Doe"`

### Comparison operators
* `2 > 3`
* `2 >= 3`
* `2 < 3`
* `2 <= 3`
* `2 == 3`
* `2 != 3`
* `'aaabbb' ^= 'aa'` - `true` if left string operand starts with right string operand
* `'aaabbb' *= 'aa'` - `true` if left string operand contains right string operand
* `'aaabbb' $= 'bb'` - `true` if left string operand ends with right string operand

### Logical operators
* `not true`, `!true`
* `true and true`, `true && true`
* `true or true`, `true || true`

### Number ranges
* `:10` - range from `0` (inclusive) to `10` (inclusive)
* `1:10` - range from `1` (inclusive) to `10` (inclusive)
* `0:2:10` - range from `0` (inclusive) to `10` (inclusive) with `2` increments
* `5:-0.1:-1.4` - floats in ranges are also supported
* `1..10` - range from `1` (inclusive) to `10` (inclusive)
* `..10` - range from `0` (inclusive) to `10` (inclusive)

### Context
Every `Opath` expression is executed in the context of **root** (denoted `$`) and **current** (denoted `@`) elements. To access any element in the object tree, it's relation to the **current** (`@`) or **root** (`$`) element needs to be defined, much like for paths in the filesystem are relative to the current directory, or filesystem root. For expressions based at the **current** element, explicit denotion of `@` can usually be omitted.
* `@.name` - returns the value of property "name" from the **current** element
* `name` - same as above
* `$.name` - returns the value of property "name" from the **root** element

### Indexing for arrays
Array elements can be accessed with `[]` notation. Arrays are indexed starting from `0`.
* `@[0]` - returns the first element of the **current** array
* `@[0, 1..3, 5]` - arrays can be indexed by multiple comma-separated indices as well as ranges of indices
* `@[-1,-2]` - negative indices are calculated from the end of an array, `-1` being the last element of an array
* `@[3..]` - when using ranges in array indexing expressions (inside `[]`), range ending value can be omitted, and it will be equal to the array length (number of array elements)

Accessing array with out-of-bounds index values yields empty result. Accessing array element on a non-array and non-object type yields empty result.

### Property access for objects
Properties in objects can be accessed with typical `.` or `[]` notations.
* `name` - returns the value of property "name" from the **current** element
* `@[name]` - same as above, with `[]` notation
* `[name]` - this is illegal!
* `@."name"`, `@["name"]` - property names can be quoted, and if so, can contain spaces and special characters
* `"name"` - this is string literal, not property access!
* `@.(first_name, last_name, age)` - one can select a few properties with a single expression using parentheses

Accessing an nonexistent property yields empty result. Accessing a property on a non-object type also yields empty result.

### Property indexing for objects
Every object can also be indexed as an array, where index value will correspond with property position within the object.
For example if **current** object will be:
```json
{
   "first_name": "John",
   "last_name": "Doe"
}
```
expression `@[1]` will yield string value `"Doe"` (value of the secod property). Objects have strictly defined and stable insertion order of properties.

### Property / element filtering
Properties in objects or elements in arrays can also be filtered with logical expressions inside `[]` notation.
* `@[@.@key $= "name"]` - yields **current** element property values for which property name ends with `"name"`.
* `@[@.@index >= 3]` - yields **current** element properties / elements with index greater or equal `3`

Note that inside the `[]` expression the **current** element (`@`) becomes the child of the outer element.

### Property / element access wildcard operator `*`
* `@.*`, `@[*]` - yields all properties of the **current** object or all elements of the **current** array, or empty result, depending on the **current** type
* `@.(@.star)` - if **current** has a `"star"` property with value `"*"` this will proto.work the same as above (FIXME byc moze to dzialanie trzeba bedzie zmienic)

### Property / element access recursive descent operator `**`
* `@.**`, `@[**]` - yields all properties of the **current** object, and recursively all of their properties in depth-first descending order.
* `@."**"`, `@['**']` - this will also proto.work as above.
* `@.(@.starstar)` - if **current** has a `"starstar"` property with value `"**"` this will proto.work the same as above (FIXME byc moze to dzialanie trzeba bedzie zmienic)
* `@.**{1,4}`, `@.**{,4}`, `@.**{2}`, `@.**{0,2}`- optionally depth level range can be specified. The depth level is specified relative from the element being accessed (**current** in those examples). 
If minimal depth level value is omitted, `1` is assumed.
If maximal depth level is omitted, descend operator will be unbound from the top, i.e. will continue for all descendants. 
If minimal depth level value is `0`, the result will also include accessed element itself.

### Parent access operator `^`
* `@^` - this yields parent element of the **current** element. 
* `@.name^` - if **current** element is an object and contains "name" property, this expression will yield **current** element.

### Ascendant access recursive operator `^**`
* `@^**` - yields all ascendants of the **current** element, in order of decreasing depth. The last element will be **root**.
* `@^**{1,4}`, `@^**{,4}`, `@^**{2}`- optionally recursive distance range can be specified, analogically like for `**`. The distance is specified relative from the element being accessed.
* `@^(@.starstar)` - if **current** has a `"starstar"` property with value `"**"` this will proto.work the same as above (FIXME byc moze to dzialanie trzeba bedzie zmienic)

### Metadata (attributes)
All elements contain readable metadata (attributes). Those attributes are accessed like regular properties, but with name prefixed with `@` character.
* `@.@index` - index of **current** element in its parent (if the parent is an object, this will be the property position)
* `@.@key` - property name of **current** element in its parent (for arrays this will be string value of index)
* `@.@level` - distance from the **root** element for **current** element,
* `@.@kind` - string value of **current** element's kind, either one of `"null"`, `"boolean"`, `"number"`, `"string"`, `"object"`, `"array"` FIXME (date, binary)
* `@.@file` - string describing the file or file structure, **current** element was read from (if any), for instance `"file<yaml>:./data.yml"`.
* `@.@file_type`- string with file type (if any), either `"file"` or `"dir"`
* `@.@file_format`- string with file format (if any), supported values are: `"json"`, `"yaml"`, `"toml"`, `"text"`, `"binary"` 
* `@.@file_path`- string with file path (if any), for instance `"./data.yml"`
* `@.@file_name`- string with file name (if any), for instance `"data.yml"`
* `@.@file_stem`- string with file stem (if any), for instance `"data"`. For file names starting with `"."`, like `".data.yml"` stem will be `".data"` 
* `@.@file_ext`- string with file extension (if any), for instance `"yml"`
* `@.@path` - path to the **current** element from the **root**, for instance `"$.nested.array[3]"`

## License

Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE]LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT]LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

## Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

## Copyright

Copyright (c) 2018 Kodegenix Sp. z o.o. [http://www.kodegenix.pl](http://www.kodegenix.pl)