Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
.vs/
dist/
Copy link
Owner

@jaredmahan jaredmahan Sep 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would you want the dist folder in source control?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npm has a configuration that allow for reference a package from source control (https://blog.npmjs.org/post/154387331670/the-right-tool-for-the-job-why-not-to-use-version.html). I must admit that i dont remember if having dist folder on source control was needed, but at the time a did it

node_modules/
59 changes: 47 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
## Recently patched and updated! Looking For Contributors.
## Recently patched and updated! Looking For Contributors.

# odata-query-builder

An eloquently fluent OData query builder.

[![Build Status](https://travis-ci.org/jaredmahan/angular-searchFilter.svg?branch=master)](https://travis-ci.org/jaredmahan/odata-query-builder)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)

## Install

```
yarn add odata-query-builder
```

or

```
npm install --save odata-query-builder
```

### Then in your code...

```
const query = new QueryBuilder()
.count()
Expand All @@ -28,17 +33,19 @@ const query = new QueryBuilder()
.toQuery()
```

Outputs:
Outputs:
`?$orderby=MyPriorityProp&$top=5&$skip=5&$count=true&$expand=NavigationProp&$filter=Property eq 'MyValue'`

# Filtering

## Filter Expressions
Filter expresssions utilize [logical operators](http://docs.oasis-open.org/odata/odata/v4.01/cs01/part2-url-conventions/odata-v4.01-cs01-part2-url-conventions.html#sec_LogicalOperatorExamples) to filter data on a specific property.

Filter expresssions utilize [logical operators](http://docs.oasis-open.org/odata/odata/v4.01/cs01/part2-url-conventions/odata-v4.01-cs01-part2-url-conventions.html#sec_LogicalOperatorExamples) to filter data on a specific property.

Operator Options:

- Equal: `eq`
- Not Eqaul: `ne`
- Not Equal: `ne`
- Greater Than: `gt`
- Greater Than or Equal: `ge`
- Less Than: `lt`
Expand All @@ -50,10 +57,12 @@ const query = new QueryBuilder()
f.filterExpression('Property1', 'eq', 'Value1')
).ToQuery();
```

Outputs: `?$filter=Property1 eq 'Value1'`

## Filter Phrases
Filter phrases are meant to be used with [canonical functions](http://docs.oasis-open.org/odata/odata/v4.01/cs01/part2-url-conventions/odata-v4.01-cs01-part2-url-conventions.html#sec_CanonicalFunctions). Filter Phrasing exposes the filter as a string which allows you to inject any of the various filtering mechanisms available in `OData v4`.

Filter phrases are meant to be used with [canonical functions](http://docs.oasis-open.org/odata/odata/v4.01/cs01/part2-url-conventions/odata-v4.01-cs01-part2-url-conventions.html#sec_CanonicalFunctions). Filter Phrasing exposes the filter as a string which allows you to inject any of the various filtering mechanisms available in `OData v4`.

Below are a few examples:

Expand All @@ -70,29 +79,54 @@ const query = new QueryBuilder()
.filterPhrase(`substring(Property1, 1, 2) eq 'ab'`)
).ToQuery();
```

Outputs: `?$filter=contains(Property1,'Value1') and startswith(Property1,'Value1') and endswith(Property1,'Value1') and indexOf(Property1,'Value1') eq 1 and length(Property1) eq 19 and substring(Property1, 1, 2) eq 'ab`

## Conditional Filtering Operators
By default when you utilize `.filter` you are using the `and` operator. You can be explict by passing your operator into the filter as a secondary parameter.

By default, when you utilize `.filter` you are using the `and` operator. You can be explict by passing your operator into the filter as a secondary parameter.

```
const query = new QueryBuilder().filter(f => f
.filterExpression('Property1', 'eq', 'Value1')
.filterExpression('Property2', 'eq', 'Value1'),
'and'
{ operator: 'and' }
).toQuery();
```

Outputs: `?$filter=Property1 eq 'Value1' and Property2 eq 'Value1'`

```
const query = new QueryBuilder().filter(f => f
.filterExpression('Property1', 'eq', 'Value1')
.filterExpression('Property2', 'eq', 'Value1'),
'or'
{ operator: 'or' }
).toQuery();
```

Outputs: `?$filter=Property1 eq 'Value1' or Property2 eq 'Value1'`

## Controlling `.filter` Behaviour

By default `.filter` method cleans all previous filters applied before when called again. This can be changed by providing a `{ cleanPreviousFilters: false }` as an option parameter.

```
const queryBuilder = new QueryBuilder().filter(f => f
.filterExpression('Propertie1', 'eq', 'Value')
)

const query = queryBuilder.filter(f => f
.filterExpression('Propertie2', 'eq', 'Value1'),
{ cleanPreviousFilters: false }
).toQuery()
```

Outputs: `?$filter=Property1 eq 'Value1' or Property2 eq 'Value1'`

## Nested Filter Chaining

Nested or [grouped](http://docs.oasis-open.org/odata/odata/v4.01/cs01/part2-url-conventions/odata-v4.01-cs01-part2-url-conventions.html#sec_Grouping) filtering is used when we need to write a more complex filter for a data set. This can be done by utilizing `.and()` or `.or()` with the filter.

```
const query = new QueryBuilder().filter(f => f
.filterExpression('Property1', 'eq', 'Value1')
Expand All @@ -103,6 +137,7 @@ Nested or [grouped](http://docs.oasis-open.org/odata/odata/v4.01/cs01/part2-url-
)
).toQuery();
```

Outputs: `?$filter=Property1 eq 'Value1' and Property2 eq 'Value2' and (Property3 eq 'Value3' and Property4 eq 'Value4')`

```
Expand All @@ -115,10 +150,11 @@ Outputs: `?$filter=Property1 eq 'Value1' and Property2 eq 'Value2' and (Property
)
).toQuery();
```
Outputs: `?$filter=Property1 eq 'Value1' and Property2 eq 'Value2' and (Property3 eq 'Value3' or Property4 eq 'Value4')`

Outputs: `?$filter=Property1 eq 'Value1' and Property2 eq 'Value2' and (Property3 eq 'Value3' or Property4 eq 'Value4')`

### Reminder: We can still explicitly control the conditional operators within each of the filters by utilizing the filter's condition operator parameter which gives us even more control over the filter.

```
const query = new QueryBuilder().filter(f => f
.filterExpression('Property1', 'eq', 'Value1')
Expand All @@ -127,9 +163,8 @@ Outputs: `?$filter=Property1 eq 'Value1' and Property2 eq 'Value2' and (Property
.filterExpression('Property3', 'eq', 'Value3')
.filterExpression('Property4', 'eq', 'Value4')
),
'and'
{ operator: 'and' }
).toQuery();
```
Outputs: `?$filter=Property1 eq 'Value1' and Property2 eq 'Value2' and (Property3 eq 'Value3' or Property4 eq 'Value4')`


Outputs: `?$filter=Property1 eq 'Value1' and Property2 eq 'Value2' and (Property3 eq 'Value3' or Property4 eq 'Value4')`
42 changes: 42 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Generated by dts-bundle v0.7.3

export enum FragmentType {
OrderBy = 1,
Top = 2,
Skip = 3,
Count = 4,
Expand = 5,
Filter = 6,
Select = 7
}

type filterExpressionType = string | number | boolean | Date;
export default class FilterBuilder {
filterExpression: (field: string, operator: string, value: filterExpressionType) => this;
filterPhrase: (phrase: string) => this;
and: (predicate: (filter: FilterBuilder) => FilterBuilder) => this;
or: (predicate: (filter: FilterBuilder) => FilterBuilder) => this;
toQuery: (operator: string) => string;
}
export class QueryBuilder {
orderBy: (fields: string) => this;
top: (top: number) => this;
skip: (skip: number) => this;
count: () => this;
expand: (fields: string) => this;
select: (fields: string) => this;
filter: (predicate: (filter: FilterBuilder) => FilterBuilder, options?: {
operator?: string;
clearPreviousFilters?: boolean;
}) => this;
clear: (fragmentType: FragmentType) => this;
toQuery: () => string;
}
export {};

export class QueryFragment {
type: FragmentType;
value: string;
constructor(type: FragmentType, value: string);
}

2 changes: 2 additions & 0 deletions dist/index.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/index.js.map

Large diffs are not rendered by default.

Loading