@nsw.io/data
v0.0.1
Published
This library is useful for easily extracting data out of an expression. It indeed uses [JSONata](https://docs.jsonata.org/overview) library but is wrapped to produce a simpler format/raw data.
Downloads
1
Readme
Miner
This library is useful for easily extracting data out of an expression. It indeed uses JSONata library but is wrapped to produce a simpler format/raw data.
Examples
Simple Query
// given
const data = { test: 'foo' };
const field = 'test';
// when
const result = await miner(data, field);
// then
expect(result).toEqual('foo');
Nested Objects
// given
const data = { test: { test2: 'foo' } };
const field = 'test';
// given
const result = await miner(data, field);
// then
expect(result).toEqual({ test2: 'foo' });
Arrays
// given
const data = { test: [{ myField: 'foo' }, { myField: 'bar' }] };
const field = 'test.myField';
// given
const result = await miner(data, field);
// then
expect(result).toEqual(['foo', 'bar']);
Arrays with Filters
//given
const data = {
test: [
{ category: 'a', myField: 'foo' },
{ category: 'b', myField: 'bar' },
{ category: 'b', myField: 'baz' },
],
};
const field = 'test[category="b"].myField';
// when
const result = await miner(data, field);
// then
expect(result).toEqual(['bar', 'baz']);
Complex Queries
//given
const data = {
test: [
{ category: 'a', myField: 1 },
{ category: 'b', myField: 2 },
{ category: 'b', myField: 3 },
{ category: 'b', myField: 4 },
],
};
const field = '$sum(test[category="b" and myField>2].myField)';
// when
const result = await miner(data, field);
// then
expect(result).toEqual(7);
What is this useful for?
Imagine you have an angular application where you need to render a list of information out of your complex data (tables, lists, summaries). With this tool you can create now an angular pipe
@Pipe(name="extract")
export class Extract implements PipeTransform {
transform(data:Record<string, unknown>, field: string): unknown {
return miner(data, field)
}
}
Now in your html you can do
<div *ngFor"let item of elements">
<div class="card">
<h1>item | extract: 'product.name'</h1>
<h2>item | extract: 'product.price' | currency<h2>
</div>
<div>
<div class="total">{{ {data:elements} | extract: '$sum(elements.price)' | currency }}</div>
And it becomes real useful when you don't now what you are displaying. Or your fields are "dynamic"
Let's say we have a database/document that contains the fields we are displaying in a table
@Component({
selector:'my-table',
template: 'my-table.html'
})
class MyTable {
columnsResolver = inject(ColumnsResolverService)
dataResolver = inject(MyDataResolver)
columns$: Observable<Column[]>
data$: Observable<Column[]>
ngOnInit() {
this.columns$ = this.columnsResolver.get()
this.data$ = this.dataResolver.get()
}
}
Now the HTML
<table *ngIf="columns$ | async as columns">
<tr>
<th *ngFor="let col of columns">
{{col.header}}
<th>
<tr>
<ng-container *ngIf="data$ | async as elements">
<tr *ngFor="let element of elements">
<td *ngFor="let col of columns">
{{element | extract: col.field}}
<td>
</tr>
<ng-container>
</table>
And just like that you have a dynamic table based on a set of configurations, as you can see, you don't need to know the column header/fields values NOR structure, as long as field
contains the proper JSONata expression.
This means that if you have complex data like
{
"Account Name": "Firefly",
"Order": [
{
"OrderID": "order103",
"Product": [
{
"Product Name": "Bowler Hat",
"ProductID": 858383,
"Description": {
"Width": 300,
"Height": 200,
"Weight": 0.75
},
"Price": 34.45,
"Quantity": 2
},
{
"Product Name": "Trilby hat",
"ProductID": 858236,
"Description": {
"Width": 300,
"Height": 200,
"Weight": 0.6
},
"Price": 21.67,
"Quantity": 1
}
]
},
]
}
You could navigate through all the levels of your information as long as the field passed to the miner is well/properly formatted. For more information about JSONata expression, visit their site at docs.jsonata.org
Contributing
Building
Run nx build data
to build the library.
Running unit tests
Run nx test data
to execute the unit tests via Jest.